Everything works perfectly in the code below if run without the 4 lines starting NotificationConfiguration . I thought this might be because of needing the topic policy before setting notification on the bucket. So have tried to do the initial create without the NotificationConfiguration lines and then add these in and update the stack.
But get the error Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; . I've tried things like putting the actual topic arn not using !Ref but no joy. Thanks!
Resources:
DeletionSNSTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName:
!Join [" ",[Data has been deleted from,!Sub '${ServiceName}-${Stage}-${AWS::AccountId}']
]
Subscription:
- Endpoint: !Sub '${DeleteNotifyEmail}'
Protocol: email
TopicName: !Sub 'delete-from-${ServiceName}-bucket'
DataBucket:
Type: AWS::S3::Bucket
DependsOn: DeletionSNSTopic
Description: Create Amazon S3 bucket from CloudFormation
Properties:
BucketName: !Sub '${ServiceName}-${Stage}-${AWS::AccountId}'
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
NotificationConfiguration:
TopicConfigurations:
- Topic: !Ref DeletionSNSTopic
Event: 's3:ObjectRemoved:*'
BucketToSNSPermission:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Id: 'deletionTopicPolicy'
Version: '2012-10-17'
Statement:
- Sid: 'deletionTopic-statement-id'
Effect: Allow
Principal:
Service: s3.amazonaws.com
Action: sns:Publish
Resource: !Ref DeletionSNSTopic
Condition:
StringEquals:
aws:SourceAccount: !Sub '${AWS::AccountId}'
ArnLike:
aws:SourceArn: !Ref DataBucket
Topics:
- !Ref DeletionSNSTopic
You have circular dependency in your code. You create bucket with notifications, before topic policy is applied. Obviously the policy can't be created before the bucket because the bucket must already exist due to !Ref DataBucket.
To solve that the bucket name must be known first, which in your case is possible:
Resources:
DeletionSNSTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName:
!Join [" ",[Data has been deleted from,!Sub '${ServiceName}-${Stage}-${AWS::AccountId}']
]
Subscription:
- Endpoint: !Sub '${DeleteNotifyEmail}'
Protocol: email
TopicName: !Sub 'delete-from-${ServiceName}-bucket'
DataBucket:
Type: AWS::S3::Bucket
DependsOn: BucketToSNSPermission
Description: Create Amazon S3 bucket from CloudFormation
Properties:
BucketName: !Sub '${ServiceName}-${Stage}-${AWS::AccountId}'
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
NotificationConfiguration:
TopicConfigurations:
- Topic: !Ref DeletionSNSTopic
Event: 's3:ObjectRemoved:*'
BucketToSNSPermission:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Id: 'deletionTopicPolicy'
Version: '2012-10-17'
Statement:
- Sid: 'deletionTopic-statement-id'
Effect: Allow
Principal:
Service: s3.amazonaws.com
Action: SNS:Publish
Resource: !Ref DeletionSNSTopic
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub "arn:aws:s3:::${ServiceName}-${Stage}-${AWS::AccountId}"
Topics:
- !Ref DeletionSNSTopic
For general case check in:
How do I avoid the "Unable to validate the following destination configurations" error in AWS CloudFormation?
Related
I have activated AWSSamples::S3BucketEncrypt::Hook with the following configuration but S3 bucket creation with encryption enabled seems to be failing because of the hook.
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "AES256"
}
}
}
}
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "aws:kms"
}
}
}
}
The following CloudFormation stacks are supposed to pass but they are failing. They only seem to work when I disable the hook. I have checked the trust policy, which seems fine for CloudFormation to access the hook and S3 bucket.
AWSTemplateFormatVersion: 2010-09-09
Description: S3 bucket with default encryption
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
DeletionPolicy: Delete
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'aws:kms'
KMSMasterKeyID: !Ref EncryptionKey
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
EncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key used to encrypt the resource type artifacts
EnableKeyRotation: true
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: Enable full access for owning account
Effect: Allow
Principal:
AWS: !Ref "AWS::AccountId"
Action: kms:*
Resource: "*"
Outputs:
EncryptedBucketName:
Value: !Ref EncryptedS3Bucket
There were multiple issues
The role need to be created using https://github.com/aws-cloudformation/aws-cloudformation-samples/blob/main/hooks/python-hooks/s3-bucket-encryption/hook-role.yaml
CF Hook Configuration need to be the following
KMS
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "aws:kms"
}
}
}
}
3.1 Use the following CF to create SSE-S3 bucket for point no 3
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'aws:kms'
KMSMasterKeyID: !Ref EncryptionKey
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
EncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key used to encrypt the resource type artifacts
EnableKeyRotation: true
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: Enable full access for owning account
Effect: Allow
Principal:
AWS: !Ref "AWS::AccountId"
Action: kms:*
Resource: "*"
Outputs:
EncryptedBucketName:
Value: !Ref EncryptedS3Bucket
OR
SSE-S3
AWSTemplateFormatVersion: 2010-09-09
Description: S3 bucket with default encryption
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'aesencryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
DeletionPolicy: Delete
4.1 Use the following CF to create SSE-S3 bucket for point no 4
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
I have a requirement to select all the rules in AWS Config while deploying the resources in newly created account through Cloudformation. But I don't know how to select all the AWS Managed rules as in Console through Cloudformation. Any help would be very helpful.
AWSTemplateFormatVersion: 2010-09-09
Description: Enable AWS Config
Parameters:
AllSupported:
Type: String
Default: True
Description: Indicates whether to record all supported resource types.
AllowedValues:
- True
- False
IncludeGlobalResourceTypes:
Type: String
Default: True
Description: Indicates whether AWS Config records all supported global resource types.
AllowedValues:
- True
- False
ResourceTypes:
Type: List<String>
Description: A list of valid AWS resource types to include in this recording group, such as AWS::EC2::Instance or AWS::CloudTrail::Trail.
Default: <All>
DeliveryChannelName:
Type: String
Default: <Generated>
Description: The name of the delivery channel.
Frequency:
Type: String
Default: 24hours
Description: The frequency with which AWS Config delivers configuration snapshots.
AllowedValues:
- 1hour
- 3hours
- 6hours
- 12hours
- 24hours
Conditions:
IsAllSupported: !Equals
- !Ref AllSupported
- True
IsGeneratedDeliveryChannelName: !Equals
- !Ref DeliveryChannelName
- <Generated>
Mappings:
Settings:
FrequencyMap:
1hour : One_Hour
3hours : Three_Hours
6hours : Six_Hours
12hours : Twelve_Hours
24hours : TwentyFour_Hours
Resources:
ConfigBucket:
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
ConfigBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ConfigBucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AWSConfigBucketPermissionsCheck
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:GetBucketAcl
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}"
- Sid: AWSConfigBucketDelivery
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:PutObject
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}/AWSLogs/${AWS::AccountId}/*"
- Sid: AWSConfigBucketSecureTransport
Action:
- s3:*
Effect: Deny
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}"
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}/*"
Principal: "*"
Condition:
Bool:
aws:SecureTransport:
false
ConfigRecorderRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
ConfigRecorder:
Type: AWS::Config::ConfigurationRecorder
DependsOn:
- ConfigBucketPolicy
Properties:
RoleARN: !GetAtt ConfigRecorderRole.Arn
RecordingGroup:
AllSupported: !Ref AllSupported
IncludeGlobalResourceTypes: !Ref IncludeGlobalResourceTypes
ResourceTypes: !If
- IsAllSupported
- !Ref AWS::NoValue
- !Ref ResourceTypes
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
DependsOn:
- ConfigBucketPolicy
Properties:
Name: !If
- IsGeneratedDeliveryChannelName
- !Ref AWS::NoValue
- !Ref DeliveryChannelName
ConfigSnapshotDeliveryProperties:
DeliveryFrequency: !FindInMap
- Settings
- FrequencyMap
- !Ref Frequency
S3BucketName: !Ref ConfigBucket
ConfigRuleForVolumeTags:
DependsOn: ConfigRecorder
Type: AWS::Config::ConfigRule
Properties:
InputParameters:
tag1Key: CostCenter
Scope:
ComplianceResourceTypes:
- "AWS::EC2::Volume"
Source:
Owner: AWS
SourceIdentifier: "REQUIRED_TAGS"
# Like this I need all the AWS Managed rules
You can't do this. There are no loops in cloudformation. But you could create a macro if you want such a functionality.
I am trying to create an elastic search domain with enabled LogPublishingOptions. While enabling LogPublishingOptions ES says it does not sufficient permissions to create a LogStream on Cloudwatch.
I tried creating a policy with a role and attaching the policy to the LogGroup which is referred by ES but it ain't working. Following is my elastic search cloud formation template,
AWSTemplateFormatVersion: 2010-09-09
Resources:
MYLOGGROUP:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: index_slow
MYESROLE:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: es.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonESFullAccess'
- 'arn:aws:iam::aws:policy/CloudWatchFullAccess'
RoleName: !Join
- '-'
- - es
- !Ref 'AWS::Region'
PolicyDocESIndexSlow :
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:PutLogEvents
- logs:CreateLogStream
Resource: 'arn:aws:logs:*'
PolicyName: !Ref MYLOGGROUP
Roles:
- !Ref MYESROLE
MYESDOMAIN:
Type: AWS::Elasticsearch::Domain
Properties:
DomainName: 'es-domain'
ElasticsearchVersion: '7.4'
ElasticsearchClusterConfig:
DedicatedMasterCount: 3
DedicatedMasterEnabled: True
DedicatedMasterType: 'r5.large.elasticsearch'
InstanceCount: '2'
InstanceType: 'r5.large.elasticsearch'
EBSOptions:
EBSEnabled: True
VolumeSize: 10
VolumeType: 'gp2'
AccessPolicies:
Version: 2012-10-17
Statement:
- Effect: Deny
Principal:
AWS: '*'
Action: 'es:*'
Resource: '*'
AdvancedOptions:
rest.action.multi.allow_explicit_index: True
LogPublishingOptions:
INDEX_SLOW_LOGS:
CloudWatchLogsLogGroupArn: !GetAtt
- MYLOGGROUP
- Arn
Enabled: True
VPCOptions:
SubnetIds:
- !Ref MYSUBNET
SecurityGroupIds:
- !Ref MYSECURITYGROUP
MYVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
MYSUBNET:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MYVPC
CidrBlock: 10.0.0.0/16
MYSECURITYGROUP:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: security group for elastic search domain
VpcId: !Ref MYVPC
GroupName: 'SG for ES'
SecurityGroupIngress:
- FromPort: '443'
IpProtocol: tcp
ToPort: '443'
CidrIp: 0.0.0.0/0
Upon execution, it creates all resources except MYESDOMAIN. It says
The Resource Access Policy specified for the CloudWatch Logs log group index_slow does not grant sufficient permissions for Amazon Elasticsearch Service to create a log stream. Please check the Resource Access Policy. (Service: AWSElasticsearch; Status Code: 400; Error Code: ValidationException)
Any idea what's missing here?
Update 2021
There is a CloudFormation resource called AWS::Logs::ResourcePolicy which allows defining policies for CloudWatch Logs in CF. The main issue I found is that it only accepts a real string as the value. Trying to assemble a string using Ref, Join, etc kept being rejected. If anyone can make that work that would be fab.
Writing it in YAML is easier as JSON requires escaping all the " characters.
OSLogGroupPolicy:
Type: AWS::Logs::ResourcePolicy
Properties:
PolicyName: AllowES
PolicyDocument: '{"Version": "2012-10-17","Statement":[{"Effect":"Allow","Principal": {"Service": ["es.amazonaws.com"]},"Action":["logs:PutLogEvents","logs:CreateLogStream"],"Resource":"*"}]}'
I believe there is some confusion here about what policies should be updated/set to enable ES writing to a log group.
I think you should apply the PolicyDocESIndexSlow policy to CloudWatch Logs.
And this can't be done in CloudFormation from what I remember. You have to use put-resource-policy, corresponding API call, or console as shown in:
Viewing Amazon Elasticsearch Service Slow Logs
The final code would be something like this,
DeployES lambda_function.py
import logging
import time
import boto3
import json
from crhelper import CfnResource
logger = logging.getLogger(__name__)
helper = CfnResource(json_logging=False, log_level='DEBUG', boto_level='CRITICAL', sleep_on_delete=120)
try:
# Init code goes here
pass
except Exception as e:
helper.init_failure(e)
#helper.create
#helper.update
def create(event, _):
logger.info("Got Create/Update")
my_log_group_arn = event['ResourceProperties']['MYLOGGROUPArn']
client = boto3.client('logs')
policy_document = dict()
policy_document['Version'] = '2012-10-17'
policy_document['Statement'] = [{
'Sid': 'ESLogsToCloudWatchLogs',
'Effect': 'Allow',
'Principal': {
'Service': [
'es.amazonaws.com'
]
},
'Action': 'logs:*',
}]
policy_document['Statement'][0]['Resource'] = my_log_group_arn
client.put_resource_policy(policyName='ESIndexSlowPolicy', policyDocument=json.dumps(policy_document))
helper.Data['success'] = True
helper.Data['message'] = 'ES policy deployment successful'
# To return an error to Cloud Formation you raise an exception:
if not helper.Data["success"]:
raise Exception('Error message to cloud formation')
return "MYESIDDEFAULT"
#helper.delete
def delete(event, _):
logger.info("Got Delete")
# Delete never returns anything. Should not fail if the underlying resources are already deleted.
# Desired state.
try:
client = boto3.client('logs')
client.delete_resource_policy(policyName='ESIndexSlowPolicy')
except Exception as ex:
logger.critical(f'ES policy delete failed with error [{repr(ex)}]')
def lambda_handler(event, context):
helper(event, context)
And some additional components in CF template
MYLAMBDAROLE:
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/AWSLambdaFullAccess'
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
- 'arn:aws:iam::aws:policy/AmazonESFullAccess'
- 'arn:aws:iam::aws:policy/CloudWatchFullAccess'
RoleName: !Join
- '-'
- - lambda-role
- !Ref 'AWS::Region'
MYLAMBDADEPLOY:
Type: 'AWS::Lambda::Function'
Properties:
Code:
S3Bucket: es-bucket-for-lambda-ta86asdf596
S3Key: es.zip
FunctionName: deploy_es
Handler: lambda_function.lambda_handler
MemorySize: 128
Role: !GetAtt
- MYLAMBDAROLE
- Arn
Runtime: python3.8
Timeout: 60
MYESSETUP:
Type: 'Custom::MYESSETUP'
Properties:
ServiceToken: !GetAtt
- MYLAMBDADEPLOY
- Arn
MYLOGGROUPArn: !GetAtt
- MYLOGGROUP
- Arn
DependsOn:
- MYLAMBDADEPLOY
- MYLOGGROUP
And just add below DependsOn to MYESDOMAIN
DependsOn:
- MYESSETUP
Adding a DependsOn in the AWS::Elasticsearch::Domain resource for the AWS::Logs::ResourcePolicy fixed this for me.
Example code:
ESLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/OpenSearchService/domains/${NamePrefix}-es/application-logs'
RetentionInDays: 30
ESLogGroupPolicy:
Type: AWS::Logs::ResourcePolicy
DependsOn: ESLogGroup
Properties:
PolicyName: !Sub "es-logs-access-policy"
PolicyDocument: '{"Version": "2012-10-17","Statement":[{"Effect":"Allow","Principal": {"Service": ["es.amazonaws.com"]},"Action":["logs:PutLogEvents","logs:CreateLogStream"],"Resource":"*"}]}'
ESDomain:
Type: AWS::Elasticsearch::Domain
DependsOn: [ESLogGroupPolicy]
Properties:
DomainName: !Sub "${NamePrefix}-es"
...
LogPublishingOptions:
ES_APPLICATION_LOGS:
CloudWatchLogsLogGroupArn: !GetAtt ESLogGroup.Arn
Enabled: true
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 have A template that creates IAM roles In cloud Formation YAML. I need service Anr in next template, But I am getting this error.
Template contains errors.: Invalid template resource property 'Fn::ImportValue'
IAMStack
Resources:
CodeDeployTrustRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Sid: '1'
Effect: Allow
Principal:
Service:
- codedeploy.us-east-1.amazonaws.com
- codedeploy.us-west-2.amazonaws.com
Action: sts:AssumeRole
Path: "/"
CodeDeployRolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: CodeDeployPolicy
PolicyDocument:
Statement:
- Effect: Allow
Resource:
- "*"
Action:
- ec2:Describe*
- Effect: Allow
Resource:
- "*"
Action:
- autoscaling:CompleteLifecycleAction
- autoscaling:DeleteLifecycleHook
- autoscaling:DescribeLifecycleHooks
- autoscaling:DescribeAutoScalingGroups
- autoscaling:PutLifecycleHook
- autoscaling:RecordLifecycleActionHeartbeat
Roles:
- Ref: CodeDeployTrustRole
InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
InstanceRolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: InstanceRole
PolicyDocument:
Statement:
- Effect: Allow
Action:
- autoscaling:Describe*
- autoscaling:EnterStandby
- autoscaling:ExitStandby
- cloudformation:Describe*
- cloudformation:GetTemplate
- s3:Get*
Resource: "*"
Roles:
- Ref: InstanceRole
InstanceRoleInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- Ref: InstanceRole
Outputs:
CodeDeployServiceRoleARN:
Value:
Fn::GetAtt:
- CodeDeployTrustRole
- Arn
==================================================================================
CodeDeploystack
---
AWSTemplateFormatVersion: '2010-09-09'
Description: This template will create an s3bucket
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
BucketName: CodeDeploy
CodeDeployApplication:
Type: 'AWS::CodeDeploy::Application'
Properties:
ComputePlatform: ec2
DeploymentGroup:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName:
!Ref CodeDeployApplication
Deployment:
Description: First time
IgnoreApplicationStopFailures: true
Revision:
RevisionType: S3
S3Location:
Bucket:
Ref: S3Bucket
ServiceRoleArn:
'Fn::ImportValue': !Sub '${IAMStack}-CodeDeployServiceRoleARN'
Outputs:
S3BucketName:
Value:
Ref: S3Bucket
Description: Name of S3 bucket
I tried rewriting your second template with the import function. Can you try something like this:
AWSTemplateFormatVersion: '2010-09-09'
Description: This template will create an s3bucket
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
BucketName: CodeDeploy
CodeDeployApplication:
Type: "AWS::CodeDeploy::Application"
Properties:
ComputePlatform: ec2
DeploymentGroup:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName: !Ref CodeDeployApplication
Deployment:
Description: First time
IgnoreApplicationStopFailures: true
Revision:
RevisionType: S3
S3Location: !Ref S3Bucket
ServiceRoleArn:
Fn::ImportValue:
Fn::Sub "${IAMStack}-CodeDeployServiceRoleARN"
Outputs:
S3BucketName:
Value: !Ref S3Bucket
Description: Name of S3 bucket
I think some quotes may be off in your version.
Issue fixed, I just change the region