I was looking into options how to serve specific versions of objects on a versioned S3 bucket with CloudFront. After doing some diggin it turned out to be pretty easy. As described in the documentation of S3 on retrieving versions, a specific version can be retrieved from S3 by adding ?version={version} to the url. When configuring CloudFront you must also allow the versionId as query string parameter in the cache settings so it will be passed to the S3 Origin. After this is done and you try to retrieve a specific version you will get a permission denied error. To solve this, you must give CloudFront s3:GetObjectVersion permission to your S3 bucket in the policy.
Complete example in CloudFormation:
Resources:
S3:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${AWS::StackName}-assets'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub '${AWS::StackName}'
S3Policy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3
PolicyDocument:
Statement:
- Sid: CloudFront
Action:
- 's3:GetObject'
- 's3:GetObjectVersion'
Effect: Allow
Resource: { 'Fn::Join': [ '/', [ !GetAtt S3.Arn , '*' ] ] }
Principal:
AWS: { 'Fn::Join': [ ' ', [ 'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity', { Ref: CloudFrontOriginAccessIdentity } ] ] }
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
IPV6Enabled: true
Enabled: true
Comment: !Sub '${AWS::StackName}'
Origins:
- Id: S3
DomainName: !GetAtt S3.DomainName
S3OriginConfig:
OriginAccessIdentity: { 'Fn::Join': [ '/', [ 'origin-access-identity', 'cloudfront', { Ref: CloudFrontOriginAccessIdentity } ] ] }
DefaultCacheBehavior:
AllowedMethods: [ HEAD, OPTIONS, GET ]
CachedMethods: [ HEAD, OPTIONS, GET ]
ForwardedValues:
QueryString: true
QueryStringCacheKeys: [ versionId ]
TargetOriginId: S3
ViewerProtocolPolicy: https-only
Compress: true
You can now get the latest version of your asset by accessing:
https://xyz.cloudfront.net/some_image.jpg
and you can request a specific version like this:
https://xyz.cloudfront.net/some_image.jpg?versionId=abcdef
You now have the benefits of servering versioned content over CloudFront, also giving you the possibility to restrict access to your content with signed cookies or signed urls.
Top comments (0)