I want CloudWatch to send CreateLogGroup messages to EventBridge.
I understand this is possible, but also that Cloudwatch doesn't seem to send these messages by default. It seems you have to configure CloudTrail to get it to forward the message. But I can't find a CloudTrail configuration which works - in general deployment fails with:
AWS::CloudTrail::Trail - "Invalid request provided: Incorrect S3 bucket policy is detected for bucket"
AWSTemplateFormatVersion: '2010-09-09'
Outputs:
HelloFunction:
Value:
Ref: HelloFunction
WatcherFunction:
Value:
Ref: WatcherFunction
WatcherTrailBucket:
Value:
Ref: WatcherTrailBucket
Parameters:
MemorySizeDefault:
Default: '512'
Type: String
RuntimeVersion:
Default: '3.8'
Type: String
TimeoutDefault:
Default: '5'
Type: String
Resources:
HelloFunction:
Properties:
Code:
ZipFile: |
def handler(event, context):
print (event)
Handler: index.handler
MemorySize:
Ref: MemorySizeDefault
Role:
Fn::GetAtt:
- HelloFunctionRole
- Arn
Runtime:
Fn::Sub: python${RuntimeVersion}
Timeout:
Ref: TimeoutDefault
Type: AWS::Lambda::Function
HelloFunctionRole:
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:
Fn::Sub: hello-function-role-policy-${AWS::StackName}
Type: AWS::IAM::Role
WatcherFunction:
Properties:
Code:
ZipFile: |
def handler(event, context):
print (event)
Handler: index.handler
MemorySize:
Ref: MemorySizeDefault
Role:
Fn::GetAtt:
- WatcherFunctionRole
- Arn
Runtime:
Fn::Sub: python${RuntimeVersion}
Timeout:
Ref: TimeoutDefault
Type: AWS::Lambda::Function
WatcherFunctionRole:
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:
Fn::Sub: watcher-function-role-policy-${AWS::StackName}
Type: AWS::IAM::Role
WatcherEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.logs
detail-type:
- "AWS API Call via CloudTrail"
detail:
eventName:
- CreateLogGroup
Targets:
- Id:
Fn::Sub: watcher-event-rule-${AWS::StackName}
Arn:
Fn::GetAtt:
- WatcherFunction
- Arn
State: ENABLED
WatcherEventRulePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
FunctionName:
Ref: WatcherFunction
SourceArn:
Fn::GetAtt:
- WatcherEventRule
- Arn
WatcherTrailBucket:
Type: AWS::S3::Bucket
WatcherTrailBucketPolicy:
DependsOn:
- WatcherTrailBucket
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WatcherTrailBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:GetBucketAcl
Resource: "*"
Condition: {}
- Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:PutObject
Resource: "*"
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
WatcherTrail:
Type: AWS::CloudTrail::Trail
Properties:
EventSelectors:
- ReadWriteType: All
IsLogging: true
S3BucketName:
Ref: WatcherTrailBucket
IsLogging: true
S3KeyPrefix: logs/
Your WatcherTrail
runs before WatcherTrailBucketPolicy
, so that's why it fails (CloudFormation does not deploy resource in the order of their definition in the template). Add explicit DependsOn
dependency on the bucket policy. Also your WatcherTrailBucketPolicy
is incorrect, and trial needs a name. So it should be:
WatcherTrailBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WatcherTrailBucket
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck20150319",
"Effect": "Allow",
"Principal": {"Service": "cloudtrail.amazonaws.com"},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::${WatcherTrailBucket}",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/MyTrial"
}
}
},
{
"Sid": "AWSCloudTrailWrite20150319",
"Effect": "Allow",
"Principal": {"Service": "cloudtrail.amazonaws.com"},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::${WatcherTrailBucket}/logs/AWSLogs/${AWS::AccountId}/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control",
"aws:SourceArn": "arn:aws:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/MyTrial"
}
}
}
]
}
WatcherTrail:
Type: AWS::CloudTrail::Trail
DependsOn: WatcherTrailBucketPolicy
Properties:
TrailName: MyTrial
EventSelectors:
- ReadWriteType: All
IsLogging: true
S3BucketName:
Ref: WatcherTrailBucket
IsLogging: true
S3KeyPrefix: logs/