Skip to content

Commit 817524c

Browse files
committed
Add Guardduty Canary CFT
1 parent 830bb8e commit 817524c

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Copyright 2024 Chris Farris <chrisf@primeharbor.com>
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# If you don't have a lot of guardduty alerts, your detection flow may be broken and you wouldn't know it.
16+
# This CFT creates a public S3 bucket every four hours, so you can alert on no GuardDuty messages in the last four hours.
17+
18+
19+
20+
AWSTemplateFormatVersion: '2010-09-09'
21+
Description: Deploy a Lambda to create a public S3 bucket every four hours to ensure GuardDuty detections are in place
22+
23+
Resources:
24+
# IAM Role for Lambda
25+
LambdaExecutionRole:
26+
Type: 'AWS::IAM::Role'
27+
Properties:
28+
AssumeRolePolicyDocument:
29+
Version: '2012-10-17'
30+
Statement:
31+
- Effect: 'Allow'
32+
Principal:
33+
Service: 'lambda.amazonaws.com'
34+
Action: 'sts:AssumeRole'
35+
Policies:
36+
- PolicyName: 'S3AccessPolicy'
37+
PolicyDocument:
38+
Version: '2012-10-17'
39+
Statement:
40+
- Effect: 'Allow'
41+
Action:
42+
- 's3:ListAllMyBuckets'
43+
- 's3:CreateBucket'
44+
- 's3:DeleteBucket'
45+
- 's3:PutBucketPolicy'
46+
- 's3:PutBucketPublicAccessBlock'
47+
Resource: '*'
48+
ManagedPolicyArns:
49+
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
50+
51+
# Lambda Function
52+
PublicS3BucketLambda:
53+
Type: 'AWS::Lambda::Function'
54+
Properties:
55+
Handler: 'index.lambda_handler'
56+
Role: !GetAtt LambdaExecutionRole.Arn
57+
Runtime: 'python3.12'
58+
Timeout: 30
59+
Code:
60+
ZipFile: |
61+
import boto3
62+
import time
63+
import json
64+
65+
def lambda_handler(event, context):
66+
s3 = boto3.client('s3')
67+
epoch_time = int(time.time())
68+
bucket_name = f'public-test-{epoch_time}'
69+
70+
# Delete existing buckets starting with 'public-test'
71+
response = s3.list_buckets()
72+
for bucket in response['Buckets']:
73+
if bucket['Name'].startswith('public-test'):
74+
s3.delete_bucket(Bucket=bucket['Name'])
75+
76+
# Create a new S3 bucket
77+
s3.create_bucket(Bucket=bucket_name)
78+
79+
# Disable Block Public Access
80+
public_access_block_config = {
81+
'BlockPublicAcls': False,
82+
'IgnorePublicAcls': False,
83+
'BlockPublicPolicy': False,
84+
'RestrictPublicBuckets': False
85+
}
86+
s3.put_public_access_block(
87+
Bucket=bucket_name,
88+
PublicAccessBlockConfiguration=public_access_block_config
89+
)
90+
91+
# Make the bucket public
92+
bucket_policy = {
93+
"Version": "2012-10-17",
94+
"Statement": [
95+
{
96+
"Effect": "Allow",
97+
"Principal": "*",
98+
"Action": "s3:GetObject",
99+
"Resource": f"arn:aws:s3:::{bucket_name}/*"
100+
}
101+
]
102+
}
103+
104+
s3.put_bucket_policy(Bucket=bucket_name, Policy=json.dumps(bucket_policy))
105+
106+
return {'statusCode': 200, 'body': f'Bucket {bucket_name} created and made public.'}
107+
108+
# EventBridge Rule to trigger Lambda every 4 hours
109+
LambdaScheduleRule:
110+
Type: 'AWS::Events::Rule'
111+
Properties:
112+
ScheduleExpression: 'rate(4 hours)'
113+
Targets:
114+
- Arn: !GetAtt PublicS3BucketLambda.Arn
115+
Id: 'PublicS3BucketLambdaTarget'
116+
117+
# Permission for EventBridge to invoke Lambda
118+
LambdaInvokePermission:
119+
Type: 'AWS::Lambda::Permission'
120+
Properties:
121+
FunctionName: !Ref PublicS3BucketLambda
122+
Action: 'lambda:InvokeFunction'
123+
Principal: 'events.amazonaws.com'
124+
SourceArn: !GetAtt LambdaScheduleRule.Arn
125+
126+
Outputs:
127+
LambdaFunctionName:
128+
Description: 'Name of the Lambda function created'
129+
Value: !Ref PublicS3BucketLambda
130+
LambdaFunctionArn:
131+
Description: 'ARN of the Lambda function created'
132+
Value: !GetAtt PublicS3BucketLambda.Arn

0 commit comments

Comments
 (0)