Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[s3] fix disabling cloudfront signing with cloudfront_signer=None #1326

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion docs/backends/amazon-S3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,49 @@ Settings
Set this to specify a custom domain for constructed URLs.

.. note::
You'll have to configure CloudFront to use the bucket as an origin for this to work.
You'll have to configure CloudFront to use the bucket as an origin for this to
work.

If your CloudFront config restricts viewer access you will also need to provide
``cloudfront_key`` / ``AWS_CLOUDFRONT_KEY`` and ``cloudfront_key_id`` /
``AWS_CLOUDFRONT_KEY_ID``; See those settings and
:ref:`cloudfront-signed-url-header` for more info.

If you have more than one storage with different viewer access permissions, you
can provide ``cloudfront_signer=None`` to disable signing on one or more
storages.

.. warning::

Django’s STATIC_URL must end in a slash and this must not. It is best to set this variable independently of STATIC_URL.

``cloudfront_key`` or ``AWS_CLOUDFRONT_KEY``

Default: ``None``

A private PEM encoded key to use in a ``boto3`` ``CloudFrontSigner``; See
:ref:`cloudfront-signed-url-header` for more info.

``cloudfront_key_id`` or ``AWS_CLOUDFRONT_KEY_ID``

Default: ``None``

The AWS key ID for the private key provided with ``cloudfront_key`` /
``AWS_CLOUDFRONT_KEY``; See :ref:`cloudfront-signed-url-header` for more info.

``cloudfront_signer``

Default: omitted

By default the ``cloudfront_signer`` is generated based on the CloudFront key and ID
provided. If both are provided URLs will be signed and will work for distributions
with restricted viewer access, but if neither are provided then URLs will not be
signed and will work for distributions with unrestricted viewer access.

If you require a custom CloudFront signer you may pass a ``boto3``
``CloudFrontSigner`` instance that can sign URLs, and to disable signing you may pass
``None``.

``signature_version`` or ``AWS_S3_SIGNATURE_VERSION``

Default: ``None``
Expand Down
7 changes: 5 additions & 2 deletions storages/backends/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ class S3Storage(CompressStorageMixin, BaseStorage):
config = None

def __init__(self, **settings):
self.cloudfront_signer = settings.pop("cloudfront_signer", None)
omitted = object()
self.cloudfront_signer = settings.pop("cloudfront_signer", omitted)

super().__init__(**settings)

Expand Down Expand Up @@ -333,7 +334,7 @@ def __init__(self, **settings):
if self.transfer_config is None:
self.transfer_config = TransferConfig(use_threads=self.use_threads)

if not self.cloudfront_signer:
if self.cloudfront_signer is omitted:
if self.cloudfront_key_id and self.cloudfront_key:
self.cloudfront_signer = self.get_cloudfront_signer(
self.cloudfront_key_id, self.cloudfront_key
Expand All @@ -343,6 +344,8 @@ def __init__(self, **settings):
"Both AWS_CLOUDFRONT_KEY_ID/cloudfront_key_id and "
"AWS_CLOUDFRONT_KEY/cloudfront_key must be provided together."
)
else:
self.cloudfront_signer = None

def get_cloudfront_signer(self, key_id, key):
return _cloud_front_signer_from_pem(key_id, key)
Expand Down
4 changes: 4 additions & 0 deletions tests/test_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,10 @@ def test_cloudfront_config(self):
storage = s3.S3Storage()
self.assertIsNotNone(storage.cloudfront_signer)

# allow disabling cloudfront signing
storage = s3.S3Storage(cloudfront_signer=None)
self.assertIsNone(storage.cloudfront_signer)

storage = s3.S3Storage(cloudfront_key_id=key_id, cloudfront_key=pem)
self.assertIsNotNone(storage.cloudfront_signer)

Expand Down