AWSTemplateFormatVersion: '2010-09-09' Description: This CloudFormation Template can be used to quickly get started with AWS GuardDuty by configuring an environment to generate and remediate AWS GuardDuty findings. Parameters: ResourceName: Type: String Default: GuardDuty-Example AllowedValues: - GuardDuty-Example Description: Prefix for the resources that are created. # KeyName: # Type: AWS::EC2::KeyPair::KeyName # ConstraintDescription: This must be the name of an existing EC2 KeyPair. # Description: 'Name of an existing EC2 KeyPair to enable SSH access to the instances created in this scenario.' EmailAddress: Description: Email address for receiving alerts. Type: String AllowedPattern: ".+" #Automatically select latest EC2 AMI based on region LatestAWSLinuxAmiId: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' Metadata: {} Conditions: {} Resources: #GuardDuty Bucket 1 GDThreatListBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: Fn::Join: - '-' - ['guardduty-example', !Ref "AWS::AccountId", !Ref "AWS::Region"] # GuardDuty Bucket 2 GDLogBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: Fn::Join: - '-' - ['guardduty-example-log', !Ref "AWS::AccountId", !Ref "AWS::Region"] AccessControl: LogDeliveryWrite PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true # GuardDuty Bucket 3 GDCompromisedBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: Fn::Join: - '-' - ['guardduty-example-finance', !Ref "AWS::AccountId", !Ref "AWS::Region"] LoggingConfiguration: DestinationBucketName: !Ref GDLogBucket PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true # VPC & EC2 Creation VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/24 EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Ref ResourceName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref ResourceName GatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: Ref: InternetGateway VpcId: !Ref VPC RouteTable: DependsOn: - VPC Type: AWS::EC2::RouteTable Properties: Tags: - Key: Name Value: !Ref ResourceName VpcId: !Ref VPC PublicRoute: Type: AWS::EC2::Route DependsOn: - VPC - InternetGateway - RouteTable Properties: DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway RouteTableId: !Ref RouteTable Subnet: Type: AWS::EC2::Subnet Properties: CidrBlock: 10.0.0.0/26 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Ref ResourceName VpcId: !Ref VPC SubnetAssoc: DependsOn: - Subnet - RouteTable Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTable SubnetId: !Ref Subnet PublicNACL: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Ref ResourceName - Key: Network Value: Public InboundPublicNACLEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref PublicNACL RuleNumber: 100 Protocol: -1 RuleAction: allow Egress: false CidrBlock: '0.0.0.0/0' PortRange: From: 0 To: 65535 OutboundPublicNACLEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref PublicNACL RuleNumber: 100 Protocol: -1 RuleAction: allow Egress: true CidrBlock: 0.0.0.0/0 PortRange: From: 0 To: 65535 SubnetNACLAssociation: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref Subnet NetworkAclId: !Ref PublicNACL TargetSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Ref ResourceName VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: icmp FromPort: '-1' ToPort: '-1' CidrIp: 0.0.0.0/0 ForensicSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Fn::Join: - '-' - [!Ref ResourceName,'Forensics'] VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: icmp FromPort: '-1' ToPort: '-1' CidrIp: 10.0.0.0/24 SecurityGroupEgress: - IpProtocol: icmp FromPort: '-1' ToPort: '-1' CidrIp: 10.0.0.0/24 # Malicious IAM User CompromisedUser: Type: "AWS::IAM::User" Properties: UserName: Fn::Join: - '-' - [!Ref ResourceName, 'Compromised', 'Simulated'] CompromisedUserKey: Type: "AWS::IAM::AccessKey" Properties: UserName: !Ref CompromisedUser CompromisedUserPolicy: Type: "AWS::IAM::Policy" Properties: PolicyName: "CompromisedUserPolicy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters - ssm:DescribeParameters Resource: Fn::Join: - ':' - ["arn:aws:ssm", !Ref "AWS::Region", !Ref "AWS::AccountId", "*"] Users: - !Ref CompromisedUser # Malicious IAM User 2 CompromisedUser2: Type: "AWS::IAM::User" Properties: UserName: Fn::Join: - '-' - [!Ref ResourceName, 'Compromised2', 'Simulated'] CompromisedUserKey2: Type: "AWS::IAM::AccessKey" Properties: UserName: !Ref CompromisedUser2 CompromisedUserPolicy2: Type: "AWS::IAM::Policy" Properties: PolicyName: "CompromisedUserPolicy2" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - s3:PutBucketPublicAccessBlock - s3:PutBucketLogging Resource: Fn::Join: - ':' - ["arn:aws:s3::", "*"] Users: - !Ref CompromisedUser2 # Malicious Instance - For GuardDuty Finding: UnauthorizedAccess:EC2/MaliciousIPCaller.Custom MaliciousIP: DependsOn: - GatewayAttachment Type: AWS::EC2::EIP Properties: InstanceId: !Ref MaliciousInstance Domain: vpc MaliciousInstance: DependsOn: - GDThreatListBucket Type: AWS::EC2::Instance Properties: InstanceType: t3.micro ImageId: !Ref LatestAWSLinuxAmiId #KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'false' DeviceIndex: '0' GroupSet: - !Ref TargetSecurityGroup SubnetId: Ref: Subnet Tags: - Key: Name Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Malicious Instance', 'Scenario 1 & 2'] - Key: GD-Finding Value: 'UnauthorizedAccess:EC2/MaliciousIPCaller.Custom' UserData: Fn::Base64: !Sub - | #!/bin/bash -ex # Start SSM Agent sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm # Create Creds and Config files mkdir /home/ec2-user/.aws touch /home/ec2-user/.aws/credentials touch /home/ec2-user/.aws/config cat <> /home/ec2-user/.aws/credentials [default] aws_access_key_id = ${AccessKey} aws_secret_access_key = ${SecretKey} EOT # Modify Permissions and Ownership chmod 746 /home/ec2-user/.aws/credentials chown ec2-user /home/ec2-user/.aws/credentials chmod 746 /home/ec2-user/.aws/config chown ec2-user /home/ec2-user/.aws/config cat <> /home/ec2-user/gd-findings.sh #!/bin/bash aws configure set default.region ${Region} aws iam get-user aws iam create-user --user-name Sarah aws dynamodb list-tables aws s3api list-buckets aws ssm describe-parameters aws ssm get-parameters --names "gd_prod_dbpwd_sample" sleep 10m aws s3api list-objects --bucket ${Bucket} EOT chmod 744 /home/ec2-user/gd-findings.sh chown ec2-user /home/ec2-user/gd-findings.sh echo "* * * * * /home/ec2-user/gd-findings.sh > /home/ec2-user/gd-findings.log 2>&1" | tee -a /var/spool/cron/ec2-user - Region: !Ref "AWS::Region" AccessKey: !Ref CompromisedUserKey SecretKey: Fn::GetAtt: - "CompromisedUserKey" - "SecretAccessKey" Bucket: !Ref GDCompromisedBucket # Malicious Instance - For GuardDuty S3 Findings, Stealth and Policy MaliciousInstance2: DependsOn: - GDCompromisedBucket Type: AWS::EC2::Instance Properties: InstanceType: t3.micro ImageId: !Ref LatestAWSLinuxAmiId #KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'true' DeviceIndex: '0' GroupSet: - !Ref TargetSecurityGroup SubnetId: Ref: Subnet Tags: - Key: Name Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Malicious Instance', 'Scenario 4'] - Key: GD-Finding Value: 'S3 findings' UserData: Fn::Base64: !Sub - | #!/bin/bash -ex # Start SSM Agent sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm # Create Creds and Config files mkdir /home/ec2-user/.aws touch /home/ec2-user/.aws/credentials touch /home/ec2-user/.aws/config cat <> /home/ec2-user/.aws/credentials [default] aws_access_key_id = ${AccessKey} aws_secret_access_key = ${SecretKey} EOT # Modify Permissions and Ownership chmod 746 /home/ec2-user/.aws/credentials chown ec2-user /home/ec2-user/.aws/credentials chmod 746 /home/ec2-user/.aws/config chown ec2-user /home/ec2-user/.aws/config sleep 20m cat <> /home/ec2-user/gd-findings.sh #!/bin/bash aws configure set default.region ${Region} aws s3api list-buckets aws s3api delete-public-access-block --bucket ${Bucket} aws s3api put-bucket-logging --bucket ${Bucket} --bucket-logging-status {} EOT chmod 744 /home/ec2-user/gd-findings.sh chown ec2-user /home/ec2-user/gd-findings.sh echo "* * * * * /home/ec2-user/gd-findings.sh > /home/ec2-user/gd-findings.log 2>&1" | tee -a /var/spool/cron/ec2-user - Region: !Ref "AWS::Region" AccessKey: !Ref CompromisedUserKey2 SecretKey: Fn::GetAtt: - "CompromisedUserKey2" - "SecretAccessKey" Bucket: !Ref GDCompromisedBucket # Compromised Instance - For GuardDuty Finding: UnauthorizedAccess:EC2/MaliciousIPCaller.Custom CompromisedInstance: Type: AWS::EC2::Instance DependsOn: MaliciousIP Properties: InstanceType: t3.micro ImageId: !Ref LatestAWSLinuxAmiId #KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'true' DeviceIndex: '0' GroupSet: - !Ref TargetSecurityGroup SubnetId: Ref: Subnet Tags: - Key: Name Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Compromised Instance', 'Scenario 1'] - Key: GD-Finding Value: 'UnauthorizedAccess:EC2/MaliciousIPCaller.Custom' UserData: Fn::Base64: !Sub | #!/bin/bash -ex exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 sleep 5m echo BEGIN echo "* * * * * ping -c 6 -i 10 ${MaliciousIP}" | tee -a /var/spool/cron/ec2-user # Compromised Instance IAM Role - For GuardDuty Finding: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS CompromisedRole: Type: AWS::IAM::Role Properties: RoleName: Fn::Join: - '-' - [!Ref ResourceName, 'EC2', 'Compromised'] AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM Policies: - PolicyName: GuardDutyCompromisedPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - ssm:PutParameter - ssm:DescribeParameters - ssm:GetParameters - ssm:DeleteParameter Resource: Fn::Join: - ':' - ["arn:aws:ssm", !Ref "AWS::Region", !Ref "AWS::AccountId", "parameter/*"] - Effect: Allow Action: - ssm:DescribeParameters Resource: "*" - Effect: Allow Action: - dynamodb:* Resource: Fn::GetAtt: - "CustDynamoDBTable" - "Arn" - Effect: Allow Action: - dynamodb:ListTables - dynamodb:DescribeTable Resource: '*' - Effect: Allow Action: - guardduty:GetDetector - guardduty:ListDetectors - guardduty:CreateThreatIntelSet - guardduty:UpdateThreatIntelSet Resource: '*' - Effect: Allow Action: 's3:PutObject' Resource: !Sub 'arn:aws:s3:::${GDThreatListBucket}/*' - Effect: Allow Action: 's3:PutAccountPublicAccessBlock' Resource: '*' - Effect: Allow Action: - iam:PutRolePolicy Resource: Fn::Join: - ':' - ["arn:aws:iam:",!Ref "AWS::AccountId", "role/aws-service-role/guardduty.amazonaws.com/*"] CompromisedInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: Fn::Join: - '-' - [!Ref ResourceName, 'Compromised','Profile'] Path: / Roles: - !Ref CompromisedRole # IAM Credential Parameter Placeholders DBPWDParameter: Type: "AWS::SSM::Parameter" Properties: Name: "gd_prod_dbpwd_sample" Type: "StringList" Value: "NA" Description: "Sample secret for generating GuardDuty findings." # Compromised Instance - For GuardDuty Finding: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS CompromisedInstance2: Type: AWS::EC2::Instance Properties: InstanceType: t3.micro IamInstanceProfile: !Ref CompromisedInstanceProfile #KeyName: !Ref KeyName ImageId: !Ref LatestAWSLinuxAmiId NetworkInterfaces: - AssociatePublicIpAddress: true DeviceIndex: 0 GroupSet: - !Ref TargetSecurityGroup SubnetId: Ref: Subnet Tags: - Key: Name Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Compromised Instance', 'Scenario 3'] - Key: GD-Finding Value: 'UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS' UserData: Fn::Base64: !Sub - | #!/bin/bash # Start SSM Agent sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm # Set Variables aws configure set default.region ${Region} uuid=$(uuidgen) list="gd-threat-list-example-$uuid.txt" maliciousip=`curl http://169.254.169.254/latest/meta-data/public-ipv4` # Create Threatlist echo ${IP} >> $list # Upload list to S3 aws s3 cp $list s3://${Bucket}/$list sleep 5 #Block public S3 access at the account level aws s3control put-public-access-block --account-id ${Account} --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" # Create GuardDuty Threat List #id=`aws guardduty list-detectors --query 'DetectorIds[0]' --output text` #aws guardduty create-threat-intel-set --activate --detector-id $id --format TXT --location https://s3.amazonaws.com/${Bucket}/$list --name Example-Threat-List # Create GuardDuty Threat List (with retry logic to ensure the threat list creates successfully) id=`aws guardduty list-detectors --query 'DetectorIds[0]' --output text` n=0 until [ "$n" -ge 5 ] do aws guardduty create-threat-intel-set --activate --detector-id $id --format TXT --location https://s3.amazonaws.com/${Bucket}/$list --name Example-Threat-List && break n=$((n+1)) sleep 5 done # Set Parameters in SSM aws ssm put-parameter --name 'gd_prod_dbpwd_sample' --type "SecureString" --value 'Password123' --overwrite # Add Item to Customer DB aws dynamodb put-item --table-name ${DB} --item '{ "name": { "S": "Joshua Tree" }, "state": {"S": "California"}, "website":{"S": "https://www.nps.gov/jotr/index.htm"} }' - Profile: !Ref CompromisedInstanceProfile Region: !Ref "AWS::Region" Account: !Ref "AWS::AccountId" DB: !Ref CustDynamoDBTable Bucket: !Ref GDThreatListBucket IP: !Ref MaliciousIP # Mock Customer Database CustDynamoDBTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: "name" AttributeType: "S" KeySchema: - AttributeName: "name" KeyType: "HASH" ProvisionedThroughput: ReadCapacityUnits: "5" WriteCapacityUnits: "5" TableName: 'GuardDuty-Example-Customer-DB' # Remediation Lambda Role - Instance Credential Exfiltration (ICE) RemediationLambdaICERole: Type: AWS::IAM::Role Properties: RoleName: Fn::Join: - '-' - [!Ref ResourceName, 'Lambda', 'InstanceCredentialExfiltration'] AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: Fn::Join: - '-' - [!Ref ResourceName, 'InstanceCredentialExfiltration'] PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - ssm:DescribeParameters Resource: '*' - Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: '*' - Effect: Allow Action: - ec2:ReplaceIamInstanceProfileAssociation Resource: '*' - Effect: Allow Action: - ec2:DescribeIamInstanceProfileAssociations Resource: '*' - Effect: Allow Action: - iam:CreateInstanceProfile Resource: '*' - Effect: Allow Action: - iam:AddRoleToInstanceProfile - iam:RemoveRoleFromInstanceProfile - iam:ListInstanceProfilesForRole Resource: '*' - Effect: Allow Action: - iam:DeleteInstanceProfile Resource: Fn::GetAtt: - "CompromisedInstanceProfile" - "Arn" - Effect: Allow Action: - iam:PassRole Resource: Fn::GetAtt: - "CompromisedRole" - "Arn" - Effect: Allow Action: - iam:PutRolePolicy Resource: Fn::GetAtt: - "CompromisedRole" - "Arn" - Effect: Allow Action: - sns:Publish Resource: !Ref GuardDutySNSTopic - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: '*' # Remediation Lambda - Instance Credential Exfiltration (ICE) RemediationLambdaICE: Type: "AWS::Lambda::Function" Properties: FunctionName: Fn::Join: - '-' - [!Ref ResourceName, 'Remediation', 'InstanceCredentialExfiltration'] Handler: "index.handler" Environment: Variables: TOPIC_ARN: !Ref GuardDutySNSTopic Role: Fn::GetAtt: - "RemediationLambdaICERole" - "Arn" Code: ZipFile: | from __future__ import print_function from botocore.exceptions import ClientError import json import datetime import boto3 import os def handler(event, context): # Log out event print("log -- Event: %s " % json.dumps(event)) # Create generic function response response = "Error auto-remediating the finding." try: # Set Clients iam = boto3.client('iam') ec2 = boto3.client('ec2') # Set Role Variable role = event['detail']['resource']['accessKeyDetails']['userName'] # Current Time time = datetime.datetime.utcnow().isoformat() # Set Revoke Policy policy = """ { "Version": "2012-10-17", "Statement": { "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": {"DateLessThan": {"aws:TokenIssueTime": "%s"}} } } """ % time # Add policy to Role to Revoke all Current Sessions iam.put_role_policy( RoleName=role, PolicyName='RevokeOldSessions', PolicyDocument=policy.replace('\n', '').replace(' ', '') ) # Send Response Email response = "GuardDuty Remediation | ID:%s: GuardDuty discovered EC2 IAM credentials (Role: %s) being used outside of the EC2 service. All sessions have been revoked. Please follow up with any additional remediation actions." % (event['detail']['id'], role) sns = boto3.client('sns') sns.publish( TopicArn=os.environ['TOPIC_ARN'], Message=response ) except ClientError as e: print(e) print("log -- Response: %s " % response) return response Runtime: "python3.8" Timeout: "35" RemediationLambdaICEInvokePermissions: DependsOn: - RemediationLambdaICE Type: "AWS::Lambda::Permission" Properties: FunctionName: !Ref "RemediationLambdaICE" Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" # Remediation Lambda Role - EC2/MaliciousIPCaller RemediationLambdaEC2Role: Type: AWS::IAM::Role Properties: RoleName: Fn::Join: - '-' - [!Ref ResourceName, 'Lambda', 'EC2MaliciousIPCaller'] AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: '/' Policies: - PolicyName: Fn::Join: - '-' - [!Ref ResourceName, 'EC2MaliciousIPCaller'] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssm:PutParameter - ec2:AuthorizeSecurityGroupEgress - ec2:AuthorizeSecurityGroupIngress - ec2:CreateSecurityGroup - ec2:DescribeSecurityGroups - ec2:RevokeSecurityGroupEgress - ec2:RevokeSecurityGroupIngress - ec2:UpdateSecurityGroupRuleDescriptionsEgress - ec2:UpdateSecurityGroupRuleDescriptionsIngress - ec2:DescribeInstances - ec2:UpdateSecurityGroupRuleDescriptionsIngress - ec2:DescribeVpcs - ec2:ModifyInstanceAttribute - lambda:InvokeFunction - cloudwatch:PutMetricData - xray:PutTraceSegments - xray:PutTelemetryRecords Resource: '*' - Effect: Allow Action: - logs:* Resource: arn:aws:logs:*:*:* - Effect: Allow Action: - sns:Publish Resource: !Ref GuardDutySNSTopic # Remediation Lambda - EC2MaliciousIPCaller RemediationLambdaEC2: Type: "AWS::Lambda::Function" Properties: FunctionName: Fn::Join: - '-' - [!Ref ResourceName, 'Remediation', 'EC2MaliciousIPCaller'] Handler: "index.handler" Environment: Variables: TOPIC_ARN: !Ref GuardDutySNSTopic FORENSICS_SG: !Ref ForensicSecurityGroup INSTANCE_ID: !Ref CompromisedInstance Role: Fn::GetAtt: - "RemediationLambdaEC2Role" - "Arn" Code: ZipFile: | from __future__ import print_function from botocore.exceptions import ClientError import boto3 import json import os def handler(event, context): # Log out event print("log -- Event: %s " % json.dumps(event)) # Create generic function response response = "Error auto-remediating the finding." try: ec2 = boto3.client('ec2') # Set Variables #vpc_id = event["detail"]["resource"]["instanceDetails"]["networkInterfaces"][0]["vpcId"] instanceID = event["detail"]["resource"]["instanceDetails"]["instanceId"] security_group_id = os.environ['FORENSICS_SG'] if instanceID == os.environ['INSTANCE_ID']: #print("log -- Security Group Created %s in vpc %s." % (security_group_id, vpc_id)) print("log -- Security Group Created %s." % (security_group_id)) # Isolate Instance ec2 = boto3.resource('ec2') instance = ec2.Instance(instanceID) print("log -- %s, %s" % (instance.id, instance.instance_type)) instance.modify_attribute(Groups=[security_group_id]) # Send Response Email response = "GuardDuty Remediation | ID:%s: GuardDuty discovered an EC2 instance (Instance ID: %s) that is communicating outbound with an IP Address on a threat list that you uploaded. All security groups have been removed and it has been isolated. Please follow up with any additional remediation actions." % (event['detail']['id'], event['detail']['resource']['instanceDetails']['instanceId']) sns = boto3.client('sns') sns.publish( TopicArn=os.environ['TOPIC_ARN'], Message=response ) print("log -- Response: %s " % response) else: print("log -- Instance unrelated to GuardDuty-Hands-On environment.") except ClientError as e: print(e) print("log -- Response: %s " % response) return response Runtime: "python3.8" Timeout: "35" RemediationLambdaEC2InvokePermissions: DependsOn: - RemediationLambdaEC2 Type: "AWS::Lambda::Permission" Properties: FunctionName: !Ref "RemediationLambdaEC2" Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" # Findings SNS Topic GuardDutySNSTopic: Type: AWS::SNS::Topic Properties: TopicName: !Ref ResourceName Subscription: - Endpoint: !Ref EmailAddress Protocol: email GuardDutySNSTopicPolicy: Type: AWS::SNS::TopicPolicy Properties: PolicyDocument: Id: ID-GD-Topic-Policy Version: '2012-10-17' Statement: - Sid: SID-GD-Example Effect: Allow Principal: Service: events.amazonaws.com Action: sns:Publish Resource: !Ref GuardDutySNSTopic Topics: - !Ref GuardDutySNSTopic # GuardDuty CloudWatch Event - For GuardDuty Finding: UnauthorizedAccess:EC2/MaliciousIPCaller.Custom GuardDutyEvent: Type: AWS::Events::Rule Properties: Name: GuardDuty-Event-EC2-MaliciousIPCaller Description: "GuardDuty Event: UnauthorizedAccess:EC2/MaliciousIPCaller.Custom" EventPattern: source: - aws.guardduty detail: type: - UnauthorizedAccess:EC2/MaliciousIPCaller.Custom State: ENABLED Targets: - Arn: !GetAtt RemediationLambdaEC2.Arn Id: "GuardDutyEvent-Lambda-Trigger" - Arn: !Ref GuardDutySNSTopic Id: "GuardDutySNSTopic-EC2-ThreatList" InputTransformer: InputTemplate: '"GuardDuty Finding | ID:: The EC2 instance may be compromised and should be investigated. Go to https://console.aws.amazon.com/guardduty/home?region=#/findings?macros=current&fId="' InputPathsMap: instanceid: $.detail.resource.instanceDetails.instanceId gdid: "$.detail.id" region: "$.detail.region" # GuardDuty CloudWatch Event - For GuardDuty Finding: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS GuardDutyEventIAM: Type: "AWS::Events::Rule" Properties: Name: GuardDuty-Event-IAMUser-InstanceCredentialExfiltration Description: "GuardDuty Event: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS" EventPattern: source: - aws.guardduty detail: type: - "UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS" State: "ENABLED" Targets: - Arn: !GetAtt RemediationLambdaICE.Arn Id: "GuardDutyEvent-Lambda-Trigger" - Arn: Ref: "GuardDutySNSTopic" Id: "GuardDutySNSTopic-EC2-IAM" InputTransformer: InputTemplate: '"GuardDuty Finding | ID:: An EC2 instance IAM credentials (Role: ) may be compromised and should be investigated. Go to https://console.aws.amazon.com/guardduty/home?region=#/findings?macros=current&fId="' InputPathsMap: userName: "$.detail.resource.accessKeyDetails.userName" gdid: "$.detail.id" region: "$.detail.region" # GuardDuty CloudWatch Event - For GuardDuty Finding: UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom GuardDutyEventIAM2: Type: "AWS::Events::Rule" Properties: Name: GuardDuty-Event-IAMUser-MaliciousIPCaller Description: "GuardDuty Event: UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom" EventPattern: source: - aws.guardduty detail: type: - "UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom" - "Discovery:S3/MaliciousIPCaller.Custom" State: "ENABLED" Targets: - Arn: Ref: "GuardDutySNSTopic" Id: "GuardDutySNSTopic-IAM-ThreatList" InputTransformer: InputTemplate: '"GuardDuty Finding | ID:: An AWS API operation was invoked (userName: ) from an IP address that is included on your threat list and should be investigated. Go to https://console.aws.amazon.com/guardduty/home?region=#/findings?macros=current&fId="' InputPathsMap: userName: "$.detail.resource.accessKeyDetails.userName" gdid: "$.detail.id" region: "$.detail.region" # GuardDuty CloudWatch Event - For GuardDuty S3 findings Stealth:S3/ServerAccessLoggingDisabled & Policy:S3/BucketBlockPublicAccessDisabled GuardDutyEventS3: Type: "AWS::Events::Rule" Properties: Name: GuardDuty-Event-S3-Stealth-Policy Description: "GuardDuty Event: Stealth:S3/ServerAccessLoggingDisabled & Policy:S3/BucketBlockPublicAccessDisabled" EventPattern: source: - aws.guardduty detail: type: - "Policy:S3/BucketBlockPublicAccessDisabled" - "Stealth:S3/ServerAccessLoggingDisabled" State: "ENABLED" Targets: - Arn: Ref: "GuardDutySNSTopic" Id: "GuardDutySNSTopic-IAM-ThreatList" InputTransformer: InputTemplate: '"GuardDuty Finding | ID:: An AWS S3 related API operation was invoked by user (userName: ) in account . This activity seems suspicious. Please investigate with the user to check if this was expectated behaviour. Go to https://console.aws.amazon.com/guardduty/home?region=#/findings?macros=current&fId="' InputPathsMap: userName: "$.detail.resource.accessKeyDetails.userName" gdid: "$.detail.id" account: "$.detail.accountId" region: "$.detail.region" Outputs: {}