I am trying to work out if it's possible to get the ARN of a Lambda function defined in a serverless.yml file to be used within the same file for Lambda#Edge on a CloudFront distribution.
My code is below, right at the bottom I want to specify the ARN of the Lambda function that I have defined within the same serverless file.
Thanks in advance.
functions:
myLambdaFunction:
handler: handler.myLambdaFunction
resources:
Resources:
WebsiteS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: website-bucket
WebsiteConfiguration:
ErrorDocument: index.html
IndexDocument: index.html
WebsiteCloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: website-bucket-cloudfront-origin-access-identity
WebsiteS3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebsiteS3Bucket
PolicyDocument:
Statement:
-
Action:
- "s3:GetObject"
- "s3:ListBucket"
Effect: "Allow"
Resource:
- Fn::Join:
- ""
-
- Fn::GetAtt: [ WebsiteS3Bucket, Arn ]
- "/*"
- Fn::Join:
- ""
-
- Fn::GetAtt: [ WebsiteS3Bucket, Arn ]
Principal:
AWS:
Fn::Join:
- ""
-
- "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity "
- Ref: WebsiteCloudFrontOriginAccessIdentity
WebsiteCloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Origins:
-
DomainName:
Fn::Join:
- ""
-
- Ref: WebsiteS3Bucket
- ".s3.amazonaws.com"
Id:
Ref: WebsiteS3Bucket
S3OriginConfig:
OriginAccessIdentity:
Fn::Join:
- ""
-
- "origin-access-identity/cloudfront/"
- Ref: WebsiteCloudFrontOriginAccessIdentity
CustomErrorResponses:
-
ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
DefaultRootObject: /index.html
DefaultCacheBehavior:
ForwardedValues:
QueryString: true
TargetOriginId:
Ref: WebsiteS3Bucket
ViewerProtocolPolicy: redirect-to-https
LambdaFunctionAssociations:
-
EventType: origin-response
LambdaFunctionARN: ## Lambda function ARN here
Ref: myLambdaFunction
It looks like you're already referencing Ref in your template. This is referenced here as to what the value will be when you use Ref on a Lambda function:
Ref Documentation
I usually reference them via:
!GetAtt [LambdaResourceName, Arn]
Related
I am trying to create a cloud formation stack to deploy a react app from an S3 bucket. The file is below. When I go to the cloud front URL, I get the following error:
ERROR
Failed to contact the origin.
Here is the file
AWSTemplateFormatVersion: 2010-09-09
Parameters:
ProjectSource:
Type: String
Default: "https://github.com/..."
Description: "Source control URL (e.g. Github)"
GithubOwner:
Type: String
Default: (myaccount)
GithubRepo:
Type: String
Default: (myrepo)
GithubOAuthToken:
Type: String
Default: "(my token)"
Description: "Github personal access token"
GithubBranch:
Type: String
Default: master
Description: "e.g. master or main"
Resources:
CodePipeline:
Type: 'AWS::CodePipeline::Pipeline'
Properties:
RoleArn: !GetAtt CodePipeLineRole.Arn
ArtifactStore:
Location: !Ref PipelineBucket
Type: S3
Stages:
-
Name: Source
Actions:
-
Name: SourceAction
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: 1
OutputArtifacts:
-
Name: NameForOutput
Configuration:
Owner: !Ref GithubOwner
Repo: !Ref GithubRepo
Branch: !Ref GithubBranch
OAuthToken: !Ref GithubOAuthToken
-
Name: Build
Actions:
-
Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
InputArtifacts:
-
Name: (NameHere)
OutputArtifacts:
-
Name: (NameBuild)
Configuration:
ProjectName: !Ref CodeBuild
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- "codebuild.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: /service-role/
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
- "s3:PutObjectAcl"
Resource:
- !GetAtt DeployBucket.Arn
- !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "cloudfront:CreateInvalidation"
Resource:
- "*"
CodePipeLineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- "codepipeline.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "codebuild:BatchGetBuilds"
- "codebuild:StartBuild"
Resource: "*"
CodeBuild:
Type: 'AWS::CodeBuild::Project'
Properties:
Name: !Sub ${AWS::StackName}-CodeBuild
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Name: MyProject
Source:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Type: LINUX_CONTAINER
Image: "aws/codebuild/nodejs:10.14.1"
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.1
phases:
pre_build:
commands:
- echo Installing source NPM dependencies...
- npm install
build:
commands:
- echo Build started on `date`
- npm run build
post_build:
on-failure: CONTINUE
commands:
- aws s3 cp --recursive --acl public-read ./build s3://${DeployBucket}/
#uncomment if you have service-worker.js
#- aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/service-worker.js s3://${DeployBucket}/
- aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/index.html s3://${DeployBucket}/
- aws cloudfront create-invalidation --distribution-id ${Distribution} --paths /index.html /service-worker.js
artifacts:
files:
- '**/*'
base-directory: build
PipelineBucket:
Type: 'AWS::S3::Bucket'
Properties: {}
DeployBucket:
Type: 'AWS::S3::Bucket'
Properties:
WebsiteConfiguration:
IndexDocument: index.html
Distribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Origins:
-
DomainName: !GetAtt DeployBucket.DomainName
Id: !Ref DeployBucket
S3OriginConfig:
OriginAccessIdentity: ''
DefaultRootObject: index.html
Enabled: true
DefaultCacheBehavior:
MinTTL: 86400
MaxTTL: 31536000
ForwardedValues:
QueryString: true
TargetOriginId: !Ref DeployBucket
ViewerProtocolPolicy: "redirect-to-https"
Your S3 bucket does not have any policy to allow Cloudfront Distribution to access files. You need to give permission to Cloudfront with CloudFrontOriginAccessIdentity.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
ProjectSource:
Type: String
Default: "https://github.com/..."
Description: "Source control URL (e.g. Github)"
GithubOwner:
Type: String
Default: (myaccount)
GithubRepo:
Type: String
Default: (myrepo)
GithubOAuthToken:
Type: String
Default: "(my token)"
Description: "Github personal access token"
GithubBranch:
Type: String
Default: master
Description: "e.g. master or main"
Resources:
CodePipeline:
Type: 'AWS::CodePipeline::Pipeline'
Properties:
RoleArn: !GetAtt CodePipeLineRole.Arn
ArtifactStore:
Location: !Ref PipelineBucket
Type: S3
Stages:
-
Name: Source
Actions:
-
Name: SourceAction
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: 1
OutputArtifacts:
-
Name: NameForOutput
Configuration:
Owner: !Ref GithubOwner
Repo: !Ref GithubRepo
Branch: !Ref GithubBranch
OAuthToken: !Ref GithubOAuthToken
-
Name: Build
Actions:
-
Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
InputArtifacts:
-
Name: (NameHere)
OutputArtifacts:
-
Name: (NameBuild)
Configuration:
ProjectName: !Ref CodeBuild
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- "codebuild.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: /service-role/
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
- "s3:PutObjectAcl"
Resource:
- !GetAtt DeployBucket.Arn
- !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "cloudfront:CreateInvalidation"
Resource:
- "*"
CodePipeLineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- "codepipeline.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "codebuild:BatchGetBuilds"
- "codebuild:StartBuild"
Resource: "*"
CodeBuild:
Type: 'AWS::CodeBuild::Project'
Properties:
Name: !Sub ${AWS::StackName}-CodeBuild
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Name: MyProject
Source:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Type: LINUX_CONTAINER
Image: "aws/codebuild/nodejs:10.14.1"
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.1
phases:
pre_build:
commands:
- echo Installing source NPM dependencies...
- npm install
build:
commands:
- echo Build started on `date`
- npm run build
post_build:
on-failure: CONTINUE
commands:
- aws s3 cp --recursive --acl public-read ./build s3://${DeployBucket}/
#uncomment if you have service-worker.js
#- aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/service-worker.js s3://${DeployBucket}/
- aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/index.html s3://${DeployBucket}/
- aws cloudfront create-invalidation --distribution-id ${Distribution} --paths /index.html /service-worker.js
artifacts:
files:
- '**/*'
base-directory: build
PipelineBucket:
Type: 'AWS::S3::Bucket'
Properties: {}
DeployBucket:
Type: 'AWS::S3::Bucket'
Properties: {}
Distribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Origins:
-
DomainName: !GetAtt DeployBucket.RegionalDomainName
Id: !Ref DeployBucket
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}'
DefaultRootObject: index.html
Enabled: true
DefaultCacheBehavior:
MinTTL: 86400
MaxTTL: 31536000
ForwardedValues:
QueryString: true
TargetOriginId: !Ref DeployBucket
ViewerProtocolPolicy: "redirect-to-https"
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: 'CloudFront OAI'
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref DeployBucket
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join ['', [!GetAtt DeployBucket.Arn, '/*']]
Principal:
AWS: !Sub 'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}'
I'm starting to build a infrastructure on AWS, the first step is to make a Cloud Front service work with two different S3 buckets (I'm uploading a simple index.html to each bucket). For that I've made the following yaml to deploy via Cloud Formation.
AWSTemplateFormatVersion: "2010-09-09"
Resources:
UserBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: my-user-bucket
Tags:
- Key: description
Value: "User page files"
AdminBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: my-admin-bucket
Tags:
- Key: description
Value: "Admin page files"
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: 'origin identity'
UserBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: my-user-bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Principal:
AWS:
Fn::Join:
- " "
-
- "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity"
-
!Ref CloudFrontOriginAccessIdentity
Resource:
- !Sub arn:aws:s3:::my-user-bucket/*
DependsOn:
- UserBucket
AdminBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: my-admin-bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Principal:
AWS:
Fn::Join:
- " "
-
- "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity"
-
!Ref CloudFrontOriginAccessIdentity
Resource:
- !Sub arn:aws:s3:::my-admin-bucket/*
DependsOn:
- AdminBucket
PublicDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: my-user-bucket.s3.sa-east-1.amazonaws.com
Id: S3-my-user-bucket
S3OriginConfig:
OriginAccessIdentity:
'Fn::Join':
- ''
- - origin-access-identity/cloudfront/
- Ref: CloudFrontOriginAccessIdentity
- DomainName: my-admin-bucket.s3.sa-east-1.amazonaws.com
Id: S3-my-admin-bucket
S3OriginConfig:
OriginAccessIdentity:
'Fn::Join':
- ''
- - origin-access-identity/cloudfront/
- Ref: CloudFrontOriginAccessIdentity
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-user-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
CacheBehaviors:
- PathPattern: user/*
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-user-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
- PathPattern: admin/*
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-admin-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
Enabled: 'true'
Comment: Some comment
DefaultRootObject: index.html
ViewerCertificate:
CloudFrontDefaultCertificate: 'true'
DependsOn:
- UserBucketPolicy
- AdminBucketPolicy
As you can see I'm trying to redirect the requests for user and admin using the Cloud Front Distribution behavior configuration.
I'm able to access the index.html file at foobar.cloudfront.net, for me that means that the OAI is working fine. But both foobar.cloudfront.net/admin/index.html and foobar.cloudfront.net/user/index.html returns the error bellow, so I'm thinking that theres something wrong with the behavior and/or path:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>YRCKS4PAV9C11CR9</RequestId>
<HostId>N9d3NJLrwZY1bECeTmXoQqRuDljsgFQk3C9pt5AX2pZyI4BEhTMCvJDB1uUAaQ4zUlppbvQbyOs=</HostId>
</Error>
Any ideas of what is wrong?
I believe you need to update your BucketPolicies to include both:
Action:
- 's3:GetObject'
- 's3:ListObjects'
and
Resource to be both:
"arn:aws:s3:::my-user-bucket/",
"arn:aws:s3:::my-user-bucket/*"
I have the following configuration in serverless.yml functioning well:
service: fx-crawler-av
frameworkVersion: '2'
provider:
name: aws
runtime: python3.8
lambdaHashingVersion: 20201221
region: eu-west-1
environment:
S3BucketName: !Ref 'S3BucketFXDataStorage'
AlphaVantageAPIKey: ${ssm:AlphaVantageAPIKey}
package:
exclude:
- requirements.txt
- package.json
- package-lock.json
- node_modules/**
- .serverless/**
- .env/**
functions:
fetch_api:
handler: handler.fetch_api
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:PutObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
- "/*"
set_ccy_pair_scope:
handler: handler.set_ccy_pair_scope
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:GetObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
- "/*"
- Effect: "Allow"
Action:
- "s3:ListBucket"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
get_ccy_list:
handler: handler.get_ccy_list
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:GetObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
- "/*"
append_parquet_file:
handler: handler.append_parquet_file
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:GetObject"
- "s3:PutObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
- "/*"
- Effect: "Allow"
Action:
- "s3:ListBucket"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "S3BucketFXDataStorage"
resources:
Resources:
S3BucketFXDataStorage:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Join
- ''
- - !Ref 'AWS::AccountId'
- '-fx-data-storage'
stepFunctions:
stateMachines:
FXCrawler:
events:
- schedule: cron(35 21 * * ? *)
definition:
Comment: "State machine for crawling AlphaVantage API for FX rates"
StartAt: GetCurrencyList
States:
GetCurrencyList:
Type: Task
Resource:
Fn::GetAtt: [get_ccy_list, Arn]
Next: SetCurrencyPairScope
SetCurrencyPairScope:
Type: Task
Resource:
Fn::GetAtt: [set_ccy_pair_scope, Arn]
Next: mapped_task
mapped_task:
Type: Map
ItemsPath: '$.ccy_pair_scope'
MaxConcurrency: 1
Iterator:
StartAt: FetchAPI
States:
FetchAPI:
Type: Task
Resource:
Fn::GetAtt: [fetch_api, Arn]
Next: WaitForAPI
WaitForAPI:
Type: Wait
Seconds: 60
End: true
End: true
plugins:
- serverless-python-requirements
- serverless-iam-roles-per-function
- serverless-step-functions
custom:
pythonRequirements:
slim: true
dockerizePip: true
useDownloadCache: true
Now I would like to add an S3 event trigger to my append_parquet_file function, e.g.:
append_parquet_file:
handler: handler.append_parquet_file
events:
- s3:
bucket: !Ref 'S3BucketFXDataStorage'
event: s3:ObjectCreated:*
rules:
- suffix: .json
But unfortunately this does not seem to work..
I get a warning during deployment Serverless: Configuration warning at 'functions.append_parquet_file.events[0].s3.bucket': should be string
The deployment fails:
Serverless Error ---------------------------------------
[object Object] - Bucket name must conform to pattern (?!^(\d{1,3}\.){3}\d{1,3}$)(^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$). Please check provider.s3.[object Object] and/or s3 events of function "append_parquet_file".
I tried multiple ways to create and inject the bucket name as variable but did not succeed. Any idea what can go wrong?
You don't need to create bucket resouces, according to the docs, you can specify the bucket and add properties you need and bucket will create and configure automatically to setup the trigger
functions:
resize:
handler: resize.handler
events:
- s3: bucketOne
provider:
s3:
bucketOne:
name: my-custom-bucket-name
# Eventual additional properties in camel case
https://www.serverless.com/framework/docs/providers/aws/events/s3#custom-bucket-configuration
You should reference your bucket as follows:
bucket: ${self:resources.Resources.S3BucketFXDataStorage.Properties.BucketName}
All you need is this: (remove the double quotes)
Resource: !Ref S3BucketFXDataStorage
event: s3:ObjectCreated:*
existing: true
and you have another problem in the policies, try this instead to reference you bucket in the policies:
Resource: !Join ["", [!GetAtt S3BucketFXDataStorage.Arn, "/*" ]]
How will I be able to disable or enable the encryption(AES256) on the S3 bucket based on a condition?
TestBucket:
Type: AWS::S3::Bucket
DependsOn: TestSnsTopicPolicy
Properties:
BucketName: !Ref TestBucket
BucketEncryption:
!If
- **conditionForEnableOrDisableEncryption**
-
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
- !Ref "AWS::NoValue"
Tags:
- Key: "EnvironmentName"
Value: !Ref EnvironmentName
- Key: "ProjectName"
Value: !Ref ProjectName
ForceEncryption:
!If
- **conditionForEnableOrDisableEncryption**
-
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref TestBucket
PolicyDocument:
Version: "2008-10-17"
Statement:
- Sid: DenyUnEncryptedObjectUploads
Effect: Deny
Principal: "*"
Action:
- s3:PutObject
Resource:
- !Join ["", ["arn:aws:s3:::", !Ref TestBucket, "/*"]]
Condition:
StringNotEquals:
"s3:x-amz-server-side-encryption":
- "AES256"
DependsOn: TestBucket
- !Ref "AWS::NoValue"
Please refer above code snippet .Iam getting error as "Invalid template resource property 'Fn::If'"
You can create conditions section in your template. For example:
Parameters:
EnableEncryption:
Type: String
Default: false
AllowedValues: [true, false]
Conditions:
ShouldEnableEncryption:
!Equals [!Ref EnableEncryption, true]
Resources:
TestBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref TestBucketName
BucketEncryption:
!If
- ShouldEnableEncryption
-
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
- !Ref "AWS::NoValue"
Tags:
- Key: "EnvironmentName"
Value: !Ref EnvironmentName
- Key: "ProjectName"
Value: !Ref ProjectName
ForceEncryption:
Type: AWS::S3::BucketPolicy
Condition: ShouldEnableEncryption
Properties:
Bucket: !Ref TestBucket
PolicyDocument:
Version: "2008-10-17"
Statement:
- Sid: DenyUnEncryptedObjectUploads
Effect: Deny
Principal: "*"
Action:
- s3:PutObject
Resource:
- !Join ["", ["arn:aws:s3:::", !Ref TestBucket, "/*"]]
Condition:
StringNotEquals:
"s3:x-amz-server-side-encryption":
- "AES256"
I'm trying to create a Yaml template for cloudfront distribution on S3 bucket.
I'm stuck on how to add principal on BucketPolicy.
I want to know how to replace the XXXXXXXXXXX on CloudFront Origin Access Identity XXXXXXXXXXX in principal for a cloudfront that will be generate by deploying the template.
Also is there a way to add the html, css sync procedure (which I'm doing through aws cli now) on yaml template?
Please let me know.
TIA
AWSTemplateFormatVersion: 2010-09-09
Resources:
Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: pridesys.webbucket
AccessControl: Private
WebsiteConfiguration:
IndexDocument: index.html
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Id: ReportPolicy
Version: "2012-10-17"
Statement:
- Sid: "1"
Effect: Allow
Action: "s3:GetObject"
Principal:
AWS: "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
Resource: !Join ['', ['arn:aws:s3:::', !Ref Bucket, '/*']]
Distro:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt Bucket.DomainName
Id: foo
S3OriginConfig: {}
Enabled: True
DefaultRootObject: index.html
DefaultCacheBehavior:
ForwardedValues:
QueryString: False
TargetOriginId: foo
ViewerProtocolPolicy: allow-all
Here is a valid sample of an S3 origin identity configuration for CloudFront:
WebUIBucket:
Type: AWS::S3::Bucket
CloudFrontOriginIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: "origin identity"
WebUIPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebUIBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ CloudFrontOriginIdentity , S3CanonicalUserId ]
Action: "s3:GetObject"
Resource: !Sub "${WebUIBucket.Arn}/*"
WebpageCDN:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub "${WebUIBucket}.s3.amazonaws.com"
Id: webpage
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginIdentity}"
As for the syncing your assets into the S3 bucket, that cannot be provided with CloudFormation functionality. You either have to implement a CustomResource or keep using the CLI.
Thanks a lot #Jens !!
Your solution was a big help. I was getting TargetOriginId & ForwarededValues error while trying to deploy your template.
This is what worked for me -
AWSTemplateFormatVersion: '2010-09-09'
Description: An AWS Serverless Specification template describing your function.
Resources:
WebUIBucket:
Type: AWS::S3::Bucket
CloudFrontOriginIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: "origin identity"
WebUIPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebUIBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ CloudFrontOriginIdentity , S3CanonicalUserId ]
Action: "s3:GetObject"
Resource: !Sub "${WebUIBucket.Arn}/*"
WebpageCDN:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub "${WebUIBucket}.s3.amazonaws.com"
Id: webpage
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginIdentity}"
Enabled: True
DefaultRootObject: index.html
DefaultCacheBehavior:
ForwardedValues:
QueryString: False
TargetOriginId: webpage
ViewerProtocolPolicy: allow-all
Transform: AWS::Serverless-2016-10-31
So you will need to have S3 origin Access Identity setup, and use the !GetAtt S3CanonicalUserId
Here is my code and it works
S3CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: A comment to describe the origin access identity. The comment cannot be longer than 128 characters.
StagingCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt myS3bucket.DomainName
Id: !Ref myS3bucket
S3OriginConfig:
OriginAccessIdentity: !Join ['', ['origin-access-identity/cloudfront/', !Ref S3CloudFrontOriginAccessIdentity]]
myS3BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
Properties:
Bucket: !Ref myS3bucket
PolicyDocument:
Id: myS3bucketPolicy
Version: 2012-10-17
Statement:
- Sid: PutObjectAccess
Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ S3CloudFrontOriginAccessIdentity, S3CanonicalUserId ]
Action:
- s3:GetObject
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref myS3bucket
- /*