Skip to content

Regression: 403 Auth Failure for S3-hosted (Cloudfront) Private Repos #3303

Closed

Description

@dvf

Issue

  • We noticed a regression from Poetry 1.0.3 to 1.1.4.
  • We're using a private PyPI repository hosted on S3 protected by Cloudfront using Basic Auth (we use s3pypi)

When we tried to install a new private dependency, or remove a non-private dependency (with common sub dependencies with a private dependency) we saw this error:

➜  project git:(master) poetry remove django-structlog
Updating dependencies
Resolving dependencies... (0.2s)

  RepositoryError

  403 Client Error: Forbidden for url: https://XXXXXXXXXXXXXXXX/pyjwt/

  at ~/.poetry/lib/poetry/repositories/legacy_repository.py:393 in _get
      389│             if response.status_code == 404:
      390│                 return
      391│             response.raise_for_status()
      392│         except requests.HTTPError as e:
    → 393│             raise RepositoryError(e)
      394│ 
      395│         if response.status_code in (401, 403):
      396│             self._log(
      397│                 "Authorization error accessing {url}".format(url=url), level="warn"

Hypothesis of why this is happening

By default, Cloudfront returns a 403 for non-existing files. This is a good security practice as it prevents leakage of information to unauthenticated parties. However, (from the above code) Poetry only falls back to public PyPI if it encounters a 404 when requesting a package.

Quick fix

The quick fix for this is to have your private repo (in our case Cloudfront) return a default error response code of 404.
Here are docs on how to do that: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages-response-code.html

Recommendations

Poetry shouldn't fall back to the public repo on a 401/403/404 without first checking if it can successfully auth to the repo. And failing that, it should throw an appropriate error.

Thanks to @proxyroot and @vagelim for helping debug and fix.

Activity

  1. added
    kind/bugSomething isn't working as expected
    status/triageThis issue needs to be triaged
    on Oct 28, 2020
  2. sschrijver commented on Nov 2, 2020

    @sschrijver

    This is also an issue (but maybe slightly different, I receive a "Forbidden" error) with a private PyPI registry that stores packages on S3 (without cloudfront). It returns a s3 URL (with temp auth token) with the message that the request is forbidden, whilst copying the URL and pasting it in a new browser initiates the correct download.

    Downgrading to 1.0.10 solved this error, this error happens from version 1.1.x

  3. abn commented on Nov 2, 2020

    @abn
    Member

    This block

    if response.status_code in (401, 403):
    self._log(
    "Authorization error accessing {url}".format(url=url), level="warn"
    )
    return

    Should move to before

    response.raise_for_status()

  4. abn commented on Nov 2, 2020

    @abn
    Member

    @dvf thank you for the great issue report! 🎉

    Regarding the fallback behaviour, I am reluctant to suggest we change at that at the moment since I think there are cases where authentication/authorsation is not available and a public package can still be added. Happy to discuss that and change behaviour in another issue. For this one, lets treat it as a bug and resolve it as such.

  5. abn commented on Nov 2, 2020

    @abn
    Member

    This is also an issue (but maybe slightly different, I receive a "Forbidden" error) with a private PyPI registry that stores packages on S3 (without cloudfront). It returns a s3 URL (with temp auth token) with the message that the request is forbidden, whilst copying the URL and pasting it in a new browser initiates the correct download.

    @sschrijver think this was reported elsewhere, the issue here is that we use basic authentication as configured along with those requests. The existence of an "Authorization" header the "authorised" url ends up failing on the server side. IIRC, this was an issue with PyPI cloud since it deviates from the defined/expected behaviour for an index. See #3041 (comment) for that bit. I have not looked into the comments after that one yet. Additionally, note that there is the issue that using "authorised" urls will have other side-effects when the token used expires as these are used in the lock file.

  6. cereblanco commented on Nov 3, 2020

    @cereblanco
    Contributor

    hello! if no one started working on this yet, I can create the fix. 💭

  7. jeremysprofile commented on Nov 10, 2020

    @jeremysprofile

    This also affects Sonatype Nexus PyPI repositories when using poetry 1.1.4, and downgrading to 1.0.10 fixes the issue there as well.

  8. added a commit that references this issue on Feb 26, 2024
    3c9ced2
  9. github-actions commented on Mar 2, 2024

    @github-actions

    This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

  10. locked as resolved and limited conversation to collaborators on Mar 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugSomething isn't working as expected

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions