Cloud Formation to add multiple S3 triggers to same S3 bucket in LambdaConfigurations - amazon-s3

My requirement is to trigger Lambda_Function_1 if input.txt file creates in S3 bucket and trigger Lambda_Function_2 if output.txt file creates in same S3 bucket.
The below cfn is not working, but it works fine if I put only one event instead of two events in same LambdaConfigurations.
Can some one please help me here?
Parameters:
S3BucketBaseName:
Type: String
Description: The base name of the Amazon S3 bucket.
Default: dw-trip
Resources:
LambdaStart:
DependsOn:
- LambdaStartStopEC2
Type: "AWS::Lambda::Function"
Properties:
FunctionName: "dw-trip-start-ec2"
Handler: "index.handler"
Role: !GetAtt LambdaStartStopEC2.Arn
Runtime: python3.7
MemorySize: 3008
Timeout: 900
Code:
ZipFile: |
import boto3
region = 'us-east-1'
instances = ['i-05d5fbec4c82956b6']
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('started your instances: ' + str(instances))
ProcessingLambdaPermissionStart:
Type: AWS::Lambda::Permission
DependsOn:
- LambdaStart
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref LambdaStart
Principal: s3.amazonaws.com
SourceArn:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
SourceAccount: !Ref AWS::AccountId
LambdaStop:
DependsOn:
- ProcessingLambdaPermissionStart
Type: "AWS::Lambda::Function"
Properties:
FunctionName: "dw-trip-stop-ec2"
Handler: "index.handler"
Role: !GetAtt LambdaStartStopEC2.Arn
Runtime: python3.7
MemorySize: 3008
Timeout: 900
Code:
ZipFile: |
import boto3
region = 'us-east-1'
instances = ['i-05d5fbec4c82956b6']
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.stop_instances(InstanceIds=instances)
print('stopping your instances: ' + str(instances))
ProcessingLambdaPermissionStop:
Type: AWS::Lambda::Permission
DependsOn:
- LambdaStop
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref LambdaStop
Principal: s3.amazonaws.com
SourceArn:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
SourceAccount: !Ref AWS::AccountId
S3KmsKey:
Type: AWS::KMS::Key
DependsOn:
- ProcessingLambdaPermissionStop
Properties:
Description: KMS key for trip S3 bucket.
Enabled: true
EnableKeyRotation: true
KeyPolicy:
Statement:
- Sid: Administration
Effect: Allow
Principal:
AWS:
- Fn::Join:
- ''
- - 'arn:aws:iam::'
- Ref: AWS::AccountId
- ':role/DW01-codepipeline-action-us-east-1'
- Fn::Join:
- ''
- - 'arn:aws:iam::'
- Ref: AWS::AccountId
- ':root'
Action: 'kms:*'
Resource: '*'
S3bucketCreate:
DependsOn:
- S3KmsKey
Type: AWS::S3::Bucket
Properties:
BucketName: !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
KMSMasterKeyID: !Ref S3KmsKey
SSEAlgorithm: "aws:kms"
NotificationConfiguration:
LambdaConfigurations:
- Event: s3:ObjectCreated:*
Function: !GetAtt LambdaStart.Arn
Filter:
S3Key:
Rules:
- Name: prefix
Value: input.txt
- Event: s3:ObjectCreated:*
Function: !GetAtt LambdaStop.Arn
Filter:
S3Key:
Rules:
- Name: prefix
Value: output.txt
S3bucketPolicy:
DependsOn:
- S3bucketCreate
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: 'S3bucketCreate'
PolicyDocument:
Statement:
- Sid: AllowEc2AccesstoBucket
Action:
- 's3:GetObject'
- 's3:PutObject'
Effect: Allow
Principal:
AWS:
- Fn::Join:
- ''
- - 'arn:aws:iam::'
- Ref: AWS::AccountId
- ':role/DevDW01-EC2-us-east-1'
Resource:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- Ref: 'S3bucketCreate'
- '/*'
LambdaStartStopEC2:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
RoleName: Lambda-StartStop-EC2
MaxSessionDuration: 43200
Policies:
- PolicyName: StartStop-EC2
PolicyDocument:
Statement:
- Action:
- s3:*
Effect: Allow
Resource: '*'
- Action:
- ec2:*
Effect: Allow
Resource: '*'
- PolicyName: logs
PolicyDocument:
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Effect: Allow
Resource: '*'
Outputs:
S3bucketCreateName:
Value:
Ref: S3bucketCreate
Export:
Name: S3bucketCreateName
S3bucketCreateArn:
Value:
Fn::GetAtt: S3bucketCreate.Arn
Export:
Name: S3bucketCreateArn
S3KmsKeyArn:
Value:
Fn::GetAtt: S3KmsKey.Arn
Export:
Name: S3KmsKeyArn

Multiple filter rules with prefix and suffix as name are allowed as long as they do not overlap. Refer here for various examples explaining how overlapping may occur and how to avoid them.
In this case, the error Template format error: YAML not well-formed is possibly due to improper YAML formatting. Use cfn-lint to validate the templates.
Adding a snippet that explicitly specifies the expected prefix and suffix of the S3 object.
NotificationConfiguration:
LambdaConfigurations:
- Event: s3:ObjectCreated:*
Function: !GetAtt LambdaStart.Arn
Filter:
S3Key:
Rules:
- Name: prefix
Value: input
- Name: suffix
Value: txt
- Event: s3:ObjectCreated:*
Function: !GetAtt LambdaStop.Arn
Filter:
S3Key:
Rules:
- Name: prefix
Value: output
- Name: suffix
Value: txt

I actually had to do it like this create multiple LambdaConfigurations.
"NotificationConfiguration": {
"LambdaConfigurations": [{
"Event": "s3:ObjectCreated:*",
"Function": {
"Fn::GetAtt": ["lambdaVodFunction", "Arn"]
},
"Filter": {
"S3Key": {
"Rules": [{
"Name": "suffix",
"Value": ".mp4"
}]
}
}
},
{
"Event": "s3:ObjectCreated:*",
"Function": {
"Fn::GetAtt": ["lambdaVodFunction", "Arn"]
},
"Filter": {
"S3Key": {
"Rules": [{
"Name": "suffix",
"Value": ".mov"
}]
}
}
}
]
}

Related

504 Error; Request could not be satisfied; S3 Static Website

