diff --git a/docs/backends/amazon-S3.rst b/docs/backends/amazon-S3.rst index 969c1075..c087e95f 100644 --- a/docs/backends/amazon-S3.rst +++ b/docs/backends/amazon-S3.rst @@ -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 `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 + `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 `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`` diff --git a/storages/backends/s3.py b/storages/backends/s3.py index 204a6ee3..466489c8 100644 --- a/storages/backends/s3.py +++ b/storages/backends/s3.py @@ -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) @@ -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 @@ -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) diff --git a/tests/test_s3.py b/tests/test_s3.py index e2340f70..36f75b32 100644 --- a/tests/test_s3.py +++ b/tests/test_s3.py @@ -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)