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/*"
Related
I have a website hosted on S3 and Cloudfront as distribution.
I would like the bucket to be only accessed by selected domains. I followed multiple AWS documentation files that point that I should forward Referer header, but I can't get it working since I always get 403 error.
The bucket is configured to be public:
FrontendBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.frontendBucketName}
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: 404.html
RoutingRules: ${file(./redirects.json)}
CorsConfiguration:
CorsRules:
- AllowedHeaders: ["*"]
AllowedMethods: ["GET"]
AllowedOrigins: ["*"]
Id: "OpenCors"
MaxAge: "3600"
Then, in order to forward the Referer header, I have created Cloudfront Cache Policy and Cloudfront Origin Request Policy:
CloudfrontCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: cache-policy
Comment: Cache Optimized Policy (forward referer and query string)
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 1
ParametersInCacheKeyAndForwardedToOrigin:
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Referer
QueryStringsConfig:
QueryStringBehavior: all
CloudfronOriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: origin-request-policy
Comment: Origin Request Policy (forward referer query string)
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Referer
QueryStringsConfig:
QueryStringBehavior: all
Then this is my Cloudfront distribution:
CloudfrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn: [FrontendBucket]
Properties:
DistributionConfig:
Enabled: true
Comment: "(${self:provider.stage}-${opt:lang})"
Aliases: ${self:custom.domainCondition.${self:provider.stage}.${opt:lang}, self:custom.domainCondition.other}
ViewerCertificate:
AcmCertificateArn: "${self:custom.certificateCondition.${self:provider.stage}.${opt:lang}, self:custom.certificateCondition.other.${opt:lang}}"
MinimumProtocolVersion: TLSv1.2_2018
SslSupportMethod: sni-only
Origins:
- Id:
Ref: FrontendBucket
DomainName: "${self:custom.frontendBucketName}.s3-website-${self:provider.region}.amazonaws.com"
CustomOriginConfig:
OriginProtocolPolicy: http-only
HTTPPort: 80
HTTPSPort: 443
DefaultCacheBehavior:
TargetOriginId:
Ref: FrontendBucket
ViewerProtocolPolicy: redirect-to-https
Compress: true
CachePolicyId:
Ref: CloudfrontCachePolicy
OriginRequestPolicyId:
Ref: CloudfronOriginRequestPolicy
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
LambdaFunctionAssociations:
- EventType: "origin-request"
LambdaFunctionARN: ${cf.us-east-1:my-website-cle-${self:provider.stage}.RequestCLELambdaFunctionQualifiedArn}
- EventType: "origin-response"
LambdaFunctionARN: ${cf.us-east-1:my-website-cle-${self:provider.stage}.ResponseCLELambdaFunctionQualifiedArn}
As you can see, there is Origin Request Lambda#Edge assigned. I am trying to log event.Records[0].cf.request.headers there, but I can't find the referer header.
And finally this the Bucket Policy:
OnlyDomainAccessPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: FrontendBucket
PolicyDocument:
Statement:
- Sid: "Allow access to the bucket only from MiracleMill website"
Effect: Deny
Action: ["s3:GetObject", "s3:GetObjectVersion"]
Resource: "arn:aws:s3:::${self:custom.frontendBucketName}/*"
Principal: "*"
Condition:
StringNotLike:
aws:Referer:
[
"http://www.example.com/*",
"https://example.com/*",
]
//at this point this should work since the bucket is public but I have also added specific Allow
- Sid: "Allow access to the bucket only from MiracleMill website"
Effect: Allow
Action: ["s3:GetObject", "s3:GetObjectVersion"]
Resource: "arn:aws:s3:::${self:custom.frontendBucketName}/*"
Principal: "*"
Condition:
StringLike:
aws:Referer:
[
"http://www.www.example.com/*",
"https://www.example.com/*",
]
I have a react app with a graphql api. I've managed to get a custom domain working with my react app via cloudfront as follows. But I've been trying to do a similar thing for the functions/graphql lambda with no success.
Is there a way of getting a hostedzoneid and dnsname for my lamda functions too? And setting these in my AWS::Route53::RecordSetGroup configuration?
BTW: I'm aware of serverless-domain-manager and I'm not keen on using it, I prefer to configure via AWS::Route53::RecordSetGroup
service: shopify-aws-poc
provider:
name: aws
profile: serverless-shop-poc
region: us-east-1
runtime: nodejs12.x
environment:
SHOPID: ${env:SHOPID}
plugins:
- serverless-dynamodb-local
- serverless-webpack
- serverless-offline
- serverless-dotenv-plugin
- serverless-s3-sync
custom:
serverless-offline:
host: 0.0.0.0
port: 4001
dontPrintOutput: true
dynamodb:
stages:
- dev
start:
region: localhost
host: localhost
port: 8000
migrate: true
seed: true
seed:
domain:
sources:
- table: 'Shop'
sources: [local/dynamodb/seed/shop.json]
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
bucketName: shop-app-vh8w37h9pjs78rnqfvmhw8
s3Sync:
- bucketName: ${self:custom.bucketName}
localDir: shop-app/build/
functions:
graphql:
handler: ./graphql/shop-api/handler.graphqlHandler
events:
- http:
path: graphql
method: post
cors: true
- http:
path: graphql
method: get
cors: true
resources:
Resources:
ShopTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
Properties:
TableName: 'Shop'
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
ShopAppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.bucketName}
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: index.html
S3AccessPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: ShopAppBucket
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal: '*'
Action:
- s3:GetObject
Resource: arn:aws:s3:::${self:custom.bucketName}/*
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: ${self:custom.bucketName}.s3.amazonaws.com
Id: ShopApp
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
Enabled: true
Aliases:
- g8976g7iuyg.mydomain.xyz
DefaultRootObject: index.html
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
TargetOriginId: ShopApp
ForwardedValues:
QueryString: false
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
ViewerCertificate:
AcmCertificateArn: arn:aws:acm:us-east-1:994996037326:certificate/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1
DNSRecords:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: mydomain.xyz.
RecordSets:
- Name: g8976g7iuyg.mydomain.xyz
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt CloudFrontDistribution.DomainName
I have my static website content put on S3, it has been given public permission and if I visit
http://subdomain.mydomain.com.s3-website-us-east-1.amazonaws.com I see the HTML.
In the Certificate Manager, I have a valid certificate generated for subdomain.mydomain.com
Now is the turn of CloudFront,
picked the correct AWS S3 bucket folder.
bucked hosted in North Virginia
Associated the subdomian certificate
in document root filled the index.html
other settings in place.
Once the site is deployed, I open <cloudfront-random-string>.cloudfront.net
This renders the Static Website as is.
Finally, I head to route53, in the A record I create an alias and insert the <cloudfront-random-string>.cloudfront.net
When I open the subdomain.mydomain.com it renders no response.
What could go wrong?
Not sure if you are getting a 403, but this article may help.
https://aws.amazon.com/premiumsupport/knowledge-center/s3-website-cloudfront-error-403/
Alternatively, you could try creating a Cloudfront Origin Access Identity & give it permission to access your S3 bucket. This way you can keep your S3 bucket private too.
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${DomainName}
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
Tags:
- Key: Domain
Value: !Ref DomainName
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub CloudFront OAI for ${DomainName}
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebsiteBucket
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join [ "", [ "arn:aws:s3:::", !Ref WebsiteBucket, "/*" ] ]
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
WebsiteCloudFront:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebsiteBucketPolicy
Properties:
DistributionConfig:
Comment: Cloudfront Distribution pointing to S3 bucket
Origins:
- DomainName: !GetAtt WebsiteBucket.DomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity:
!Join [ "", [ "origin-access-identity/cloudfront/", !Ref CloudFrontOriginAccessIdentity ] ]
Enabled: true
HttpVersion: 'http2'
DefaultRootObject: index.html
Aliases:
- !Ref DomainName
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
Compress: true
TargetOriginId: S3Origin
ForwardedValues:
QueryString: true
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_100
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArn
SslSupportMethod: sni-only
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
- /*
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]