I am attempting to check my website using my s3 bucket link, which works fine. But my Cloudfront link does not work. I get a 504 request could not be satisfied.
Resources:
MyWebsite:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
BucketName: mcderkaderkas-first-website
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
PolicyDocument:
Id: MyPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: ""
Action: "s3:GetObject"
Resource: !Join
- ""
- - "arn:aws:s3:::"
- !Ref MyWebsite
- /
Bucket: !Ref MyWebsite
MyDistribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
DefaultCacheBehavior:
ViewerProtocolPolicy: allow-all
TargetOriginId: mcderkaderkas-first-website.s3.us-east-1.amazonaws.com
DefaultTTL: 0
MinTTL: 0
MaxTTL: 0
ForwardedValues:
QueryString: false
PathPattern: /*
Origins:
- DomainName: mcderkaderkas-first-website.s3.us-east-1.amazonaws.com
Id: mcderkaderkas-first-website.s3.us-east-1.amazonaws.com
CustomOriginConfig:
OriginProtocolPolicy: match-viewer
Enabled: "true"
DefaultRootObject: index.html

SNS topic not receiving CodeBuild notifications

Trying to get CodeBuild to push notifications to an SNS topic (bound to a Lambda), via a CloudWatch Events Rule.
Cloudformation template (see below) deploys fine.
CodeBuild process works fine (have tested).
SNS topic and bound Lambda work fine - I can push a message to the topic via AWS CLI and see Lambda dump that message to Cloudwatch logs.
The Cloudwatch Event Rule seems to be configured fine - I can see it in the cosole, it looks well formed, seems to be bound to SNS topic.
In addition I have been careful to give the Event Rule a role with permissions to sns:Publish, and also defined an AWS::SNS::TopicPolicy for the SNS topic -
Unable to successfully set up SNS on CodeBuild project through CFT but works manually
But still nothing - CodeBuild successfully completes but I don't receive any notifications.
Any thoughts as to what might be wrong ?
TIA :)
---
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
AppName:
Type: String
StagingBucket:
Type: String
RepoOwner:
Type: String
RepoName:
Type: String
RepoBranch:
Type: String
RepoPAT:
Type: String
CodeBuildBuildSpec:
Type: String
CodeBuildType:
Type: String
Default: LINUX_CONTAINER
CodeBuildComputeType:
Type: String
Default: BUILD_GENERAL1_SMALL
CodeBuildImage:
Type: String
Default: aws/codebuild/standard:4.0
LambdaHandler:
Type: String
Default: "index.handler"
LambdaMemory:
Type: Number
Default: 128
LambdaTimeout:
Type: Number
Default: 30
LambdaRuntime:
Type: String
Default: python3.8
Resources:
CodeBuildProject:
DependsOn:
- CodeBuildSourceCredential
Properties:
Environment:
ComputeType:
Ref: CodeBuildComputeType
Image:
Ref: CodeBuildImage
Type:
Ref: CodeBuildType
Name:
Ref: AppName
ServiceRole:
Fn::GetAtt:
- CodeBuildRole
- Arn
Source:
Location:
Fn::Sub:
- "https://github.com/${repo_owner}/${repo_name}.git"
- repo_owner:
Ref: RepoOwner
repo_name:
Ref: RepoName
Type: GITHUB
BuildSpec:
Fn::Sub:
- "${build_spec}"
- build_spec:
Ref: CodeBuildBuildSpec
Artifacts:
Type: S3
Location:
Ref: StagingBucket
SourceVersion:
Ref: RepoBranch
Triggers:
Webhook: true
FilterGroups:
- - Type: EVENT
Pattern: PUSH
ExcludeMatchedPattern: false
- Type: HEAD_REF
Pattern: "refs/tags/.*"
ExcludeMatchedPattern: false
Type: AWS::CodeBuild::Project
CodeBuildSourceCredential:
Type: AWS::CodeBuild::SourceCredential
Properties:
Token:
Ref: RepoPAT
ServerType: GITHUB
AuthType: PERSONAL_ACCESS_TOKEN
CodeBuildRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
Path: /
Type: AWS::IAM::Role
CodeBuildNotificationFunction:
Properties:
Code:
ZipFile: "def handler(event, context):\n print (event)"
Handler:
Ref: LambdaHandler
MemorySize:
Ref: LambdaMemory
Role:
Fn::GetAtt:
- CodeBuildNotificationFunctionRole
- Arn
Runtime:
Ref: LambdaRuntime
Timeout:
Ref: LambdaTimeout
Type: AWS::Lambda::Function
CodeBuildNotificationFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: '2012-10-17'
Policies:
- PolicyDocument:
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Effect: Allow
Resource: '*'
Version: '2012-10-17'
PolicyName: code-build-notification-role-policy
Type: AWS::IAM::Role
CodeBuildNotificationTopic:
Properties:
Subscription:
- Protocol: lambda
Endpoint:
Fn::GetAtt:
- CodeBuildNotificationFunction
- Arn
Type: AWS::SNS::Topic
CodeBuildNotificationTopicPolicy:
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: "events.amazonaws.com"
Action:
- "sns:Publish"
Resource:
Ref: CodeBuildNotificationTopic
Topics:
- Ref: CodeBuildNotificationTopic
Type: AWS::SNS::TopicPolicy
CodeBuildNotificationLambdaInvokePermission:
Properties:
Action: "lambda:InvokeFunction"
FunctionName:
Ref: CodeBuildNotificationFunction
Principal: "sns.amazonaws.com"
SourceArn:
Ref: CodeBuildNotificationTopic
Type: AWS::Lambda::Permission
SampleNotificationRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
Fn::Sub:
- '{"source": ["aws.codebuild"], "detail-type": ["Codebuild Build Phase Change"], "detail": {"completed-phase": ["SUBMITTED", "PROVISIONING", "DOWNLOAD_SOURCE", "INSTALL", "PRE_BUILD", "BUILD", "POST_BUILD", "UPLOAD_ARTIFACTS", "FINALIZING"], "completed-phase-status": ["TIMED_OUT", "STOPPED", "FAILED", "SUCCEEDED", "FAULT", "CLIENT_ERROR"], "project-name": ["${project_name}"]}}'
- project_name:
Ref: CodeBuildProject
State: ENABLED
RoleArn:
Fn::GetAtt:
- SampleNotificationRuleRole
- Arn
Targets:
- Arn:
Ref: CodeBuildNotificationTopic
Id: sample-notification
SampleNotificationRuleRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: events.amazonaws.com
Version: '2012-10-17'
Policies:
- PolicyDocument:
Statement:
- Action:
- "sns:Publish"
Effect: Allow
Resource: '*'
Version: '2012-10-17'
PolicyName: sample-notification-rule-role-policy
Type: AWS::IAM::Role
Fixed - AWS::Events::Rule target was missing an InputTransformer block like so
Targets:
- Arn:
Ref: CodeBuildNotificationTopic
Id: sample-notification
InputTransformer:
InputPathsMap:
build-id: "$.detail.build-id"
project-name: "$.detail.project-name"
completed-phase: "$.detail.completed-phase"
completed-phase-status: "$.detail.completed-phase-status"
InputTemplate: |
"Build '<build-id>' for build project '<project-name>' has completed the build phase of '<completed-phase>' with a status of '<completed-phase-status>'."

How to grant public read only access to S3 Bucket in AWS SAM template

I am creating an S3 bucket in a SAM template and would like to give it public read access. This is what I came up with so far:
ProductBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${ProductBucketName}${Stage}
ProductBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ProductBucket
PolicyDocument:
Id: PublicReadPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: 's3:GetObject'
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref ProductBucket
This fails with a malformed exception.
Your template is fine except the line that says - - 'arn:aws:s3:::' where its malformed. Just a suggestion that you can use Fn::Sub over Fn::Join when delimiter is an empty string.
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
ProductBucketName:
Type: String
Resources:
ProductBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${ProductBucketName}-${AWS::StackName}
ProductBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ProductBucket
PolicyDocument:
Id: PublicReadPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: 's3:GetObject'
Resource: !Sub arn:aws:s3:::${ProductBucket}/*
Hope this help you move forward.
I found the AWS documentation's yaml example to look a bit funny, but I followed it and gave my CF stack IAM s3:PutBucketPolicy permissions, and it worked. Below is my SAM.
ExampleBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub <bucket-name>
ExampleBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: "ExampleBucket"
PolicyDocument:
Statement:
- Action:
- "s3:GetObject"
Effect: "Allow"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- Ref: "ExampleBucket"
- "/*"
Principal: "*"
Here is the AWS documentation page you've probably already consulted: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-policy.html.

S3 Put cloudformation lambda trigger

I need some help writing the cloud formation that would get triggered by S3 put, from reading the documentation I see that you need NotificationConfiguration with event and function specified in bucket definition, but I keep getting the error " Unable to validate the following destination configurations" and it craps out and rollback the update. Can someone take a look at my CF script and identify what I am doing wrong, I think the issue could be in either NotificationConfiguration or rLambdaInvokePermission, but I am not sure which much appreciated!
here's my yaml:
Resources:
rAppBucketS3Policy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref rS3bucket
PolicyDocument:
Statement:
# SSL access enforced
- Sid: EnforceSecureTransport
Action: s3:*
Effect: Deny
Principal: '*'
Resource: !Join ["",[ "arn:aws:s3:::", Ref: rS3bucket, '/*' ] ]
Condition:
Bool:
aws:SecureTransport: 'false'
- Sid: EnforceEncryptionOnPut
Effect: Deny
Principal: '*'
Action: s3:PutObject
Resource: !Join ["",[ "arn:aws:s3:::", Ref: rS3bucket, '/*' ] ]
Condition:
StringNotEquals:
s3:x-amz-server-side-encryption: AES256
rLambdaInvokePermission:
#DependsOn: "int1-draps-us-east-1"
Type: AWS::Lambda::Permission
Properties:
FunctionName: us-east-1-upload
#FunctionName: !GetAtt rUploadLambda.Arn
Action: lambda:InvokeFunction
Principal: s3.amazonaws.com
SourceArn: !GetAtt rS3bucket.Arn
rS3bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: !Sub ${pAWSAccountLC}-${pParentVPCLC}-${pAppNameLC}-${AWS::Region}
CorsConfiguration:
CorsRules:
- AllowedHeaders: [ChecksumValue, CheckDate]
AllowedMethods: [GET, PUT, POST, DELETE]
ExposedHeaders: [ChecksumValue, CheckDate]
AllowedOrigins: ['*']
LifecycleConfiguration:
Rules:
- Id: Transition1day
Status: Enabled
Transitions:
- TransitionInDays: !Ref pS3GLACIERTransitionPeriod
StorageClass: GLACIER
**NotificationConfiguration:
LambdaConfigurations:
-
Event: "s3:ObjectCreated:*"
Function:
Fn::ImportValue:
Fn::Sub: "us-east-1-upload-rUploadLambda"**

CloudFormation BucketPolicy stuck at CREATE. Never finished CREATE

Cloud forming an S3 bucket with user, user access keys, and policy. It should create the stack and output the user access keys needed to work with the created S3 bucket via the SDK. Bucket Policy gets stuck in the CREATING phase forever when trying to reference the BucketUser ARN in the BucketPolicy Principal.
CloudFormation is successful with
BucketPolicy: ... Principal: "*"
But BucketPolicy resource is stuck in CREATE forever with
BucketPolicy: ... Principal: !GetAtt BucketUser.Arn
This successfully returns the BucketUser.Arn when BucketPolicy: ... Principal: "*"
Outputs:
BucketUserArn:
Value: !GetAtt BucketUser.Arn
Desired Template:
AWSTemplateFormatVersion: "2010-09-09"
Description: "Creates bucket with bucket policy"
#Metadata:
Parameters:
app:
Type: String
Description: (required) Application name (Also used for bucket name. Follow S3 bucket name conventions)
Default: ymessage-bucket-test
Resources:
BucketUser:
Type: "AWS::IAM::User"
Properties:
UserName: !Ref app
UserAccessKey:
Type: "AWS::IAM::AccessKey"
Properties:
Status: Active
UserName: !Ref app
DependsOn: BucketUser
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref app
BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref app
PolicyDocument:
Statement:
-
Action:
- "s3:*"
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
- !Ref app
- "/*"
Principal: !GetAtt BucketUser.Arn
DependsOn: BucketUser
Outputs:
AccessKeyId:
Value: !Ref UserAccessKey
AccessKeySecret:
Value: !GetAtt UserAccessKey.SecretAccessKey
BucketURL:
Value: !GetAtt Bucket.WebsiteURL
BucketUserArn:
Value: !GetAtt BucketUser.Arn
Working Template:
AWSTemplateFormatVersion: "2010-09-09"
Description: "Creates bucket with bucket policy"
#Metadata:
Parameters:
app:
Type: String
Description: (required) Application name (Also used for bucket name. Follow S3 bucket name conventions)
Default: ymessage-bucket-test
Resources:
BucketUser:
Type: "AWS::IAM::User"
Properties:
UserName: !Ref app
UserAccessKey:
Type: "AWS::IAM::AccessKey"
Properties:
Status: Active
UserName: !Ref app
DependsOn: BucketUser
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref app
BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref app
PolicyDocument:
Statement:
-
Action:
- "s3:*"
Effect: "Allow"
Resource:
Fn::Join:
- ""
-
- "arn:aws:s3:::"
- !Ref app
- "/*"
Principal: "*"
DependsOn: BucketUser
Outputs:
AccessKeyId:
Value: !Ref UserAccessKey
AccessKeySecret:
Value: !GetAtt UserAccessKey.SecretAccessKey
BucketURL:
Value: !GetAtt Bucket.WebsiteURL
BucketUserArn:
Value: !GetAtt BucketUser.Arn
Found the issue: In the BucketPolicy it can directly accept Principal: "*" but if you want to use an arn do this:
Principal:
AWS:
- !GetAtt BucketUser.Arn