├── lesson1-automation ├── README.md ├── ccoa-1-cfn.yml └── ccoa-1-pipeline.yml ├── lesson2-preventive ├── README.md ├── input.json ├── volume.yml ├── volume-encrypted.yml ├── buildspec.yml └── ccoa-2-cfn-nag-pipeline.yml ├── lesson3-detective ├── README.md └── ccoa-config-rules-s3.yml ├── lesson5-remediation ├── README.md ├── ccoa-5-cloudtrail.yml ├── ccoa-5-config-recorder.yml └── ccoa-5-ec2-eip-remediation.yml ├── lesson4-detective-more └── README.md ├── lesson6-continuous ├── README.md ├── package.json ├── volume.yml ├── ccoa-6-cwe-pattern.json ├── ccoa-6-s3-policy.json ├── buildspec.yml ├── s3-bucket-policy.json ├── buildspec-lambda.yml ├── index.js ├── sam-s3-remediation.yml └── ccoa-6-pipeline.yml ├── README.md ├── lesson0-setup ├── managed-config-rules │ ├── ccoa-mcr-examples.zip │ ├── buildspec.yml │ ├── README.md │ └── managed-config-rules-pipeline.yml ├── test-config-rules-rds.yml ├── test-get-azs-per-region.py ├── test-config-rules-ddb.yml ├── test-config-rules-cloudtrail.yml ├── ccoa-delete-config.py ├── test-dynamodb.yml ├── test-config-recorder.yml ├── test-desired-instance-type-remediation.yml └── README.md ├── .gitignore ├── .taskcat.yml ├── LICENSE ├── update-taskcat.sh ├── launch-taskcat.sh ├── delete-taskcat.sh └── pipeline-taskcat.yml /lesson1-automation/README.md: -------------------------------------------------------------------------------- 1 | # aws-security-workshop -------------------------------------------------------------------------------- /lesson2-preventive/README.md: -------------------------------------------------------------------------------- 1 | # aws-security-workshop -------------------------------------------------------------------------------- /lesson3-detective/README.md: -------------------------------------------------------------------------------- 1 | # aws-security-workshop -------------------------------------------------------------------------------- /lesson5-remediation/README.md: -------------------------------------------------------------------------------- 1 | # aws-security-workshop -------------------------------------------------------------------------------- /lesson4-detective-more/README.md: -------------------------------------------------------------------------------- 1 | # aws-security-workshop -------------------------------------------------------------------------------- /lesson6-continuous/README.md: -------------------------------------------------------------------------------- 1 | # s3-bucket-public-write-prohibited-app Lesson 6 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Go to the [Wiki](https://github.com/PaulDuvall/aws-compliance-workshop/wiki) 2 | -------------------------------------------------------------------------------- /lesson0-setup/managed-config-rules/ccoa-mcr-examples.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaulDuvall/aws-compliance-workshop/HEAD/lesson0-setup/managed-config-rules/ccoa-mcr-examples.zip -------------------------------------------------------------------------------- /lesson2-preventive/input.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey":"CodeCommitS3Bucket", 4 | "ParameterValue":"ccoa-workshop" 5 | }, 6 | { 7 | "ParameterKey":"CodeCommitS3Key", 8 | "ParameterValue":"2/ccoa-2-examples.zip" 9 | } 10 | ] -------------------------------------------------------------------------------- /lesson6-continuous/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "s3-bucket-public-write-prohibited-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"run some tests here\"" 8 | }, 9 | "author": "", 10 | "license": "ABC" 11 | } -------------------------------------------------------------------------------- /lesson6-continuous/volume.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: cfn_nag demo template 4 | 5 | Resources: 6 | EBSVolume: 7 | Type: "AWS::EC2::Volume" 8 | Properties: 9 | Encrypted: false 10 | AvailabilityZone: us-east-1a 11 | Size: 100 -------------------------------------------------------------------------------- /lesson2-preventive/volume.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: cfn_nag demo template 4 | 5 | Resources: 6 | EBSVolume: 7 | Type: "AWS::EC2::Volume" 8 | Properties: 9 | Encrypted: false 10 | AvailabilityZone: us-east-1a 11 | Size: 100 12 | -------------------------------------------------------------------------------- /lesson2-preventive/volume-encrypted.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: cfn_nag demo template 4 | 5 | Resources: 6 | EBSVolume: 7 | Type: "AWS::EC2::Volume" 8 | Properties: 9 | Encrypted: true 10 | AvailabilityZone: us-east-1a 11 | Size: 100 12 | -------------------------------------------------------------------------------- /lesson6-continuous/ccoa-6-cwe-pattern.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":[ 3 | "aws.config" 4 | ], 5 | "detail":{ 6 | "requestParameters":{ 7 | "evaluations":{ 8 | "complianceType":[ 9 | "NON_COMPLIANT" 10 | ] 11 | } 12 | }, 13 | "additionalEventData":{ 14 | "managedRuleIdentifier":[ 15 | "S3_BUCKET_PUBLIC_WRITE_PROHIBITED" 16 | ] 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /lesson6-continuous/ccoa-6-s3-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "s3:DeleteBucketPolicy", 8 | "logs:CreateLogGroup", 9 | "logs:CreateLogStream", 10 | "logs:PutLogEvents" 11 | ], 12 | "Resource": "*" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /lesson2-preventive/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | runtime-versions: 6 | ruby: 2.7 7 | commands: 8 | - ruby --version 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - gem install cfn-nag 13 | - cfn_nag_scan --input-path volume.yml 14 | post_build: 15 | commands: 16 | - echo Build completed on `date` 17 | artifacts: 18 | files: 19 | - '**/*' 20 | -------------------------------------------------------------------------------- /lesson6-continuous/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | runtime-versions: 6 | ruby: 2.7 7 | commands: 8 | - ruby --version 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - gem install cfn-nag 13 | - cfn_nag_scan --input-path volume.yml 14 | post_build: 15 | commands: 16 | - echo Build completed on `date` 17 | artifacts: 18 | files: 19 | - '**/*' 20 | -------------------------------------------------------------------------------- /lesson0-setup/managed-config-rules/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | build: 4 | commands: 5 | - >- 6 | wget 7 | https://s3.amazonaws.com/aws-configservice-us-east-1/cloudformation-templates-for-managed-rules/CLOUD_TRAIL_ENCRYPTION_ENABLED.template 8 | post_build: 9 | commands: 10 | - echo Build completed on `date` 11 | artifacts: 12 | type: zip 13 | files: 14 | - CLOUD_TRAIL_ENCRYPTION_ENABLED.template 15 | -------------------------------------------------------------------------------- /lesson1-automation/ccoa-1-cfn.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: Stelligent CloudFormation Sample Template ** This template creates one 4 | or more Amazon resources. You will be billed for the AWS resources used if you create 5 | a stack from this template. 6 | Resources: 7 | MyQueue: 8 | Type: AWS::SQS::Queue 9 | Properties: 10 | QueueName: !Sub SampleQueue-${AWS::StackName} 11 | Outputs: 12 | MyAWSAccountId: 13 | Value: 14 | Ref: AWS::AccountId 15 | -------------------------------------------------------------------------------- /lesson6-continuous/s3-bucket-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": "*", 7 | "Action": [ 8 | "s3:Abort*", 9 | "s3:DeleteObject", 10 | "s3:GetBucket*", 11 | "s3:GetObject", 12 | "s3:List*", 13 | "s3:PutObject" 14 | ], 15 | "Resource": [ 16 | "arn:aws:s3:::ccoa-6-s3-violation-ACCOUNTID", 17 | "arn:aws:s3:::ccoa-6-s3-violation-ACCOUNTID/*" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /lesson0-setup/test-config-rules-rds.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Deploy AWS Config Rules 3 | Resources: 4 | AWSConfigRuleForDDB: 5 | Type: AWS::Config::ConfigRule 6 | Properties: 7 | ConfigRuleName: rds-storage-encrypted 8 | Description: Checks whether storage encryption is enabled for your RDS DB instances. 9 | Scope: 10 | ComplianceResourceTypes: 11 | - AWS::RDS::DBInstance 12 | Source: 13 | Owner: AWS 14 | SourceIdentifier: RDS_STORAGE_ENCRYPTED 15 | -------------------------------------------------------------------------------- /lesson6-continuous/buildspec-lambda.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | install: 4 | runtime-versions: 5 | nodejs: 16 6 | commands: 7 | - echo "Installing Node.js version 12 ..." 8 | - n $NODE_16_VERSION 9 | build: 10 | commands: 11 | - npm install 12 | - npm install aws-cli-js 13 | - >- 14 | aws cloudformation package --template sam-s3-remediation.yml --s3-bucket 15 | $S3_BUCKET --output-template template-export.json 16 | artifacts: 17 | type: zip 18 | files: 19 | - template-export.json 20 | -------------------------------------------------------------------------------- /lesson0-setup/test-get-azs-per-region.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | 3 | ec2 = boto3.client('ec2') 4 | 5 | # Retrieves all regions/endpoints that work with EC2 6 | aws_regions = ec2.describe_regions() 7 | 8 | # Get a list of regions and then instantiate a new ec2 client for each region in order to get list of AZs for the region 9 | for region in aws_regions['Regions']: 10 | my_region_name = region['RegionName'] 11 | ec2_region = boto3.client('ec2', region_name=my_region_name) 12 | my_region = [{'Name': 'region-name', 'Values': [my_region_name]}] 13 | print ("Current Region is %s" % my_region_name) 14 | aws_azs = ec2_region.describe_availability_zones(Filters=my_region) 15 | for az in aws_azs['AvailabilityZones']: 16 | zone = az['ZoneName'] 17 | print(zone) -------------------------------------------------------------------------------- /lesson0-setup/test-config-rules-ddb.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Deploy AWS Config Rules for DynamoDB 3 | Parameters: 4 | ConfigRuleName1: 5 | Type: String 6 | Default: dynamodb-table-encryption-enabled 7 | Description: The name that you assign to the AWS Config rule for dynamodb-table-encryption-enabled. 8 | MinLength: '1' 9 | ConstraintDescription: This parameter is required. 10 | Resources: 11 | AWSConfigRuleForDDB: 12 | Type: AWS::Config::ConfigRule 13 | Properties: 14 | ConfigRuleName: !Ref 'ConfigRuleName1' 15 | Description: Checks whether the Amazon DynamoDB tables are encrypted and checks their status. The rule is compliant if the status is enabled or enabling. 16 | Scope: 17 | ComplianceResourceTypes: 18 | - AWS::DynamoDB::Table 19 | Source: 20 | Owner: AWS 21 | SourceIdentifier: DYNAMODB_TABLE_ENCRYPTION_ENABLED -------------------------------------------------------------------------------- /lesson6-continuous/index.js: -------------------------------------------------------------------------------- 1 | var AWS = require('aws-sdk'); 2 | 3 | exports.handler = function(event) { 4 | console.log("request:", JSON.stringify(event, undefined, 2)); 5 | 6 | var s3 = new AWS.S3({apiVersion: '2006-03-01'}); 7 | var resource = event['detail']['requestParameters']['evaluations']; 8 | console.log("evaluations:", JSON.stringify(resource, null, 2)); 9 | 10 | 11 | for (var i = 0, len = resource.length; i < len; i++) { 12 | if (resource[i]["complianceType"] == "NON_COMPLIANT") 13 | { 14 | console.log(resource[i]["complianceResourceId"]); 15 | var params = { 16 | Bucket: resource[i]["complianceResourceId"] 17 | }; 18 | 19 | s3.deleteBucketPolicy(params, function(err, data) { 20 | if (err) console.log(err, err.stack); // an error occurred 21 | else console.log(data); // successful response 22 | }); 23 | } 24 | } 25 | 26 | 27 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # TaskCat 2 | taskcat_outputs 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | 32 | # Project ignores 33 | dist/ 34 | environment.sh 35 | .kitchen/ 36 | .kitchen.local.yml 37 | ddb-local/ 38 | 39 | # you might want to take this out if you ever start using files in a non-hacky way. 40 | cookbooks/dromedary/files/default/app 41 | 42 | # IDE 43 | .idea/ 44 | *.iml -------------------------------------------------------------------------------- /.taskcat.yml: -------------------------------------------------------------------------------- 1 | project: 2 | name: ccoa 3 | regions: 4 | - us-east-1 5 | tests: 6 | lesson1-sqs: 7 | template: ./lesson1-automation/ccoa-1-cfn.yml 8 | lesson1-pipeline: 9 | parameters: 10 | CodeCommitS3Bucket: S3_BUCKET_TOKEN 11 | CodeCommitS3Key: ccoa-1-examples.zip 12 | EmailAddress: fake-email@fake-fake-fake-email.com 13 | template: ./lesson1-automation/ccoa-1-pipeline.yml 14 | lesson2-cfn-nag: 15 | parameters: 16 | CodeCommitS3Bucket: S3_BUCKET_TOKEN 17 | CodeCommitS3Key: ccoa-2-examples.zip 18 | template: ./lesson2-preventive/ccoa-2-cfn-nag-pipeline.yml 19 | lesson3-config-rules-s3: 20 | template: ./lesson3-detective/ccoa-config-rules-s3.yml 21 | lesson5-remediation: 22 | template: ./lesson5-remediation/ccoa-5-ec2-eip-remediation.yml 23 | lesson6-continuous: 24 | parameters: 25 | CodeCommitS3Bucket: S3_BUCKET_TOKEN 26 | CodeCommitS3Key: ccoa-6-examples.zip 27 | CreateConfig: donotcreate 28 | template: ./lesson6-continuous/ccoa-6-pipeline.yml 29 | -------------------------------------------------------------------------------- /lesson0-setup/managed-config-rules/README.md: -------------------------------------------------------------------------------- 1 | # Run all AWS Config Managed Rules in CloudFormation 2 | 3 | ``` 4 | aws s3 mb s3://ccoa-mcr-$(aws sts get-caller-identity --output text --query 'Account') 5 | cd ~/environment/aws-compliance-workshop/lesson0-setup/managed-config-rules 6 | zip ccoa-mcr-examples.zip *.* 7 | aws s3 sync ~/environment/aws-compliance-workshop/lesson0-setup/managed-config-rules s3://ccoa-mcr-$(aws sts get-caller-identity --output text --query 'Account') 8 | ``` 9 | 10 | 11 | ``` 12 | aws cloudformation create-stack --stack-name managed-config-rules-pipeline --template-body file:///home/ec2-user/environment/aws-compliance-workshop/lesson0-setup/managed-config-rules/managed-config-rules-pipeline.yml --parameters ParameterKey=EmailAddress,ParameterValue=fake-email@fake-fake-fake-email.com ParameterKey=CodeCommitS3Bucket,ParameterValue=ccoa-mcr-$(aws sts get-caller-identity --output text --query 'Account') ParameterKey=CodeCommitS3Key,ParameterValue=ccoa-mcr-examples.zip --capabilities CAPABILITY_NAMED_IAM --disable-rollback 13 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Paul Duvall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lesson6-continuous/sam-s3-remediation.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Transform: 3 | - 'AWS::Serverless-2016-10-31' 4 | Resources: 5 | PermissionForEventsToInvokeLambda: 6 | Type: 'AWS::Lambda::Permission' 7 | Properties: 8 | FunctionName: 9 | Ref: S3F 10 | Action: 'lambda:InvokeFunction' 11 | Principal: events.amazonaws.com 12 | SourceArn: 13 | 'Fn::GetAtt': 14 | - S3F 15 | - Arn 16 | S3F: 17 | Type: 'AWS::Serverless::Function' 18 | Properties: 19 | Handler: index.handler 20 | Runtime: nodejs16.x 21 | Events: 22 | S3CWE: 23 | Type: CloudWatchEvent 24 | Properties: 25 | Pattern: 26 | source: 27 | - aws.config 28 | detail: 29 | requestParameters: 30 | evaluations: 31 | complianceType: 32 | - NON_COMPLIANT 33 | additionalEventData: 34 | managedRuleIdentifier: 35 | - S3_BUCKET_PUBLIC_WRITE_PROHIBITED 36 | Role: 37 | 'Fn::ImportValue': 38 | 'Fn::Join': 39 | - '-' 40 | - - Ref: 'AWS::StackName' 41 | - LambdaTrustRole -------------------------------------------------------------------------------- /lesson5-remediation/ccoa-5-cloudtrail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | Resources: 3 | AWSConfigRule: 4 | Type: AWS::Config::ConfigRule 5 | Properties: 6 | ConfigRuleName: 7 | Ref: ConfigRuleName 8 | Description: Checks whether AWS CloudTrail creates a signed digest file with 9 | logs. AWS recommends that the file validation must be enabled on all trails. 10 | The rule is noncompliant if the validation is not enabled. 11 | InputParameters: {} 12 | Scope: {} 13 | Source: 14 | Owner: AWS 15 | SourceIdentifier: CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED 16 | MaximumExecutionFrequency: 17 | Ref: MaximumExecutionFrequency 18 | Parameters: 19 | ConfigRuleName: 20 | Type: String 21 | Default: cloud-trail-log-file-validation-enabled 22 | Description: The name that you assign to the AWS Config rule. 23 | MinLength: '1' 24 | ConstraintDescription: This parameter is required. 25 | MaximumExecutionFrequency: 26 | Type: String 27 | Default: TwentyFour_Hours 28 | Description: The frequency that you want AWS Config to run evaluations for the 29 | rule. 30 | MinLength: '1' 31 | ConstraintDescription: This parameter is required. 32 | AllowedValues: 33 | - One_Hour 34 | - Three_Hours 35 | - Six_Hours 36 | - Twelve_Hours 37 | - TwentyFour_Hours 38 | Metadata: 39 | AWS::CloudFormation::Interface: 40 | ParameterGroups: 41 | - Label: 42 | default: Required 43 | Parameters: [] 44 | - Label: 45 | default: Optional 46 | Parameters: [] 47 | Conditions: {} -------------------------------------------------------------------------------- /lesson0-setup/test-config-rules-cloudtrail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | Resources: 3 | AWSConfigRule: 4 | Type: AWS::Config::ConfigRule 5 | Properties: 6 | ConfigRuleName: 7 | Ref: ConfigRuleName 8 | Description: Checks whether AWS CloudTrail creates a signed digest file with 9 | logs. AWS recommends that the file validation must be enabled on all trails. 10 | The rule is noncompliant if the validation is not enabled. 11 | InputParameters: {} 12 | Scope: {} 13 | Source: 14 | Owner: AWS 15 | SourceIdentifier: CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED 16 | MaximumExecutionFrequency: 17 | Ref: MaximumExecutionFrequency 18 | Parameters: 19 | ConfigRuleName: 20 | Type: String 21 | Default: cloud-trail-log-file-validation-enabled 22 | Description: The name that you assign to the AWS Config rule. 23 | MinLength: '1' 24 | ConstraintDescription: This parameter is required. 25 | MaximumExecutionFrequency: 26 | Type: String 27 | Default: TwentyFour_Hours 28 | Description: The frequency that you want AWS Config to run evaluations for the 29 | rule. 30 | MinLength: '1' 31 | ConstraintDescription: This parameter is required. 32 | AllowedValues: 33 | - One_Hour 34 | - Three_Hours 35 | - Six_Hours 36 | - Twelve_Hours 37 | - TwentyFour_Hours 38 | Metadata: 39 | AWS::CloudFormation::Interface: 40 | ParameterGroups: 41 | - Label: 42 | default: Required 43 | Parameters: [] 44 | - Label: 45 | default: Optional 46 | Parameters: [] 47 | Conditions: {} 48 | -------------------------------------------------------------------------------- /update-taskcat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # sudo chmod +x *.sh 3 | # ./update-taskcat.sh my-pipeline-name-bucket 4 | 5 | set -euo pipefail 6 | IFS=$'\n\t' 7 | 8 | #/ Usage: update-taskcat.sh [PIPELINE_BUCKET] 9 | #/ Description: Change all S3_BUCKET_TOKEN references in the TaskCat configuration file to the autogenerated S3 Bucket name used as the ArtifactStore for CodePipeline in the pipeline-taskcat.yml template. 10 | #/ Examples: 11 | #/ launch-stack.sh (launches a stack using the the env var PIPELINE_BUCKET, or shows you these docs if it is unset) 12 | #/ update-taskcat.sh my-pipeline-bucket-name 13 | #/ Options: 14 | #/ --help: Display this help message 15 | usage() { grep '^#/' "$0" | cut -c4- ; exit 1 ; } 16 | expr "$*" : ".*--help" > /dev/null && usage 17 | 18 | readonly LOG_FILE="/tmp/$(basename "$0").log" 19 | info() { echo "[INFO] $@" | tee -a "$LOG_FILE" >&2 ; } 20 | warning() { echo "[WARNING] $@" | tee -a "$LOG_FILE" >&2 ; } 21 | error() { echo "[ERROR] $@" | tee -a "$LOG_FILE" >&2 ; } 22 | fatal() { echo "[FATAL] $@" | tee -a "$LOG_FILE" >&2 ; exit 1 ; } 23 | 24 | PIPELINE_BUCKET=${1:-${PIPELINE_BUCKET:-}} 25 | if [ -z "$PIPELINE_BUCKET" ]; then 26 | usage 27 | fi 28 | 29 | echo "Running update-taskcat.sh" 30 | 31 | PIPELINE_BUCKET=${1:-PIPELINE_BUCKETisrequired} 32 | 33 | echo "$PIPELINE_BUCKET is $PIPELINE_BUCKET" 34 | 35 | echo "Change all S3_BUCKET_TOKEN references in the TaskCat configuration file to the autogenerated S3 Bucket name used as the ArtifactStore for CodePipeline in the pipeline-taskcat.yml template" 36 | sed -i "s/S3_BUCKET_TOKEN/$PIPELINE_BUCKET/g" .taskcat.yml 37 | 38 | echo "Updated update-taskcat.sh" 39 | 40 | cat .taskcat.yml -------------------------------------------------------------------------------- /lesson3-detective/ccoa-config-rules-s3.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Deploy AWS Config Rules for S3 3 | Parameters: 4 | ConfigRuleName3: 5 | Type: String 6 | Default: s3-bucket-public-read-prohibited 7 | Description: The name that you assign to the AWS Config rule for S3-BUCKET-PUBLIC-READ-PROHIBITED. 8 | MinLength: '1' 9 | ConstraintDescription: This parameter is required. 10 | ConfigRuleName4: 11 | Type: String 12 | Default: s3-bucket-public-write-prohibited 13 | Description: The name that you assign to the AWS Config rule for S3-BUCKET-PUBLIC-WRITE-PROHIBITED. 14 | MinLength: '1' 15 | ConstraintDescription: This parameter is required. 16 | Resources: 17 | AWSConfigRuleForS3PublicRead: 18 | Type: AWS::Config::ConfigRule 19 | Properties: 20 | ConfigRuleName: !Ref 'ConfigRuleName3' 21 | Description: Checks that your S3 buckets do not allow public read access. If an S3 bucket policy or bucket ACL allows public read access, the bucket is noncompliant. 22 | Scope: 23 | ComplianceResourceTypes: 24 | - AWS::S3::Bucket 25 | Source: 26 | Owner: AWS 27 | SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED 28 | AWSConfigRuleForPublicWrite: 29 | Type: AWS::Config::ConfigRule 30 | Properties: 31 | ConfigRuleName: !Ref 'ConfigRuleName4' 32 | Description: Checks that your S3 buckets do not allow public write access. If an S3 bucket policy or bucket ACL allows public write access, the bucket is noncompliant. 33 | Scope: 34 | ComplianceResourceTypes: 35 | - AWS::S3::Bucket 36 | Source: 37 | Owner: AWS 38 | SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED -------------------------------------------------------------------------------- /lesson0-setup/ccoa-delete-config.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from botocore.exceptions import ClientError 3 | 4 | # Code based on https://github.com/erpost/aws-config/blob/master/config_remove.py 5 | def del_recorder(region): 6 | try: 7 | client = boto3.client('config', region_name=region) 8 | response = client.delete_configuration_recorder( 9 | ConfigurationRecorderName='default' 10 | ) 11 | print('Recorder removed for region: {}'.format(region)) 12 | 13 | return response 14 | 15 | except ClientError as err: 16 | if err.response['Error']['Code'] == 'NoSuchConfigurationRecorderException': 17 | print('No Recorder configured for region: {}'.format(region)) 18 | 19 | else: 20 | print('\nUnknown error: ', err.response) 21 | return err.response['Error']['Message'] 22 | 23 | 24 | def del_channel(region): 25 | try: 26 | client = boto3.client('config', region_name=region) 27 | response = client.delete_delivery_channel( 28 | DeliveryChannelName='default' 29 | ) 30 | print('Delivery Channel removed for region: {}'.format(region)) 31 | 32 | return response 33 | 34 | except ClientError as err: 35 | if err.response['Error']['Code'] == 'NoSuchDeliveryChannelException': 36 | print('No Delivery Channel configured for region: {}'.format(region)) 37 | 38 | else: 39 | print('\nUnknown error: ', err.response) 40 | return err.response['Error']['Message'] 41 | 42 | 43 | if __name__ == "__main__": 44 | aws_regions = ['us-east-1'] 45 | for aws_region in aws_regions: 46 | print(aws_region) 47 | 48 | for aws_region in aws_regions: 49 | del_recorder(aws_region) 50 | del_channel(aws_region) -------------------------------------------------------------------------------- /launch-taskcat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Bash template based on https://github.com/eppeters/bashtemplate.sh 3 | # sudo chmod +x *.sh 4 | # ./launch-taskcat.sh GH_BRANCH 5 | set -euo pipefail 6 | IFS=$'\n\t' 7 | 8 | #/ Usage: launch-stack.sh GH_BRANCH 9 | #/ Description: Launch Stack that runs TaskCat tests on CCOA. 10 | #/ Examples: 11 | #/ launch-stack.sh (launches a stack using the the env var GH_BRANCH, or shows you these docs if it is unset) 12 | #/ launch-stack.sh eddie (launches a stack with buckets and stack names autogenerated based on the name "eddie") 13 | #/ Options: 14 | #/ --help: Display this help message 15 | usage() { grep '^#/' "$0" | cut -c4- ; exit 1 ; } 16 | expr "$*" : ".*--help" > /dev/null && usage 17 | 18 | readonly LOG_FILE="/tmp/$(basename "$0").log" 19 | info() { echo "[INFO] $@" | tee -a "$LOG_FILE" >&2 ; } 20 | warning() { echo "[WARNING] $@" | tee -a "$LOG_FILE" >&2 ; } 21 | error() { echo "[ERROR] $@" | tee -a "$LOG_FILE" >&2 ; } 22 | fatal() { echo "[FATAL] $@" | tee -a "$LOG_FILE" >&2 ; exit 1 ; } 23 | 24 | AWS_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/\(.*\)[a-z]/\1/') 25 | 26 | echo "Removing buckets previously used by this script" 27 | aws s3api list-buckets --query 'Buckets[?starts_with(Name, `tasckat-ccoa`) == `true`].[Name]' --output text | xargs -I {} aws s3 rb s3://{} --force 28 | 29 | aws s3api list-buckets --query 'Buckets[?starts_with(Name, `tcat-ccoa`) == `true`].[Name]' --output text | xargs -I {} aws s3 rb s3://{} --force 30 | 31 | echo "Deleting taskcat-ccoa stack" 32 | aws cloudformation delete-stack --stack-name taskcat-ccoa 33 | aws cloudformation wait stack-delete-complete --stack-name taskcat-ccoa 34 | 35 | GH_BRANCH=${1:-${GH_BRANCH:-}} 36 | if [ -z "$GH_BRANCH" ]; then 37 | usage 38 | fi 39 | 40 | aws cloudformation create-stack --stack-name taskcat-ccoa-$GH_BRANCH --capabilities CAPABILITY_NAMED_IAM --disable-rollback --template-body file://pipeline-taskcat.yml --parameters ParameterKey=GitHubBranch,ParameterValue=$GH_BRANCH -------------------------------------------------------------------------------- /lesson0-setup/test-dynamodb.yml: -------------------------------------------------------------------------------- 1 | 2 | AWSTemplateFormatVersion: "2010-09-09" 3 | Resources: 4 | myDynamoDBTable: 5 | Type: AWS::DynamoDB::Table 6 | Properties: 7 | SSESpecification: 8 | SSEEnabled: false 9 | AttributeDefinitions: 10 | - 11 | AttributeName: "Album" 12 | AttributeType: "S" 13 | - 14 | AttributeName: "Artist" 15 | AttributeType: "S" 16 | - 17 | AttributeName: "Sales" 18 | AttributeType: "N" 19 | - 20 | AttributeName: "NumberOfSongs" 21 | AttributeType: "N" 22 | KeySchema: 23 | - 24 | AttributeName: "Album" 25 | KeyType: "HASH" 26 | - 27 | AttributeName: "Artist" 28 | KeyType: "RANGE" 29 | ProvisionedThroughput: 30 | ReadCapacityUnits: "5" 31 | WriteCapacityUnits: "5" 32 | TableName: 33 | Ref: AWS::StackName 34 | GlobalSecondaryIndexes: 35 | - 36 | IndexName: "myGSI" 37 | KeySchema: 38 | - 39 | AttributeName: "Sales" 40 | KeyType: "HASH" 41 | - 42 | AttributeName: "Artist" 43 | KeyType: "RANGE" 44 | Projection: 45 | NonKeyAttributes: 46 | - "Album" 47 | - "NumberOfSongs" 48 | ProjectionType: "INCLUDE" 49 | ProvisionedThroughput: 50 | ReadCapacityUnits: "5" 51 | WriteCapacityUnits: "5" 52 | - 53 | IndexName: "myGSI2" 54 | KeySchema: 55 | - 56 | AttributeName: "NumberOfSongs" 57 | KeyType: "HASH" 58 | - 59 | AttributeName: "Sales" 60 | KeyType: "RANGE" 61 | Projection: 62 | NonKeyAttributes: 63 | - "Album" 64 | - "Artist" 65 | ProjectionType: "INCLUDE" 66 | ProvisionedThroughput: 67 | ReadCapacityUnits: "5" 68 | WriteCapacityUnits: "5" 69 | LocalSecondaryIndexes: 70 | - 71 | IndexName: "myLSI" 72 | KeySchema: 73 | - 74 | AttributeName: "Album" 75 | KeyType: "HASH" 76 | - 77 | AttributeName: "Sales" 78 | KeyType: "RANGE" 79 | Projection: 80 | NonKeyAttributes: 81 | - "Artist" 82 | - "NumberOfSongs" 83 | ProjectionType: "INCLUDE" 84 | -------------------------------------------------------------------------------- /lesson5-remediation/ccoa-5-config-recorder.yml: -------------------------------------------------------------------------------- 1 | Description: Setup AWS Config Service 2 | Resources: 3 | ConfigBucket: 4 | Type: AWS::S3::Bucket 5 | DeletionPolicy: Retain 6 | Properties: 7 | AccessControl: BucketOwnerFullControl 8 | DeliveryChannel: 9 | Type: AWS::Config::DeliveryChannel 10 | Properties: 11 | ConfigSnapshotDeliveryProperties: 12 | DeliveryFrequency: "Six_Hours" 13 | S3BucketName: 14 | Ref: ConfigBucket 15 | SnsTopicARN: 16 | Ref: ConfigTopic 17 | ConfigBucketPolicy: 18 | Type: AWS::S3::BucketPolicy 19 | Properties: 20 | Bucket: !Ref 'ConfigBucket' 21 | PolicyDocument: 22 | Version: '2012-10-17' 23 | Id: PutObjPolicy 24 | Statement: 25 | - Sid: DenyUnEncryptedObjects 26 | Effect: Deny 27 | Principal: '*' 28 | Action: s3:PutObject 29 | Resource: !Sub arn:aws:s3:::${ConfigBucket}/* 30 | Condition: 31 | StringNotEquals: 32 | s3:x-amz-server-side-encryption: AES256 33 | ConfigTopic: 34 | Type: AWS::SNS::Topic 35 | Properties: 36 | DisplayName: !Sub 'ccoa-5-${AWS::StackName}-sns-topic' 37 | TopicName: !Sub 'ccoa-5-${AWS::StackName}-sns-topic' 38 | ConfigRole: 39 | Type: AWS::IAM::Role 40 | Properties: 41 | AssumeRolePolicyDocument: 42 | Statement: 43 | - Action: 44 | - sts:AssumeRole 45 | Effect: Allow 46 | Principal: 47 | Service: 48 | - config.amazonaws.com 49 | Version: '2012-10-17' 50 | Path: / 51 | Policies: 52 | - PolicyDocument: 53 | Statement: 54 | - Effect: Allow 55 | Action: sns:Publish 56 | Resource: !Ref 'ConfigTopic' 57 | - Effect: Allow 58 | Action: 59 | - s3:PutObject 60 | Resource: !Sub arn:aws:s3:::${ConfigBucket}/AWSLogs/${AWS::AccountId}/* 61 | Condition: 62 | StringLike: 63 | s3:x-amz-acl: bucket-owner-full-control 64 | - Effect: Allow 65 | Action: 66 | - s3:GetBucketAcl 67 | Resource: !Sub arn:aws:s3:::${ConfigBucket} 68 | PolicyName: root 69 | ManagedPolicyArns: 70 | - arn:aws:iam::aws:policy/service-role/AWSConfigRole 71 | ConfigRecorderCcoa5: 72 | Type: AWS::Config::ConfigurationRecorder 73 | Properties: 74 | RecordingGroup: 75 | AllSupported: true 76 | IncludeGlobalResourceTypes: true 77 | RoleARN: !GetAtt 'ConfigRole.Arn' 78 | Outputs: 79 | StackName: 80 | Value: !Ref 'AWS::StackName' -------------------------------------------------------------------------------- /lesson0-setup/test-config-recorder.yml: -------------------------------------------------------------------------------- 1 | Description: Setup AWS Config Service 2 | Resources: 3 | ConfigBucket: 4 | Type: AWS::S3::Bucket 5 | DeletionPolicy: Retain 6 | Properties: 7 | AccessControl: BucketOwnerFullControl 8 | BucketName: !Sub '${AWS::AccountId}-${AWS::StackName}-awsconfig' 9 | DeliveryChannel: 10 | Type: AWS::Config::DeliveryChannel 11 | Properties: 12 | ConfigSnapshotDeliveryProperties: 13 | DeliveryFrequency: "Six_Hours" 14 | S3BucketName: 15 | Ref: ConfigBucket 16 | SnsTopicARN: 17 | Ref: ConfigTopic 18 | ConfigBucketPolicy: 19 | Type: AWS::S3::BucketPolicy 20 | Properties: 21 | Bucket: !Ref 'ConfigBucket' 22 | PolicyDocument: 23 | Version: '2012-10-17' 24 | Id: PutObjPolicy 25 | Statement: 26 | - Sid: DenyUnEncryptedObjects 27 | Effect: Deny 28 | Principal: '*' 29 | Action: s3:PutObject 30 | Resource: !Join 31 | - '' 32 | - - 'arn:aws:s3:::' 33 | - !Ref 'ConfigBucket' 34 | - /* 35 | Condition: 36 | StringNotEquals: 37 | s3:x-amz-server-side-encryption: AES256 38 | ConfigTopic: 39 | Type: AWS::SNS::Topic 40 | Properties: 41 | DisplayName: config-sns-topic 42 | TopicName: config-sns-topic 43 | ConfigRole: 44 | Type: AWS::IAM::Role 45 | Properties: 46 | AssumeRolePolicyDocument: 47 | Statement: 48 | - Action: 49 | - sts:AssumeRole 50 | Effect: Allow 51 | Principal: 52 | Service: 53 | - config.amazonaws.com 54 | Version: '2012-10-17' 55 | Path: / 56 | Policies: 57 | - PolicyDocument: 58 | Statement: 59 | - Effect: Allow 60 | Action: sns:Publish 61 | Resource: !Ref 'ConfigTopic' 62 | - Effect: Allow 63 | Action: 64 | - s3:PutObject 65 | Resource: 66 | - !Join 67 | - '' 68 | - - 'arn:aws:s3:::' 69 | - !Ref 'ConfigBucket' 70 | - /AWSLogs/ 71 | - !Ref 'AWS::AccountId' 72 | - /* 73 | Condition: 74 | StringLike: 75 | s3:x-amz-acl: bucket-owner-full-control 76 | - Effect: Allow 77 | Action: 78 | - s3:GetBucketAcl 79 | Resource: !Join 80 | - '' 81 | - - 'arn:aws:s3:::' 82 | - !Ref 'ConfigBucket' 83 | PolicyName: root 84 | ManagedPolicyArns: 85 | - arn:aws:iam::aws:policy/service-role/AWSConfigRole 86 | ConfigRecorder: 87 | Type: AWS::Config::ConfigurationRecorder 88 | Properties: 89 | Name: aws-config-recorder 90 | RecordingGroup: 91 | AllSupported: true 92 | IncludeGlobalResourceTypes: true 93 | RoleARN: !GetAtt 'ConfigRole.Arn' 94 | Outputs: 95 | StackName: 96 | Value: !Ref 'AWS::StackName' -------------------------------------------------------------------------------- /lesson0-setup/test-desired-instance-type-remediation.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 'Auto Remediation Config Rule' 3 | Parameters: 4 | InstanceType: 5 | Description: EC2 instanceType 6 | Type: String 7 | Default: t2.medium 8 | Resources: 9 | DesiredInstanceTypeRule: 10 | Type: 'AWS::Config::ConfigRule' 11 | Properties: 12 | ConfigRuleName: desired-instance-type 13 | Description: >- 14 | Auto remediation configuration to stop or terminate EC2 instances using 15 | unapproved instance types. Detection uses a managed AWS Config Rule and 16 | remediation is with SSM Automation. 17 | Scope: 18 | ComplianceResourceTypes: 19 | - 'AWS::EC2::Instance' 20 | Source: 21 | Owner: AWS 22 | SourceIdentifier: DESIRED_INSTANCE_TYPE 23 | InputParameters: 24 | instanceType: !Ref InstanceType 25 | AuoRemediationEventRule: 26 | Type: 'AWS::Events::Rule' 27 | Properties: 28 | Name: auto-remediate-desired-instance-type 29 | Description: 'auto remediation rule for config rule: desired-instance-type' 30 | State: ENABLED 31 | EventPattern: 32 | detail-type: 33 | - Config Rules Compliance Change 34 | source: 35 | - aws.config 36 | detail: 37 | newEvaluationResult: 38 | complianceType: 39 | - NON_COMPLIANT 40 | configRuleARN: 41 | - 'Fn::GetAtt': 42 | - DesiredInstanceTypeRule 43 | - Arn 44 | Targets: 45 | - Id: RemediationAction 46 | RoleArn: 47 | 'Fn::GetAtt': 48 | - AutoRemediationRole 49 | - Arn 50 | Arn: 51 | 'Fn::Sub': >- 52 | arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-StopEC2Instance 53 | InputTransformer: 54 | InputPathsMap: 55 | instance_id: $.detail.resourceId 56 | InputTemplate: 57 | 'Fn::Sub': >- 58 | {"InstanceId":[],"AutomationAssumeRole":["${AutoRemediationRole.Arn}"]} 59 | AutoRemediationRole: 60 | Type: 'AWS::IAM::Role' 61 | Properties: 62 | AssumeRolePolicyDocument: 63 | Version: '2012-10-17' 64 | Statement: 65 | - Effect: Allow 66 | Principal: 67 | Service: 68 | - ec2.amazonaws.com 69 | - events.amazonaws.com 70 | - ssm.amazonaws.com 71 | Action: 72 | - 'sts:AssumeRole' 73 | ManagedPolicyArns: 74 | - 'arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole' 75 | Policies: [] 76 | AutomationPassRolePolicy: 77 | Type: 'AWS::IAM::Policy' 78 | Properties: 79 | PolicyName: passAutomationRole 80 | PolicyDocument: 81 | Version: '2012-10-17' 82 | Statement: 83 | - Effect: Allow 84 | Action: 85 | - 'iam:PassRole' 86 | Resource: 87 | 'Fn::GetAtt': 88 | - AutoRemediationRole 89 | - Arn 90 | Roles: 91 | - Ref: AutoRemediationRole -------------------------------------------------------------------------------- /lesson5-remediation/ccoa-5-ec2-eip-remediation.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Create EIP Auto Remediation using SSM Automation 3 | Resources: 4 | ConfigRule: 5 | Type: 'AWS::Config::ConfigRule' 6 | Properties: 7 | ConfigRuleName: eip-attached 8 | Description: >- 9 | Auto remediation configuration to release unattached Elastic IPs. 10 | Detection uses a managed AWS Config Rule and remediation is with SSM 11 | Automation. Based on https://asecure.cloud/l/auto_remediation/ 12 | Scope: 13 | ComplianceResourceTypes: 14 | - 'AWS::EC2::EIP' 15 | Source: 16 | Owner: AWS 17 | SourceIdentifier: EIP_ATTACHED 18 | AutoRemediationEventRule: 19 | Type: 'AWS::Events::Rule' 20 | Properties: 21 | Name: auto-remediate-eip-attached 22 | Description: 'auto remediation rule for config rule: eip-attached' 23 | State: ENABLED 24 | EventPattern: 25 | detail-type: 26 | - Config Rules Compliance Change 27 | source: 28 | - aws.config 29 | detail: 30 | newEvaluationResult: 31 | complianceType: 32 | - NON_COMPLIANT 33 | configRuleARN: 34 | - 'Fn::GetAtt': 35 | - ConfigRule 36 | - Arn 37 | Targets: 38 | - Id: RemediationAction 39 | RoleArn: 40 | 'Fn::GetAtt': 41 | - AutoRemediationIamRole 42 | - Arn 43 | Arn: 44 | 'Fn::Sub': >- 45 | arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-ReleaseElasticIP 46 | InputTransformer: 47 | InputPathsMap: 48 | eip_allocid: $.detail.resourceId 49 | InputTemplate: 50 | 'Fn::Sub': >- 51 | {"AllocationId":[],"AutomationAssumeRole":["${AutoRemediationIamRole.Arn}"]} 52 | AutoRemediationIamRole: 53 | Type: 'AWS::IAM::Role' 54 | Properties: 55 | AssumeRolePolicyDocument: 56 | Version: '2012-10-17' 57 | Statement: 58 | - Effect: Allow 59 | Principal: 60 | Service: 61 | - ec2.amazonaws.com 62 | - events.amazonaws.com 63 | - ssm.amazonaws.com 64 | Action: 65 | - 'sts:AssumeRole' 66 | ManagedPolicyArns: 67 | - 'arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole' 68 | Policies: 69 | - PolicyName: ReleaseElasticIPPermissions 70 | PolicyDocument: 71 | Statement: 72 | - Action: 73 | - events:DescribeRule 74 | - ec2:ReleaseAddress 75 | Effect: Allow 76 | Resource: "*" 77 | Version: '2012-10-17' 78 | AutomationPassRolePolicy: 79 | Type: 'AWS::IAM::Policy' 80 | Properties: 81 | PolicyName: passAutomationRole 82 | PolicyDocument: 83 | Version: '2012-10-17' 84 | Statement: 85 | - Effect: Allow 86 | Action: 87 | - 'iam:PassRole' 88 | Resource: 89 | 'Fn::GetAtt': 90 | - AutoRemediationIamRole 91 | - Arn 92 | Roles: 93 | - Ref: AutoRemediationIamRole -------------------------------------------------------------------------------- /delete-taskcat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # sudo chmod +x *.sh 3 | # ./delete-taskcat.sh 4 | 5 | PREFIX=tCaT 6 | S3_PREFIX=tcat 7 | # Name used in .taskcat.yml 8 | PROJECT_NAME=ccoa 9 | 10 | AWS_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/\(.*\)[a-z]/\1/') 11 | 12 | # Generated Code by TaskCat. For example: 7806754vf2r1494aa8b64d1av821418881 13 | TASKCAT_CODE=${1:-TBD} 14 | # Generated App Code for Nested Stacks. For example: 2G44LSVW82291 15 | NESTED_APP_CODE=${2:-TBD} 16 | 17 | echo Environment: $TASKCAT_CODE 18 | 19 | echo "Removing buckets previously used by this script" 20 | aws s3api list-buckets --query 'Buckets[?starts_with(Name, `'$S3_PREFIX-$PROJECT_NAME'`) == `true`].[Name]' --output text | xargs -I {} aws s3 rb s3://{} --force 21 | 22 | 23 | # echo "Deleting ccoa-taskcat stack" 24 | # aws s3api list-buckets --query 'Buckets[?starts_with(Name, `ccoa`) == `true`].[Name]' --output text | xargs -I {} aws s3 rb s3://{} --force 25 | # aws cloudformation delete-stack --stack-name ccoa-taskcat 26 | # aws cloudformation wait stack-delete-complete --stack-name 27 | 28 | # Remove Config Recorder 29 | echo "Deleting ccoa-cr stack" 30 | aws cloudformation delete-stack --stack-name ccoa-cr 31 | aws cloudformation wait stack-delete-complete --stack-name ccoa-cr 32 | 33 | # Lesson 6 34 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE-$AWS_REGION stack" 35 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE-$AWS_REGION 36 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE-$AWS_REGION 37 | 38 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE stack" 39 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE 40 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson6-continuous-$TASKCAT_CODE 41 | 42 | # Lesson 5 43 | echo "Deleting $PREFIX-$PROJECT_NAME-l5-cr-$TASKCAT_CODE stack" 44 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-l5-cr-$TASKCAT_CODE 45 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson5-config-recorder-$TASKCAT_CODE 46 | 47 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson5-remediation-$TASKCAT_CODE stack" 48 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson5-remediation-$TASKCAT_CODE 49 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson5-remediation-$TASKCAT_CODE 50 | 51 | # Lesson 3 52 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson3-config-rules-s3-$TASKCAT_CODE stack" 53 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson3-config-rules-s3-$TASKCAT_CODE 54 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson3-config-rules-s3-$TASKCAT_CODE 55 | 56 | # Lesson 2 57 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson2-cfn-nag-$TASKCAT_CODE stack" 58 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson2-cfn-nag-$TASKCAT_CODE 59 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson2-cfn-nag-$TASKCAT_CODE 60 | 61 | # Lesson 1 62 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson1-pipeline-$TASKCAT_CODE stack" 63 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson1-pipeline-$TASKCAT_CODE 64 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson1-pipeline-$TASKCAT_CODE 65 | 66 | echo "Deleting $PREFIX-$PROJECT_NAME-lesson1-sqs-$TASKCAT_CODE stack" 67 | aws cloudformation delete-stack --stack-name $PREFIX-$PROJECT_NAME-lesson1-sqs-$TASKCAT_CODE 68 | aws cloudformation wait stack-delete-complete --stack-name $PREFIX-$PROJECT_NAME-lesson1-sqs-$TASKCAT_CODE -------------------------------------------------------------------------------- /lesson1-automation/ccoa-1-pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: Simple CodePipeline example with CodeCommit and Approval 4 | Parameters: 5 | EmailAddress: 6 | Description: Email Address for sending SNS notifications for CodeCommit 7 | Type: String 8 | RepositoryBranch: 9 | Description: The name of the branch for the CodeCommit repo 10 | Type: String 11 | Default: main 12 | AllowedPattern: "[\\x20-\\x7E]*" 13 | ConstraintDescription: Can contain only ASCII characters. 14 | CodeCommitS3Bucket: 15 | Description: S3 bucket that holds zip of source code for CodeCommit Repo 16 | Type: String 17 | AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" 18 | MaxLength: 63 19 | CodeCommitS3Key: 20 | Description: zipfile key located in CodeCommitS3Bucket 21 | Type: String 22 | Resources: 23 | MySNSTopic: 24 | Type: AWS::SNS::Topic 25 | Properties: 26 | Subscription: 27 | - Endpoint: 28 | Ref: EmailAddress 29 | Protocol: email 30 | CodeCommitRepo: 31 | Type: AWS::CodeCommit::Repository 32 | Properties: 33 | RepositoryName: 34 | Ref: AWS::StackName 35 | RepositoryDescription: CodeCommit Repository for cfn_nag solution 36 | Code: 37 | S3: 38 | Bucket: !Ref CodeCommitS3Bucket 39 | Key: !Ref CodeCommitS3Key 40 | Triggers: 41 | - Name: MasterTrigger 42 | CustomData: 43 | Ref: AWS::StackName 44 | DestinationArn: 45 | Ref: MySNSTopic 46 | Events: 47 | - all 48 | CodeBuildRole: 49 | Type: AWS::IAM::Role 50 | Properties: 51 | AssumeRolePolicyDocument: 52 | Statement: 53 | - Effect: Allow 54 | Principal: 55 | Service: 56 | - codebuild.amazonaws.com 57 | Action: 58 | - sts:AssumeRole 59 | Path: "/" 60 | Policies: 61 | - PolicyName: codebuild-service 62 | PolicyDocument: 63 | Statement: 64 | - Effect: Allow 65 | Action: "*" 66 | Resource: "*" 67 | Version: '2012-10-17' 68 | CodePipelineRole: 69 | Type: AWS::IAM::Role 70 | Properties: 71 | AssumeRolePolicyDocument: 72 | Statement: 73 | - Effect: Allow 74 | Principal: 75 | Service: 76 | - codepipeline.amazonaws.com 77 | Action: 78 | - sts:AssumeRole 79 | Path: "/" 80 | Policies: 81 | - PolicyName: codepipeline-service 82 | PolicyDocument: 83 | Statement: 84 | - Action: 85 | - s3:GetObject 86 | - s3:GetObjectVersion 87 | - s3:GetBucketVersioning 88 | Resource: "*" 89 | Effect: Allow 90 | - Action: 91 | - s3:PutObject 92 | Resource: 93 | - arn:aws:s3:::codepipeline* 94 | Effect: Allow 95 | - Action: 96 | - s3:GetObject 97 | - s3:GetObjectVersion 98 | - s3:GetBucketVersioning 99 | - s3:PutObject 100 | - iam:PassRole 101 | Resource: "*" 102 | Effect: Allow 103 | - Action: 104 | - codecommit:* 105 | - codebuild:* 106 | Resource: "*" 107 | Effect: Allow 108 | Version: '2012-10-17' 109 | PipelineBucket: 110 | Type: AWS::S3::Bucket 111 | DeletionPolicy: Retain 112 | UpdateReplacePolicy: Retain 113 | Pipeline: 114 | Type: AWS::CodePipeline::Pipeline 115 | Properties: 116 | RoleArn: !GetAtt CodePipelineRole.Arn 117 | Stages: 118 | - Name: Source 119 | Actions: 120 | - InputArtifacts: [] 121 | Name: Source 122 | ActionTypeId: 123 | Category: Source 124 | Owner: AWS 125 | Version: '1' 126 | Provider: CodeCommit 127 | OutputArtifacts: 128 | - Name: MyApp 129 | Configuration: 130 | BranchName: 131 | Ref: RepositoryBranch 132 | RepositoryName: 133 | Ref: AWS::StackName 134 | RunOrder: 1 135 | - Name: Deploy 136 | Actions: 137 | - Name: Deploy 138 | ActionTypeId: 139 | Category: Approval 140 | Owner: AWS 141 | Version: '1' 142 | Provider: Manual 143 | Configuration: 144 | ExternalEntityLink: https://mphasis.com 145 | RunOrder: 1 146 | ArtifactStore: 147 | Type: S3 148 | Location: !Ref PipelineBucket 149 | Outputs: 150 | PipelineUrl: 151 | Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline} 152 | Description: CodePipeline URL 153 | -------------------------------------------------------------------------------- /lesson2-preventive/ccoa-2-cfn-nag-pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: Run cfn_nag as part of AWS CodeBuild in CodePipeline 4 | Parameters: 5 | EmailAddress: 6 | Description: Email Address for sending SNS notifications for CodeCommit 7 | Type: String 8 | Default: fake-email@fake-fake-fake-email.com 9 | RepositoryBranch: 10 | Description: The name of the branch for the CodeCommit repo 11 | Type: String 12 | Default: main 13 | AllowedPattern: "[\\x20-\\x7E]*" 14 | ConstraintDescription: Can contain only ASCII characters. 15 | CodeCommitS3Bucket: 16 | Description: S3 bucket that holds zip of source code for CodeCommit Repo 17 | Type: String 18 | AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" 19 | MaxLength: 63 20 | CodeCommitS3Key: 21 | Description: zipfile key located in CodeCommitS3Bucket 22 | Type: String 23 | Resources: 24 | MySNSTopic: 25 | Type: AWS::SNS::Topic 26 | Properties: 27 | Subscription: 28 | - Endpoint: 29 | Ref: EmailAddress 30 | Protocol: email 31 | CodeCommitRepo: 32 | Type: AWS::CodeCommit::Repository 33 | Properties: 34 | RepositoryName: 35 | Ref: AWS::StackName 36 | RepositoryDescription: CodeCommit Repository for cfn_nag solution 37 | Code: 38 | S3: 39 | Bucket: 40 | Ref: CodeCommitS3Bucket 41 | Key: 42 | Ref: CodeCommitS3Key 43 | Triggers: 44 | - Name: MasterTrigger 45 | CustomData: 46 | Ref: AWS::StackName 47 | DestinationArn: 48 | Ref: MySNSTopic 49 | Events: 50 | - all 51 | CodeBuildRole: 52 | Type: AWS::IAM::Role 53 | Properties: 54 | AssumeRolePolicyDocument: 55 | Statement: 56 | - Effect: Allow 57 | Action: 'sts:AssumeRole' 58 | Principal: 59 | Service: codebuild.amazonaws.com 60 | Version: 2012-10-17 61 | Policies: 62 | - PolicyName: CanLog 63 | PolicyDocument: 64 | Version: 2012-10-17 65 | Statement: 66 | - Effect: Allow 67 | Action: 68 | - logs:CreateLogStream 69 | - logs:CreateLogGroup 70 | - logs:PutLogEvents 71 | Resource: 72 | - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${AWS::StackName}*:log-stream:*' 73 | - Effect: Allow 74 | Action: 75 | - s3:GetObject 76 | - s3:PutObject 77 | Resource: 78 | - !GetAtt PipelineBucket.Arn 79 | - !Sub '${PipelineBucket.Arn}/*' 80 | - PolicyName: CanAccessS3 81 | PolicyDocument: 82 | Version: 2012-10-17 83 | Statement: 84 | - Effect: Allow 85 | Action: 86 | - s3:GetObject 87 | Resource: 88 | - !GetAtt PipelineBucket.Arn 89 | CodePipelineRole: 90 | Type: AWS::IAM::Role 91 | Properties: 92 | AssumeRolePolicyDocument: 93 | Version: 2012-10-17 94 | Statement: 95 | - Effect: Allow 96 | Principal: 97 | Service: [codepipeline.amazonaws.com] 98 | Action: ['sts:AssumeRole'] 99 | Policies: 100 | - PolicyName: CanAccessCodeCommit 101 | PolicyDocument: 102 | Version: 2012-10-17 103 | Statement: 104 | - Effect: Allow 105 | Action: 106 | - codecommit:GetBranch 107 | - codecommit:GetCommit 108 | - codecommit:UploadArchive 109 | - codecommit:GetUploadArchiveStatus 110 | Resource: '*' 111 | - PolicyName: CanAccessS3 112 | PolicyDocument: 113 | Version: 2012-10-17 114 | Statement: 115 | - Effect: Allow 116 | Action: s3:ListBucket 117 | Resource: '*' 118 | - Effect: Allow 119 | Action: 120 | - s3:GetObject 121 | - s3:GetObjectVersion 122 | - s3:GetBucketVersioning 123 | - s3:PutObject 124 | - s3:GetBucketPolicy 125 | - s3:GetObjectAcl 126 | - s3:PutObjectAcl 127 | - s3:DeleteObject 128 | Resource: 129 | - !GetAtt PipelineBucket.Arn 130 | - !Sub '${PipelineBucket.Arn}/*' 131 | - Effect: Allow 132 | Action: 133 | - codebuild:BatchGetBuilds 134 | - codebuild:StartBuild 135 | Resource: 136 | - !GetAtt CodeBuildCfnNag.Arn 137 | CodeBuildCfnNag: 138 | Type: AWS::CodeBuild::Project 139 | Properties: 140 | Name: 141 | Ref: AWS::StackName 142 | Description: Build application 143 | ServiceRole: 144 | Fn::GetAtt: 145 | - CodeBuildRole 146 | - Arn 147 | Artifacts: 148 | Type: NO_ARTIFACTS 149 | Environment: 150 | Type: LINUX_CONTAINER 151 | ComputeType: BUILD_GENERAL1_SMALL 152 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 153 | Source: 154 | BuildSpec: buildspec.yml 155 | Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/${AWS::StackName}/ 156 | Type: CODECOMMIT 157 | TimeoutInMinutes: 10 158 | Tags: 159 | - Key: Owner 160 | Value: MyCodeBuildProject 161 | PipelineBucket: 162 | Type: AWS::S3::Bucket 163 | DeletionPolicy: Retain 164 | UpdateReplacePolicy: Retain 165 | Pipeline: 166 | Type: AWS::CodePipeline::Pipeline 167 | Properties: 168 | RoleArn: !GetAtt CodePipelineRole.Arn 169 | Stages: 170 | - Name: Source 171 | Actions: 172 | - InputArtifacts: [] 173 | Name: Source 174 | ActionTypeId: 175 | Category: Source 176 | Owner: AWS 177 | Version: '1' 178 | Provider: CodeCommit 179 | OutputArtifacts: 180 | - Name: MyApp 181 | Configuration: 182 | BranchName: 183 | Ref: RepositoryBranch 184 | RepositoryName: 185 | Ref: AWS::StackName 186 | RunOrder: 1 187 | - Name: Build 188 | Actions: 189 | - InputArtifacts: 190 | - Name: MyApp 191 | Name: cfn_nag 192 | ActionTypeId: 193 | Category: Test 194 | Owner: AWS 195 | Version: '1' 196 | Provider: CodeBuild 197 | OutputArtifacts: [] 198 | Configuration: 199 | ProjectName: 200 | Ref: CodeBuildCfnNag 201 | RunOrder: 1 202 | - Name: Deploy 203 | Actions: 204 | - Name: Deploy 205 | ActionTypeId: 206 | Category: Approval 207 | Owner: AWS 208 | Version: '1' 209 | Provider: Manual 210 | RunOrder: 2 211 | ArtifactStore: 212 | Type: S3 213 | Location: !Ref PipelineBucket 214 | Outputs: 215 | PipelineUrl: 216 | Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline} 217 | Description: CodePipeline URL 218 | -------------------------------------------------------------------------------- /pipeline-taskcat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: CodePipeline with CodeBuild workflow to run TaskCat test CloudFormation templates 4 | Parameters: 5 | GitHubUser: 6 | Type: String 7 | Description: GitHub User 8 | Default: "PaulDuvall" 9 | GitHubRepo: 10 | Type: String 11 | Description: GitHub Repo to pull from. Only the Name. not the URL 12 | Default: "aws-compliance-workshop" 13 | GitHubBranch: 14 | Type: String 15 | Description: GitHub Branch 16 | Default: "master" 17 | GitHubToken: 18 | NoEcho: true 19 | Type: String 20 | Default: '{{resolve:secretsmanager:github/personal-access-token:SecretString}}' 21 | Description: GitHub Token. Must be defined in AWS Secrets Manager and here https://github.com/settings/tokens 22 | Metadata: 23 | AWS::CloudFormation::Interface: 24 | ParameterGroups: 25 | - Label: 26 | default: "GitHub Configuration" 27 | Parameters: 28 | - GitHubToken 29 | - GitHubUser 30 | - GitHubRepo 31 | - GitHubBranch 32 | ParameterLabels: 33 | GitHubToken: 34 | default: GitHub OAuth2 Token 35 | GitHubUser: 36 | default: GitHub User/Org Name 37 | GitHubRepo: 38 | default: GitHub Repository Name 39 | GitHubBranch: 40 | default: GitHub Branch Name 41 | Resources: 42 | SiteBucket: 43 | Type: AWS::S3::Bucket 44 | DeletionPolicy: Retain 45 | Properties: 46 | AccessControl: PublicRead 47 | WebsiteConfiguration: 48 | IndexDocument: index.html 49 | CodePipelineRole: 50 | Type: AWS::IAM::Role 51 | Properties: 52 | AssumeRolePolicyDocument: 53 | Statement: 54 | - Effect: Allow 55 | Principal: 56 | Service: 57 | - codepipeline.amazonaws.com 58 | Action: 59 | - sts:AssumeRole 60 | Path: "/" 61 | Policies: 62 | - PolicyName: codepipeline-service 63 | PolicyDocument: 64 | Statement: 65 | - Action: 66 | - logs:* 67 | - lambda:* 68 | - cloudwatch:* 69 | - codebuild:* 70 | - s3:* 71 | Resource: "*" 72 | Effect: Allow 73 | - Action: 74 | - s3:PutObject 75 | Resource: 76 | - arn:aws:s3:::codepipeline* 77 | Effect: Allow 78 | - Action: 79 | - logs:* 80 | - lambda:* 81 | - cloudwatch:* 82 | - codebuild:* 83 | - s3:* 84 | - ec2:* 85 | - iam:PassRole 86 | Resource: "*" 87 | Effect: Allow 88 | Version: '2012-10-17' 89 | CodeBuildRole: 90 | Type: AWS::IAM::Role 91 | Properties: 92 | AssumeRolePolicyDocument: 93 | Statement: 94 | - Effect: Allow 95 | Principal: 96 | Service: 97 | - codebuild.amazonaws.com 98 | Action: 99 | - sts:AssumeRole 100 | Path: "/" 101 | Policies: 102 | - PolicyName: codebuild-service 103 | PolicyDocument: 104 | Statement: 105 | - Action: 106 | - cloudformation:* 107 | - cloudwatch:* 108 | - codebuild:* 109 | - codecommit:* 110 | - codepipeline:* 111 | - config:* 112 | - dynamodb:* 113 | - ec2:* 114 | - events:* 115 | - iam:* 116 | - lambda:* 117 | - logs:* 118 | - s3:* 119 | - sns:* 120 | - sqs:* 121 | Effect: Allow 122 | Resource: "*" 123 | Version: '2012-10-17' 124 | CodeBuildSetup: 125 | Type: AWS::CodeBuild::Project 126 | DependsOn: CodeBuildRole 127 | Properties: 128 | Description: Setup Test Files. For example uploading to S3 129 | ServiceRole: !GetAtt CodeBuildRole.Arn 130 | Artifacts: 131 | Type: NO_ARTIFACTS 132 | Environment: 133 | Type: LINUX_CONTAINER 134 | ComputeType: BUILD_GENERAL1_SMALL 135 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 136 | EnvironmentVariables: 137 | - Name: PIPELINE_BUCKET 138 | Type: PLAINTEXT 139 | Value: 140 | Fn::Sub: ${PipelineBucket} 141 | Source: 142 | Type: GITHUB 143 | Location: !Sub https://github.com/${GitHubUser}/${GitHubRepo}.git 144 | BuildSpec: buildspec-setup.yml 145 | TimeoutInMinutes: 10 146 | CodeBuildCleanup: 147 | Type: AWS::CodeBuild::Project 148 | DependsOn: CodeBuildRole 149 | Properties: 150 | Description: Setup Test Files. For example uploading to S3 151 | ServiceRole: !GetAtt CodeBuildRole.Arn 152 | Artifacts: 153 | Type: NO_ARTIFACTS 154 | Environment: 155 | Type: LINUX_CONTAINER 156 | ComputeType: BUILD_GENERAL1_SMALL 157 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 158 | Source: 159 | Type: GITHUB 160 | Location: !Sub https://github.com/${GitHubUser}/${GitHubRepo}.git 161 | BuildSpec: buildspec-cleanup.yml 162 | TimeoutInMinutes: 10 163 | CodeBuildTaskCatTest: 164 | Type: AWS::CodeBuild::Project 165 | DependsOn: CodeBuildRole 166 | Properties: 167 | Description: Run TaskCat 168 | ServiceRole: !GetAtt CodeBuildRole.Arn 169 | Artifacts: 170 | Type: CODEPIPELINE 171 | Environment: 172 | Type: LINUX_CONTAINER 173 | ComputeType: BUILD_GENERAL1_SMALL 174 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 175 | Source: 176 | Type: CODEPIPELINE 177 | TimeoutInMinutes: 60 178 | CodeBuildDashboard: 179 | Type: AWS::CodeBuild::Project 180 | DependsOn: CodeBuildRole 181 | Properties: 182 | Description: Deploy site to S3 183 | ServiceRole: !GetAtt CodeBuildRole.Arn 184 | Artifacts: 185 | Type: CODEPIPELINE 186 | Environment: 187 | Type: LINUX_CONTAINER 188 | ComputeType: BUILD_GENERAL1_SMALL 189 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 190 | Source: 191 | Type: CODEPIPELINE 192 | BuildSpec: !Sub | 193 | version: 0.2 194 | phases: 195 | install: 196 | runtime-versions: 197 | python: 3.9 198 | post_build: 199 | commands: 200 | - aws s3 cp --recursive --acl public-read ./taskcat_outputs s3://${SiteBucket}/ 201 | artifacts: 202 | type: zip 203 | files: 204 | - ./index.html 205 | TimeoutInMinutes: 10 206 | PipelineBucket: 207 | Type: AWS::S3::Bucket 208 | DeletionPolicy: Delete 209 | Pipeline: 210 | Type: AWS::CodePipeline::Pipeline 211 | Properties: 212 | RoleArn: !GetAtt CodePipelineRole.Arn 213 | Stages: 214 | - Name: Source 215 | Actions: 216 | - InputArtifacts: [] 217 | Name: Source 218 | ActionTypeId: 219 | Category: Source 220 | Owner: ThirdParty 221 | Version: '1' 222 | Provider: GitHub 223 | OutputArtifacts: 224 | - Name: SourceArtifacts 225 | Configuration: 226 | Owner: !Ref GitHubUser 227 | Repo: !Ref GitHubRepo 228 | Branch: !Ref GitHubBranch 229 | OAuthToken: !Ref GitHubToken 230 | RunOrder: 1 231 | - Name: Build 232 | Actions: 233 | - InputArtifacts: 234 | - Name: SourceArtifacts 235 | Name: Setup 236 | ActionTypeId: 237 | Category: Test 238 | Owner: AWS 239 | Version: '1' 240 | Provider: CodeBuild 241 | OutputArtifacts: 242 | - Name: SetupArtifacts 243 | Configuration: 244 | ProjectName: 245 | Ref: CodeBuildSetup 246 | RunOrder: 1 247 | - InputArtifacts: 248 | - Name: SetupArtifacts 249 | Name: RunTaskCat 250 | ActionTypeId: 251 | Category: Test 252 | Owner: AWS 253 | Version: '1' 254 | Provider: CodeBuild 255 | OutputArtifacts: 256 | - Name: TaskCatArtifacts 257 | Configuration: 258 | ProjectName: 259 | Ref: CodeBuildTaskCatTest 260 | RunOrder: 10 261 | - InputArtifacts: 262 | - Name: TaskCatArtifacts 263 | Name: TaskCatDashboard 264 | ActionTypeId: 265 | Category: Test 266 | Owner: AWS 267 | Version: '1' 268 | Provider: CodeBuild 269 | OutputArtifacts: [] 270 | Configuration: 271 | ProjectName: 272 | Ref: CodeBuildDashboard 273 | RunOrder: 20 274 | - Name: Cleanup 275 | Actions: 276 | - InputArtifacts: 277 | - Name: SourceArtifacts 278 | Name: RemoveS3Buckets 279 | ActionTypeId: 280 | Category: Test 281 | Owner: AWS 282 | Version: '1' 283 | Provider: CodeBuild 284 | OutputArtifacts: [] 285 | Configuration: 286 | ProjectName: 287 | Ref: CodeBuildCleanup 288 | RunOrder: 1 289 | ArtifactStore: 290 | Type: S3 291 | Location: !Ref PipelineBucket 292 | Outputs: 293 | PipelineUrl: 294 | Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline} 295 | Description: CodePipeline URL 296 | TaskCatDashboardUrl: 297 | Value: !Sub http://${SiteBucket}.s3-website-us-east-1.amazonaws.com 298 | Description: URL for TaskCat Dashboard (Available after the CodePipeline completes) -------------------------------------------------------------------------------- /lesson0-setup/managed-config-rules/managed-config-rules-pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: CodePipeline for Deploying Multiple Managed Config Rules 4 | Parameters: 5 | RepositoryBranch: 6 | Description: The name of the branch for the CodeCommit repo 7 | Type: String 8 | Default: main 9 | AllowedPattern: "[\\x20-\\x7E]*" 10 | ConstraintDescription: Can contain only ASCII characters. 11 | CodeCommitS3Bucket: 12 | Description: S3 bucket that holds zip of source code for CodeCommit Repo 13 | Type: String 14 | CodeCommitS3Key: 15 | Description: zipfile key located in CodeCommitS3Bucket 16 | Type: String 17 | Resources: 18 | ArtifactBucket: 19 | Type: AWS::S3::Bucket 20 | DeletionPolicy: Delete 21 | CodeBuildRole: 22 | Type: AWS::IAM::Role 23 | Properties: 24 | AssumeRolePolicyDocument: 25 | Statement: 26 | - Effect: Allow 27 | Principal: 28 | Service: 29 | - codebuild.amazonaws.com 30 | Action: 31 | - sts:AssumeRole 32 | Path: "/" 33 | Policies: 34 | - PolicyName: codebuild-service 35 | PolicyDocument: 36 | Statement: 37 | - Action: 38 | - logs:* 39 | - cloudwatch:* 40 | - codebuild:* 41 | - s3:* 42 | Effect: Allow 43 | Resource: "*" 44 | Version: '2012-10-17' 45 | CodeBuildConfigRules: 46 | Type: AWS::CodeBuild::Project 47 | DependsOn: CodeBuildRole 48 | Properties: 49 | Name: 50 | Fn::Join: 51 | - '' 52 | - - Run 53 | - "CodePipeline" 54 | - Ref: AWS::StackName 55 | Description: Build application 56 | ServiceRole: 57 | Fn::GetAtt: 58 | - CodeBuildRole 59 | - Arn 60 | Artifacts: 61 | Type: no_artifacts 62 | Environment: 63 | EnvironmentVariables: 64 | - Name: S3_BUCKET 65 | Value: 66 | Ref: ArtifactBucket 67 | Type: LINUX_CONTAINER 68 | ComputeType: BUILD_GENERAL1_SMALL 69 | Image: aws/codebuild/eb-nodejs-4.4.6-amazonlinux-64:2.1.3 70 | Source: 71 | BuildSpec: buildspec.yml 72 | Location: 73 | Fn::Join: 74 | - '' 75 | - - https://git-codecommit. 76 | - Ref: AWS::Region 77 | - ".amazonaws.com/v1/repos/" 78 | - Ref: AWS::StackName 79 | Type: CODECOMMIT 80 | TimeoutInMinutes: 10 81 | Tags: 82 | - Key: Owner 83 | Value: MyCodeBuildProject 84 | MySNSTopic: 85 | Type: AWS::SNS::Topic 86 | CodeCommitRepo: 87 | Type: AWS::CodeCommit::Repository 88 | Properties: 89 | RepositoryName: 90 | Ref: AWS::StackName 91 | RepositoryDescription: CodeCommit Repository for Config Rule solution 92 | Code: 93 | S3: 94 | Bucket: !Ref CodeCommitS3Bucket 95 | Key: !Ref CodeCommitS3Key 96 | Triggers: 97 | - Name: MasterTrigger 98 | CustomData: 99 | Ref: AWS::StackName 100 | DestinationArn: 101 | Ref: MySNSTopic 102 | Events: 103 | - all 104 | CloudFormationTrustRole: 105 | DependsOn: 106 | - ArtifactBucket 107 | Description: Creating service role in IAM for AWS CloudFormation 108 | Properties: 109 | AssumeRolePolicyDocument: 110 | Statement: 111 | - Action: sts:AssumeRole 112 | Effect: Allow 113 | Principal: 114 | Service: 115 | - cloudformation.amazonaws.com 116 | Path: "/" 117 | Policies: 118 | - PolicyDocument: 119 | Statement: 120 | - Action: 121 | - s3:PutObject 122 | - s3:GetObject 123 | - s3:GetObjectVersion 124 | Effect: Allow 125 | Resource: 126 | - Fn::Join: 127 | - '' 128 | - - 'arn:aws:s3:::' 129 | - Ref: ArtifactBucket 130 | - Fn::Join: 131 | - '' 132 | - - 'arn:aws:s3:::' 133 | - Ref: ArtifactBucket 134 | - "/*" 135 | - Action: 136 | - sns:CreateTopic 137 | - sns:DeleteTopic 138 | - sns:ListTopics 139 | - sns:GetTopicAttributes 140 | - sns:SetTopicAttributes 141 | - s3:CreateBucket 142 | - s3:DeleteBucket 143 | - events:* 144 | - config:* 145 | Effect: Allow 146 | Resource: "*" 147 | - Action: 148 | - iam:PassRole 149 | Effect: Allow 150 | Resource: "*" 151 | - Action: 152 | - cloudformation:CreateChangeSet 153 | - config:* 154 | Effect: Allow 155 | Resource: 156 | - arn:aws:cloudformation:us-east-1:aws:transform/Serverless-2016-10-31 157 | PolicyName: CloudFormationRolePolicy 158 | RoleName: 159 | Fn::Join: 160 | - "-" 161 | - - stelligent 162 | - Ref: AWS::StackName 163 | - CloudFormation 164 | Type: AWS::IAM::Role 165 | CodePipelineRole: 166 | Type: AWS::IAM::Role 167 | Properties: 168 | AssumeRolePolicyDocument: 169 | Statement: 170 | - Effect: Allow 171 | Principal: 172 | Service: 173 | - codepipeline.amazonaws.com 174 | Action: 175 | - sts:AssumeRole 176 | Path: "/" 177 | Policies: 178 | - PolicyName: codepipeline-service 179 | PolicyDocument: 180 | Statement: 181 | - Action: 182 | - s3:GetObject 183 | - s3:GetObjectVersion 184 | - s3:GetBucketVersioning 185 | Resource: "*" 186 | Effect: Allow 187 | - Action: 188 | - s3:PutObject 189 | Resource: 190 | - arn:aws:s3:::codepipeline* 191 | Effect: Allow 192 | - Action: 193 | - s3:GetObject 194 | - s3:GetObjectVersion 195 | - s3:GetBucketVersioning 196 | - s3:PutObject 197 | - iam:PassRole 198 | Resource: "*" 199 | Effect: Allow 200 | - Action: 201 | - codecommit:* 202 | - codebuild:* 203 | - cloudformation:* 204 | Resource: "*" 205 | Effect: Allow 206 | Version: '2012-10-17' 207 | PipelineBucket: 208 | Type: AWS::S3::Bucket 209 | DeletionPolicy: Delete 210 | Pipeline: 211 | Type: AWS::CodePipeline::Pipeline 212 | Properties: 213 | RoleArn: !GetAtt CodePipelineRole.Arn 214 | Properties: 215 | RoleArn: 216 | Fn::Join: 217 | - '' 218 | - - 'arn:aws:iam::' 219 | - Ref: AWS::AccountId 220 | - ":role/" 221 | - Ref: CodePipelineRole 222 | Stages: 223 | - Name: Source 224 | Actions: 225 | - InputArtifacts: [] 226 | Name: Source 227 | ActionTypeId: 228 | Category: Source 229 | Owner: AWS 230 | Version: '1' 231 | Provider: CodeCommit 232 | OutputArtifacts: 233 | - Name: MyApp 234 | Configuration: 235 | BranchName: 236 | Ref: RepositoryBranch 237 | RepositoryName: 238 | Ref: AWS::StackName 239 | RunOrder: 1 240 | - Name: Build 241 | Actions: 242 | - InputArtifacts: 243 | - Name: MyApp 244 | Name: StoreConfigRules 245 | ActionTypeId: 246 | Category: Build 247 | Owner: AWS 248 | Version: '1' 249 | Provider: CodeBuild 250 | OutputArtifacts: 251 | - Name: ConfigRuleTemplateArtifacts 252 | Configuration: 253 | ProjectName: 254 | Ref: CodeBuildConfigRules 255 | RunOrder: 1 256 | - Name: Deploy 257 | Actions: 258 | - InputArtifacts: 259 | - Name: ConfigRuleTemplateArtifacts 260 | Name: DeployCloudTrailEncryptionTemplate 261 | ActionTypeId: 262 | Category: Deploy 263 | Owner: AWS 264 | Version: '1' 265 | Provider: CloudFormation 266 | OutputArtifacts: [] 267 | Configuration: 268 | ActionMode: CHANGE_SET_REPLACE 269 | ChangeSetName: pipeline-changeset 270 | RoleArn: 271 | Fn::GetAtt: 272 | - CloudFormationTrustRole 273 | - Arn 274 | Capabilities: CAPABILITY_IAM 275 | StackName: 276 | Fn::Join: 277 | - '' 278 | - - "" 279 | - Ref: AWS::StackName 280 | - "-" 281 | - Ref: AWS::Region 282 | - "" 283 | TemplatePath: ConfigRuleTemplateArtifacts::CLOUD_TRAIL_ENCRYPTION_ENABLED.template 284 | RunOrder: 1 285 | - ActionTypeId: 286 | Category: Deploy 287 | Owner: AWS 288 | Provider: CloudFormation 289 | Version: 1 290 | Configuration: 291 | ActionMode: CHANGE_SET_EXECUTE 292 | ChangeSetName: pipeline-changeset 293 | StackName: 294 | Fn::Join: 295 | - '' 296 | - - "" 297 | - Ref: AWS::StackName 298 | - "-" 299 | - Ref: AWS::Region 300 | - "" 301 | InputArtifacts: [] 302 | Name: ExecuteChangeSetCloudTrailEncryption 303 | OutputArtifacts: [] 304 | RunOrder: 2 305 | ArtifactStore: 306 | Type: S3 307 | Location: !Ref PipelineBucket 308 | Outputs: 309 | PipelineUrl: 310 | Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline} 311 | Description: CodePipeline URL -------------------------------------------------------------------------------- /lesson6-continuous/ccoa-6-pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: CodePipeline for Config Rules, CloudWatch Event Rules, and Lambda 4 | Parameters: 5 | EmailAddress: 6 | Description: Email Address for sending SNS notifications for CodeCommit 7 | Type: String 8 | Default: fake-email@fake-fake-fake-email.com 9 | RepositoryBranch: 10 | Description: The name of the branch for the CodeCommit repo 11 | Type: String 12 | Default: main 13 | AllowedPattern: "[\\x20-\\x7E]*" 14 | ConstraintDescription: Can contain only ASCII characters. 15 | CodeCommitS3Bucket: 16 | Description: S3 bucket that holds zip of source code for CodeCommit Repo 17 | Type: String 18 | AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" 19 | MaxLength: 63 20 | CodeCommitS3Key: 21 | Description: zipfile key located in CodeCommitS3Bucket 22 | Type: String 23 | ConfigRuleName: 24 | Type: String 25 | Default: s3-bucket-public-write-prohibited 26 | Description: The name that you assign to the AWS Config rule. 27 | MinLength: '1' 28 | ConstraintDescription: This parameter is required. 29 | MaximumExecutionFrequency: 30 | Type: String 31 | Default: TwentyFour_Hours 32 | Description: The frequency that you want AWS Config to run evaluations for the 33 | rule. 34 | MinLength: '1' 35 | ConstraintDescription: This parameter is required. 36 | AllowedValues: 37 | - One_Hour 38 | - Three_Hours 39 | - Six_Hours 40 | - Twelve_Hours 41 | - TwentyFour_Hours 42 | CreateConfig: 43 | Description: Flag to Create a Config Recorder and Delivery Channel 44 | Default: create 45 | Type: String 46 | AllowedValues: 47 | - create 48 | - donotcreate 49 | ConstraintDescription: must specify create or donotcreate. 50 | Conditions: 51 | CreateNewConfigResources: !Equals [ !Ref CreateConfig, create ] 52 | Resources: 53 | ConfigBucket: 54 | Type: AWS::S3::Bucket 55 | Condition: CreateNewConfigResources 56 | DeletionPolicy: Retain 57 | UpdateReplacePolicy: Retain 58 | Properties: 59 | AccessControl: BucketOwnerFullControl 60 | ConfigTopic: 61 | Type: AWS::SNS::Topic 62 | Condition: CreateNewConfigResources 63 | DeliveryChannel: 64 | Type: AWS::Config::DeliveryChannel 65 | Condition: CreateNewConfigResources 66 | Properties: 67 | ConfigSnapshotDeliveryProperties: 68 | DeliveryFrequency: "Six_Hours" 69 | S3BucketName: 70 | Ref: ConfigBucket 71 | SnsTopicARN: 72 | Ref: ConfigTopic 73 | ConfigBucketPolicy: 74 | Type: AWS::S3::BucketPolicy 75 | Condition: CreateNewConfigResources 76 | Properties: 77 | Bucket: !Ref 'ConfigBucket' 78 | PolicyDocument: 79 | Version: '2012-10-17' 80 | Id: PutObjPolicy 81 | Statement: 82 | - Sid: DenyUnEncryptedObjects 83 | Effect: Deny 84 | Principal: '*' 85 | Action: s3:PutObject 86 | Resource: !Join 87 | - '' 88 | - - 'arn:aws:s3:::' 89 | - !Ref 'ConfigBucket' 90 | - /* 91 | Condition: 92 | StringNotEquals: 93 | s3:x-amz-server-side-encryption: AES256 94 | ConfigRole: 95 | Type: AWS::IAM::Role 96 | Condition: CreateNewConfigResources 97 | Properties: 98 | AssumeRolePolicyDocument: 99 | Statement: 100 | - Action: 101 | - sts:AssumeRole 102 | Effect: Allow 103 | Principal: 104 | Service: 105 | - config.amazonaws.com 106 | Version: '2012-10-17' 107 | Path: / 108 | Policies: 109 | - PolicyDocument: 110 | Statement: 111 | - Effect: Allow 112 | Action: sns:Publish 113 | Resource: !Ref 'ConfigTopic' 114 | - Effect: Allow 115 | Action: 116 | - s3:PutObject 117 | Resource: !Sub arn:aws:s3:::${ConfigBucket}/AWSLogs/${AWS::AccountId}/* 118 | Condition: 119 | StringLike: 120 | s3:x-amz-acl: bucket-owner-full-control 121 | - Effect: Allow 122 | Action: 123 | - s3:GetBucketAcl 124 | Resource: !Sub arn:aws:s3:::${ConfigBucket} 125 | PolicyName: root 126 | ManagedPolicyArns: 127 | - arn:aws:iam::aws:policy/service-role/AWSConfigRole 128 | ConfigRecorder: 129 | Type: AWS::Config::ConfigurationRecorder 130 | Condition: CreateNewConfigResources 131 | Properties: 132 | RecordingGroup: 133 | AllSupported: true 134 | IncludeGlobalResourceTypes: true 135 | RoleARN: !GetAtt 'ConfigRole.Arn' 136 | AWSConfigRule: 137 | Type: AWS::Config::ConfigRule 138 | Condition: CreateNewConfigResources 139 | DependsOn: ConfigRecorder 140 | Properties: 141 | ConfigRuleName: 142 | Ref: ConfigRuleName 143 | Description: Checks that your Amazon S3 buckets do not allow public write access. 144 | The rule checks the Block Public Access settings, the bucket policy, and the 145 | bucket access control list (ACL). 146 | InputParameters: {} 147 | Scope: 148 | ComplianceResourceTypes: 149 | - AWS::S3::Bucket 150 | Source: 151 | Owner: AWS 152 | SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED 153 | MaximumExecutionFrequency: 154 | Ref: MaximumExecutionFrequency 155 | ArtifactBucket: 156 | Type: AWS::S3::Bucket 157 | DeletionPolicy: Retain 158 | UpdateReplacePolicy: Retain 159 | MyLambdaTrustRole: 160 | Properties: 161 | AssumeRolePolicyDocument: 162 | Statement: 163 | - Action: sts:AssumeRole 164 | Effect: Allow 165 | Principal: 166 | Service: 167 | - lambda.amazonaws.com 168 | ManagedPolicyArns: 169 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 170 | Path: "/" 171 | Policies: 172 | - PolicyDocument: 173 | Statement: 174 | - Action: 175 | - s3:DeleteBucketPolicy 176 | - logs:CreateLogGroup 177 | - logs:CreateLogStream 178 | - logs:PutLogEvents 179 | Effect: Allow 180 | Resource: "*" 181 | Version: '2012-10-17' 182 | PolicyName: MyLambdaWorkerPolicy 183 | Type: AWS::IAM::Role 184 | CodeBuildRole: 185 | Type: AWS::IAM::Role 186 | Properties: 187 | AssumeRolePolicyDocument: 188 | Statement: 189 | - Effect: Allow 190 | Principal: 191 | Service: 192 | - codebuild.amazonaws.com 193 | Action: 194 | - sts:AssumeRole 195 | Path: "/" 196 | Policies: 197 | - PolicyName: codebuild-service 198 | PolicyDocument: 199 | Statement: 200 | - Action: 201 | - logs:* 202 | - lambda:* 203 | - cloudwatch:* 204 | - codebuild:* 205 | - s3:* 206 | Effect: Allow 207 | Resource: "*" 208 | Version: '2012-10-17' 209 | CodeBuildLambdaTrigger: 210 | Type: AWS::CodeBuild::Project 211 | Properties: 212 | Description: Package SAM Artifacts 213 | ServiceRole: 214 | Fn::GetAtt: 215 | - CodeBuildRole 216 | - Arn 217 | Artifacts: 218 | Type: NO_ARTIFACTS 219 | Environment: 220 | EnvironmentVariables: 221 | - Name: S3_BUCKET 222 | Value: 223 | Ref: ArtifactBucket 224 | Type: LINUX_CONTAINER 225 | ComputeType: BUILD_GENERAL1_SMALL 226 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 227 | Source: 228 | BuildSpec: buildspec-lambda.yml 229 | Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/${AWS::StackName}/ 230 | Type: CODECOMMIT 231 | TimeoutInMinutes: 10 232 | Tags: 233 | - Key: Owner 234 | Value: MyCodeBuildProject 235 | MySNSTopic: 236 | Type: AWS::SNS::Topic 237 | Properties: 238 | Subscription: 239 | - Endpoint: 240 | Ref: EmailAddress 241 | Protocol: email 242 | CodeCommitRepo: 243 | Type: AWS::CodeCommit::Repository 244 | Properties: 245 | RepositoryName: 246 | Ref: AWS::StackName 247 | RepositoryDescription: CodeCommit Repository for Config Rule solution 248 | Code: 249 | S3: 250 | Bucket: !Ref CodeCommitS3Bucket 251 | Key: !Ref CodeCommitS3Key 252 | Triggers: 253 | - Name: MasterTrigger 254 | CustomData: 255 | Ref: AWS::StackName 256 | DestinationArn: 257 | Ref: MySNSTopic 258 | Events: 259 | - all 260 | CloudFormationTrustRole: 261 | Properties: 262 | AssumeRolePolicyDocument: 263 | Statement: 264 | - Action: sts:AssumeRole 265 | Effect: Allow 266 | Principal: 267 | Service: 268 | - cloudformation.amazonaws.com 269 | Path: "/" 270 | Policies: 271 | - PolicyDocument: 272 | Statement: 273 | - Action: 274 | - s3:PutObject 275 | - s3:GetObject 276 | - s3:GetObjectVersion 277 | Effect: Allow 278 | Resource: 279 | - !Sub arn:aws:s3:::${ArtifactBucket} 280 | - !Sub arn:aws:s3:::${ArtifactBucket}/* 281 | - Action: 282 | - lambda:CreateFunction 283 | - lambda:DeleteFunction 284 | - lambda:AddPermission 285 | - lambda:UpdateFunction 286 | - lambda:UpdateFunctionCode 287 | - lambda:GetFunctionConfiguration 288 | - lambda:UpdateFunctionConfiguration 289 | - lambda:RemovePermission 290 | - lambda:TagResource 291 | - lambda:ListTags 292 | - lambda:UntagResource 293 | - lambda:InvokeFunction 294 | - sns:CreateTopic 295 | - sns:DeleteTopic 296 | - sns:ListTopics 297 | - sns:GetTopicAttributes 298 | - sns:SetTopicAttributes 299 | - s3:CreateBucket 300 | - s3:DeleteBucket 301 | - events:* 302 | Effect: Allow 303 | Resource: "*" 304 | - Action: 305 | - iam:PassRole 306 | Effect: Allow 307 | Resource: 308 | - Fn::GetAtt: 309 | - MyLambdaTrustRole 310 | - Arn 311 | - Action: 312 | - cloudformation:CreateChangeSet 313 | Effect: Allow 314 | Resource: 315 | - arn:aws:cloudformation:us-east-1:aws:transform/Serverless-2016-10-31 316 | PolicyName: CloudFormationRolePolicy 317 | Type: AWS::IAM::Role 318 | CodePipelineRole: 319 | Type: AWS::IAM::Role 320 | Properties: 321 | AssumeRolePolicyDocument: 322 | Statement: 323 | - Effect: Allow 324 | Principal: 325 | Service: 326 | - codepipeline.amazonaws.com 327 | Action: 328 | - sts:AssumeRole 329 | Path: "/" 330 | Policies: 331 | - PolicyName: codepipeline-service 332 | PolicyDocument: 333 | Statement: 334 | - Action: 335 | - s3:GetObject 336 | - s3:GetObjectVersion 337 | - s3:GetBucketVersioning 338 | Resource: "*" 339 | Effect: Allow 340 | - Action: 341 | - s3:PutObject 342 | Resource: 343 | - arn:aws:s3:::codepipeline* 344 | Effect: Allow 345 | - Action: 346 | - s3:GetObject 347 | - s3:GetObjectVersion 348 | - s3:GetBucketVersioning 349 | - s3:PutObject 350 | - iam:PassRole 351 | Resource: "*" 352 | Effect: Allow 353 | - Action: 354 | - codecommit:* 355 | - codebuild:* 356 | - cloudformation:* 357 | Resource: "*" 358 | Effect: Allow 359 | Version: '2012-10-17' 360 | CodeBuildCfnNag: 361 | Type: AWS::CodeBuild::Project 362 | Properties: 363 | Name: 364 | Ref: AWS::StackName 365 | Description: Build application 366 | ServiceRole: 367 | Fn::GetAtt: 368 | - CodeBuildRole 369 | - Arn 370 | Artifacts: 371 | Type: NO_ARTIFACTS 372 | Environment: 373 | Type: LINUX_CONTAINER 374 | ComputeType: BUILD_GENERAL1_SMALL 375 | Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0" 376 | Source: 377 | BuildSpec: buildspec.yml 378 | Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/${AWS::StackName}/ 379 | Type: CODECOMMIT 380 | TimeoutInMinutes: 10 381 | Tags: 382 | - Key: Owner 383 | Value: MyCodeBuildProject 384 | PipelineBucket: 385 | Type: AWS::S3::Bucket 386 | DeletionPolicy: Retain 387 | UpdateReplacePolicy: Retain 388 | Pipeline: 389 | Type: AWS::CodePipeline::Pipeline 390 | Properties: 391 | RoleArn: !GetAtt CodePipelineRole.Arn 392 | Stages: 393 | - Name: Source 394 | Actions: 395 | - InputArtifacts: [] 396 | Name: Source 397 | ActionTypeId: 398 | Category: Source 399 | Owner: AWS 400 | Version: '1' 401 | Provider: CodeCommit 402 | OutputArtifacts: 403 | - Name: MyApp 404 | Configuration: 405 | BranchName: 406 | Ref: RepositoryBranch 407 | RepositoryName: 408 | Ref: AWS::StackName 409 | RunOrder: 1 410 | - Name: Build 411 | Actions: 412 | - InputArtifacts: 413 | - Name: MyApp 414 | Name: cfn_nag 415 | ActionTypeId: 416 | Category: Test 417 | Owner: AWS 418 | Version: '1' 419 | Provider: CodeBuild 420 | OutputArtifacts: [] 421 | Configuration: 422 | ProjectName: 423 | Ref: CodeBuildCfnNag 424 | RunOrder: 1 425 | - InputArtifacts: 426 | - Name: MyApp 427 | Name: BuildLambdaFunctions 428 | ActionTypeId: 429 | Category: Build 430 | Owner: AWS 431 | Version: '1' 432 | Provider: CodeBuild 433 | OutputArtifacts: 434 | - Name: lambdatrigger-BuildArtifact 435 | Configuration: 436 | ProjectName: 437 | Ref: CodeBuildLambdaTrigger 438 | RunOrder: 1 439 | - Name: Deploy 440 | Actions: 441 | - InputArtifacts: 442 | - Name: lambdatrigger-BuildArtifact 443 | Name: GenerateChangeSetLambdaFunction 444 | ActionTypeId: 445 | Category: Deploy 446 | Owner: AWS 447 | Version: '1' 448 | Provider: CloudFormation 449 | OutputArtifacts: [] 450 | Configuration: 451 | ActionMode: CHANGE_SET_REPLACE 452 | ChangeSetName: pipeline-changeset 453 | RoleArn: 454 | Fn::GetAtt: 455 | - CloudFormationTrustRole 456 | - Arn 457 | Capabilities: CAPABILITY_IAM 458 | StackName: !Sub ${AWS::StackName}-${AWS::Region} 459 | TemplatePath: lambdatrigger-BuildArtifact::template-export.json 460 | RunOrder: 1 461 | - ActionTypeId: 462 | Category: Deploy 463 | Owner: AWS 464 | Provider: CloudFormation 465 | Version: '1' 466 | Configuration: 467 | ActionMode: CHANGE_SET_EXECUTE 468 | ChangeSetName: pipeline-changeset 469 | StackName: !Sub ${AWS::StackName}-${AWS::Region} 470 | InputArtifacts: [] 471 | Name: ExecuteChangeSetLambdaFunction 472 | OutputArtifacts: [] 473 | RunOrder: 2 474 | ArtifactStore: 475 | Type: S3 476 | Location: !Ref PipelineBucket 477 | Outputs: 478 | PipelineUrl: 479 | Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline} 480 | Description: CodePipeline URL 481 | LambdaTrustRole: 482 | Description: IAM role for AWS Lambda used for passRole to Lambda functions. 483 | Export: 484 | Name: !Sub ${AWS::StackName}-${AWS::Region}-LambdaTrustRole 485 | Value: 486 | Fn::GetAtt: 487 | - MyLambdaTrustRole 488 | - Arn -------------------------------------------------------------------------------- /lesson0-setup/README.md: -------------------------------------------------------------------------------- 1 | # Automatically Remediate Non-Compliant AWS Resources 2 | **Using AWS Config Rules, CloudWatch Events Rules, and Lambda** 3 | 4 | ``` 5 | aws sts get-caller-identity --output text --query 'Account' 6 | ``` 7 | 8 | # Cleanup 9 | 10 | ``` 11 | aws configure get region --output text 12 | aws configservice describe-configuration-recorders --region REGIONCODE 13 | aws configservice delete-configuration-recorder --configuration-recorder-name CONFIGRECORDERNAME --region REGIONCODE 14 | aws configservice describe-delivery-channels --region REGIONCODE 15 | aws configservice delete-delivery-channel --delivery-channel-name DELIVERYCHANNELNAME --region REGIONCODE 16 | aws s3 rb s3://ccoa-cloudtrail-$(aws sts get-caller-identity --output text --query 'Account') --force --region REGIONCODE 17 | aws s3 rb s3://ccoa-awsconfig-ccoa-config-cloudtrail-$(aws sts get-caller-identity --output text --query 'Account') --force --region REGIONCODE 18 | aws cloudformation delete-stack --stack-name ccoa-config-cloudtrail --region us-east-2 --region REGIONCODE 19 | aws s3 rb s3://ccoa-s3-write-violation-$(aws sts get-caller-identity --output text --query 'Account') --region REGIONCODE 20 | aws iam delete-policy --policy-arn arn:aws:iam::$(aws sts get-caller-identity --output text --query 'Account'):policy/ccoa-s3-write-policy --region REGIONCODE 21 | aws lambda delete-function --function-name "ccoa-s3-write-remediation" --region REGIONCODE 22 | aws configservice delete-config-rule --config-rule-name ccoa-s3-write-rule --region REGIONCODE 23 | aws events list-targets-by-rule --rule "ccoa-s3-write-cwe" --region REGIONCODE 24 | aws events remove-targets --rule "ccoa-s3-write-cwe" --ids "TARGETIDSFROMABOVE" --region REGIONCODE 25 | ``` 26 | 27 | # Automated Remediation CloudFormation and CodePipeline with Stack Updates 28 | 29 | ## CloudFormation Resources 30 | * [AWS::S3::Bucket](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html) 31 | * [AWS::CloudTrail::Trail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudtrail-trail.html) 32 | * [AWS::Logs::LogGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html) 33 | * [AWS::SNS::Topic](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html) 34 | * [AWS::Config::ConfigurationRecorder](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configurationrecorder.html) 35 | * [AWS::Config::DeliveryChannel](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html) 36 | * [AWS::S3::BucketPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-policy.html) 37 | * [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html) 38 | * [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) 39 | * [AWS::Config::ConfigRule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configrule.html) 40 | * [AWS::Events::Rule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html) 41 | 42 | 43 | ## Create CloudFormation Template to enable ConfigRecorder 44 | 45 | The following CloudFormation Resources are created in this section: 46 | 47 | * [AWS::S3::Bucket](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html) (1 for Config Snapshots and 1 for CloudTrail logs) 48 | * [AWS::CloudTrail::Trail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudtrail-trail.html) (1 for CloudTrail) 49 | * [AWS::SNS::Topic](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html) (1 for Config and 1 for CloudTrail logs) 50 | * [AWS::Config::ConfigurationRecorder](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configurationrecorder.html) (1 for Config) 51 | * [AWS::Config::DeliveryChannel](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html) (1 for Config) 52 | * [AWS::S3::BucketPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-policy.html) (1 for Config and 1 for CloudTrail logs) 53 | * [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html) (1 for Config) 54 | 55 | 56 | 1. Create `lesson0` directory from your AWS Cloud9 environment: 57 | 58 | ``` 59 | mkdir ~/environment/lesson0 60 | ``` 61 | 62 | 2. Change directory: 63 | 64 | ``` 65 | cd ~/environment/lesson0 66 | ``` 67 | 68 | 3. Create a new file 69 | 70 | ``` 71 | touch ccoa-cloudtrail.yml 72 | ``` 73 | 74 | 4. Paste contents 75 | 76 | 77 | ``` 78 | --- 79 | AWSTemplateFormatVersion: '2010-09-09' 80 | Parameters: 81 | OperatorEmail: 82 | Description: Email address to notify when new logs are published. 83 | Type: String 84 | Resources: 85 | S3Bucket: 86 | DeletionPolicy: Retain 87 | Type: AWS::S3::Bucket 88 | Properties: {} 89 | BucketPolicy: 90 | Type: AWS::S3::BucketPolicy 91 | Properties: 92 | Bucket: 93 | Ref: S3Bucket 94 | PolicyDocument: 95 | Version: '2012-10-17' 96 | Statement: 97 | - Sid: AWSCloudTrailAclCheck 98 | Effect: Allow 99 | Principal: 100 | Service: cloudtrail.amazonaws.com 101 | Action: s3:GetBucketAcl 102 | Resource: 103 | Fn::Join: 104 | - '' 105 | - - 'arn:aws:s3:::' 106 | - Ref: S3Bucket 107 | - Sid: AWSCloudTrailWrite 108 | Effect: Allow 109 | Principal: 110 | Service: cloudtrail.amazonaws.com 111 | Action: s3:PutObject 112 | Resource: 113 | Fn::Join: 114 | - '' 115 | - - 'arn:aws:s3:::' 116 | - Ref: S3Bucket 117 | - "/AWSLogs/" 118 | - Ref: AWS::AccountId 119 | - "/*" 120 | Condition: 121 | StringEquals: 122 | s3:x-amz-acl: bucket-owner-full-control 123 | Topic: 124 | Type: AWS::SNS::Topic 125 | Properties: 126 | Subscription: 127 | - Endpoint: 128 | Ref: OperatorEmail 129 | Protocol: email 130 | TopicPolicy: 131 | Type: AWS::SNS::TopicPolicy 132 | Properties: 133 | Topics: 134 | - Ref: Topic 135 | PolicyDocument: 136 | Version: '2008-10-17' 137 | Statement: 138 | - Sid: AWSCloudTrailSNSPolicy 139 | Effect: Allow 140 | Principal: 141 | Service: cloudtrail.amazonaws.com 142 | Resource: "*" 143 | Action: SNS:Publish 144 | myTrail: 145 | DependsOn: 146 | - BucketPolicy 147 | - TopicPolicy 148 | Type: AWS::CloudTrail::Trail 149 | Properties: 150 | S3BucketName: 151 | Ref: S3Bucket 152 | SnsTopicName: 153 | Fn::GetAtt: 154 | - Topic 155 | - TopicName 156 | IsLogging: true 157 | IsMultiRegionTrail: false 158 | ``` 159 | 160 | From your AWS Cloud9 environment, run the following command: 161 | 162 | ``` 163 | aws cloudformation create-stack --stack-name ccoa-cloudtrail --template-body file:///home/ec2-user/environment/lesson0/ccoa-cloudtrail.yml --parameters ParameterKey=OperatorEmail,ParameterValue=YOUREMAILADDRESS@example.com --capabilities CAPABILITY_NAMED_IAM --disable-rollback --region us-east-2 164 | ``` 165 | 166 | 3. Create a new file 167 | 168 | ``` 169 | touch ccoa-config-recorder.yml 170 | ``` 171 | 172 | 4. Paste the contents of the CloudFormation template into `ccoa-config-recorder.yml` and save the file 173 | 174 | ``` 175 | Description: Setup AWS Config Service 176 | Resources: 177 | ConfigBucket: 178 | Type: AWS::S3::Bucket 179 | DeletionPolicy: Retain 180 | Properties: 181 | AccessControl: BucketOwnerFullControl 182 | BucketName: !Sub 'ccoa-awsconfig-${AWS::StackName}-${AWS::AccountId}' 183 | DeliveryChannel: 184 | Type: AWS::Config::DeliveryChannel 185 | Properties: 186 | ConfigSnapshotDeliveryProperties: 187 | DeliveryFrequency: "Six_Hours" 188 | S3BucketName: 189 | Ref: ConfigBucket 190 | SnsTopicARN: 191 | Ref: ConfigTopic 192 | ConfigBucketPolicy: 193 | Type: AWS::S3::BucketPolicy 194 | Properties: 195 | Bucket: !Ref 'ConfigBucket' 196 | PolicyDocument: 197 | Version: '2012-10-17' 198 | Id: PutObjPolicy 199 | Statement: 200 | - Sid: DenyUnEncryptedObjects 201 | Effect: Deny 202 | Principal: '*' 203 | Action: s3:PutObject 204 | Resource: !Join 205 | - '' 206 | - - 'arn:aws:s3:::' 207 | - !Ref 'ConfigBucket' 208 | - /* 209 | Condition: 210 | StringNotEquals: 211 | s3:x-amz-server-side-encryption: AES256 212 | ConfigTopic: 213 | Type: AWS::SNS::Topic 214 | Properties: 215 | DisplayName: !Sub 'ccoa-${AWS::StackName}-sns-topic' 216 | TopicName: !Sub 'ccoa-${AWS::StackName}-sns-topic' 217 | ConfigRole: 218 | Type: AWS::IAM::Role 219 | Properties: 220 | AssumeRolePolicyDocument: 221 | Statement: 222 | - Action: 223 | - sts:AssumeRole 224 | Effect: Allow 225 | Principal: 226 | Service: 227 | - config.amazonaws.com 228 | Version: '2012-10-17' 229 | Path: / 230 | Policies: 231 | - PolicyDocument: 232 | Statement: 233 | - Effect: Allow 234 | Action: sns:Publish 235 | Resource: !Ref 'ConfigTopic' 236 | - Effect: Allow 237 | Action: 238 | - s3:PutObject 239 | Resource: 240 | - !Join 241 | - '' 242 | - - 'arn:aws:s3:::' 243 | - !Ref 'ConfigBucket' 244 | - /AWSLogs/ 245 | - !Ref 'AWS::AccountId' 246 | - /* 247 | Condition: 248 | StringLike: 249 | s3:x-amz-acl: bucket-owner-full-control 250 | - Effect: Allow 251 | Action: 252 | - s3:GetBucketAcl 253 | Resource: !Join 254 | - '' 255 | - - 'arn:aws:s3:::' 256 | - !Ref 'ConfigBucket' 257 | PolicyName: root 258 | ManagedPolicyArns: 259 | - arn:aws:iam::aws:policy/service-role/AWSConfigRole 260 | ConfigRecorder: 261 | Type: AWS::Config::ConfigurationRecorder 262 | Properties: 263 | Name: !Sub 'ccoa-${AWS::StackName}' 264 | RecordingGroup: 265 | AllSupported: true 266 | IncludeGlobalResourceTypes: true 267 | RoleARN: !GetAtt 'ConfigRole.Arn' 268 | Outputs: 269 | StackName: 270 | Value: !Ref 'AWS::StackName' 271 | ``` 272 | 273 | 274 | ## Launch the CloudFormation stack to enable the ConfigRecorder 275 | 276 | From your AWS Cloud9 environment, run the following command: 277 | 278 | ``` 279 | aws cloudformation create-stack --stack-name ccoa-config-recorder --template-body file:///home/ec2-user/environment/lesson0/ccoa-config-recorder.yml --capabilities CAPABILITY_NAMED_IAM --disable-rollback --region us-east-2 280 | ``` 281 | 282 | ### Check CloudFormation stack status 283 | 284 | ``` 285 | aws cloudformation describe-stacks --stack-name ccoa-config-recorder 286 | ``` 287 | 288 | or, go to [CloudFormation console](https://console.aws.amazon.com/cloudformation/) 289 | 290 | 291 | ## Create a Config Rule 292 | 293 | 1. Change directory: 294 | 295 | ``` 296 | cd ~/environment/lesson0 297 | ``` 298 | 299 | 2. Create a new file 300 | 301 | ``` 302 | touch ccoa-configrule.yml 303 | ``` 304 | 305 | 3. Paste contents 306 | 307 | 308 | ``` 309 | --- 310 | Resources: 311 | AWSConfigRule: 312 | Type: AWS::Config::ConfigRule 313 | Properties: 314 | ConfigRuleName: 315 | Ref: ConfigRuleName 316 | Description: Checks that your Amazon S3 buckets do not allow public write access. 317 | The rule checks the Block Public Access settings, the bucket policy, and the 318 | bucket access control list (ACL). 319 | InputParameters: {} 320 | Scope: 321 | ComplianceResourceTypes: 322 | - AWS::S3::Bucket 323 | Source: 324 | Owner: AWS 325 | SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED 326 | MaximumExecutionFrequency: 327 | Ref: MaximumExecutionFrequency 328 | AutoRemediationEventRule: 329 | Type: 'AWS::Events::Rule' 330 | Properties: 331 | Name: 332 | Ref: AWS::StackName 333 | Description: 'auto remediation rule for config rule: s3-bucket-public-write-prohibited' 334 | State: ENABLED 335 | EventPattern: 336 | source: 337 | - aws.config 338 | detail: 339 | requestParameters: 340 | evaluations: 341 | complianceType: 342 | - NON_COMPLIANT 343 | additionalEventData: 344 | managedRuleIdentifier: 345 | - S3_BUCKET_PUBLIC_WRITE_PROHIBITED 346 | Targets: 347 | - Arn: !Sub '${LambdaArn}' 348 | Id: !Sub '${LambdaId}' 349 | AutoRemediationIamRole: 350 | Type: AWS::IAM::Role 351 | Properties: 352 | AssumeRolePolicyDocument: 353 | Statement: 354 | - Effect: Allow 355 | Principal: 356 | Service: 357 | - lambda.amazonaws.com 358 | Action: 359 | - sts:AssumeRole 360 | Path: "/" 361 | Policies: 362 | - PolicyName: lambda-policy 363 | PolicyDocument: 364 | Statement: 365 | - Effect: Allow 366 | Action: "*" 367 | Resource: "*" 368 | Version: '2012-10-17' 369 | Parameters: 370 | ConfigRuleName: 371 | Type: String 372 | Default: s3-bucket-public-write-prohibited 373 | Description: The name that you assign to the AWS Config rule. 374 | MinLength: '1' 375 | ConstraintDescription: This parameter is required. 376 | LambdaArn: 377 | Type: String 378 | Description: The Arn for an existing Lambda function 379 | MinLength: '1' 380 | ConstraintDescription: This parameter is required. 381 | LambdaId: 382 | Type: String 383 | Description: The Id for an existing Lambda function 384 | MinLength: '1' 385 | ConstraintDescription: This parameter is required. 386 | MaximumExecutionFrequency: 387 | Type: String 388 | Default: TwentyFour_Hours 389 | Description: The frequency that you want AWS Config to run evaluations for the 390 | rule. 391 | MinLength: '1' 392 | ConstraintDescription: This parameter is required. 393 | AllowedValues: 394 | - One_Hour 395 | - Three_Hours 396 | - Six_Hours 397 | - Twelve_Hours 398 | - TwentyFour_Hours 399 | ``` 400 | 401 | 4. From your AWS Cloud9 environment, run the following command: 402 | 403 | ``` 404 | aws cloudformation create-stack --stack-name ccoa-config-rule --template-body file:///home/ec2-user/environment/lesson0/ccoa-config-rule.yml --parameters ParameterKey=LambdaArn,ParameterValue=LAMBDAARN ParameterKey=LambdaId,ParameterValue=LAMBDAID --capabilities CAPABILITY_NAMED_IAM --disable-rollback --region us-east-2 405 | ``` 406 | 407 | 5. Manually edit the CloudWatch Events Rule and Save (Not sure why yet!) 408 | 6. Run Config Rule 409 | 7. Check S3 bucket 410 | 8. Run Config Rule again 411 | 412 | 413 | ## Create a CloudWatch Events Rule 414 | 415 | 1. Change directory: 416 | 417 | ``` 418 | cd ~/environment/lesson0 419 | ``` 420 | 421 | 2. Create a new file 422 | 423 | ``` 424 | touch ccoa-cwe-rule.yml 425 | ``` 426 | 427 | 3. Paste contents 428 | 429 | 430 | ``` 431 | ``` 432 | 433 | 434 | # Create a Lambda Function that Auto Remediates S3 Bucket using CloudFormation 435 | 436 | 1. Zip the files and upload to S3 437 | ``` 438 | aws s3 ls 439 | aws s3 rb s3://ccoa-rem-awsconfig --region REGIONCODE --force 440 | aws s3 rb s3://PIPELINEBUCKET --region REGIONCODE --force 441 | aws s3 rb s3://ARTIFACTBUCKET --region REGIONCODE --force 442 | aws s3 rb s3://$(aws sts get-caller-identity --output text --query 'Account')-pmd-rem-awsconfig --region REGIONCODE --force 443 | aws cloudformation delete-stack --stack-name ccoa-rem-$(aws configure get region --output text) --region REGIONCODE 444 | aws cloudformation delete-stack --stack-name ccoa-rem --region REGIONCODE 445 | 446 | 447 | sudo rm -rf ~/environment/tmp 448 | mkdir ~/environment/tmp 449 | cd ~/environment/tmp 450 | mkdir codecommit 451 | cd ~/environment/aws-compliance-workshop/lesson0-setup 452 | zip ccoa-lesson0-examples.zip *.* 453 | mv ccoa-lesson0-examples.zip ~/environment/tmp/codecommit 454 | aws s3 sync ~/environment/tmp/codecommit/ s3://pmd-compliance-workshop 455 | ``` 456 | 457 | 4. Launch the CloudFormation stack for Config Rules, CWE, and Pipeline 458 | 459 | ``` 460 | aws cloudformation create-stack --stack-name ccoa-rem --template-body file:///home/ec2-user/environment/aws-compliance-workshop/lesson0-setup/ccoa-remediation-pipeline.yml --parameters ParameterKey=EmailAddress,ParameterValue=EMAILADDRESS@example.com ParameterKey=CodeCommitS3Bucket,ParameterValue=pmd-compliance-workshop ParameterKey=CodeCommitS3Key,ParameterValue=ccoa-lesson0-examples.zip --capabilities CAPABILITY_NAMED_IAM --disable-rollback --region REGIONCODE 461 | ```` 462 | 463 | # Autoremediate from the AWS Console 464 | 465 | ## Create an S3 Bucket for CloudTrail Trail 466 | `ccoa-cloudtrail-ACCOUNTID` 467 | 1. Go to the [S3](https://console.aws.amazon.com/s3/) console 468 | 2. Click the **Create bucket** button 469 | 3. Enter `ccoa-cloudtrail-ACCOUNTID` in the **Bucket name** field (replacing `ACCOUNTID` with your account id) 470 | 4. Click **Next** on the *Configure Options* screen 471 | 5. Click **Next** on the *Set Permissions* screen 472 | 6. Click **Create bucket** on the *Review* screen 473 | 474 | ## Create a CloudTrail Trail 475 | `ccoa-cloudtrail` 476 | 1. Go to the [CloudTrail](https://console.aws.amazon.com/cloudtrail/) console 477 | 2. Click the **Create trail** button 478 | 3. Enter **ccoa-cloudtrail** in the *Trail name* field 479 | 4. Choose the checkbox next to **Select all S3 buckets in your account** in the *Data events* section 480 | 4. Choose the **No** radio button for the *Create a new S3 bucket* field in the *Storage location* section. 481 | 5. Choose the S3 bucket you just created from the *S3 bucket* dropdown. 482 | 6. Click the **Create** button 483 | 484 | ## Cloudwatch Logs 485 | 1. Go to the [CloudWatch](https://console.aws.amazon.com/cloudwatch/) console 486 | 487 | 488 | ## Create an AWS Config Recorder 489 | NOTE: If you've already enabled Config on your AWS account, you do not need to go through these instructions 490 | 1. Go to the [Config](https://console.aws.amazon.com/config/) console 491 | 2. If it's your first time using Config, click the **Get Started** button 492 | 3. Select the **Include global resources (e.g., AWS IAM resources)** checkbox 493 | 4. In the *Amazon SNS topic* section, select the **Stream configuration changes and notifications to an Amazon SNS topic.** checkbox 494 | 5. Choose the **Create a topic** radio button in the *Amazon SNS topic* section 495 | 6. In the *Amazon S3 bucket* section, select the **Create a bucket** radio button 496 | 8. In the *AWS Config role* section, select the **Use an existing AWS Config service-linked role** radio button 497 | 9. Click the **Next** button 498 | 10. Click the **Skip** button on the *AWS Config rules* page 499 | 11. Click the **Confirm** button on the *Review* page 500 | 501 | NOTE: This creates a Config Delivery Channel 502 | 503 | ## Create an S3 Bucket in violation 504 | `ccoa-s3-write-violation-ACCOUNTID` 505 | 1. Go to the [S3](https://console.aws.amazon.com/s3/) console 506 | 2. Click the **Create bucket** button 507 | 3. Enter `ccoa-s3-write-violation-ACCOUNTID` in the **Bucket name** field (replacing `ACCOUNTID` with your account id) 508 | 4. Click **Next** on the *Configure Options* screen 509 | 5. Unselect the **Block all public access** checkbox and click **Next** on the *Set Permissions* screen 510 | 6. Click **Create bucket** on the *Review* screen 511 | 7. Select the `ccoa-s3-write-violation-ACCOUNTID` bucket and choose the **Permissions** tab 512 | 8. Click on **Bucket Policy** and paste the contents from below into the *Bucket policy editor* text area (replace both `mybucketname` values with the `ccoa-s3-write-violation-ACCOUNTID` bucket you just created) 513 | 9. Click the **Save** button 514 | 515 | ``` 516 | { 517 | "Version": "2012-10-17", 518 | "Statement": [ 519 | { 520 | "Effect": "Allow", 521 | "Principal": "*", 522 | "Action": [ 523 | "s3:Abort*", 524 | "s3:DeleteObject", 525 | "s3:GetBucket*", 526 | "s3:GetObject", 527 | "s3:List*", 528 | "s3:PutObject" 529 | ], 530 | "Resource": [ 531 | "arn:aws:s3:::mybucketname", 532 | "arn:aws:s3:::mybucketname/*" 533 | ] 534 | } 535 | ] 536 | } 537 | ``` 538 | 539 | You'll receive this message: *You have provided public access to this bucket. We highly recommend that you never grant any kind of public access to your S3 bucket.* 540 | 541 | ## Create an IAM Policy and Role for Lambda 542 | `ccoa-s3-write-policy` 543 | 1. Go to the [IAM](https://console.aws.amazon.com/iam/) console 544 | 2. Click on **Policies** 545 | 3. Click **Create policy** 546 | 4. Click the **JSON** tab 547 | 5. Copy and **replace** the contents below into the **JSON** text area 548 | 6. Click the **Review policy** button 549 | 7. Enter **ccoa-s3-write-policy** in the **Name* field 550 | 8. Click the **Create policy** button 551 | 552 | ``` 553 | { 554 | "Version": "2012-10-17", 555 | "Statement": [ 556 | { 557 | "Effect": "Allow", 558 | "Action": [ 559 | "cloudwatch:*", 560 | "config:*", 561 | "iam:*", 562 | "lambda:*", 563 | "logs:*", 564 | "s3:*" 565 | ], 566 | "Resource": "*" 567 | } 568 | ] 569 | } 570 | 571 | ``` 572 | 9. Click on **Roles** 573 | 10. Click the **Create role** button 574 | 11. Click **Lambda** from the *Choose the service that will use this role* section 575 | 12. Click the **Next: Permissions** button 576 | 13. Click **ccoa-s3-write-policy** in the *Filter policies* search field 577 | 14. Select the checkbox next to **ccoa-s3-write-policy** and click on the **Next: Tags** button 578 | 15. Click the **Next: Review** button 579 | 16. Enter `ccoa-s3-write-role` in the **Role name** field 580 | 17. Click the **Create role** button 581 | 582 | ## Create a Lambda function 583 | `ccoa-s3-write-remediation` 584 | 1. Go to the [Lambda](https://console.aws.amazon.com/lambda/) console 585 | 2. Click the **Create function** button 586 | 3. Keep the *Author from scratch* radio button selected and enter `ccoa-s3-write-remediation` in the *Function name* field 587 | 4. Choose `Node.js 10.x` for the **Runtime** 588 | 5. Under *Permissions* choose the **Choose or create an execution role** 589 | 6. Under **Execution role**, choose **Use an existing role** 590 | 7. In the **Existing role** dropdown, choose `ccoa-s3-write-role` 591 | 8. Click the **Create function** button 592 | 9. Scroll to the *Function code* section and within the `index.js` pane, copy and **replace** the code from below 593 | 594 | 595 | ``` 596 | var AWS = require('aws-sdk'); 597 | 598 | exports.handler = function(event) { 599 | console.log("request:", JSON.stringify(event, undefined, 2)); 600 | 601 | var s3 = new AWS.S3({apiVersion: '2006-03-01'}); 602 | var resource = event['detail']['requestParameters']['evaluations']; 603 | console.log("evaluations:", JSON.stringify(resource, null, 2)); 604 | 605 | 606 | for (var i = 0, len = resource.length; i < len; i++) { 607 | if (resource[i]["complianceType"] == "NON_COMPLIANT") 608 | { 609 | console.log(resource[i]["complianceResourceId"]); 610 | var params = { 611 | Bucket: resource[i]["complianceResourceId"] 612 | }; 613 | 614 | s3.deleteBucketPolicy(params, function(err, data) { 615 | if (err) console.log(err, err.stack); // an error occurred 616 | else console.log(data); // successful response 617 | }); 618 | } 619 | } 620 | 621 | 622 | }; 623 | ``` 624 | 10. Click the **Save** button 625 | 626 | 627 | ## Create a Config Rule (Managed Rule which runs Lambda function) 628 | `ccoa-s3-write-rule` 629 | 1. Go to the [Config](https://console.aws.amazon.com/config/) console 630 | 2. Click **Rules** 631 | 3. Click the **Add rule** button 632 | 4. In the *filter* box, type `s3-bucket-public-write-prohibited` 633 | 5. Choose the **s3-bucket-public-write-prohibited** rule 634 | 6. Click on the **Remediation action** dropdown within the *Choose remediation action* section 635 | 7. Choose the **AWS-PublishSNSNotification** remediation in the dropdown 636 | 8. Click **Yes** in the *Auto remediation* field 637 | 9. In the **Parameters** field, enter `arn:aws:iam::123456789012:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM` in the **AutomationAssumeRole** field (replacing `123456789012` with your AWS account id) 638 | 10. In the **Parameters** field, enter `s3-bucket-public-write-prohibited violated` in the **Message** field 639 | 11. In the **Parameters** field, enter `arn:aws:sns:us-east-1:123456789012:ccoa-awsconfig-123456789012` in the **TopicArn** field (replacing `123456789012` with your AWS account id) 640 | 12. Click the **Save** button 641 | 642 | ## Cloudwatch Event Rule 643 | `ccoa-s3-write-cwe` 644 | 1. Go to the [CloudWatch](https://console.aws.amazon.com/cloudwatch/) console 645 | 2. Click on **Rules** 646 | 3. Click the **Create rule** button 647 | 4. Choose **Event pattern** in the *Event Source* section 648 | 4. In the *Event Pattern Preview* section, click **Edit** 649 | 5. Copy the contents from below and **replace** in the *Event pattern* text area 650 | 6. Click the **Save** button 651 | 7. Click the **Add target** button 652 | 8. Choose **Lambda function** 653 | 9. Select the `ccoa-s3-write-remediation` function you'd previously created. 654 | 10. Click the **Configure details** button 655 | 11. Enter `ccoa-s3-write-cwe` in the **Name** field 656 | 12. Click the **Create rule** button 657 | 658 | 659 | ``` 660 | { 661 | "source":[ 662 | "aws.config" 663 | ], 664 | "detail":{ 665 | "requestParameters":{ 666 | "evaluations":{ 667 | "complianceType":[ 668 | "NON_COMPLIANT" 669 | ] 670 | } 671 | }, 672 | "additionalEventData":{ 673 | "managedRuleIdentifier":[ 674 | "S3_BUCKET_PUBLIC_WRITE_PROHIBITED" 675 | ] 676 | } 677 | } 678 | } 679 | ``` 680 | 681 | ## View Config Rules 682 | 1. Go to the [Config](https://console.aws.amazon.com/config/) console 683 | 2. Click on **Rules** 684 | 3. Select the **s3-bucket-public-write-prohibited** rule 685 | 4. Click the **Re-evaluate** button 686 | 5. Go back **Rules** in the [Config](https://console.aws.amazon.com/config/) console 687 | 6. Go to the [S3](https://console.aws.amazon.com/s3/) console and choose the `ccoa-s3-write-violation-ACCOUNTID` bucket that the bucket policy has been removed. 688 | 7. Go back **Rules** in the [Config](https://console.aws.amazon.com/config/) console and confirm that the **s3-bucket-public-write-prohibited** rule is **Compliant** 689 | 690 | ================================================== 691 | 692 | # AWS Chatbot 693 | 694 | ![AWS Chatbot](https://github.com/PaulDuvall/aws-compliance-workshop/wiki/img/remediation/remediation-aws-chatbot.png 695 | ) 696 | 697 | ## Create an Amazon SNS Topic 698 | 1. Go to the [Simple Notification Service](https://console.aws.amazon.com/sns/) console. 699 | 2. Select **Topics** 700 | 3. Click **Create topic** 701 | 4. Enter `ccoa-chatbot-topic` in the **Name** and **Display name** fields 702 | 5. Click the **Create topic** button 703 | 704 | ## Create an IAM Policy and Role for Chatbot 705 | 706 | 1. Go to the [IAM](https://console.aws.amazon.com/iam/) console 707 | 2. Click on **Policies** 708 | 3. Click **Create policy** 709 | 4. Click the **JSON** tab 710 | 5. Copy and **replace** the contents below into the **JSON** text area 711 | 6. Click the **Review policy** button 712 | 7. Enter **ccoa-chatbot-policy** in the **Name* field 713 | 8. Click the **Create policy** button 714 | 715 | ``` 716 | { 717 | "Version": "2012-10-17", 718 | "Statement": [ 719 | { 720 | "Effect": "Allow", 721 | "Action": [ 722 | "chatbot:*", 723 | "cloudwatch:*", 724 | "config:*", 725 | "iam:*", 726 | "lambda:*", 727 | "logs:*", 728 | "s3:*", 729 | "sns:*" 730 | ], 731 | "Resource": "*" 732 | } 733 | ] 734 | } 735 | 736 | ``` 737 | 738 | 9. Click on **Roles** 739 | 10. Click the **Create role** button 740 | 11. Click **Lambda** from the *Choose the service that will use this role* section 741 | 12. Click the **Next: Permissions** button 742 | 13. Click **ccoa-chatbot-policy** in the *Filter policies* search field 743 | 14. Select the checkbox next to **ccoa-chatbot-policy** and click on the **Next: Tags** button 744 | 15. Click the **Next: Review** button 745 | 16. Enter `ccoa-chatbot-role` in the **Role name** field 746 | 17. Click the **Create role** button 747 | 748 | 749 | ## Create a Lambda function for Chatbot 750 | 751 | 1. Go to the [Lambda](https://console.aws.amazon.com/lambda/) console 752 | 2. Click the **Create function** button 753 | 3. Keep the *Author from scratch* radio button selected and enter `ccoa-chatbot-remediation` in the *Function name* field 754 | 4. Choose `Node.js 10.x` for the **Runtime** 755 | 5. Under *Permissions* choose the **Choose or create an execution role** 756 | 6. Under **Execution role**, choose **Use an existing role** 757 | 7. In the **Existing role** dropdown, choose `ccoa-chatbot-role` 758 | 8. Click the **Create function** button 759 | 9. Scroll to the *Function code* section and within the `index.js` pane, copy and **replace** the code from below 760 | 761 | 762 | ``` 763 | var AWS = require('aws-sdk'); 764 | 765 | exports.handler = function(event) { 766 | console.log("request:", JSON.stringify(event, undefined, 2)); 767 | 768 | var s3 = new AWS.S3({apiVersion: '2006-03-01'}); 769 | var resource = event['detail']['requestParameters']['evaluations']; 770 | console.log("evaluations:", JSON.stringify(resource, null, 2)); 771 | 772 | 773 | for (var i = 0, len = resource.length; i < len; i++) { 774 | if (resource[i]["complianceType"] == "NON_COMPLIANT") 775 | { 776 | console.log(resource[i]["complianceResourceId"]); 777 | var params = { 778 | Bucket: resource[i]["complianceResourceId"] 779 | }; 780 | 781 | s3.deleteBucketPolicy(params, function(err, data) { 782 | if (err) console.log(err, err.stack); // an error occurred 783 | else console.log(data); // successful response 784 | }); 785 | } 786 | } 787 | 788 | 789 | }; 790 | ``` 791 | 792 | ## Create an S3 Bucket in violation for Chatbot 793 | 794 | 1. Go to the [S3](https://console.aws.amazon.com/s3/) console 795 | 2. Click the **Create bucket** button 796 | 3. Enter `ccoa-s3-violation-chatbot-ACCOUNTID` in the **Bucket name** field (replacing `ACCOUNTID` with your account id) 797 | 4. Click **Next** on the *Configure Options* screen 798 | 5. Unselect the **Block all public access** checkbox and click **Next** on the *Set Permissions* screen 799 | 6. Click **Create bucket** on the *Review* screen 800 | 7. Select the `ccoa-s3-violation-chatbot-ACCOUNTID` bucket and choose the **Permissions** tab 801 | 8. Click on **Bucket Policy** and paste the contents from below into the *Bucket policy editor* text area (replace both `mybucketname` values with the `ccoa-s3-write-violation-ACCOUNTID` bucket you just created) 802 | 9. Click the **Save** button 803 | 804 | ``` 805 | { 806 | "Version": "2012-10-17", 807 | "Statement": [ 808 | { 809 | "Effect": "Allow", 810 | "Principal": "*", 811 | "Action": [ 812 | "s3:Abort*", 813 | "s3:DeleteObject", 814 | "s3:GetBucket*", 815 | "s3:GetObject", 816 | "s3:List*", 817 | "s3:PutObject" 818 | ], 819 | "Resource": [ 820 | "arn:aws:s3:::mybucketname", 821 | "arn:aws:s3:::mybucketname/*" 822 | ] 823 | } 824 | ] 825 | } 826 | ``` 827 | 828 | ## Create a Config Rule for Chatbot 829 | 1. Go to the [Config](https://console.aws.amazon.com/config/) console 830 | 2. Click **Rules** 831 | 3. Click the **Add rule** button 832 | 4. In the *filter* box, type `s3-bucket-public-write-prohibited` 833 | 5. Choose the **s3-bucket-public-write-prohibited** rule 834 | 6. Click on the **Remediation action** dropdown within the *Choose remediation action* section 835 | 7. Choose the **AWS-PublishSNSNotification** remediation in the dropdown 836 | 8. Click **Yes** in the *Auto remediation* field 837 | 9. In the **Parameters** field, enter `arn:aws:iam::ACCOUNTID:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM` in the **AutomationAssumeRole** field (replacing `ACCOUNTID` with your AWS account id) 838 | 10. In the **Parameters** field, enter `s3-bucket-public-write-prohibited violated` in the **Message** field 839 | 11. In the **Parameters** field, enter `arn:aws:sns:us-east-1:ACCOUNTID:ccoa-awsconfig-ACCOUNTID` in the **TopicArn** field (replacing `ACCOUNTID` with your AWS account id) 840 | 12. Click the **Save** button 841 | 842 | 843 | ## CloudWatch Events Rule Event Pattern for Chatbot 844 | 845 | 1. Go to the [CloudWatch](https://console.aws.amazon.com/cloudwatch/) console 846 | 2. Click on **Rules** 847 | 3. Click the **Create rule** button 848 | 4. Choose **Event pattern** in the *Event Source* section 849 | 4. In the *Event Pattern Preview* section, click **Edit** 850 | 5. Copy the contents from below and **replace** in the *Event pattern* text area 851 | 6. Click the **Save** button 852 | 7. Click the **Add target** button 853 | 8. Choose **Lambda function** 854 | 9. Select the `ccoa-chatbot-remediation` function you'd previously created. 855 | 10. Click the **Configure details** button 856 | 11. Enter `ccoa-chatbot-cwe` in the **Name** field 857 | 12. Click the **Create rule** button 858 | 859 | 860 | ``` 861 | { 862 | "source":[ 863 | "aws.config" 864 | ], 865 | "detail":{ 866 | "requestParameters":{ 867 | "evaluations":{ 868 | "complianceType":[ 869 | "NON_COMPLIANT" 870 | ] 871 | } 872 | }, 873 | "additionalEventData":{ 874 | "managedRuleIdentifier":[ 875 | "S3_BUCKET_PUBLIC_WRITE_PROHIBITED" 876 | ] 877 | } 878 | } 879 | } 880 | ``` 881 | 882 | ## View Config Rules 883 | 1. Go to the [Config](https://console.aws.amazon.com/config/) console 884 | 2. Click on **Rules** 885 | 3. Select the **s3-bucket-public-write-prohibited** rule 886 | 4. Click the **Re-evaluate** button 887 | 5. Go back **Rules** in the [Config](https://console.aws.amazon.com/config/) console 888 | 6. Go to the [S3](https://console.aws.amazon.com/s3/) console and choose the `ccoa-chatbot-ACCOUNTID` bucket that the bucket policy has been removed. 889 | 7. Go back **Rules** in the [Config](https://console.aws.amazon.com/config/) console and confirm that the **s3-bucket-public-write-prohibited** rule is **Compliant** 890 | 891 | ## AWS Chatbot - Configure client (select Slack) - using SNS Topic and IAM Role 892 | 893 | 1. Go to the [Chatbot](https://console.aws.amazon.com/chatbot/) console 894 | 2. From the *Configure new client* page, click on **Slack** and click the **Configure** button 895 | 3. Click the **Allow** button on the *On <>, AWS Chatbot (Beta) would like to* page 896 | 4. Select the **Channel type** and name 897 | 5. In the **IAM permissions** section, choose the IAM role you previously created. 898 | 6. Choose **SNS Region** and the **SNS topics** (choosing the region and topic you previously created) in the *SNS topics* section 899 | 7. Click the **Configure** button 900 | 901 | https://us-east-2.console.aws.amazon.com/chatbot/ 902 | https://console.aws.amazon.com/sns/ 903 | https://console.aws.amazon.com/lambda/ 904 | https://console.aws.amazon.com/cloudwatch/ 905 | https://console.aws.amazon.com/iam/ 906 | https://docs.aws.amazon.com/config/latest/developerguide/monitor-config-with-cloudwatchevents.html 907 | 908 | ### Notes 909 | 910 | * https://aws.amazon.com/chatbot/ 911 | * https://aws.amazon.com/blogs/devops/introducing-aws-chatbot-chatops-for-aws/ 912 | 913 | The identity provider(s) cloudwatch.amazonaws.com 914 | CloudWatchFullAccess 915 | CloudWatchEventsFullAccess 916 | 917 | #### Create an IAM Role 918 | 919 | 1. Go to the [IAM](https://console.aws.amazon.com/iam/) console 920 | 2. Click on **Roles** 921 | 3. Click the **Create role** button 922 | 4. Click **CloudWatch** from the *Choose the service that will use this role* section 923 | 5. Click the **Next: Permissions** button 924 | 6. Click **CloudWatchFullAccess** in the *Filter policies* search field 925 | 7. Select the checkbox next to **CloudWatchFullAccess** 926 | 8. Click **CloudWatchEventsFullAccess** in the *Filter policies* search field 927 | 9. Select the checkbox next to **CloudWatchFullAccess** 928 | 10. Click on the **Next: Tags** button 929 | 15. Click the **Next: Review** button 930 | 16. Enter `ccoa-chatbot-role` in the **Role name** field 931 | 17. Click the **Create role** button 932 | 933 | 934 | ============================================================= 935 | 936 | # Setup CLI 937 | 938 | ## CloudFormation Resources 939 | * [AWS::S3::Bucket](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html) 940 | * [AWS::CloudTrail::Trail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudtrail-trail.html) 941 | * [AWS::Logs::LogGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html) 942 | * [AWS::SNS::Topic](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html) 943 | * [AWS::Config::ConfigurationRecorder](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configurationrecorder.html) 944 | * [AWS::Config::DeliveryChannel](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html) 945 | * [AWS::S3::BucketPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-policy.html) 946 | * [AWS::IAM::Policy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-policy.html) 947 | * [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html) 948 | * [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) 949 | * [AWS::Config::ConfigRule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configrule.html) 950 | * [AWS::Config::RemediationConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-remediationconfiguration.html) 951 | * [AWS::Events::Rule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html) 952 | 953 | 954 | ## Create an SNS Topic and Subscription 955 | 956 | Replace `my-email@example.com` with your email address. 957 | 958 | ``` 959 | aws sns create-topic --name ccoa-config-topic 960 | 961 | aws sns subscribe --topic-arn arn:aws:sns:$(aws configure get region --output text):$(aws sts get-caller-identity --output text --query 'Account'):ccoa-config-topic --protocol email --notification-endpoint my-email@example.com 962 | 963 | ``` 964 | 965 | 1. Delete the S3 bucket used by AWS Config 966 | 967 | ``` 968 | aws s3 rb s3://ccoa-awsconfig-$(aws sts get-caller-identity --output text --query 'Account') --force 969 | 970 | aws s3 rb s3://config-bucket-$(aws sts get-caller-identity --output text --query 'Account') --force 971 | ``` 972 | 973 | 2. List any AWS Config Recorders 974 | 975 | 976 | ``` 977 | aws configservice describe-configuration-recorders 978 | ``` 979 | 980 | 3. Run the command below replacing `CONFIGRECORDERNAME` with the output from the above command 981 | 982 | ``` 983 | aws configservice delete-configuration-recorder --configuration-recorder-name CONFIGRECORDERNAME 984 | ``` 985 | 986 | 4. List any AWS Config Delivery Channels 987 | 988 | ``` 989 | aws configservice describe-delivery-channels 990 | ``` 991 | 992 | 5. Run the command below replacing `DELIVERYCHANNELNAME` with the output from the above command (the name is probably `default`): 993 | 994 | 995 | ``` 996 | aws configservice delete-delivery-channel --delivery-channel-name DELIVERYCHANNELNAME 997 | ``` 998 | 999 | 1000 | ## Create CloudFormation Template to enable ConfigRecorder 1001 | 1002 | ![Compliance CloudFormation](https://github.com/PaulDuvall/aws-compliance-workshop/wiki/img/compliance/compliance-cfn-pipeline.png) 1003 | 1004 | 1. Create `lesson0` directory from your AWS Cloud9 environment: 1005 | 1006 | ``` 1007 | mkdir ~/environment/lesson0 1008 | ``` 1009 | 1010 | 2. Change directory: 1011 | 1012 | ``` 1013 | cd ~/environment/lesson0 1014 | ``` 1015 | 1016 | 3. Create a new file 1017 | 1018 | ``` 1019 | touch config-recorder.yml 1020 | ``` 1021 | 1022 | 4. Paste the contents of the CloudFormation template into `config-recorder.yml` and save the file 1023 | 1024 | ```AWSTemplateFormatVersion: '2010-09-09' 1025 | Description: Setup AWS Config Service 1026 | Resources: 1027 | ConfigBucket: 1028 | Type: AWS::S3::Bucket 1029 | DeletionPolicy: Retain 1030 | Properties: 1031 | AccessControl: BucketOwnerFullControl 1032 | BucketName: !Sub '${AWS::StackName}-${AWS::AccountId}' 1033 | ConfigTopic: 1034 | Type: AWS::SNS::Topic 1035 | DeliveryChannel: 1036 | Type: AWS::Config::DeliveryChannel 1037 | Properties: 1038 | ConfigSnapshotDeliveryProperties: 1039 | DeliveryFrequency: "Six_Hours" 1040 | S3BucketName: 1041 | Ref: ConfigBucket 1042 | SnsTopicARN: 1043 | Ref: ConfigTopic 1044 | ConfigBucketPolicy: 1045 | Type: AWS::S3::BucketPolicy 1046 | Properties: 1047 | Bucket: !Ref 'ConfigBucket' 1048 | PolicyDocument: 1049 | Version: '2012-10-17' 1050 | Id: PutObjPolicy 1051 | Statement: 1052 | - Sid: DenyUnEncryptedObjects 1053 | Effect: Deny 1054 | Principal: '*' 1055 | Action: s3:PutObject 1056 | Resource: !Join 1057 | - '' 1058 | - - 'arn:aws:s3:::' 1059 | - !Ref 'ConfigBucket' 1060 | - /* 1061 | Condition: 1062 | StringNotEquals: 1063 | s3:x-amz-server-side-encryption: AES256 1064 | ConfigTopic: 1065 | Type: AWS::SNS::Topic 1066 | Properties: 1067 | DisplayName: !Sub '${AWS::StackName}'-sns-topic 1068 | TopicName: !Sub '${AWS::StackName}'-sns-topic 1069 | ConfigRole: 1070 | Type: AWS::IAM::Role 1071 | Properties: 1072 | AssumeRolePolicyDocument: 1073 | Statement: 1074 | - Action: 1075 | - sts:AssumeRole 1076 | Effect: Allow 1077 | Principal: 1078 | Service: 1079 | - config.amazonaws.com 1080 | Version: '2012-10-17' 1081 | Path: / 1082 | Policies: 1083 | - PolicyDocument: 1084 | Statement: 1085 | - Effect: Allow 1086 | Action: sns:Publish 1087 | Resource: !Ref 'ConfigTopic' 1088 | - Effect: Allow 1089 | Action: 1090 | - s3:PutObject 1091 | Resource: 1092 | - !Join 1093 | - '' 1094 | - - 'arn:aws:s3:::' 1095 | - !Ref 'ConfigBucket' 1096 | - /AWSLogs/ 1097 | - !Ref 'AWS::AccountId' 1098 | - /* 1099 | Condition: 1100 | StringLike: 1101 | s3:x-amz-acl: bucket-owner-full-control 1102 | - Effect: Allow 1103 | Action: 1104 | - s3:GetBucketAcl 1105 | Resource: !Join 1106 | - '' 1107 | - - 'arn:aws:s3:::' 1108 | - !Ref 'ConfigBucket' 1109 | PolicyName: root 1110 | ManagedPolicyArns: 1111 | - arn:aws:iam::aws:policy/service-role/AWSConfigRole 1112 | ConfigRecorder: 1113 | Type: AWS::Config::ConfigurationRecorder 1114 | Properties: 1115 | Name: !Sub 'ccoa-${AWS::StackName}' 1116 | RecordingGroup: 1117 | AllSupported: true 1118 | IncludeGlobalResourceTypes: true 1119 | RoleARN: !GetAtt 'ConfigRole.Arn' 1120 | Outputs: 1121 | StackName: 1122 | Value: !Ref 'AWS::StackName' 1123 | ``` 1124 | 1125 | 1126 | ## Launch the CloudFormation stack to enable the ConfigRecorder 1127 | 1128 | From your AWS Cloud9 environment, run the following command: 1129 | 1130 | ``` 1131 | aws cloudformation create-stack --stack-name ccoa-awsconfig --template-body file:///home/ec2-user/environment/lesson0/config-recorder.yml --capabilities CAPABILITY_NAMED_IAM --disable-rollback 1132 | ``` 1133 | 1134 | ## Create an S3 Bucket 1135 | 1136 | ``` 1137 | aws s3 mb s3://ccoa-s3-public-write-prohibited-$(aws sts get-caller-identity --output text --query 'Account') --region us-east-1 1138 | ``` 1139 | 1140 | ### Create an S3 Bucket Policy and assign to Bucket 1141 | 1142 | **CAREFUL: This gives public write access to `mybucketname` (replace with the name of the bucket you just created). This is for demonstration purposes and AWS highly recommends that you never grant any kind of public access to your S3 bucket.** 1143 | 1144 | 1. Create a new file called `policy.json`. 1145 | 1146 | ``` 1147 | cd ~/environment/lesson0 1148 | touch policy.json 1149 | ``` 1150 | 1151 | 2. Open the `policy.json` file and paste the contents below (replacing `mybucketname` with the name of the bucket you created above. Save the file. 1152 | 1153 | ``` 1154 | { 1155 | "Version": "2012-10-17", 1156 | "Statement": [ 1157 | { 1158 | "Effect": "Allow", 1159 | "Principal": "*", 1160 | "Action": [ 1161 | "s3:Abort*", 1162 | "s3:DeleteObject", 1163 | "s3:GetBucket*", 1164 | "s3:GetObject", 1165 | "s3:List*", 1166 | "s3:PutObject" 1167 | ], 1168 | "Resource": [ 1169 | "arn:aws:s3:::mybucketname", 1170 | "arn:aws:s3:::mybucketname/*" 1171 | ] 1172 | } 1173 | ] 1174 | } 1175 | ``` 1176 | 1177 | 3. Apply the S3 Bucket Policy to the Bucket by running the command below: 1178 | 1179 | ``` 1180 | aws s3api put-bucket-policy --bucket s3-bucket-public-write-prohibited-$(aws sts get-caller-identity --output text --query 'Account') --policy file:///home/ec2-user/environment/lesson0/policy.json 1181 | ``` 1182 | 1183 | ## Create an AWS Config Rule 1184 | 1185 | 1186 | Alternatively, you can use the [AWS Config Console](https://console.aws.amazon.com/config/home?region=us-east-1#/rules/view) to add a rule. Name the rule `s3-bucket-public-write-prohibited-rule`. 1187 | 1188 | 1. Create a new file called `s3-bucket-public-write-prohibited.json`. 1189 | 1190 | ``` 1191 | cd ~/environment/lesson0 1192 | touch s3-bucket-public-write-prohibited.json 1193 | ``` 1194 | 1195 | 2. Open the `s3-bucket-public-write-prohibited.json` file and paste the contents below and save the file. 1196 | 1197 | 1198 | ``` 1199 | { 1200 | "ConfigRuleName":"s3-bucket-public-write-prohibited-rule", 1201 | "Description":"Checks that your Amazon S3 buckets do not allow public write access. The rule checks the Block Public Access settings, the bucket policy, and the bucket access control list (ACL).", 1202 | "InputParameters":{ 1203 | 1204 | }, 1205 | "Scope":{ 1206 | "ComplianceResourceTypes":[ 1207 | "AWS::S3::Bucket" 1208 | ] 1209 | }, 1210 | "Source":{ 1211 | "Owner":"AWS", 1212 | "SourceIdentifier":"S3_BUCKET_PUBLIC_WRITE_PROHIBITED" 1213 | } 1214 | } 1215 | ``` 1216 | 1217 | 3. Run the command to apply the Config Rule 1218 | 1219 | ``` 1220 | aws configservice put-config-rule --config-rule file:///home/ec2-user/environment/lesson0/s3-bucket-public-write-prohibited.json 1221 | ``` 1222 | 1223 | ``` 1224 | 1225 | s3-bucket-public-write-prohibited 1226 | S3_BUCKET_PUBLIC_WRITE_PROHIBITED 1227 | 1228 | Remediation Action: AWS-PublishSNSNotification 1229 | 1230 | AutomationAssumeRole: arn:aws:iam::123456789012:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM 1231 | Message: s3-bucket-public-write-prohibited violated 1232 | TopicArn: arn:aws:sns:us-east-1:123456789012:ccoa-config-topic 1233 | 1234 | 1235 | ``` 1236 | 1237 | ## Create a IAM Role for Lambda function 1238 | 1239 | 1. Create a new file called `ccoa-lambda-s3-remediation-policy.json`: 1240 | 1241 | ``` 1242 | cd ~/environment/lesson0 1243 | touch ccoa-lambda-s3-remediation-policy.json 1244 | ``` 1245 | 1246 | 2. Open the `ccoa-lambda-s3-remediation-policy.json` file and paste the contents below and save the file: 1247 | 1248 | ``` 1249 | { 1250 | "Version": "2012-10-17", 1251 | "Statement": [ 1252 | { 1253 | "Effect": "Allow", 1254 | "Action": [ 1255 | "cloudwatch:*", 1256 | "config:*", 1257 | "iam:*", 1258 | "lambda:*", 1259 | "logs:*", 1260 | "s3:*" 1261 | ], 1262 | "Resource": "*" 1263 | } 1264 | ] 1265 | } 1266 | 1267 | ``` 1268 | 1269 | 3. Create the IAM Policy 1270 | 1271 | ``` 1272 | aws iam create-policy --policy-name ccoa-lambda-s3-remediation-policy --policy-document file:///home/ec2-user/environment/lesson0/ccoa-lambda-s3-remediation-policy.json 1273 | ``` 1274 | 1275 | 4. Create the IAM Role 1276 | 1277 | Create a new [IAM Role](https://console.aws.amazon.com/iam/home?region=us-east-1#/roles). Give it the name: `ccoa-lambda-s3-remediation-role` and apply the `ccoa-lambda-s3-remediation-policy` to the new IAM role. 1278 | 1279 | ``` 1280 | aws iam create-role --role-name ccoa-lambda-s3-remediation-role --assume-role-policy-document file:///home/ec2-user/environment/lesson0/ccoa-lambda-s3-remediation-policy.json 1281 | ``` 1282 | 1283 | ## Create a Lambda Function 1284 | 1285 | Create a new [Lambda Function](https://console.aws.amazon.com/lambda/) and paste the following Node.js code below and save the function. Name the function `ccoa-s3-write-remediation` 1286 | 1287 | ``` 1288 | var AWS = require('aws-sdk'); 1289 | 1290 | exports.handler = function(event) { 1291 | console.log("request:", JSON.stringify(event, undefined, 2)); 1292 | 1293 | var s3 = new AWS.S3({apiVersion: '2006-03-01'}); 1294 | var resource = event['detail']['requestParameters']['evaluations']; 1295 | console.log("evaluations:", JSON.stringify(resource, null, 2)); 1296 | 1297 | 1298 | for (var i = 0, len = resource.length; i < len; i++) { 1299 | if (resource[i]["complianceType"] == "NON_COMPLIANT") 1300 | { 1301 | console.log(resource[i]["complianceResourceId"]); 1302 | var params = { 1303 | Bucket: resource[i]["complianceResourceId"] 1304 | }; 1305 | 1306 | s3.deleteBucketPolicy(params, function(err, data) { 1307 | if (err) console.log(err, err.stack); // an error occurred 1308 | else console.log(data); // successful response 1309 | }); 1310 | } 1311 | } 1312 | 1313 | 1314 | }; 1315 | ``` 1316 | 1317 | ## CloudWatch Events Rule Event Pattern 1318 | 1319 | [CloudWatch Events Rule](https://console.aws.amazon.com/cloudwatch/). Name it `ccoa-s3-write-cwe`. 1320 | 1321 | ``` 1322 | { 1323 | "source":[ 1324 | "aws.config" 1325 | ], 1326 | "detail":{ 1327 | "requestParameters":{ 1328 | "evaluations":{ 1329 | "complianceType":[ 1330 | "NON_COMPLIANT" 1331 | ] 1332 | } 1333 | }, 1334 | "additionalEventData":{ 1335 | "managedRuleIdentifier":[ 1336 | "S3_BUCKET_PUBLIC_WRITE_PROHIBITED" 1337 | ] 1338 | } 1339 | } 1340 | } 1341 | ``` 1342 | 1343 | # Other 1344 | ## SNS Topic and Subscription for Config 1345 | `ccoa-config-topic` 1346 | 1. Go to the [Simple Notification Service](https://console.aws.amazon.com/sns/) console. 1347 | 2. Select **Topics** 1348 | 3. Click **Create topic** 1349 | 4. Enter `ccoa-config-topic` in the **Name** and **Display name** fields 1350 | 5. Click the **Create topic** button 1351 | 6. Click the **Create subscription** button 1352 | 7. Choose **email** from the **Protocol** dropdown 1353 | 8. Enter your **email address** in the **Endpoint** field 1354 | 9. Click the **Create subscription** button 1355 | 10. Confirm the subscription once you receive the email from AWS 1356 | 1357 | ## Create an S3 Bucket for Config 1358 | `ccoa-config-ACCOUNTID` 1359 | 1. Go to the [S3](https://console.aws.amazon.com/s3/) console 1360 | 2. Click the **Create bucket** button 1361 | 3. Enter `ccoa-config-ACCOUNTID` in the **Bucket name** field (replacing `ACCOUNTID` with your account id) 1362 | 4. Click **Next** on the *Configure Options* screen 1363 | 5. Click **Next** on the *Set Permissions* screen 1364 | 6. Click **Create bucket** on the *Review* screen 1365 | 1366 | 1367 | --------------------------------------------------------------------------------