i'm trying to create a cachePolicy that forward all ( cookies, querystrings and headers ) and acctualy doesn't cache annything at all:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Comment: Cache Policy
DefaultTTL: 0
MaxTTL: 0
MinTTL: 0
Name: !Sub ${AWS::StackName}-cache-policy
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- "*"
QueryStringsConfig:
QueryStringBehavior: all
and my OriginRequestPolicy:
OriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: !Sub ${AWS::StackName}-origin-request
CookiesConfig:
CookieBehavior: all
HeadersConfig:
HeaderBehavior: allViewer
QueryStringsConfig:
QueryStringBehavior: all
but whem i try to upload the stack, i get a generic error:
The following resource(s) failed to create: [OriginRequestPolicy, CachePolicy]. Rollback requested by user. OriginRequestPolicy CREATE_FAILED Resource creation cancelled CachePolicy CREATE_FAILED Invalid request provided: AWS::CloudFront::CachePolicy
what am i missing?
obs: I can't only create an AWS::CloudFront::OriginRequestPolicy cause it's seems that i can only have a OriginRequestPolicy if alredy exists a cacheRequestPolicy first..
I don't know why the "manual way" doesn't work, but i found from the documentation 2 pre-made policies that satisfy my needs:
Name: Managed-CachingDisabled
ID: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
This policy disables caching. This policy is useful for dynamic content and for requests that are not cacheable.
and
Name: Managed-AllViewer
ID: 216adef6-5c7f-47e4-b989-5492eafa07d3
This policy includes all values (query strings, headers, and cookies) in the viewer request.
doc reference:
https://docs.amazonaws.cn/en_us/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html
https://docs.amazonaws.cn/en_us/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html
This error seems to be caused by the name property. For me, having a '.' in the name produces the error.
Nothing is stated regarding this in the documentation unfortunately:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-name
This works:
AWSTemplateFormatVersion: 2010-09-09
Resources:
CachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
DefaultTTL: 1
MaxTTL: 1
MinTTL: 1
Name: test
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
EnableAcceptEncodingBrotli: false
EnableAcceptEncodingGzip: false
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: all
Hyphen in the name works:
AWSTemplateFormatVersion: 2010-09-09
Resources:
CachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
DefaultTTL: 1
MaxTTL: 1
MinTTL: 1
Name: test-id
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
EnableAcceptEncodingBrotli: false
EnableAcceptEncodingGzip: false
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: all
Does not work:
AWSTemplateFormatVersion: 2010-09-09
Resources:
CachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
DefaultTTL: 1
MaxTTL: 1
MinTTL: 1
Name: test-id.test
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
EnableAcceptEncodingBrotli: false
EnableAcceptEncodingGzip: false
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: all
Related
I am trying to create an AWS ElasticSearch Domain (now as AWS OpenSearch service) by cloudformation template but getting error "Resource handler returned message: "null" (RequestToken: 90149a2b-10a1-2609-20e0-9e839731fc2f, HandlerErrorCode: InternalFailure)".
CloudFormation template:
AWSTemplateFormatVersion: "2010-09-09"
Description: ""
Resources:
LogsLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: "/aws/aes/domains/domainName/application-logs"
LogsLogGroup2:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: "/aws/aes/domains/domainName/index-logs"
LogsLogGroup3:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: "/aws/aes/domains/domainName/search-logs"
OpenSearchServiceDomain:
Type: "AWS::OpenSearchService::Domain"
DependsOn:
- LogsLogGroup
- LogsLogGroup2
- LogsLogGroup3
Properties:
DomainName: "domainName"
ClusterConfig:
DedicatedMasterCount: 3
DedicatedMasterEnabled: true
DedicatedMasterType: "c4.large.search"
InstanceCount: 2
InstanceType: "c4.large.search"
ZoneAwarenessEnabled: true
ZoneAwarenessConfig:
AvailabilityZoneCount: 2
WarmEnabled: false
AccessPolicies:
Version: '2012-10-17'
Statement:
-
Effect: 'Allow'
Principal:
AWS: '*'
Action: 'es:*'
Resource: 'arn:aws:es:us-east-1:xxxxxxxxx:domain/domainName/*'
VPCOptions:
SecurityGroupIds:
- !ImportValue "sg-xxxxxxxxx"
SubnetIds:
- !ImportValue "subnet-xxxxxxxxx"
- !ImportValue "subnet-xxxxxxxxx"
- !ImportValue "subnet-xxxxxxxxx"
EncryptionAtRestOptions:
Enabled: true
NodeToNodeEncryptionOptions:
Enabled: true
AdvancedOptions:
"rest.action.multi.allow_explicit_index": "true"
EBSOptions:
EBSEnabled: true
VolumeType: "gp2"
VolumeSize: 200
LogPublishingOptions:
ES_APPLICATION_LOGS:
CloudWatchLogsLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/aes/domains/domainName/application-logs"
Enabled: true
INDEX_SLOW_LOGS:
CloudWatchLogsLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/aes/domains/domainName/index-logs"
Enabled: true
SEARCH_SLOW_LOGS:
CloudWatchLogsLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/aes/domains/domainName/search-logs"
Enabled: true
DomainEndpointOptions:
EnforceHTTPS: true
TLSSecurityPolicy: "Policy-Min-TLS-1-0-2019-07"
AdvancedSecurityOptions:
Enabled: true
InternalUserDatabaseEnabled: true
MasterUserOptions:
MasterUserName: "user"
MasterUserPassword: "password"
We had the same vague error. Adding AmazonOpenSearchServiceFullAccess policy to the deploy user got beyond it.
Just an FYI - you don't need AccessPolicies if you're creating an VPC based Domain OR you don't need Security Groups/Subnets if you're creating an Internet based Domain.
AccessPolicies are only required for an Internet based Domains
VPCOptions are only required for VPC based Domains
Within a SAM template file I have defined an API as well as two Lambda functions that have events configured for a few routes.
At API level I have enabled the caching for the API and a TTL. I would now want to have the caching settings overridden for one of the API routes but I don't seem to find out how to go about doing that.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Elrond API Facade
Resources:
Api:
Type: AWS::Serverless::Api
Properties:
Name: api
StageName: Prod
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- CachingEnabled: true
CacheTtlInSeconds: 30
HttpMethod: '*'
ResourcePath: '/*'
Handler:
Type: AWS::Serverless::Function
Properties:
FunctionName: handler
CodeUri: ./handler
Handler: ./handler/index.handler
Events:
Method:
Type: Api
Properties:
RestApiId: !Ref Api
Path: /method
Method: get
# --> what to add here to override global caching settings?
Lambda functions don't include caching out of the box. Lets try instead to:
Create another "AWS::Serverless::Api" Resource with your new caching needs
Have your intended "AWS::Serverless::Function" resource use it instead.
Here is an example of a new "AWS::Serverless::Api" with more caching added into the mix
Resources:
Api:
Type: AWS::Serverless::Api
Properties:
Name: api
StageName: Prod
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- CachingEnabled: true
CacheTtlInSeconds: 30
HttpMethod: '*'
ResourcePath: '/*'
BiggerCacheApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- CachingEnabled: true
CacheTtlInSeconds: 3000
HttpMethod: '*'
ResourcePath: '/*'
Handler:
Type: AWS::Serverless::Function
Properties:
FunctionName: handler
CodeUri: ./handler
Handler: ./handler/index.handler
Events:
Method:
Type: Api
Properties:
RestApiId: !Ref BiggerCacheApi
Path: /method
Method: get
OtherHandler:
Type: AWS::Serverless::Function
Properties:
...
RestApiId: !Ref Api
...
I have been trying for a day to configure automating a lambda#Edge to be associated with a Distribution through the serverless framework but things aren't working well.
Here is the documentation and they said we can use a predefined cloud front distribution from resources but not shown how?
Here is my Resources.yml that include the S3 bucket and associated two distribution's origins to it:
Resources:
ResourcesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.resourcesBucketName}
AccessControl: Private
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: ['PUT']
AllowedOrigins: ['*']
ResourcesBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: ResourcesBucket
PolicyDocument:
Statement:
# Read permission for CloudFront
- Action: s3:GetObject
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
-
Ref: "ResourcesBucket"
- "/*"
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment:
Fn::Join:
- ""
-
- "Identity for accessing CloudFront from S3 within stack "
-
Ref: "AWS::StackName"
- ""
# I can use this instead of Fn::Join !Sub 'Identity for accessing CloudFront from S3 within stack #{AWS::StackName}' Getting benefit of
# serverless-pseudo-parameters plugin
# Cloudfront distro backed by ResourcesBucket
ResourcesCdnDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
# S3 origin for private resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3-${self:provider.region}.amazonaws.com'
Id: S3OriginPrivate
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
# S3 origin for public resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3-${self:provider.region}.amazonaws.com'
Id: S3OriginPublic
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
Enabled: true
Comment: CDN for public and provate static content.
DefaultRootObject: index.html
HttpVersion: http2
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
TargetOriginId: S3OriginPublic
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
CacheBehaviors:
-
PathPattern: 'private/*'
TargetOriginId: S3OriginPrivate
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
-
PathPattern: 'public/*'
TargetOriginId: S3OriginPublic
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_200
Now I have all set regarding the CloudFront and I just want to add a lambda at the edge to authenticate my private content (The Origin with Id: S3OriginPrivate). So here is my serverless.yml file:
service: mda-app-uploads
plugins:
- serverless-offline
- serverless-pseudo-parameters
- serverless-iam-roles-per-function
custom:
stage: ${opt:stage, self:provider.stage}
resourcesBucketName: ${self:custom.stage}-mda-resources-bucket
provider:
name: aws
runtime: nodejs12.x
stage: ${opt:stage, 'dev'}
region: us-east-1
versionFunctions: true
resources:
- ${file(resources/s3-cloudfront.yml)}
# functions:
functions:
mdaAuthEdge:
handler: mda-edge-auth.handler
events:
- cloudFront:
eventType: viewer-request
origin:
Id: S3OriginPrivate
When deploying I am getting this issue:
TypeError: Cannot read property 'replace' of undefined
This telling that this id already exists and can't be replaced as I think. My main focus is to get the lambda at edge deployed and associated with the cloud front within the serverless framework, so I made another trial to add almost everything to the cloud formation resources and depend only on the serverless framework in deploying the function and here was my serverless.yml and the resources file:
service: mda-app-uploads
plugins:
- serverless-offline
- serverless-pseudo-parameters
- serverless-iam-roles-per-function
custom:
stage: ${opt:stage, self:provider.stage}
resourcesBucketName: ${self:custom.stage}-mda-resources-bucket
provider:
name: aws
runtime: nodejs12.x
stage: ${opt:stage, 'dev'}
region: us-east-1
versionFunctions: true
resources:
# Buckets
- ${file(resources/s3-cloudfront.yml)}
# functions:
functions:
mdaAuthEdge:
handler: mda-edge-auth.handler
role: LambdaEdgeFunctionRole
The resources:
Resources:
LambdaEdgeFunctionRole:
Type: "AWS::IAM::Role"
Properties:
Path: "/"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Sid: "AllowLambdaServiceToAssumeRole"
Effect: "Allow"
Action:
- "sts:AssumeRole"
Principal:
Service:
- "lambda.amazonaws.com"
- "edgelambda.amazonaws.com"
LambdaEdgeFunctionPolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: MainEdgePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
Effect: "Allow"
Action:
- "lambda:GetFunction"
- "lambda:GetFunctionConfiguration"
Resource: !Ref MdaAuthAtEdgeLambdaFunction.Version #!Join [':', [!GetAtt MdaAuthAtEdgeLambdaFunction.Arn, '2']]
Roles:
- !Ref LambdaEdgeFunctionRole
ResourcesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.resourcesBucketName}
AccessControl: Private
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: ['PUT']
AllowedOrigins: ['*']
ResourcesBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: ResourcesBucket
PolicyDocument:
Statement:
# Read permission for CloudFront
- Action: s3:GetObject
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
-
Ref: "ResourcesBucket"
- "/*"
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment:
Fn::Join:
- ""
-
- "Identity for accessing CloudFront from S3 within stack "
-
Ref: "AWS::StackName"
- ""
# I can use this instead of Fn::Join !Sub 'Identity for accessing CloudFront from S3 within stack #{AWS::StackName}' Getting benefit of
# serverless-pseudo-parameters plugin
# Cloudfront distro backed by ResourcesBucket
ResourcesCdnDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
# S3 origin for private resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3-${self:provider.region}.amazonaws.com'
Id: S3OriginPrivate
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
# S3 origin for public resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3-${self:provider.region}.amazonaws.com'
Id: S3OriginPublic
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
Enabled: true
Comment: CDN for public and provate static content.
DefaultRootObject: index.html
HttpVersion: http2
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
TargetOriginId: S3OriginPublic
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
CacheBehaviors:
-
PathPattern: 'private/*'
TargetOriginId: S3OriginPrivate
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
LambdaFunctionAssociations:
-
EventType: origin-request
LambdaFunctionARN: !Ref MdaAuthEdgeLambdaFunction.Version
#!Join [':', [!GetAtt MdaAuthAtEdgeLambdaFunction.Arn, '2']]
# arn:aws:lambda:eu-west-1:219511374676:function:mda-aws-functions-dev-authLambdaAtEdge:1
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
-
PathPattern: 'public/*'
TargetOriginId: S3OriginPublic
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_200
But I've faced many errors related to defining the version and so on. I searched, debugged, and investigated that for many hours but seems hard configuration. Any help on how to get lambda edge works with predefined cloud front through the serverless framework?
It's a bit tricky to do so using a serverless framework but I solved it by combining cloud formation with the serverless framework. I have the answer here to another question which contains a full description of how to do so:
How to access AWS CloudFront that connected with S3 Bucket via Bearer token of a specific user (JWT Custom Auth)
I don't want to repeat everything again here and also I found the question so important and facing many people without a concrete solution so pleas let me know in case you are facing any issue.
The approach is to just create the function inside the serverless.yml then inside the cloud formation you can do all the magic of creating the versions, roles and another function that will help you publish your arn and use it dynamically.
Here is my Serverless.yml:
service: mda-app-uploads
plugins:
- serverless-offline
- serverless-pseudo-parameters
- serverless-iam-roles-per-function
- serverless-bundle
custom:
stage: ${opt:stage, self:provider.stage}
resourcesBucketName: ${self:custom.stage}-mda-resources-bucket
resourcesStages:
prod: prod
dev: dev
resourcesStage: ${self:custom.resourcesStages.${self:custom.stage}, self:custom.resourcesStages.dev}
provider:
name: aws
runtime: nodejs12.x
stage: ${opt:stage, 'dev'}
region: us-east-1
versionFunctions: true
functions:
oauthEdge:
handler: src/mda-edge-auth.handler
role: LambdaEdgeFunctionRole
memorySize: 128
timeout: 5
resources:
- ${file(resources/s3-cloudfront.yml)}
Here is my resources/s3-cloudfront.yml:
Resources:
AuthEdgeLambdaVersion:
Type: Custom::LatestLambdaVersion
Properties:
ServiceToken: !GetAtt PublishLambdaVersion.Arn
FunctionName: !Ref OauthEdgeLambdaFunction
Nonce: "Test"
PublishLambdaVersion:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Runtime: nodejs12.x
Role: !GetAtt PublishLambdaVersionRole.Arn
Code:
ZipFile: |
const {Lambda} = require('aws-sdk')
const {send, SUCCESS, FAILED} = require('cfn-response')
const lambda = new Lambda()
exports.handler = (event, context) => {
const {RequestType, ResourceProperties: {FunctionName}} = event
if (RequestType == 'Delete') return send(event, context, SUCCESS)
lambda.publishVersion({FunctionName}, (err, {FunctionArn}) => {
err
? send(event, context, FAILED, err)
: send(event, context, SUCCESS, {FunctionArn})
})
}
PublishLambdaVersionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: PublishVersion
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: lambda:PublishVersion
Resource: '*'
LambdaEdgeFunctionRole:
Type: "AWS::IAM::Role"
Properties:
Path: "/"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Sid: "AllowLambdaServiceToAssumeRole"
Effect: "Allow"
Action:
- "sts:AssumeRole"
Principal:
Service:
- "lambda.amazonaws.com"
- "edgelambda.amazonaws.com"
LambdaEdgeFunctionPolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: MainEdgePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
Effect: "Allow"
Action:
- "lambda:GetFunction"
- "lambda:GetFunctionConfiguration"
Resource: !GetAtt AuthEdgeLambdaVersion.FunctionArn
Roles:
- !Ref LambdaEdgeFunctionRole
ResourcesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.resourcesBucketName}
AccessControl: Private
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: ['PUT']
AllowedOrigins: ['*']
ResourcesBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: ResourcesBucket
PolicyDocument:
Statement:
# Read permission for CloudFront
- Action: s3:GetObject
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
-
Ref: "ResourcesBucket"
- "/*"
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
- Action: s3:PutObject
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
-
Ref: "ResourcesBucket"
- "/*"
Principal:
AWS: !GetAtt LambdaEdgeFunctionRole.Arn
- Action: s3:GetObject
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
-
Ref: "ResourcesBucket"
- "/*"
Principal:
AWS: !GetAtt LambdaEdgeFunctionRole.Arn
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment:
Fn::Join:
- ""
-
- "Identity for accessing CloudFront from S3 within stack "
-
Ref: "AWS::StackName"
- ""
# Cloudfront distro backed by ResourcesBucket
ResourcesCdnDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
# S3 origin for private resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3.amazonaws.com'
Id: S3OriginPrivate
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
# S3 origin for public resources
- DomainName: !Sub '${self:custom.resourcesBucketName}.s3.amazonaws.com'
Id: S3OriginPublic
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/#{CloudFrontOriginAccessIdentity}'
Enabled: true
Comment: CDN for public and provate static content.
DefaultRootObject: index.html
HttpVersion: http2
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
TargetOriginId: S3OriginPublic
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
CacheBehaviors:
-
PathPattern: 'private/*'
TargetOriginId: S3OriginPrivate
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
LambdaFunctionAssociations:
-
EventType: viewer-request
LambdaFunctionARN: !GetAtt AuthEdgeLambdaVersion.FunctionArn
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
-
PathPattern: 'public/*'
TargetOriginId: S3OriginPublic
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Compress: true
ForwardedValues:
QueryString: false
Headers:
- Origin
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_200
But you will find the full description in my other question's answer.
I am deploying a API which is mapped to a loadbalancer. I could test the API successfully on the console but while using the invoke link in the stage, I am getting a 403. The ELB is a http end point and the invoke url is https which is normal I would say.
Also if I use the ELB DNS Name, I could get the desired result. Looks like requests are not going through API Gateway.
I am doing all of this using Cloudformation and swagger. Here is the relevant part
EmployeeApi:
Type: AWS::ApiGateway::RestApi
Properties:
BodyS3Location:
Bucket: !Ref S3Bucket
Key: "swagger.yaml"
EmployeeApiDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref EmployeeApi
EmployeeApiStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId: !Ref EmployeeApiDeployment
RestApiId: !Ref EmployeeApi
StageName: dev
Variables:
employeeELB:
Fn::ImportValue:
!Sub ${NetworkStackName}-ELB
EmployeeApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: !Ref EmployeeApi
Stage: !Ref EmployeeApiStage
UsagePlanName: Basic
EmployeeApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: employee-api-key
Enabled: true
StageKeys:
- RestApiId: !Ref EmployeeApi
StageName: !Ref EmployeeApiStage
Relevant part of my swagger file is
swagger: "2.0"
info:
version: 1.0.0
title: employee-service
description: Welcome to API documentation of Employee Service
schemes:
- https
securityDefinitions:
api_key:
type: apiKey
name: x-api-key
in: header
x-amazon-apigateway-request-validators:
RequestValidator:
validateRequestBody: true
validateRequestParameters: true
x-amazon-apigateway-request-validator: RequestValidator
paths:
/employees:
get:
security:
- api_key: []
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
uri: http://${stageVariables.employeeELB}/employees
passthroughBehavior: when_no_match
httpMethod: GET
contentHandling: "CONVERT_TO_TEXT"
type: http_proxy
I'm trying to add a dynamodb stream with the following template.yml
MyFunc:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./myfunc
Handler: main
Runtime: go1.x
Events:
MyStream:
Type: DynamoDB
Properties:
Stream: !GetAtt MyTable.StreamArn
BatchSize: 1
StartingPosition: LATEST
Role:
Fn::ImportValue:
!Join ['-', [!Ref 'ProjectId', !Ref 'AWS::Region', 'LambdaTrustRole']]
However, I'm getting the following error during the deploy stage:
Please ensure the role can perform the GetRecords, GetShardIterator, DescribeStream, and ListStreams Actions on your stream in IAM.
Attempt 1
So I tried fixing the problem by adding the following policies to my IAM, CodeStarWorker-myproject-CloudFormation:
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:DescribeStream",
"dynamodb:ListStreams",
That didn't work, still giving me the same error
Attempt 2
Tried using policies stead of role in template.yml
MyFunc:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./myfunc
Handler: main
Runtime: go1.x
Events:
MyStream:
Type: DynamoDB
Properties:
Stream: !GetAtt MyTable.StreamArn
BatchSize: 1
StartingPosition: LATEST
Policies:
- IAMFullAccess
- AWSLambdaFullAccess
But it gave me the following error
API: iam:CreateRole User: arn:aws:sts::xxx:assumed-role/CodeStarWorker-xxx-CloudFormation/AWSCloudFormation is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::xxx:role/awscodestar-xxx-lambda-MyFuncRole-1BO7G545IR5IC
Attempt 3
Specifying a role in template.yml
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow #allow lambda to assume this role
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: LambdaRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow # allow to write logs to cloudwatch
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
- Effect: Allow # allow lambda to read from the event stream
Action:
- dynamodb:DescribeStream
- dynamodb:GetRecords
- dynamodb:GetShardIterator
- dynamodb:ListStreams
Resource: "*"
And assign it to MyFunc
Role:
Fn::GetAtt: [ LambdaRole , Arn ]
However, it's also giving me the same error indicating that I'm not authorized to perform iam:CreateRole
Any help?
iam:CreateRole - you would need this action to create a role. The user that you use to run the Cloudformation template would need to include the "CreateRole" action.