diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de86e6e..663468c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,6 @@ All notable changes to this project will be documented in this file. --- - ## 2023-10-23 Updated [Firewall Manager](https://github.com/aws-samples/aws-security-reference-architecture-examples/tree/main/aws_sra_examples/solutions/firewall_manager/firewall_manager_org) solution to make AWS Control Tower optional. diff --git a/README.md b/README.md index bea4d5df..b928d440 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ _Note: The `Quick Setup` is not designed to be used with the `Easy Setup` proced | [Inspector](aws_sra_examples/solutions/inspector/inspector_org) | Configure Inspector within a delegated admin account for all accounts and governed regions within the organization. | | | | [Detective](aws_sra_examples/solutions/detective/detective) | The Detective Organization solution will automate enabling Amazon Detective by delegating administration to an account (e.g. Audit or Security Tooling) and configuring Detective for all the existing and future AWS Organization accounts. **Note:** As of 06/07/2023, this solution is not included in the quick setup (it will be in a future code release) | | | + ## Utils - packaging_scripts/stage-solution.sh (Package and stage all the AWS SRA example solutions. For more information see [Staging script details](aws_sra_examples/docs/DOWNLOAD-AND-STAGE-SOLUTIONS.md#staging-script-details)) diff --git a/aws_sra_examples/easy_setup/customizations_for_aws_control_tower/manifest.yaml b/aws_sra_examples/easy_setup/customizations_for_aws_control_tower/manifest.yaml index eb5cacdb..efa2d66b 100644 --- a/aws_sra_examples/easy_setup/customizations_for_aws_control_tower/manifest.yaml +++ b/aws_sra_examples/easy_setup/customizations_for_aws_control_tower/manifest.yaml @@ -194,7 +194,7 @@ resources: # Inspector Solution - parameter_key: pScanComponents - parameter_value: 'EC2, ECR, LAMBDA' + parameter_value: 'EC2, ECR, LAMBDA, LAMBDA_CODE' - parameter_key: pEcrRescanDuration parameter_value: 'LIFETIME' diff --git a/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml b/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml index 1f47f6cb..f5d4d2a8 100644 --- a/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml +++ b/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml @@ -226,7 +226,7 @@ Metadata: default: SRA Staging S3 Bucket Stack Name pScanComponents: - default: Comma separated list of scan components (EC2, ECR, LAMBDA) + default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE) pEcrRescanDuration: default: ECR Rescan Duration pDeployInspectorSolution: @@ -522,8 +522,8 @@ Parameters: Type: String pScanComponents: - AllowedValues: [EC2, ECR, LAMBDA] - Default: EC2, ECR, LAMBDA + AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE] + Default: EC2, ECR, LAMBDA, LAMBDA_CODE Description: Lambda Function Logging Level Type: CommaDelimitedList pEcrRescanDuration: diff --git a/aws_sra_examples/modules/cloudtrail-org-module/templates/sra-cloudtrail-org-module-main.yaml b/aws_sra_examples/modules/cloudtrail-org-module/templates/sra-cloudtrail-org-module-main.yaml new file mode 100644 index 00000000..7bca4764 --- /dev/null +++ b/aws_sra_examples/modules/cloudtrail-org-module/templates/sra-cloudtrail-org-module-main.yaml @@ -0,0 +1,1177 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: '2010-09-09' +Description: Installs the AWS SRA cloudtrail solution. If needed, the AWS SRA common prerequisite solution is also installed. (sra-1u3sd7f8d) + +Metadata: + SRA: + Version: 1.0 + Order: 1 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pSRAHelperBucketNamePrefix + - pRandomParameter + - Label: + default: Landing Zone + Parameters: + - pControlTower + - pGovernedRegions + - pSecurityAccountId + - pLogArchiveAccountId + - pCreateAWSControlTowerExecutionRole + - Label: + default: SRA Code Repo + Parameters: + - pRepoURL + - pRepoBranch + - pTemplateURL + - Label: + default: CodeBuild + Parameters: + - pCodeBuildProjectName + - pCodeBuildProjectLambdaFunctionName + - pCodeBuildRoleName + - pCodeBuildProjectLambdaRoleName + - Label: + default: Lambda + Parameters: + - pCreateLambdaLogGroup + - pLambdaLogGroupKmsKey + - pLambdaLogGroupRetention + - pLambdaLogLevel + - pCheckForResourceLambdaFunctionName + - pGetCommonOutputsLambdaFunctionName + - pCheckForResourceLambdaRoleName + + - Label: + default: CloudTrail + Parameters: + - pCloudTrailName + - pEnableDataEventsOnly + - pEnableLambdaDataEvents + - pEnableS3DataEvents + - pBucketNamePrefix + - pCloudTrailLogGroupKmsKey + - pCloudTrailLogGroupRetention + - pCreateCloudTrailLogGroup + - pOrganizationCloudTrailKeyAlias + + ParameterLabels: + pSRASolutionName: + default: pSRASolutionName + pSRAHelperBucketNamePrefix: + default: pSRAHelperBucketNamePrefix + pRandomParameter: + default: pRandomParameter + pControlTower: + default: pControlTower + pGovernedRegions: + default: pGovernedRegions + pSecurityAccountId: + default: pSecurityAccountId + pLogArchiveAccountId: + default: pLogArchiveAccountId + pRepoURL: + default: pRepoURL + pRepoBranch: + default: pRepoBranch + pTemplateURL: + default: pTemplateURL + pCodeBuildProjectName: + default: pCodeBuildProjectName + pCodeBuildProjectLambdaFunctionName: + default: pCodeBuildProjectLambdaFunctionName + pCodeBuildRoleName: + default: pCodeBuildRoleName + pCodeBuildProjectLambdaRoleName: + default: pCodeBuildProjectLambdaRoleName + pCreateLambdaLogGroup: + default: pCreateLambdaLogGroup + pLambdaLogGroupKmsKey: + default: pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: + default: pLambdaLogGroupRetention + pLambdaLogLevel: + default: pLambdaLogLevel + pCheckForResourceLambdaFunctionName: + default: pCheckForResourceLambdaFunctionName + pGetCommonOutputsLambdaFunctionName: + default: pGetCommonOutputsLambdaFunctionName + pCheckForResourceLambdaRoleName: + default: pCheckForResourceLambdaRoleName + + pCloudTrailName: + default: CloudTrail Name + pEnableDataEventsOnly: + default: Enable Data Events Only + pEnableLambdaDataEvents: + default: Enable Lambda Data Events + pEnableS3DataEvents: + default: Enable S3 Data Events + pBucketNamePrefix: + default: S3 Log Bucket Name Prefix + pCloudTrailLogGroupKmsKey: + default: (Optional) CloudTrail CloudWatch Logs KMS Key + pCloudTrailLogGroupRetention: + default: CloudTrail Log Group Retention + pCreateCloudTrailLogGroup: + default: Create CloudTrail CloudWatch Log Group + pOrganizationCloudTrailKeyAlias: + default: Organization CloudTrail KMS Key Alias + pCreateAWSControlTowerExecutionRole: + default: Create AWS Control Tower Execution Role + +Parameters: + pRepoURL: + Default: https://github.com/aws-samples/aws-security-reference-architecture-examples.git + Description: + SRA Code Library Repository URL + Type: String + pRepoBranch: + Default: tags/v3.0.4 + Description: + SRA Code Library Repository branch name. Can be used as branch or as tags (e.g. tags/v3.0.1) + Type: String + pTemplateURL: + Default: https://raw.githubusercontent.com/aws-samples/aws-security-reference-architecture-examples/v3.0.4/aws_sra_examples/modules/cloudtrail-org-module/templates/sra-cloudtrail-org-solution.yaml + Description: + SRA module solution template URL + Type: String + + pControlTower: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: + Indicates whether AWS Control Tower is deployed and being used for this AWS environment. + Type: String + pGovernedRegions: + AllowedPattern: '^(ct-regions)|((\b(?--. Example = sra-staging-123456789012-us-east-1. + Type: String + pSRAStagingS3BucketStackName: + AllowedValues: [sra-common-prerequisites-staging-s3-bucket] + Default: sra-common-prerequisites-staging-s3-bucket + Description: + SRA Common Prerequisite Staging S3 bucket stack name. This stack will be created by the SRA CodeBuild Project. + Type: String + + pCreateLambdaLogGroup: + AllowedValues: ['Yes', 'No'] + Default: 'No' + Description: + Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS + Key for encryption. + Type: String + pDeployConfigManagementSolution: + AllowedValues: ['No', 'Already Deployed'] + Default: 'Already Deployed' + Description: Deploy the AWS Config Management solution. Note, if solution was previously deployed, choose 'Already Deployed'. + Type: String + pDeploySecurityHubSolution: + AllowedValues: ['Yes', 'No'] + Default: 'Yes' + Description: Deploy the Security Hub solution + Type: String + pLambdaLogGroupKmsKey: + AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' + ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' + Default: '' + Description: + (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side + encryption keys. + Type: String + pLambdaLogGroupRetention: + AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] + Default: 14 + Description: Specifies the number of days you want to retain log events + Type: String + pLambdaLogLevel: + AllowedValues: [INFO, ERROR, DEBUG] + Default: INFO + Description: Lambda Function Logging Level + Type: String + pCreateAWSControlTowerExecutionRole: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Indicates whether the AWS Control Tower Execution role should be created. + Type: String + + pDeployCloudTrailSolution: + AllowedValues: ['Yes', 'No'] + Default: 'Yes' + Description: Deploy the CloudTrail solution + Type: String + pCloudTrailName: + AllowedPattern: '^[A-Za-z0-9][a-zA-Z0-9-\-_.]{2,127}$' + ConstraintDescription: + Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-) Start with a letter or number, and end with a + letter or number Be between 3 and 128 characters Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are + invalid. Not be in IP address format (for example, 192.168.5.4) + Default: sra-org-trail + Description: CloudTrail name + Type: String + pEnableDataEventsOnly: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Only Enable Cloud Trail Data Events + Type: String + pEnableLambdaDataEvents: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Enable Cloud Trail Data Events for all Lambda functions + Type: String + pEnableS3DataEvents: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Enable Cloud Trail S3 Data Events for all buckets + Type: String + pBucketNamePrefix: + AllowedPattern: ^$|^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + ConstraintDescription: + S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). + Default: sra-org-trail-logs + Description: S3 bucket prefix. The account and region will get added to the end. e.g. bucket-prefix-123456789012-us-east-1 + Type: String + pCloudTrailLogGroupKmsKey: + AllowedPattern: ^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ + ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' + Default: '' + Description: + (Optional) KMS Key ARN to use for encrypting the CloudTrail log group data. If empty, encryption is enabled with CloudWatch Logs managing the + server-side encryption keys. + Type: String + pCloudTrailLogGroupRetention: + AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] + Default: 400 + Description: Specifies the number of days you want to retain log events + Type: String + pCreateCloudTrailLogGroup: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: + Indicates whether a CloudWatch Log Group should be created for the CloudTrail, to allow for setting a Log Retention and/or KMS Key for + encryption. + Type: String + pOrganizationCloudTrailKeyAlias: + Default: sra-cloudtrail-org-key + Description: Organization CloudTrail KMS Key Alias + Type: String + +Rules: + DeploySecurityHubSolutionValidation: + RuleCondition: !Equals [!Ref pDeploySecurityHubSolution, 'Yes'] + Assertions: + - Assert: !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed'] + AssertDescription: + "'Deploy the AWS Config Management Solution' parameter must be set to 'Already Deployed', if the security hub solution + is being deployed." + +Conditions: + cUsingKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] + cUseGraviton: !Or + - !Equals [!Ref 'AWS::Region', ap-northeast-1] + - !Equals [!Ref 'AWS::Region', ap-south-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-2] + - !Equals [!Ref 'AWS::Region', eu-central-1] + - !Equals [!Ref 'AWS::Region', eu-west-1] + - !Equals [!Ref 'AWS::Region', eu-west-2] + - !Equals [!Ref 'AWS::Region', us-east-1] + - !Equals [!Ref 'AWS::Region', us-east-2] + - !Equals [!Ref 'AWS::Region', us-west-2] + + cCommonPrerequisitesNotInstalled: !Equals [!Ref pCommonPrerequisitesInstalled, 'false'] + cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'Yes'] + cDeployCloudTrailSolution: !Equals [!Ref pDeployCloudTrailSolution, 'Yes'] + cLambdaLogGrouOutput: !And + - !Condition cCommonPrerequisitesNotInstalled + - !Condition cCreateLambdaLogGroup + +Resources: + rCodeBuildProject: + Type: AWS::CodeBuild::Project + Condition: cCommonPrerequisitesNotInstalled + Properties: + Name: !Sub '${pCodeBuildProjectName}' + Artifacts: + Type: NO_ARTIFACTS + Description: "Codebuild project to get SRA code from github" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + EnvironmentVariables: + - Name: AWS_DEFAULT_REGION + Value: !Ref AWS::Region + - Name: AWS_ACCOUNT_ID + Value: !Ref "AWS::AccountId" + - Name: SRA_STAGING_S3_BUCKET_STACK_NAME + Value: !Ref pSRAStagingS3BucketStackName + - Name: SRA_REPO_URL + Value: !Ref pRepoURL + - Name: SRA_REPO_BRANCH_NAME + Value: !Ref pRepoBranch + Image: "aws/codebuild/standard:5.0" + PrivilegedMode: true + Type: "LINUX_CONTAINER" + ServiceRole: !GetAtt rCodeBuildRole.Arn + TimeoutInMinutes: 120 + Source: + Type: NO_SOURCE + BuildSpec: !Sub | + version: 0.2 + phases: + pre_build: + commands: + - echo Build started on `date`... + build: + commands: + - echo Build started on `date` in ${AWS::Region} region + - echo Cloning SRA code repository from $SRA_REPO_URL... + - git clone $SRA_REPO_URL + - echo Listing current directory... + - ls + - cd aws-security-reference-architecture-examples + - git checkout $SRA_REPO_BRANCH_NAME + - echo Showing current caller identity... + - aws sts get-caller-identity + - echo Deploying SRA staging bucket cloudformation template... + - aws cloudformation deploy --template-file ./aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml --stack-name $SRA_STAGING_S3_BUCKET_STACK_NAME --capabilities CAPABILITY_NAMED_IAM + - echo Staging SRA solutions... + - ./aws_sra_examples/utils/packaging_scripts/stage_solution.sh + post_build: + commands: + - echo Build completed on `date` + + rCommonPrerequisitesManagementAccountParametersStack: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rStartCodeBuildProjectCustomResource + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-management-account-parameters.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pControlTower: !Ref pControlTower + pGovernedRegions: !Ref pGovernedRegions + pSecurityAccountId: !Ref pSecurityAccountId + pLogArchiveAccountId: !Ref pLogArchiveAccountId + + rCommonPrerequisitesMainSsm: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesManagementAccountParametersStack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-main-ssm.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pCreateAWSControlTowerExecutionRole: !Ref pCreateAWSControlTowerExecutionRole + pControlTower: !Ref pControlTower + + rCodeBuildRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Sub '${pCodeBuildRoleName}' + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - codebuild.amazonaws.com + Action: + - "sts:AssumeRole" + Policies: + - PolicyName: "logs-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" + - PolicyName: "cloudformation-changeset-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:CreateChangeSet + - cloudformation:DescribeChangeSet + - cloudformation:ExecuteChangeSet + - cloudformation:GetTemplateSummary + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/*" + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:changeSet/*" + - PolicyName: "cloudformation-describe-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DescribeStacks + Resource: "*" + - PolicyName: "IAM-Access-Policy" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:GetRole + - iam:PassRole + - iam:GetRolePolicy + - iam:PutRolePolicy + - iam:CreateRole + - iam:DeleteRolePolicy + - iam:DeleteRole + - iam:TagRole + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:GetFunction + - lambda:GetFunctionCodeSigningConfig + - lambda:GetRuntimeManagementConfig + - lambda:CreateFunction + - lambda:DeleteFunction + - lambda:TagResource + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:DeleteBucket + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "s3-create-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:PutBucketPolicy + - s3:PutBucketTagging + - s3:PutBucketPublicAccessBlock + - s3:GetEncryptionConfiguration + - s3:PutEncryptionConfiguration + - s3:PutBucketOwnershipControls + - s3:CreateBucket + - s3:PutBucketAcl + - s3:PutBucketObjectLockConfiguration + - s3:PutBucketVersioning + - s3:SetBucketEncryption + - s3:PutBucketEncryption + Resource: + - "arn:aws:s3:::*" + - PolicyName: "ssm-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - ssm:GetParameter + - ssm:GetParameters + - ssm:PutParameter + - ssm:AddTagsToResource + Resource: + - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*" + + rStartCodeBuildProjectCustomResource: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCodeBuildProject + Type: Custom::LambdaCustomResource + Version: '1.0' + Properties: + ServiceToken: !GetAtt rStartCodeBuildProjectLambdaFunction.Arn + + rStartCodeBuildProjectLambdaFunction: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: Lambda role provides access to CloudWatch Logs + - id: W89 + reason: Lambda does not need to communicate with VPC resources. + - id: W92 + reason: Lambda does not need reserved concurrent executions. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Type: AWS::Lambda::Function + Condition: cCommonPrerequisitesNotInstalled + Properties: + FunctionName: !Ref pCodeBuildProjectLambdaFunctionName + Description: Start SRA codebuild project + Architectures: !If + - cUseGraviton + - [arm64] + - !Ref AWS::NoValue + Handler: index.lambda_handler + Role: !GetAtt rStartCodeBuildProjectLambdaRole.Arn + Runtime: python3.9 + Timeout: 900 + Environment: + Variables: + LOG_LEVEL: !Ref pLambdaLogLevel + CODE_BUILD_PROJECT_NAME: !Ref pCodeBuildProjectName + SRA_STAGING_S3_BUCKET_NAME: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + SRA_STAGING_S3_BUCKET_STACK_NAME: !Ref pSRAStagingS3BucketStackName + SRA_CUSTOM_RESOURCE_NAME: !Sub ${pCodeBuildProjectLambdaFunctionName}-Custom-Resource + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Code: + ZipFile: | + # type: ignore + """Custom Resource to start codebuild project. + + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: MIT-0 + """ + import logging + import os + + import boto3 + import cfnresponse + import time + from botocore.exceptions import ClientError + + LOGGER = logging.getLogger(__name__) + log_level: str = os.environ.get("LOG_LEVEL", "INFO") + LOGGER.setLevel(log_level) + CODE_BUILD_PROJECT_NAME: str = os.environ.get("CODE_BUILD_PROJECT_NAME") + SRA_CUSTOM_RESOURCE_NAME: str = os.environ.get("SRA_CUSTOM_RESOURCE_NAME") + + + def start_build(): + management_account_session = boto3.Session() + codebuild_client = management_account_session.client("codebuild") + response = codebuild_client.start_build(projectName=CODE_BUILD_PROJECT_NAME) + LOGGER.info({"API_Call": "codebuild:StartBuild", "API_Response": response}) + buildId = response["build"]["id"] + return wait_for_build([buildId], codebuild_client) + + + def wait_for_build(BuildId, client): + buildWaitStatus = "FAILURE_WAIT_TIMEOUT" + counter = 0 + while counter < 60: + time.sleep(10) + counter = counter + 1 + buildStatus = get_build_status(BuildId, client) + if buildStatus == "SUCCEEDED": + buildWaitStatus = "SUCCESS" + break + elif buildStatus == "FAILED" or buildStatus == "FAULT" or buildStatus == "STOPPED" or buildStatus == "TIMED_OUT": + buildWaitStatus = "BUILD " + buildStatus + " (check codebuild project cloudwatch log group for details)" + break + return buildWaitStatus + + + def get_build_status(buildId, client): + build = client.batch_get_builds(ids=buildId) + return build["builds"][0]["buildStatus"] + + + def create_event(event, context): + try: + data = {"data": start_build()} + if data["data"] == "SUCCESS": + cfnresponse.send(event, context, cfnresponse.SUCCESS, data, SRA_CUSTOM_RESOURCE_NAME) + else: + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name} and CloudFormation Events'" + cfnresponse.send(event, context, cfnresponse.FAILED, data, SRA_CUSTOM_RESOURCE_NAME) + except Exception: + LOGGER.exception("Unexpected!") + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name}'" + cfnresponse.send(event, context, cfnresponse.FAILED, {}, SRA_CUSTOM_RESOURCE_NAME, reason=reason) + return SRA_CUSTOM_RESOURCE_NAME + + + def delete_event(event, context): + LOGGER.info("entered delete_event function. Nothing to do...") + cfnresponse.send(event, context, cfnresponse.SUCCESS, {"delete_operation": "succeeded deleting"}, SRA_CUSTOM_RESOURCE_NAME) + + + def lambda_handler(event, context): + LOGGER.info(event) + if event["RequestType"] == "Create": + LOGGER.info("CREATE EVENT!!") + create_event(event, context) + if event["RequestType"] == "Update": + LOGGER.info("UPDATE EVENT!!") + + if event["RequestType"] == "Delete": + LOGGER.info("DELETE EVENT!!") + delete_event(event, context) + + rStartCodeBuildProjectLambdaLogGroup: + DeletionPolicy: Retain + Type: AWS::Logs::LogGroup + Condition: cCommonPrerequisitesNotInstalled + UpdateReplacePolicy: Retain + Properties: + LogGroupName: !Sub /aws/lambda/${pCodeBuildProjectLambdaFunctionName} + KmsKeyId: !If + - cUsingKmsKey + - !Ref pLambdaLogGroupKmsKey + - !Ref AWS::NoValue + RetentionInDays: !Ref pLambdaLogGroupRetention + + rStartCodeBuildProjectLambdaRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + # - id: W11 + # reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Ref pCodeBuildProjectLambdaRoleName + Description: !Sub Role for '${pCodeBuildProjectLambdaRoleName}' Lambda function + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - lambda.amazonaws.com + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Policies: + - PolicyName: codebuild-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: codebuildStartBuild + Effect: Allow + Action: + - codebuild:StartBuild + - codebuild:BatchGetBuilds + Resource: !GetAtt rCodeBuildProject.Arn + - PolicyName: CloudWatchLogGroup-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: CloudWatchLogs + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pCodeBuildProjectLambdaFunctionName}:log-stream:* + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:GetObjectAcl + - s3:PutObjectAcl + - s3:DeleteBucket + - s3:DeleteObject + - s3:DeleteObjectVersion + - s3:GetBucketVersioning + - s3:DeleteBucketPolicy + - s3:ListBucketVersions + - s3:PutBucketVersioning + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:DeleteFunction + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "cloudformation-stack-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DeleteStack + - cloudformation:DescribeStacks + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/sra*" + - PolicyName: "IAM-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:DeleteRole + - iam:DeleteRolePolicy + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + + + rCloudTrailSolutionStack: + Type: AWS::CloudFormation::Stack + DependsOn: WaitCondition + Condition: cDeployCloudTrailSolution + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}.s3.${AWS::Region}.${AWS::URLSuffix}/sra-cloudtrail-org/templates/sra-cloudtrail-org-main-ssm.yaml + Parameters: + pBucketNamePrefix: !Ref pBucketNamePrefix + pCloudTrailLogGroupKmsKey: !Ref pCloudTrailLogGroupKmsKey + pCloudTrailLogGroupRetention: !Ref pCloudTrailLogGroupRetention + pCloudTrailName: !Ref pCloudTrailName + pCreateCloudTrailLogGroup: !Ref pCreateCloudTrailLogGroup + pCreateLambdaLogGroup: !If [cCreateLambdaLogGroup, true, false] + pEnableDataEventsOnly: !Ref pEnableDataEventsOnly + pEnableLambdaDataEvents: !Ref pEnableLambdaDataEvents + pEnableS3DataEvents: !Ref pEnableS3DataEvents + pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention + pLambdaLogLevel: !Ref pLambdaLogLevel + pOrganizationCloudTrailKeyAlias: !Ref pOrganizationCloudTrailKeyAlias + + + CommonPrerequisitesMainSsmWaitHandle: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesMainSsm + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitHandle: + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitCondition: + Type: "AWS::CloudFormation::WaitCondition" + Properties: + Handle: !If [cCommonPrerequisitesNotInstalled, !Ref CommonPrerequisitesMainSsmWaitHandle, !Ref WaitHandle] + Timeout: "1" + Count: 0 + +Outputs: + oAuditAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Audit Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oAuditAccountId] + oCustomerControlTowerRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Customer Control Tower Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oCustomerControlTowerRegions] + oEnabledRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegions] + oEnabledRegionsWithoutHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions without Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegionsWithoutHomeRegion] + oHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Control Tower Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oHomeRegion] + oLogArchiveAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Log Archive Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oLogArchiveAccountId] + oManagementAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountId] + oRootOrganizationalUnitId: + Condition: cCommonPrerequisitesNotInstalled + Description: Root Organizational Unit ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oRootOrganizationalUnitId] + oManagementAccountParametersLambdaFunctionArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Function ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaFunctionArn] + oManagementAccountParametersLambdaLogGroupArn: + Condition: cLambdaLogGrouOutput + Description: Management Account Parameters Lambda Log Group ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaLogGroupArn] + oManagementAccountParametersLambdaRoleArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Role ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaRoleArn] + + oOrganizationCloudTrailS3BucketName: + Condition: cDeployCloudTrailSolution + Description: Organization CloudTrail S3 Bucket Name + Value: !GetAtt [rCloudTrailSolutionStack, Outputs.oOrganizationCloudTrailS3BucketName] + oOrganizationCloudTrailS3BucketArn: + Condition: cDeployCloudTrailSolution + Description: Organization CloudTrail S3 Bucket Arn + Value: !GetAtt [rCloudTrailSolutionStack, Outputs.oOrganizationCloudTrailS3BucketArn] diff --git a/aws_sra_examples/modules/guardduty-org-module/templates/sra-guardduty-org-module-main.yaml b/aws_sra_examples/modules/guardduty-org-module/templates/sra-guardduty-org-module-main.yaml new file mode 100644 index 00000000..b2cf5b3a --- /dev/null +++ b/aws_sra_examples/modules/guardduty-org-module/templates/sra-guardduty-org-module-main.yaml @@ -0,0 +1,1207 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: '2010-09-09' +Description: Installs the AWS SRA GuardDuty solution. If needed, the AWS SRA common prerequisite solution is also installed. (sra-1u3sd7f8m) +Metadata: + SRA: + Version: 1.0 + Order: 1 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pSRAHelperBucketNamePrefix + - pRandomParameter + - pDisableGuardDuty + - pSRAAlarmEmail + - Label: + default: Landing Zone + Parameters: + - pControlTower + - pGovernedRegions + - pSecurityAccountId + - pLogArchiveAccountId + - pCreateAWSControlTowerExecutionRole + - Label: + default: SRA Code Repo + Parameters: + - pRepoURL + - pRepoBranch + - pTemplateURL + - Label: + default: CodeBuild + Parameters: + - pCodeBuildProjectName + - pCodeBuildProjectLambdaFunctionName + - pCodeBuildRoleName + - pCodeBuildProjectLambdaRoleName + - Label: + default: Lambda + Parameters: + - pCreateLambdaLogGroup + - pLambdaLogGroupKmsKey + - pLambdaLogGroupRetention + - pLambdaLogLevel + - pCheckForResourceLambdaFunctionName + - pGetCommonOutputsLambdaFunctionName + - pCheckForResourceLambdaRoleName + - Label: + default: GuardDuty + Parameters: + - pDisableGuardDuty + - pAutoEnableS3Logs + - pAutoEnableKubernetesAuditLogs + - pAutoEnableMalwareProtection + - pEnableRdsLoginEvents + - pEnableEksRuntimeMonitoring + - pEnableEksAddonManagement + - pEnableLambdaNetworkLogs + - pGuardDutyFindingPublishingFrequency + - pGuardDutyOrgDeliveryBucketPrefix + - pGuardDutyOrgDeliveryKeyAlias + + ParameterLabels: + pSRASolutionName: + default: pSRASolutionName + pSRAHelperBucketNamePrefix: + default: pSRAHelperBucketNamePrefix + pRandomParameter: + default: pRandomParameter + pSRAAlarmEmail: + default: pSRAAlarmEmail + pControlTower: + default: pControlTower + pGovernedRegions: + default: pGovernedRegions + pSecurityAccountId: + default: pSecurityAccountId + pLogArchiveAccountId: + default: pLogArchiveAccountId + pRepoURL: + default: pRepoURL + pRepoBranch: + default: pRepoBranch + pTemplateURL: + default: pTemplateURL + pCodeBuildProjectName: + default: pCodeBuildProjectName + pCodeBuildProjectLambdaFunctionName: + default: pCodeBuildProjectLambdaFunctionName + pCodeBuildRoleName: + default: pCodeBuildRoleName + pCodeBuildProjectLambdaRoleName: + default: pCodeBuildProjectLambdaRoleName + pCreateLambdaLogGroup: + default: pCreateLambdaLogGroup + pLambdaLogGroupKmsKey: + default: pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: + default: pLambdaLogGroupRetention + pLambdaLogLevel: + default: pLambdaLogLevel + pCheckForResourceLambdaFunctionName: + default: pCheckForResourceLambdaFunctionName + pGetCommonOutputsLambdaFunctionName: + default: pGetCommonOutputsLambdaFunctionName + pCheckForResourceLambdaRoleName: + default: pCheckForResourceLambdaRoleName + pDisableGuardDuty: + default: pDisableGuardDuty + pAutoEnableS3Logs: + default: pAutoEnableS3Logs + pAutoEnableKubernetesAuditLogs: + default: pAutoEnableKubernetesAuditLogs + pAutoEnableMalwareProtection: + default: pAutoEnableMalwareProtection + pEnableRdsLoginEvents: + default: pEnableRdsLoginEvents + pEnableEksRuntimeMonitoring: + default: pEnableEksRuntimeMonitoring + pEnableEksAddonManagement: + default: pEnableEksAddonManagement + pEnableLambdaNetworkLogs: + default: pEnableLambdaNetworkLogs + pGuardDutyFindingPublishingFrequency: + default: pGuardDutyFindingPublishingFrequency + pGuardDutyOrgDeliveryBucketPrefix: + default: pGuardDutyOrgDeliveryBucketPrefix + pGuardDutyOrgDeliveryKeyAlias: + default: pGuardDutyOrgDeliveryKeyAlias + pCreateAWSControlTowerExecutionRole: + default: Create AWS Control Tower Execution Role + +Parameters: + pSRAHelperBucketNamePrefix: + AllowedValues: [sra-helper] + Default: sra-helper + Description: + SRA helper S3 bucket name prefix + Type: String + pCodeBuildProjectName: + AllowedValues: [sra-helper-guardduty-codebuild-project] + Default: sra-helper-guardduty-codebuild-project + Description: + SRA CodeBuild project name + Type: String + pTemplateURL: + Default: https://raw.githubusercontent.com/aws-samples/aws-security-reference-architecture-examples/v3.0.4/aws_sra_examples/modules/guardduty-org-module/templates/sra-guardduty-org-solution.yaml + Description: + SRA module solution template URL + Type: String + pRepoURL: + Default: https://github.com/aws-samples/aws-security-reference-architecture-examples.git + Description: + SRA Code Library Repository URL + Type: String + pRepoBranch: + Default: tags/v3.0.4 + Description: + SRA Code Library Repository branch name. Can be used as branch or as tags (e.g. tags/v3.0.1) + Type: String + + pControlTower: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: + Indicates whether AWS Control Tower is deployed and being used for this AWS environment. + Type: String + pGovernedRegions: + AllowedPattern: '^(ct-regions)|((\b(?--. Example = sra-staging-123456789012-us-east-1. + Type: String + pSRAStagingS3BucketStackName: + AllowedValues: [sra-common-prerequisites-staging-s3-bucket] + Default: sra-common-prerequisites-staging-s3-bucket + Description: + SRA Common Prerequisite Staging S3 bucket stack name. This stack will be created by the SRA CodeBuild Project. + Type: String + + pCreateLambdaLogGroup: + AllowedValues: ['Yes', 'No'] + Default: 'No' + Description: + Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS + Key for encryption. + Type: String + + pLambdaLogGroupKmsKey: + AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' + ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' + Default: '' + Description: + (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side + encryption keys. + Type: String + pLambdaLogGroupRetention: + AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] + Default: 14 + Description: Specifies the number of days you want to retain log events + Type: String + pLambdaLogLevel: + AllowedValues: [INFO, ERROR, DEBUG] + Default: INFO + Description: Lambda Function Logging Level + Type: String + + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Must be a valid email address. + Default: '' + Description: (Optional) Email address for receiving SRA alarms + Type: String + pCreateAWSControlTowerExecutionRole: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Indicates whether the AWS Control Tower Execution role should be created. + Type: String + + pDeployGuardDutySolution: + AllowedValues: ['Yes', 'No'] + Default: 'Yes' + Description: Deploy the GuardDuty solution + Type: String + pDisableGuardDuty: + AllowedValues: ['Yes', 'No'] + Default: 'No' + Description: Disable the GuardDuty solution in all accounts and regions before deleting the stack. + Type: String + pAutoEnableS3Logs: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable S3 logs + Type: String + pAutoEnableKubernetesAuditLogs: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable Kubernetes Audit Logs + Type: String + pAutoEnableMalwareProtection: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable Malware Protection + Type: String + pEnableRdsLoginEvents: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable RDS Login Events + Type: String + pEnableEksRuntimeMonitoring: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable EKS Runtime Monitoring + Type: String + pEnableEksAddonManagement: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable EKS Add-on Management + Type: String + pEnableLambdaNetworkLogs: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Auto enable Lambda Network Logs + Type: String + pGuardDutyFindingPublishingFrequency: + AllowedValues: [FIFTEEN_MINUTES, ONE_HOUR, SIX_HOURS] + Default: FIFTEEN_MINUTES + Description: Finding publishing frequency + Type: String + pGuardDutyOrgDeliveryBucketPrefix: + AllowedPattern: '^$|^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' + ConstraintDescription: + S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). + Default: sra-guardduty-org-delivery + Description: + GuardDuty Delivery S3 bucket prefix. The account and region will get added to the end. e.g. sra-guardduty-delivery-123456789012-us-east-1 + Type: String + pGuardDutyOrgDeliveryKeyAlias: + Default: sra-guardduty-org-delivery-key + Description: GuardDuty Delivery KMS Key Alias + Type: String + +# Rules: + +Conditions: + cUsingKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] + cUseGraviton: !Or + - !Equals [!Ref 'AWS::Region', ap-northeast-1] + - !Equals [!Ref 'AWS::Region', ap-south-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-2] + - !Equals [!Ref 'AWS::Region', eu-central-1] + - !Equals [!Ref 'AWS::Region', eu-west-1] + - !Equals [!Ref 'AWS::Region', eu-west-2] + - !Equals [!Ref 'AWS::Region', us-east-1] + - !Equals [!Ref 'AWS::Region', us-east-2] + - !Equals [!Ref 'AWS::Region', us-west-2] + + cCommonPrerequisitesNotInstalled: !Equals [!Ref pCommonPrerequisitesInstalled, 'false'] + cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'Yes'] + cDeployGuardDutySolution: !Equals [!Ref pDeployGuardDutySolution, 'Yes'] + cDisableGuardDuty: !Equals [!Ref pDisableGuardDuty, 'Yes'] + cCreateLogGroupAndCommonPrereqInstalled: !And + - !Condition cCreateLambdaLogGroup + - !Condition cCommonPrerequisitesNotInstalled + + +Resources: + rCodeBuildProject: + Type: AWS::CodeBuild::Project + Condition: cCommonPrerequisitesNotInstalled + Properties: + Name: !Sub '${pCodeBuildProjectName}' + Artifacts: + Type: NO_ARTIFACTS + Description: "Codebuild project to get SRA code from github" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + EnvironmentVariables: + - Name: AWS_DEFAULT_REGION + Value: !Ref AWS::Region + - Name: AWS_ACCOUNT_ID + Value: !Ref "AWS::AccountId" + - Name: SRA_STAGING_S3_BUCKET_STACK_NAME + Value: !Ref pSRAStagingS3BucketStackName + - Name: SRA_REPO_URL + Value: !Ref pRepoURL + - Name: SRA_REPO_BRANCH_NAME + Value: !Ref pRepoBranch + Image: "aws/codebuild/standard:5.0" + PrivilegedMode: true + Type: "LINUX_CONTAINER" + ServiceRole: !GetAtt rCodeBuildRole.Arn + TimeoutInMinutes: 120 + Source: + Type: NO_SOURCE + BuildSpec: !Sub | + version: 0.2 + phases: + pre_build: + commands: + - echo Build started on `date`... + build: + commands: + - echo Build started on `date` in ${AWS::Region} region + - echo Cloning SRA code repository from $SRA_REPO_URL... + - git clone $SRA_REPO_URL + - echo Listing current directory... + - ls + - cd aws-security-reference-architecture-examples + - git checkout $SRA_REPO_BRANCH_NAME + - echo Showing current caller identity... + - aws sts get-caller-identity + - echo Deploying SRA staging bucket cloudformation template... + - aws cloudformation deploy --template-file ./aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml --stack-name $SRA_STAGING_S3_BUCKET_STACK_NAME --capabilities CAPABILITY_NAMED_IAM + - echo Staging SRA solutions... + - ./aws_sra_examples/utils/packaging_scripts/stage_solution.sh + post_build: + commands: + - echo Build completed on `date` + + rCommonPrerequisitesManagementAccountParametersStack: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rStartCodeBuildProjectCustomResource + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-management-account-parameters.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pControlTower: !Ref pControlTower + pGovernedRegions: !Ref pGovernedRegions + pSecurityAccountId: !Ref pSecurityAccountId + pLogArchiveAccountId: !Ref pLogArchiveAccountId + + rCommonPrerequisitesMainSsm: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesManagementAccountParametersStack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-main-ssm.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pCreateAWSControlTowerExecutionRole: !Ref pCreateAWSControlTowerExecutionRole + pControlTower: !Ref pControlTower + + rCodeBuildRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Sub '${pCodeBuildRoleName}' + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - codebuild.amazonaws.com + Action: + - "sts:AssumeRole" + Policies: + - PolicyName: "logs-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" + - PolicyName: "cloudformation-changeset-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:CreateChangeSet + - cloudformation:DescribeChangeSet + - cloudformation:ExecuteChangeSet + - cloudformation:GetTemplateSummary + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/*" + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:changeSet/*" + - PolicyName: "cloudformation-describe-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DescribeStacks + Resource: "*" + - PolicyName: "IAM-Access-Policy" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:GetRole + - iam:PassRole + - iam:GetRolePolicy + - iam:PutRolePolicy + - iam:CreateRole + - iam:DeleteRolePolicy + - iam:DeleteRole + - iam:TagRole + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:GetFunction + - lambda:GetFunctionCodeSigningConfig + - lambda:GetRuntimeManagementConfig + - lambda:CreateFunction + - lambda:DeleteFunction + - lambda:TagResource + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:DeleteBucket + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "s3-create-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:PutBucketPolicy + - s3:PutBucketTagging + - s3:PutBucketPublicAccessBlock + - s3:GetEncryptionConfiguration + - s3:PutEncryptionConfiguration + - s3:PutBucketOwnershipControls + - s3:CreateBucket + - s3:PutBucketAcl + - s3:PutBucketObjectLockConfiguration + - s3:PutBucketVersioning + - s3:SetBucketEncryption + - s3:PutBucketEncryption + Resource: + - "arn:aws:s3:::*" + - PolicyName: "ssm-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - ssm:GetParameter + - ssm:GetParameters + - ssm:PutParameter + - ssm:AddTagsToResource + Resource: + - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*" + + rStartCodeBuildProjectCustomResource: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCodeBuildProject + Type: Custom::LambdaCustomResource + Version: '1.0' + Properties: + ServiceToken: !GetAtt rStartCodeBuildProjectLambdaFunction.Arn + + rStartCodeBuildProjectLambdaFunction: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: Lambda role provides access to CloudWatch Logs + - id: W89 + reason: Lambda does not need to communicate with VPC resources. + - id: W92 + reason: Lambda does not need reserved concurrent executions. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Type: AWS::Lambda::Function + Condition: cCommonPrerequisitesNotInstalled + Properties: + FunctionName: !Ref pCodeBuildProjectLambdaFunctionName + Description: Start SRA codebuild project + Architectures: !If + - cUseGraviton + - [arm64] + - !Ref AWS::NoValue + Handler: index.lambda_handler + Role: !GetAtt rStartCodeBuildProjectLambdaRole.Arn + Runtime: python3.9 + Timeout: 900 + Environment: + Variables: + LOG_LEVEL: !Ref pLambdaLogLevel + CODE_BUILD_PROJECT_NAME: !Ref pCodeBuildProjectName + SRA_STAGING_S3_BUCKET_NAME: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + SRA_STAGING_S3_BUCKET_STACK_NAME: !Ref pSRAStagingS3BucketStackName + SRA_CUSTOM_RESOURCE_NAME: !Sub ${pCodeBuildProjectLambdaFunctionName}-Custom-Resource + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Code: + ZipFile: | + # type: ignore + """Custom Resource to start codebuild project. + + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: MIT-0 + """ + import logging + import os + + import boto3 + import cfnresponse + import time + from botocore.exceptions import ClientError + + LOGGER = logging.getLogger(__name__) + log_level: str = os.environ.get("LOG_LEVEL", "INFO") + LOGGER.setLevel(log_level) + CODE_BUILD_PROJECT_NAME: str = os.environ.get("CODE_BUILD_PROJECT_NAME") + SRA_CUSTOM_RESOURCE_NAME: str = os.environ.get("SRA_CUSTOM_RESOURCE_NAME") + + + def start_build(): + management_account_session = boto3.Session() + codebuild_client = management_account_session.client("codebuild") + response = codebuild_client.start_build(projectName=CODE_BUILD_PROJECT_NAME) + LOGGER.info({"API_Call": "codebuild:StartBuild", "API_Response": response}) + buildId = response["build"]["id"] + return wait_for_build([buildId], codebuild_client) + + + def wait_for_build(BuildId, client): + buildWaitStatus = "FAILURE_WAIT_TIMEOUT" + counter = 0 + while counter < 60: + time.sleep(10) + counter = counter + 1 + buildStatus = get_build_status(BuildId, client) + if buildStatus == "SUCCEEDED": + buildWaitStatus = "SUCCESS" + break + elif buildStatus == "FAILED" or buildStatus == "FAULT" or buildStatus == "STOPPED" or buildStatus == "TIMED_OUT": + buildWaitStatus = "BUILD " + buildStatus + " (check codebuild project cloudwatch log group for details)" + break + return buildWaitStatus + + + def get_build_status(buildId, client): + build = client.batch_get_builds(ids=buildId) + return build["builds"][0]["buildStatus"] + + + def create_event(event, context): + try: + data = {"data": start_build()} + if data["data"] == "SUCCESS": + cfnresponse.send(event, context, cfnresponse.SUCCESS, data, SRA_CUSTOM_RESOURCE_NAME) + else: + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name} and CloudFormation Events'" + cfnresponse.send(event, context, cfnresponse.FAILED, data, SRA_CUSTOM_RESOURCE_NAME) + except Exception: + LOGGER.exception("Unexpected!") + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name}'" + cfnresponse.send(event, context, cfnresponse.FAILED, {}, SRA_CUSTOM_RESOURCE_NAME, reason=reason) + return SRA_CUSTOM_RESOURCE_NAME + + + def delete_event(event, context): + LOGGER.info("entered delete_event function. Nothing to do...") + cfnresponse.send(event, context, cfnresponse.SUCCESS, {"delete_operation": "succeeded deleting"}, SRA_CUSTOM_RESOURCE_NAME) + + + def lambda_handler(event, context): + LOGGER.info(event) + if event["RequestType"] == "Create": + LOGGER.info("CREATE EVENT!!") + create_event(event, context) + if event["RequestType"] == "Update": + LOGGER.info("UPDATE EVENT!!") + + if event["RequestType"] == "Delete": + LOGGER.info("DELETE EVENT!!") + delete_event(event, context) + + rStartCodeBuildProjectLambdaLogGroup: + DeletionPolicy: Retain + Type: AWS::Logs::LogGroup + Condition: cCommonPrerequisitesNotInstalled + UpdateReplacePolicy: Retain + Properties: + LogGroupName: !Sub /aws/lambda/${pCodeBuildProjectLambdaFunctionName} + KmsKeyId: !If + - cUsingKmsKey + - !Ref pLambdaLogGroupKmsKey + - !Ref AWS::NoValue + RetentionInDays: !Ref pLambdaLogGroupRetention + + rStartCodeBuildProjectLambdaRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + # - id: W11 + # reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Ref pCodeBuildProjectLambdaRoleName + Description: !Sub Role for '${pCodeBuildProjectLambdaRoleName}' Lambda function + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - lambda.amazonaws.com + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Policies: + - PolicyName: codebuild-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: codebuildStartBuild + Effect: Allow + Action: + - codebuild:StartBuild + - codebuild:BatchGetBuilds + Resource: !GetAtt rCodeBuildProject.Arn + - PolicyName: CloudWatchLogGroup-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: CloudWatchLogs + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pCodeBuildProjectLambdaFunctionName}:log-stream:* + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:GetObjectAcl + - s3:PutObjectAcl + - s3:DeleteBucket + - s3:DeleteObject + - s3:DeleteObjectVersion + - s3:GetBucketVersioning + - s3:DeleteBucketPolicy + - s3:ListBucketVersions + - s3:PutBucketVersioning + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:DeleteFunction + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "cloudformation-stack-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DeleteStack + - cloudformation:DescribeStacks + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/sra*" + - PolicyName: "IAM-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:DeleteRole + - iam:DeleteRolePolicy + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + + + rGuardDutySolutionStack: + Type: AWS::CloudFormation::Stack + DependsOn: WaitCondition + Condition: cDeployGuardDutySolution + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}.s3.${AWS::Region}.${AWS::URLSuffix}/sra-guardduty-org/templates/sra-guardduty-org-main-ssm.yaml + Parameters: + pAutoEnableS3Logs: !Ref pAutoEnableS3Logs + pAutoEnableKubernetesAuditLogs: !Ref pAutoEnableKubernetesAuditLogs + pAutoEnableMalwareProtection: !Ref pAutoEnableMalwareProtection + pEnableRdsLoginEvents: !Ref pEnableRdsLoginEvents + pEnableEksRuntimeMonitoring: !Ref pEnableEksRuntimeMonitoring + pEnableEksAddonManagement: !Ref pEnableEksAddonManagement + pEnableLambdaNetworkLogs: !Ref pEnableLambdaNetworkLogs + pCreateLambdaLogGroup: !If [cCreateLambdaLogGroup, true, false] + pDisableGuardDuty: !If [cDisableGuardDuty, true, false] + pFindingPublishingFrequency: !Ref pGuardDutyFindingPublishingFrequency + pGuardDutyOrgDeliveryBucketPrefix: !Ref pGuardDutyOrgDeliveryBucketPrefix + pGuardDutyOrgDeliveryKeyAlias: !Ref pGuardDutyOrgDeliveryKeyAlias + pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention + pLambdaLogLevel: !Ref pLambdaLogLevel + pSRAAlarmEmail: !Ref pSRAAlarmEmail + + CommonPrerequisitesMainSsmWaitHandle: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesMainSsm + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitHandle: + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitCondition: + Type: "AWS::CloudFormation::WaitCondition" + Properties: + Handle: !If [cCommonPrerequisitesNotInstalled, !Ref CommonPrerequisitesMainSsmWaitHandle, !Ref WaitHandle] + Timeout: "1" + Count: 0 + +Outputs: + oAuditAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Audit Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oAuditAccountId] + oCustomerControlTowerRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Customer Control Tower Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oCustomerControlTowerRegions] + oEnabledRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegions] + oEnabledRegionsWithoutHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions without Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegionsWithoutHomeRegion] + oHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Control Tower Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oHomeRegion] + oLogArchiveAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Log Archive Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oLogArchiveAccountId] + oManagementAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountId] + oRootOrganizationalUnitId: + Condition: cCommonPrerequisitesNotInstalled + Description: Root Organizational Unit ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oRootOrganizationalUnitId] + oManagementAccountParametersLambdaFunctionArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Function ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaFunctionArn] + oManagementAccountParametersLambdaLogGroupArn: + Condition: cCreateLogGroupAndCommonPrereqInstalled + Description: Management Account Parameters Lambda Log Group ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaLogGroupArn] + oManagementAccountParametersLambdaRoleArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Role ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaRoleArn] + + oPublishingDestinationBucketName: + Condition: cDeployGuardDutySolution + Description: Publishing Destination Bucket Name + Value: !GetAtt [rGuardDutySolutionStack, Outputs.oPublishingDestinationBucketName] + oPublishingDestinationBucketArn: + Condition: cDeployGuardDutySolution + Description: Publishing Destination Bucket Name + Value: !GetAtt [rGuardDutySolutionStack, Outputs.oPublishingDestinationBucketArn] + oGuardDutyDeliveryKeyArn: + Condition: cDeployGuardDutySolution + Description: GuardDuty Delivery KMS Key ARN + Value: !GetAtt [rGuardDutySolutionStack, Outputs.oGuardDutyDeliveryKeyArn] diff --git a/aws_sra_examples/modules/securityhub-org-module/templates/sra-securityhub-org-module-main.yaml b/aws_sra_examples/modules/securityhub-org-module/templates/sra-securityhub-org-module-main.yaml new file mode 100644 index 00000000..efa9b27f --- /dev/null +++ b/aws_sra_examples/modules/securityhub-org-module/templates/sra-securityhub-org-module-main.yaml @@ -0,0 +1,1173 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: '2010-09-09' +Description: Installs the AWS SRA Security Hub solution. If needed, the AWS SRA common prerequisite solution is also installed. (sra-1u3sd7f90) +Metadata: + SRA: + Version: 1.0 + Order: 1 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pSRAHelperBucketNamePrefix + - pRandomParameter + - pComplianceFrequency + - pDisableSecurityHub + - pRegionLinkingMode + - pSRAAlarmEmail + - Label: + default: Landing Zone + Parameters: + - pControlTower + - pGovernedRegions + - pSecurityAccountId + - pLogArchiveAccountId + - pCreateAWSControlTowerExecutionRole + - Label: + default: SRA Code Repo + Parameters: + - pRepoURL + - pRepoBranch + - pTemplateURL + - Label: + default: CodeBuild + Parameters: + - pCodeBuildProjectName + - pCodeBuildProjectLambdaFunctionName + - pCodeBuildRoleName + - pCodeBuildProjectLambdaRoleName + - Label: + default: Lambda + Parameters: + - pCreateLambdaLogGroup + - pLambdaLogGroupKmsKey + - pLambdaLogGroupRetention + - pLambdaLogLevel + - pCheckForResourceLambdaFunctionName + - pGetCommonOutputsLambdaFunctionName + - pCheckForResourceLambdaRoleName + - Label: + default: Standards + Parameters: + - pCISStandardVersion + - pEnableCISStandard + - pEnablePCIStandard + - pEnableNISTStandard + - pNISTStandardVersion + - pEnableSecurityBestPracticesStandard + ParameterLabels: + pSRASolutionName: + default: pSRASolutionName + pSRAHelperBucketNamePrefix: + default: pSRAHelperBucketNamePrefix + pRandomParameter: + default: pRandomParameter + pComplianceFrequency: + default: pComplianceFrequency + pDisableSecurityHub: + default: pDisableSecurityHub + pRegionLinkingMode: + default: pRegionLinkingMode + pSRAAlarmEmail: + default: pSRAAlarmEmail + pControlTower: + default: pControlTower + pGovernedRegions: + default: pGovernedRegions + pSecurityAccountId: + default: pSecurityAccountId + pLogArchiveAccountId: + default: pLogArchiveAccountId + pRepoURL: + default: pRepoURL + pRepoBranch: + default: pRepoBranch + pTemplateURL: + default: pTemplateURL + pCodeBuildProjectName: + default: pCodeBuildProjectName + pCodeBuildProjectLambdaFunctionName: + default: pCodeBuildProjectLambdaFunctionName + pCodeBuildRoleName: + default: pCodeBuildRoleName + pCodeBuildProjectLambdaRoleName: + default: pCodeBuildProjectLambdaRoleName + pCreateLambdaLogGroup: + default: pCreateLambdaLogGroup + pLambdaLogGroupKmsKey: + default: pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: + default: pLambdaLogGroupRetention + pLambdaLogLevel: + default: pLambdaLogLevel + pCheckForResourceLambdaFunctionName: + default: pCheckForResourceLambdaFunctionName + pGetCommonOutputsLambdaFunctionName: + default: pGetCommonOutputsLambdaFunctionName + pCheckForResourceLambdaRoleName: + default: pCheckForResourceLambdaRoleName + pCISStandardVersion: + default: pCISStandardVersion + pEnableCISStandard: + default: pEnableCISStandard + pEnablePCIStandard: + default: pEnablePCIStandard + pEnableNISTStandard: + default: pEnableNISTStandard + pNISTStandardVersion: + default: pNISTStandardVersion + pEnableSecurityBestPracticesStandard: + default: pEnableSecurityBestPracticesStandard + pCreateAWSControlTowerExecutionRole: + default: Create AWS Control Tower Execution Role + + +Parameters: + pRepoURL: + Default: https://github.com/aws-samples/aws-security-reference-architecture-examples.git + Description: + SRA Code Library Repository URL + Type: String + pRepoBranch: + Default: tags/v3.0.4 + Description: + SRA Code Library Repository branch name. Can be used as branch or as tags (e.g. tags/v3.0.1) + Type: String + pTemplateURL: + Default: https://raw.githubusercontent.com/aws-samples/aws-security-reference-architecture-examples/v3.0.4/aws_sra_examples/modules/securityhub-org-module/templates/sra-securityhub-org-solution.yaml + Description: + SRA module solution template URL + Type: String + + pControlTower: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: + Indicates whether AWS Control Tower is deployed and being used for this AWS environment. + Type: String + pGovernedRegions: + AllowedPattern: '^(ct-regions)|((\b(?--. Example = sra-staging-123456789012-us-east-1. + Type: String + pSRAStagingS3BucketStackName: + AllowedValues: [sra-common-prerequisites-staging-s3-bucket] + Default: sra-common-prerequisites-staging-s3-bucket + Description: + SRA Common Prerequisite Staging S3 bucket stack name. This stack will be created by the SRA CodeBuild Project. + Type: String + + pCISStandardVersion: + AllowedValues: [1.2.0, 1.4.0] + Default: 1.4.0 + Description: CIS Standard Version + Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number + pCreateLambdaLogGroup: + AllowedValues: ['Yes', 'No'] + Default: 'No' + Description: + Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS + Key for encryption. + Type: String + pDeployConfigManagementSolution: + AllowedValues: ['No', 'Already Deployed'] + Default: 'Already Deployed' + Description: Deploy the AWS Config Management solution. Note, if solution was previously deployed, choose 'Already Deployed'. + Type: String + pDeploySecurityHubSolution: + AllowedValues: ['Yes', 'No'] + Default: 'Yes' + Description: Deploy the Security Hub solution + Type: String + pDisableSecurityHub: + AllowedValues: ['Yes', 'No'] + Default: 'No' + Description: Disable the Security Hub solution in all accounts and regions before deleting the stack. + Type: String + pEnableCISStandard: + AllowedValues: ['true', 'false'] + Default: 'false' + Description: Indicates whether to enable the CIS AWS Foundations Benchmark Standard. + Type: String + pEnablePCIStandard: + AllowedValues: ['true', 'false'] + Default: 'false' + Description: Indicates whether to enable the Payment Card Industry Data Security Standard (PCI DSS). + Type: String + pEnableSecurityBestPracticesStandard: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Indicates whether to enable the AWS Foundational Security Best Practices Standard. + Type: String + pLambdaLogGroupKmsKey: + AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' + ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' + Default: '' + Description: + (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side + encryption keys. + Type: String + pLambdaLogGroupRetention: + AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] + Default: 14 + Description: Specifies the number of days you want to retain log events + Type: String + pLambdaLogLevel: + AllowedValues: [INFO, ERROR, DEBUG] + Default: INFO + Description: Lambda Function Logging Level + Type: String + pEnableNISTStandard: + AllowedValues: ['true', 'false'] + Default: 'false' + Description: Indicates whether to enable the National Institute of Standards and Technology (NIST) SP 800-53 Rev. 5. + Type: String + pNISTStandardVersion: + AllowedValues: [5.0.0] + Default: 5.0.0 + Description: NIST Standard Version + Type: String + pRegionLinkingMode: + AllowedValues: [SPECIFIED_REGIONS, ALL_REGIONS] + Default: SPECIFIED_REGIONS + Description: + Indicates whether to aggregate findings from all of the available Regions in the current partition. Also determines whether to automatically + aggregate findings from new Regions as Security Hub supports them and you opt into them. + Type: String + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Must be a valid email address. + Default: '' + Description: (Optional) Email address for receiving SRA alarms + Type: String + pCreateAWSControlTowerExecutionRole: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Indicates whether the AWS Control Tower Execution role should be created. + Type: String + +Rules: + DeploySecurityHubSolutionValidation: + RuleCondition: !Equals [!Ref pDeploySecurityHubSolution, 'Yes'] + Assertions: + - Assert: !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed'] + AssertDescription: + "'Deploy the AWS Config Management Solution' parameter must be set to 'Already Deployed', if the security hub solution + is being deployed." + +Conditions: + cUsingKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] + cUseGraviton: !Or + - !Equals [!Ref 'AWS::Region', ap-northeast-1] + - !Equals [!Ref 'AWS::Region', ap-south-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-2] + - !Equals [!Ref 'AWS::Region', eu-central-1] + - !Equals [!Ref 'AWS::Region', eu-west-1] + - !Equals [!Ref 'AWS::Region', eu-west-2] + - !Equals [!Ref 'AWS::Region', us-east-1] + - !Equals [!Ref 'AWS::Region', us-east-2] + - !Equals [!Ref 'AWS::Region', us-west-2] + + cCommonPrerequisitesNotInstalled: !Equals [!Ref pCommonPrerequisitesInstalled, 'false'] + cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'Yes'] + cDeployConfigManagementSolution: !Equals [!Ref pDeployConfigManagementSolution, 'Yes'] + cDeployConfigManagementSolutionAlreadyDeployed: !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed'] + cDeploySecurityHubSolution: !And + - !Or + - !Condition cDeployConfigManagementSolution + - !Condition cDeployConfigManagementSolutionAlreadyDeployed + - !Equals [!Ref pDeploySecurityHubSolution, 'Yes'] + cDisableSecurityHub: !Equals [!Ref pDisableSecurityHub, 'Yes'] + cCreateLogGroupAndCommonPrereqInstalled: !And + - !Condition cCreateLambdaLogGroup + - !Condition cCommonPrerequisitesNotInstalled + + +Resources: + rCodeBuildProject: + Type: AWS::CodeBuild::Project + Condition: cCommonPrerequisitesNotInstalled + Properties: + Name: !Sub '${pCodeBuildProjectName}' + Artifacts: + Type: NO_ARTIFACTS + Description: "Codebuild project to get SRA code from github" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + EnvironmentVariables: + - Name: AWS_DEFAULT_REGION + Value: !Ref AWS::Region + - Name: AWS_ACCOUNT_ID + Value: !Ref "AWS::AccountId" + - Name: SRA_STAGING_S3_BUCKET_STACK_NAME + Value: !Ref pSRAStagingS3BucketStackName + - Name: SRA_REPO_URL + Value: !Ref pRepoURL + - Name: SRA_REPO_BRANCH_NAME + Value: !Ref pRepoBranch + Image: "aws/codebuild/standard:5.0" + PrivilegedMode: true + Type: "LINUX_CONTAINER" + ServiceRole: !GetAtt rCodeBuildRole.Arn + TimeoutInMinutes: 120 + Source: + Type: NO_SOURCE + BuildSpec: !Sub | + version: 0.2 + phases: + pre_build: + commands: + - echo Build started on `date`... + build: + commands: + - echo Build started on `date` in ${AWS::Region} region + - echo Cloning SRA code repository from $SRA_REPO_URL... + - git clone $SRA_REPO_URL + - echo Listing current directory... + - ls + - cd aws-security-reference-architecture-examples + - git checkout $SRA_REPO_BRANCH_NAME + - echo Showing current caller identity... + - aws sts get-caller-identity + - echo Deploying SRA staging bucket cloudformation template... + - aws cloudformation deploy --template-file ./aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml --stack-name $SRA_STAGING_S3_BUCKET_STACK_NAME --capabilities CAPABILITY_NAMED_IAM + - echo Staging SRA solutions... + - ./aws_sra_examples/utils/packaging_scripts/stage_solution.sh + post_build: + commands: + - echo Build completed on `date` + + rCommonPrerequisitesManagementAccountParametersStack: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rStartCodeBuildProjectCustomResource + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-management-account-parameters.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pControlTower: !Ref pControlTower + pGovernedRegions: !Ref pGovernedRegions + pSecurityAccountId: !Ref pSecurityAccountId + pLogArchiveAccountId: !Ref pLogArchiveAccountId + + rCommonPrerequisitesMainSsm: + Type: AWS::CloudFormation::Stack + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesManagementAccountParametersStack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub + - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-main-ssm.yaml + - SRAStagingS3BucketName: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + Parameters: + pCreateAWSControlTowerExecutionRole: !Ref pCreateAWSControlTowerExecutionRole + pControlTower: !Ref pControlTower + + rCodeBuildRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Sub '${pCodeBuildRoleName}' + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - codebuild.amazonaws.com + Action: + - "sts:AssumeRole" + Policies: + - PolicyName: "logs-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" + - PolicyName: "cloudformation-changeset-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:CreateChangeSet + - cloudformation:DescribeChangeSet + - cloudformation:ExecuteChangeSet + - cloudformation:GetTemplateSummary + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/*" + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:changeSet/*" + - PolicyName: "cloudformation-describe-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DescribeStacks + Resource: "*" + - PolicyName: "IAM-Access-Policy" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:GetRole + - iam:PassRole + - iam:GetRolePolicy + - iam:PutRolePolicy + - iam:CreateRole + - iam:DeleteRolePolicy + - iam:DeleteRole + - iam:TagRole + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:GetFunction + - lambda:GetFunctionCodeSigningConfig + - lambda:GetRuntimeManagementConfig + - lambda:CreateFunction + - lambda:DeleteFunction + - lambda:TagResource + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:DeleteBucket + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "s3-create-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:PutBucketPolicy + - s3:PutBucketTagging + - s3:PutBucketPublicAccessBlock + - s3:GetEncryptionConfiguration + - s3:PutEncryptionConfiguration + - s3:PutBucketOwnershipControls + - s3:CreateBucket + - s3:PutBucketAcl + - s3:PutBucketObjectLockConfiguration + - s3:PutBucketVersioning + - s3:SetBucketEncryption + - s3:PutBucketEncryption + Resource: + - "arn:aws:s3:::*" + - PolicyName: "ssm-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - ssm:GetParameter + - ssm:GetParameters + - ssm:PutParameter + - ssm:AddTagsToResource + Resource: + - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*" + + rStartCodeBuildProjectCustomResource: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCodeBuildProject + Type: Custom::LambdaCustomResource + Version: '1.0' + Properties: + ServiceToken: !GetAtt rStartCodeBuildProjectLambdaFunction.Arn + + rStartCodeBuildProjectLambdaFunction: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: Lambda role provides access to CloudWatch Logs + - id: W89 + reason: Lambda does not need to communicate with VPC resources. + - id: W92 + reason: Lambda does not need reserved concurrent executions. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Type: AWS::Lambda::Function + Condition: cCommonPrerequisitesNotInstalled + Properties: + FunctionName: !Ref pCodeBuildProjectLambdaFunctionName + Description: Start SRA codebuild project + Architectures: !If + - cUseGraviton + - [arm64] + - !Ref AWS::NoValue + Handler: index.lambda_handler + Role: !GetAtt rStartCodeBuildProjectLambdaRole.Arn + Runtime: python3.9 + Timeout: 900 + Environment: + Variables: + LOG_LEVEL: !Ref pLambdaLogLevel + CODE_BUILD_PROJECT_NAME: !Ref pCodeBuildProjectName + SRA_STAGING_S3_BUCKET_NAME: !Sub ${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region} + SRA_STAGING_S3_BUCKET_STACK_NAME: !Ref pSRAStagingS3BucketStackName + SRA_CUSTOM_RESOURCE_NAME: !Sub ${pCodeBuildProjectLambdaFunctionName}-Custom-Resource + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Code: + ZipFile: | + # type: ignore + """Custom Resource to start codebuild project. + + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: MIT-0 + """ + import logging + import os + + import boto3 + import cfnresponse + import time + from botocore.exceptions import ClientError + + LOGGER = logging.getLogger(__name__) + log_level: str = os.environ.get("LOG_LEVEL", "INFO") + LOGGER.setLevel(log_level) + CODE_BUILD_PROJECT_NAME: str = os.environ.get("CODE_BUILD_PROJECT_NAME") + SRA_CUSTOM_RESOURCE_NAME: str = os.environ.get("SRA_CUSTOM_RESOURCE_NAME") + + + def start_build(): + management_account_session = boto3.Session() + codebuild_client = management_account_session.client("codebuild") + response = codebuild_client.start_build(projectName=CODE_BUILD_PROJECT_NAME) + LOGGER.info({"API_Call": "codebuild:StartBuild", "API_Response": response}) + buildId = response["build"]["id"] + return wait_for_build([buildId], codebuild_client) + + + def wait_for_build(BuildId, client): + buildWaitStatus = "FAILURE_WAIT_TIMEOUT" + counter = 0 + while counter < 60: + time.sleep(10) + counter = counter + 1 + buildStatus = get_build_status(BuildId, client) + if buildStatus == "SUCCEEDED": + buildWaitStatus = "SUCCESS" + break + elif buildStatus == "FAILED" or buildStatus == "FAULT" or buildStatus == "STOPPED" or buildStatus == "TIMED_OUT": + buildWaitStatus = "BUILD " + buildStatus + " (check codebuild project cloudwatch log group for details)" + break + return buildWaitStatus + + + def get_build_status(buildId, client): + build = client.batch_get_builds(ids=buildId) + return build["builds"][0]["buildStatus"] + + + def create_event(event, context): + try: + data = {"data": start_build()} + if data["data"] == "SUCCESS": + cfnresponse.send(event, context, cfnresponse.SUCCESS, data, SRA_CUSTOM_RESOURCE_NAME) + else: + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name} and CloudFormation Events'" + cfnresponse.send(event, context, cfnresponse.FAILED, data, SRA_CUSTOM_RESOURCE_NAME) + except Exception: + LOGGER.exception("Unexpected!") + reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name}'" + cfnresponse.send(event, context, cfnresponse.FAILED, {}, SRA_CUSTOM_RESOURCE_NAME, reason=reason) + return SRA_CUSTOM_RESOURCE_NAME + + + def delete_event(event, context): + LOGGER.info("entered delete_event function. Nothing to do...") + cfnresponse.send(event, context, cfnresponse.SUCCESS, {"delete_operation": "succeeded deleting"}, SRA_CUSTOM_RESOURCE_NAME) + + + def lambda_handler(event, context): + LOGGER.info(event) + if event["RequestType"] == "Create": + LOGGER.info("CREATE EVENT!!") + create_event(event, context) + if event["RequestType"] == "Update": + LOGGER.info("UPDATE EVENT!!") + + if event["RequestType"] == "Delete": + LOGGER.info("DELETE EVENT!!") + delete_event(event, context) + + + rStartCodeBuildProjectLambdaLogGroup: + DeletionPolicy: Retain + Type: AWS::Logs::LogGroup + Condition: cCommonPrerequisitesNotInstalled + UpdateReplacePolicy: Retain + Properties: + LogGroupName: !Sub /aws/lambda/${pCodeBuildProjectLambdaFunctionName} + KmsKeyId: !If + - cUsingKmsKey + - !Ref pLambdaLogGroupKmsKey + - !Ref AWS::NoValue + RetentionInDays: !Ref pLambdaLogGroupRetention + + rStartCodeBuildProjectLambdaRole: + Type: AWS::IAM::Role + Condition: cCommonPrerequisitesNotInstalled + Metadata: + cfn_nag: + rules_to_suppress: + # - id: W11 + # reason: Allow * in resource when required + - id: W28 + reason: The role name is defined to identify automation resources + Properties: + RoleName: !Ref pCodeBuildProjectLambdaRoleName + Description: !Sub Role for '${pCodeBuildProjectLambdaRoleName}' Lambda function + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - lambda.amazonaws.com + Tags: + - Key: !Ref pSRASolutionTagKey + Value: !Ref pSRASolutionName + Policies: + - PolicyName: codebuild-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: codebuildStartBuild + Effect: Allow + Action: + - codebuild:StartBuild + - codebuild:BatchGetBuilds + Resource: !GetAtt rCodeBuildProject.Arn + - PolicyName: CloudWatchLogGroup-access + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: CloudWatchLogs + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pCodeBuildProjectLambdaFunctionName}:log-stream:* + - PolicyName: "s3-staging-bucket-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketPolicy + - s3:GetObjectAcl + - s3:PutObjectAcl + - s3:DeleteBucket + - s3:DeleteObject + - s3:DeleteObjectVersion + - s3:GetBucketVersioning + - s3:DeleteBucketPolicy + - s3:ListBucketVersions + - s3:PutBucketVersioning + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}" + - !Sub "arn:${AWS::Partition}:s3:::${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/*" + - PolicyName: "lambda-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - lambda:DeleteFunction + - lambda:InvokeFunction + Resource: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:sra*" + - PolicyName: "cloudformation-stack-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - cloudformation:DeleteStack + - cloudformation:DescribeStacks + Resource: + - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/sra*" + - PolicyName: "IAM-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:DeleteRole + - iam:DeleteRolePolicy + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/sra*" + + + rSecurityHubSolutionStack: + Type: AWS::CloudFormation::Stack + DependsOn: WaitCondition + Condition: cDeploySecurityHubSolution + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}.s3.${AWS::Region}.${AWS::URLSuffix}/sra-securityhub-org/templates/sra-securityhub-org-main-ssm.yaml + Parameters: + pCISStandardVersion: !Ref pCISStandardVersion + pComplianceFrequency: !Ref pComplianceFrequency + pCreateLambdaLogGroup: !If [cCreateLambdaLogGroup, true, false] + pDisableSecurityHub: !If [cDisableSecurityHub, true, false] + pEnableCISStandard: !Ref pEnableCISStandard + pEnablePCIStandard: !Ref pEnablePCIStandard + pEnableSecurityBestPracticesStandard: !Ref pEnableSecurityBestPracticesStandard + pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention + pLambdaLogLevel: !Ref pLambdaLogLevel + pRegionLinkingMode: !Ref pRegionLinkingMode + pSRAAlarmEmail: !Ref pSRAAlarmEmail + pEnableNISTStandard: !Ref pEnableNISTStandard + pNISTStandardVersion: !Ref pNISTStandardVersion + + CommonPrerequisitesMainSsmWaitHandle: + Condition: cCommonPrerequisitesNotInstalled + DependsOn: rCommonPrerequisitesMainSsm + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitHandle: + Type: "AWS::CloudFormation::WaitConditionHandle" + + WaitCondition: + Type: "AWS::CloudFormation::WaitCondition" + Properties: + Handle: !If [cCommonPrerequisitesNotInstalled, !Ref CommonPrerequisitesMainSsmWaitHandle, !Ref WaitHandle] + Timeout: "1" + Count: 0 + +Outputs: + oAuditAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Audit Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oAuditAccountId] + oCustomerControlTowerRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Customer Control Tower Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oCustomerControlTowerRegions] + oEnabledRegions: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegions] + oEnabledRegionsWithoutHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Enabled Regions without Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oEnabledRegionsWithoutHomeRegion] + oHomeRegion: + Condition: cCommonPrerequisitesNotInstalled + Description: Control Tower Home Region + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oHomeRegion] + oLogArchiveAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Log Archive Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oLogArchiveAccountId] + oManagementAccountId: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountId] + oRootOrganizationalUnitId: + Condition: cCommonPrerequisitesNotInstalled + Description: Root Organizational Unit ID + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oRootOrganizationalUnitId] + oManagementAccountParametersLambdaFunctionArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Function ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaFunctionArn] + oManagementAccountParametersLambdaLogGroupArn: + Condition: cCreateLogGroupAndCommonPrereqInstalled + Description: Management Account Parameters Lambda Log Group ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaLogGroupArn] + oManagementAccountParametersLambdaRoleArn: + Condition: cCommonPrerequisitesNotInstalled + Description: Management Account Parameters Lambda Role ARN + Value: !GetAtt [rCommonPrerequisitesManagementAccountParametersStack, Outputs.oManagementAccountParametersLambdaRoleArn] \ No newline at end of file diff --git a/aws_sra_examples/quick_setup/customizations_for_aws_control_tower/manifest-v2.yaml b/aws_sra_examples/quick_setup/customizations_for_aws_control_tower/manifest-v2.yaml index 649bc537..ec0861d9 100644 --- a/aws_sra_examples/quick_setup/customizations_for_aws_control_tower/manifest-v2.yaml +++ b/aws_sra_examples/quick_setup/customizations_for_aws_control_tower/manifest-v2.yaml @@ -185,7 +185,7 @@ resources: - parameter_key: pDeployInspectorSolution parameter_value: 'Yes' - parameter_key: pScanComponents - parameter_value: 'EC2, ECR, LAMBDA' + parameter_value: 'EC2, ECR, LAMBDA, LAMBDA_CODE' - parameter_key: pEcrRescanDuration parameter_value: 'LIFETIME' diff --git a/aws_sra_examples/quick_setup/templates/sra-quick-setup-ssm.yaml b/aws_sra_examples/quick_setup/templates/sra-quick-setup-ssm.yaml index 63a07a2c..34ba7422 100644 --- a/aws_sra_examples/quick_setup/templates/sra-quick-setup-ssm.yaml +++ b/aws_sra_examples/quick_setup/templates/sra-quick-setup-ssm.yaml @@ -358,7 +358,7 @@ Metadata: pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name pScanComponents: - default: Comma separated list of scan components (EC2, ECR, LAMBDA) + default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE) pSecurityContactAction: default: Security Alternate Contact Action pSecurityEmail: @@ -929,8 +929,8 @@ Parameters: name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: AWS::SSM::Parameter::Value pScanComponents: - AllowedValues: [EC2, ECR, LAMBDA] - Default: EC2, ECR, LAMBDA + AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE] + Default: EC2, ECR, LAMBDA, LAMBDA_CODE Description: Lambda Function Logging Level Type: CommaDelimitedList pSecurityContactAction: diff --git a/aws_sra_examples/solutions/account/account_alternate_contacts/README.md b/aws_sra_examples/solutions/account/account_alternate_contacts/README.md index e64d17c2..f6816389 100644 --- a/aws_sra_examples/solutions/account/account_alternate_contacts/README.md +++ b/aws_sra_examples/solutions/account/account_alternate_contacts/README.md @@ -100,7 +100,7 @@ The Account Alternate Contacts solution sets alternate contacts for all existing #### 2.2 Configuration IAM Role -- See [1.3 Configuration IAM Role](#13-configuration-iam-role) +- See [1.2 IAM Role](#12-iam-roles) #### 2.3 Account Alternate Contacts diff --git a/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx b/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx index 65dabba3..6e1fb186 100644 Binary files a/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx and b/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx differ diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-main-ssm.yaml b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-main-ssm.yaml index 69fd440e..d4cec19e 100644 --- a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-main-ssm.yaml @@ -331,3 +331,15 @@ Resources: pLambdaLogLevel: !Ref pLambdaLogLevel pOrganizationCloudTrailKMSKeyId: !Sub '{{resolve:secretsmanager:arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${pAuditAccountId}:secret:sra/cloudtrail_org_key_arn:SecretString:OrganizationCloudTrailKeyArn:AWSCURRENT}}' pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName + +Outputs: + oOrganizationCloudTrailS3BucketName: + Description: Organization CloudTrail S3 Bucket Name + Value: !Sub ${pBucketNamePrefix}-${pLogArchiveAccountId}-${AWS::Region} + Export: + Name: eOrganizationCloudTrailS3BucketName + oOrganizationCloudTrailS3BucketArn: + Description: Organization CloudTrail S3 Bucket Arn + Value: !Sub arn:${AWS::Partition}:s3:::${pBucketNamePrefix}-${pLogArchiveAccountId}-${AWS::Region} + Export: + Name: eOrganizationCloudTrailS3BucketArn \ No newline at end of file diff --git a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-main-ssm.yaml b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-main-ssm.yaml index 6c2de7a0..17f89b1d 100644 --- a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-main-ssm.yaml +++ b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-main-ssm.yaml @@ -252,8 +252,8 @@ Resources: rControlTowerExecutionRoleStack: Type: AWS::CloudFormation::Stack Condition: cAWSControlTowerPlusExecutionRole - DeletionPolicy: Delete - UpdateReplacePolicy: Delete + DeletionPolicy: Retain + UpdateReplacePolicy: Retain Properties: TemplateURL: !Sub - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-control-tower-execution-role.yaml @@ -265,8 +265,8 @@ Resources: rExecutionRoleStack: Type: AWS::CloudFormation::Stack DependsOn: rAdminRoleStack - DeletionPolicy: Delete - UpdateReplacePolicy: Delete + DeletionPolicy: Retain + UpdateReplacePolicy: Retain Properties: TemplateURL: !Sub - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-stackset-execution-role.yaml @@ -279,8 +279,8 @@ Resources: rAdminRoleStack: Type: AWS::CloudFormation::Stack - DeletionPolicy: Delete - UpdateReplacePolicy: Delete + DeletionPolicy: Retain + UpdateReplacePolicy: Retain Properties: TemplateURL: !Sub - https://${SRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-common-prerequisites-stackset-admin-role.yaml @@ -293,6 +293,8 @@ Resources: rExecutionRoleStackSet: DependsOn: rAdminRoleStack Type: AWS::CloudFormation::StackSet + DeletionPolicy: Retain + UpdateReplacePolicy: Retain Properties: StackSetName: sra-stackset-execution-role AutoDeployment: diff --git a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-management-account-parameters.yaml b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-management-account-parameters.yaml index 19acd2e4..c2817c98 100644 --- a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-management-account-parameters.yaml +++ b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-management-account-parameters.yaml @@ -315,40 +315,59 @@ Outputs: oAuditAccountId: Description: Audit Account ID Value: !GetAtt rManagementAccountParametersLambdaCustomResource.AuditAccountId + Export: + Name: eAuditAccountId oCustomerControlTowerRegions: Description: Customer Control Tower Regions Value: !Join [',', !GetAtt rManagementAccountParametersLambdaCustomResource.CustomerControlTowerRegions] - oCustomerControlTowerRegionsWithoutHomeRegion: - Description: Customer Control Tower Regions without Home Region - Value: !Join [',', !GetAtt rManagementAccountParametersLambdaCustomResource.CustomerControlTowerRegionsWithoutHomeRegion] + Export: + Name: eCustomerControlTowerRegions oEnabledRegions: Description: Enabled Regions Value: !Join [',', !GetAtt rManagementAccountParametersLambdaCustomResource.EnabledRegions] + Export: + Name: eEnabledRegions oEnabledRegionsWithoutHomeRegion: Description: Enabled Regions without Home Region Value: !Join [',', !GetAtt rManagementAccountParametersLambdaCustomResource.EnabledRegionsWithoutHomeRegion] + Export: + Name: eEnabledRegionsWithoutHomeRegion oHomeRegion: Description: Control Tower Home Region Value: !GetAtt rManagementAccountParametersLambdaCustomResource.HomeRegion + Export: + Name: eHomeRegion oLogArchiveAccountId: Description: Log Archive Account ID Value: !GetAtt rManagementAccountParametersLambdaCustomResource.LogArchiveAccountId + Export: + Name: eLogArchiveAccountId oManagementAccountId: Description: Management Account ID Value: !GetAtt rManagementAccountParametersLambdaCustomResource.ManagementAccountId + Export: + Name: eManagementAccountId oOrganizationId: Description: Organization ID Value: !GetAtt rManagementAccountParametersLambdaCustomResource.OrganizationId oRootOrganizationalUnitId: Description: Root Organizational Unit ID Value: !GetAtt rManagementAccountParametersLambdaCustomResource.RootOrganizationalUnitId + Export: + Name: eRootOrganizationalUnitId oManagementAccountParametersLambdaFunctionArn: Description: Management Account Parameters Lambda Function ARN Value: !GetAtt rManagementAccountParametersLambdaFunction.Arn + Export: + Name: eManagementAccountParametersLambdaFunctionArn oManagementAccountParametersLambdaLogGroupArn: Condition: cCreateLambdaLogGroup Description: Management Account Parameters Lambda Log Group ARN Value: !GetAtt rManagementAccountParametersLambdaLogGroup.Arn + Export: + Name: eManagementAccountParametersLambdaLogGroupArn oManagementAccountParametersLambdaRoleArn: Description: Management Account Parameters Lambda Role ARN Value: !GetAtt rManagementAccountParametersLambdaRole.Arn + Export: + Name: eManagementAccountParametersLambdaRoleArn diff --git a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml index a25bd959..9ea30d8a 100644 --- a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml +++ b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml @@ -296,6 +296,8 @@ Resources: rSRAStagingS3Bucket: Type: AWS::S3::Bucket + DeletionPolicy: Retain + UpdateReplacePolicy: Retain Metadata: cfn_nag: rules_to_suppress: @@ -403,21 +405,33 @@ Outputs: Condition: cCreateCustomResource Description: Organization ID Value: !GetAtt rOrgIdLambdaCustomResource.OrganizationId + Export: + Name: eOrganizationId oOrgIdLambdaFunctionArn: Condition: cCreateCustomResource Description: AWS Organization ID Lambda Function ARN Value: !GetAtt rOrgIdLambdaFunction.Arn + Export: + Name: eOrgIdLambdaFunctionArn oOrgIdLambdaLogGroupArn: Condition: cCreateLambdaLogGroupAndCreateCustomResource Description: AWS Organization ID Lambda Log Group ARN Value: !GetAtt rOrgIdLambdaLogGroup.Arn + Export: + Name: eOrgIdLambdaLogGroupArn oOrgIdLambdaRoleArn: Condition: cCreateCustomResource Description: AWS Organization ID Lambda Role ARN Value: !GetAtt rOrgIdLambdaRole.Arn + Export: + Name: eOrgIdLambdaRoleArn oSRAStagingS3BucketName: Description: SRA Staging S3 Bucket Name SSM parameter Value: !GetAtt rSSMParameterSRAStagingS3BucketName.Value + Export: + Name: eSRAStagingS3BucketName oSRAStagingS3BucketNamePrefix: Description: SRA Staging S3 Bucket Name Prefix SSM parameter Value: !GetAtt rSSMParameterSRAStagingS3BucketNamePrefix.Value + Export: + Name: eSRAStagingS3BucketNamePrefix diff --git a/aws_sra_examples/solutions/config/config_conformance_pack_org/README.md b/aws_sra_examples/solutions/config/config_conformance_pack_org/README.md index 692d8dd4..ea68db8a 100644 --- a/aws_sra_examples/solutions/config/config_conformance_pack_org/README.md +++ b/aws_sra_examples/solutions/config/config_conformance_pack_org/README.md @@ -58,10 +58,9 @@ evaluate your AWS environment, use one of the sample conformance pack templates. --- -### 3.0 Audit Account +### 3.0 Audit Account (Security Tooling) -The example solutions use `Audit Account` instead of `Security Tooling Account` to align with the default account name used within the AWS Control Tower setup process for the Security Account. The Account ID for the `Audit Account` SSM parameter is -populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet. +The example solutions use `Audit Account` instead of `Security Tooling Account` to align with the default account name used within the AWS Control Tower setup process for the Security Account. The Account ID for the `Audit Account` can be determined from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet in AWS Control Tower environments, but is specified manually in other environments, and then stored in an SSM parameter (this is all done in the common prerequisites solution). #### 3.1 AWS CloudFormation diff --git a/aws_sra_examples/solutions/config/config_conformance_pack_org/scripts/list_config_recorder_status.py b/aws_sra_examples/solutions/config/config_conformance_pack_org/scripts/list_config_recorder_status.py index e7801e19..d6ba1525 100644 --- a/aws_sra_examples/solutions/config/config_conformance_pack_org/scripts/list_config_recorder_status.py +++ b/aws_sra_examples/solutions/config/config_conformance_pack_org/scripts/list_config_recorder_status.py @@ -26,6 +26,7 @@ if TYPE_CHECKING: from mypy_boto3_cloudformation import CloudFormationClient from mypy_boto3_organizations import OrganizationsClient + from mypy_boto3_ssm.client import SSMClient from mypy_boto3_sts.client import STSClient # Logging Settings @@ -34,18 +35,17 @@ logging.getLogger("botocore").setLevel(logging.CRITICAL) # Global Variables -CLOUDFORMATION_PAGE_SIZE = 20 -CLOUDFORMATION_THROTTLE_PERIOD = 0.2 MAX_THREADS = 20 ORG_PAGE_SIZE = 20 # Max page size for list_accounts ORG_THROTTLE_PERIOD = 0.2 -ASSUME_ROLE_NAME = "AWSControlTowerExecution" +ASSUME_ROLE_NAME = "sra-execution" BOTO3_CONFIG = Config(retries={"max_attempts": 10, "mode": "standard"}) try: MANAGEMENT_ACCOUNT_SESSION = boto3.Session() ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations", config=BOTO3_CONFIG) CFN_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation", config=BOTO3_CONFIG) + SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm") except Exception as error: LOGGER.error({"Unexpected_Error": error}) raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None @@ -101,29 +101,14 @@ def get_all_organization_accounts() -> list: def get_control_tower_regions() -> list: # noqa: CCR001 - """Query 'AWSControlTowerBP-BASELINE-CLOUDWATCH' CloudFormation stack to identify customer regions. + """Query SSM Parameter Store to identify customer regions. Returns: - Customer regions chosen in Control Tower + Customer regions """ - paginator = CFN_CLIENT.get_paginator("list_stack_instances") - customer_regions = set() - aws_account = "" - all_regions_identified = False - for page in paginator.paginate(StackSetName="AWSControlTowerBP-BASELINE-CLOUDWATCH", PaginationConfig={"PageSize": CLOUDFORMATION_PAGE_SIZE}): - for instance in page["Summaries"]: - if not aws_account: - aws_account = instance["Account"] - customer_regions.add(instance["Region"]) - continue - if aws_account == instance["Account"]: - customer_regions.add(instance["Region"]) - continue - all_regions_identified = True - break - if all_regions_identified: - break - sleep(CLOUDFORMATION_THROTTLE_PERIOD) + customer_regions = [] + ssm_response = SSM_CLIENT.get_parameter(Name="/sra/regions/customer-control-tower-regions") + customer_regions = ssm_response["Parameter"]["Value"].split(",") return list(customer_regions) diff --git a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-delivery-bucket.yaml b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-delivery-bucket.yaml index 97e6226f..da3223d9 100644 --- a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-delivery-bucket.yaml +++ b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-delivery-bucket.yaml @@ -94,7 +94,7 @@ Resources: StringLike: aws:PrincipalArn: - !Sub arn:${AWS::Partition}:iam::*:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms - - !Sub arn:${AWS::Partition}:iam::*:role/AWSControlTowerExecution + - !Sub arn:${AWS::Partition}:iam::*:role/sra-execution Resource: !Sub arn:${AWS::Partition}:s3:::${rConformancePackBucket} Principal: '*' diff --git a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main-ssm.yaml b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main-ssm.yaml index 4c40ab79..9af8ed82 100644 --- a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main-ssm.yaml @@ -20,6 +20,12 @@ Metadata: - pSRAStagingS3BucketName - pSourceStackName + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole + - Label: default: Conformance Pack Properties Parameters: @@ -38,6 +44,10 @@ Metadata: - pOrganizationId ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pAuditAccountId: default: Audit Account ID pConformancePackName: @@ -66,6 +76,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pAuditAccountId: AllowedPattern: ^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$ ConstraintDescription: @@ -176,10 +196,10 @@ Resources: Type: AWS::CloudFormation::StackSet Properties: StackSetName: sra-config-conformance-pack-org-delivery-bucket - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !Sub ${pSRASolutionVersion} - Creates S3 bucket to store the conformance pack results - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: @@ -208,7 +228,7 @@ Resources: DependsOn: rConfigConformancePackOrgDeliveryBucketStackSet Properties: StackSetName: sra-config-conformance-pack-org-deployment - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !If - cRegisterDelegatedAdmin @@ -220,7 +240,7 @@ Resources: ] - !Sub ${pSRASolutionVersion} - This template creates an AWS Organizations Config Conformance Pack in the Control Tower Audit account. - 'config_conformance_pack_org' solution in repo, https://github.com/aws-samples/aws-security-reference-architecture-examples. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main.yaml b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main.yaml index db6f9a75..11935780 100644 --- a/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main.yaml +++ b/aws_sra_examples/solutions/config/config_conformance_pack_org/templates/sra-config-conformance-pack-org-main.yaml @@ -18,6 +18,12 @@ Metadata: - pSRAStagingS3BucketName - pSRASolutionVersion + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole + - Label: default: Conformance Pack Properties Parameters: @@ -36,6 +42,10 @@ Metadata: - pOrganizationId ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pAuditAccountId: default: Audit Account ID pConformancePackName: @@ -62,6 +72,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pAuditAccountId: AllowedPattern: ^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$ ConstraintDescription: @@ -163,10 +183,10 @@ Resources: Type: AWS::CloudFormation::StackSet Properties: StackSetName: sra-config-conformance-pack-org-delivery-bucket - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !Sub ${pSRASolutionVersion} - Creates S3 bucket to store the conformance pack results - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: @@ -195,7 +215,7 @@ Resources: DependsOn: rConfigConformancePackOrgDeliveryBucketStackSet Properties: StackSetName: sra-config-conformance-pack-org-deployment - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !If - cRegisterDelegatedAdmin @@ -207,7 +227,7 @@ Resources: ] - !Sub ${pSRASolutionVersion} - This template creates an AWS Organizations Config Conformance Pack in the Control Tower Audit account. - 'config_conformance_pack_org' solution in repo, https://github.com/aws-samples/aws-security-reference-architecture-examples. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/config/config_management_account/README.md b/aws_sra_examples/solutions/config/config_management_account/README.md index c3a8efac..c59005fc 100644 --- a/aws_sra_examples/solutions/config/config_management_account/README.md +++ b/aws_sra_examples/solutions/config/config_management_account/README.md @@ -74,10 +74,10 @@ accounts/regions. --- -### 2.0 Audit Account +### 2.0 Audit Account (Security Tooling) + +The example solutions use `Audit Account` instead of `Security Tooling Account` to align with the default account name used within the AWS Control Tower setup process for the Security Account. The Account ID for the `Audit Account` can be determined from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet in AWS Control Tower environments, but is specified manually in other environments, and then stored in an SSM parameter (this is all done in the common prerequisites solution). -The example solutions use `Audit Account` instead of `Security Tooling Account` to align with the default account name used within the AWS Control Tower setup process for the Security Account. The Account ID for the `Audit Account` SSM parameter is -populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet. #### 2.1 AWS Config Aggregator diff --git a/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main-ssm.yaml b/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main-ssm.yaml index b0fe73bc..f3814f5b 100644 --- a/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main-ssm.yaml +++ b/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main-ssm.yaml @@ -25,6 +25,11 @@ Metadata: - pLogArchiveAccountId - pOrganizationId - pHomeRegion + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole - Label: default: Config Recorder Properties Parameters: @@ -45,6 +50,10 @@ Metadata: - pLambdaLogGroupKmsKey - pLambdaLogLevel ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pAllSupported: default: All Supported pAuditAccountId: @@ -81,6 +90,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pAllSupported: AllowedValues: ['true', 'false'] Default: 'true' @@ -214,10 +233,10 @@ Resources: Type: AWS::CloudFormation::StackSet Properties: StackSetName: sra-config-management-account - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !Sub ${pSRASolutionVersion} - Enables AWS Config in the Control Tower Management account. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main.yaml b/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main.yaml index 7518a3cd..915c3158 100644 --- a/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main.yaml +++ b/aws_sra_examples/solutions/config/config_management_account/templates/sra-config-management-account-main.yaml @@ -24,6 +24,11 @@ Metadata: - pLogArchiveAccountId - pOrganizationId - pHomeRegion + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole - Label: default: Config Recorder Properties Parameters: @@ -44,6 +49,10 @@ Metadata: - pLambdaLogGroupKmsKey - pLambdaLogLevel ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pAllSupported: default: All Supported pAuditAccountId: @@ -80,6 +89,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pAllSupported: AllowedValues: ['true', 'false'] Default: 'true' @@ -204,10 +223,10 @@ Resources: Type: AWS::CloudFormation::StackSet Properties: StackSetName: sra-config-management-account - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Description: !Sub ${pSRASolutionVersion} - Enables AWS Config in the Control Tower Management account. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/detective/detective_org/README.md b/aws_sra_examples/solutions/detective/detective_org/README.md index 319dd0fc..35f19b02 100644 --- a/aws_sra_examples/solutions/detective/detective_org/README.md +++ b/aws_sra_examples/solutions/detective/detective_org/README.md @@ -78,11 +78,11 @@ The Detective Organization solution will automate enabling Amazon Detective by d --- -### 2.0 Audit Account +### 2.0 Audit Account (Security Tooling) The example solutions use `Audit Account` instead of `Security Tooling Account` to align with the default account name used within the AWS Control Tower setup process for the Security Account. The Account ID for the `Audit Account` SSM parameter is -populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet. +populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-BASELINE-CONFIG` StackSet, but is specified manually in other environments, and then stored in an SSM parameter (this is all done in the common prerequisites solution). #### 2.1 AWS CloudFormation diff --git a/aws_sra_examples/solutions/detective/detective_org/lambda/src/common.py b/aws_sra_examples/solutions/detective/detective_org/lambda/src/common.py index 8dfea8ab..92f7b0c9 100644 --- a/aws_sra_examples/solutions/detective/detective_org/lambda/src/common.py +++ b/aws_sra_examples/solutions/detective/detective_org/lambda/src/common.py @@ -16,9 +16,9 @@ from botocore.exceptions import ClientError, EndpointConnectionError if TYPE_CHECKING: - from mypy_boto3_cloudformation import CloudFormationClient from mypy_boto3_iam.client import IAMClient from mypy_boto3_organizations import OrganizationsClient + from mypy_boto3_ssm.client import SSMClient from mypy_boto3_sts.client import STSClient # Setup Default Logger @@ -27,15 +27,13 @@ LOGGER.setLevel(log_level) # Global variables -CLOUDFORMATION_PAGE_SIZE = 20 -CLOUDFORMATION_THROTTLE_PERIOD = 0.2 ORGANIZATIONS_PAGE_SIZE = 20 ORGANIZATIONS_THROTTLE_PERIOD = 0.2 try: MANAGEMENT_ACCOUNT_SESSION = boto3.Session() - CLOUDFORMATION_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation") ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations") + SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm") except Exception as error: LOGGER.error({"Unexpected_Error": error}) raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None @@ -101,32 +99,13 @@ def get_active_organization_accounts(exclude_accounts: list = None) -> list: def get_control_tower_regions() -> list: # noqa: CCR001 - """Query 'AWSControlTowerBP-BASELINE-CLOUDWATCH' CloudFormation stack to identify customer regions. + """Query SSM Parameter Store to identify customer regions. Returns: - Customer regions chosen in Control Tower + Customer regions """ - paginator = CLOUDFORMATION_CLIENT.get_paginator("list_stack_instances") - customer_regions = [] - aws_account = "" - all_regions_identified = False - for page in paginator.paginate( - StackSetName="AWSControlTowerBP-BASELINE-CLOUDWATCH", - PaginationConfig={"PageSize": CLOUDFORMATION_PAGE_SIZE}, - ): - for instance in page["Summaries"]: - if not aws_account: - aws_account = instance["Account"] - customer_regions.append(instance["Region"]) - continue - if aws_account == instance["Account"]: - customer_regions.append(instance["Region"]) - continue - all_regions_identified = True - break - if all_regions_identified: - break - sleep(CLOUDFORMATION_THROTTLE_PERIOD) + ssm_response = SSM_CLIENT.get_parameter(Name="/sra/regions/customer-control-tower-regions") + customer_regions = ssm_response["Parameter"]["Value"].split(",") return list(customer_regions) diff --git a/aws_sra_examples/solutions/detective/detective_org/templates/sra-detective-org-configuration.yaml b/aws_sra_examples/solutions/detective/detective_org/templates/sra-detective-org-configuration.yaml index c0fe88e7..40ae11c9 100644 --- a/aws_sra_examples/solutions/detective/detective_org/templates/sra-detective-org-configuration.yaml +++ b/aws_sra_examples/solutions/detective/detective_org/templates/sra-detective-org-configuration.yaml @@ -281,6 +281,18 @@ Resources: - detective:DisableOrganizationAdminAccount - detective:ListOrganizationAdminAccount Resource: '*' + + - PolicyName: "ssm-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - ssm:GetParameter + - ssm:GetParameters + Resource: + - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*" + - PolicyName: sra-detective-org-policy-iam PolicyDocument: Version: 2012-10-17 diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png index d2ff464d..a668ee5f 100644 Binary files a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png and b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png differ diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx index e1cec17f..e8e095bf 100644 Binary files a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx and b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx differ diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py index 131fbee1..cc630796 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py @@ -31,6 +31,7 @@ from mypy_boto3_organizations.type_defs import AccountTypeDef, DescribeAccountResponseTypeDef, TagTypeDef from mypy_boto3_sns import SNSClient from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef, PublishResponseTypeDef + from mypy_boto3_ssm.client import SSMClient from mypy_boto3_sts import STSClient # Setup Default Logger @@ -55,6 +56,7 @@ CFN_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation", config=BOTO3_CONFIG) ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations", config=BOTO3_CONFIG) SNS_CLIENT: SNSClient = MANAGEMENT_ACCOUNT_SESSION.client("sns", config=BOTO3_CONFIG) + SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm") except Exception as error: LOGGER.error({"Unexpected_Error": error}) raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None @@ -92,30 +94,14 @@ def assume_role(role: str, role_session_name: str, account: str = None, session: def get_control_tower_regions() -> list: # noqa: CCR001 - """Query 'AWSControlTowerBP-BASELINE-CLOUDWATCH' CloudFormation stack to identify customer regions. + """Query ssm to identify customer regions. Returns: Customer regions chosen in Control Tower """ - paginator = CFN_CLIENT.get_paginator("list_stack_instances") - customer_regions = set() - aws_account = "" - all_regions_identified = False - for page in paginator.paginate(StackSetName="AWSControlTowerBP-BASELINE-CLOUDWATCH", PaginationConfig={"PageSize": CLOUDFORMATION_PAGE_SIZE}): - for instance in page["Summaries"]: - if not aws_account: - aws_account = instance["Account"] - customer_regions.add(instance["Region"]) - continue - if aws_account == instance["Account"]: - customer_regions.add(instance["Region"]) - continue - all_regions_identified = True - break - if all_regions_identified: - break - sleep(CLOUDFORMATION_THROTTLE_PERIOD) - + customer_regions = [] + ssm_response = SSM_CLIENT.get_parameter(Name="/sra/regions/customer-control-tower-regions") + customer_regions = ssm_response["Parameter"]["Value"].split(",") return list(customer_regions) @@ -332,7 +318,6 @@ def process_accounts(event: Union[CloudFormationCustomResourceEvent, dict], para sns_messages = [] accounts = get_active_organization_accounts() for account in accounts: - if is_account_with_exclude_tags(account, params): continue diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml index aeadb87d..0353cd57 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml @@ -53,7 +53,7 @@ Resources: source: - aws.organizations detail-type: - - AWS API Call via CloudTrail + - AWS Service Event via CloudTrail detail: eventSource: - organizations.amazonaws.com diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml index 725ee6b5..d0b3bbfb 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml @@ -23,6 +23,12 @@ Metadata: - pRootOrganizationalUnitId - pSRAAlarmEmail + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole + - Label: default: EC2 Default EBS Encryption Properties Parameters: @@ -45,6 +51,10 @@ Metadata: - pComplianceFrequency ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pComplianceFrequency: default: Frequency to Check for Organizational Compliance pControlTowerRegionsOnly: @@ -75,6 +85,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pComplianceFrequency: ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. Default: 7 @@ -256,13 +276,13 @@ Resources: DependsOn: rEC2DefaultEBSEncryptionStack Properties: StackSetName: sra-ec2-default-ebs-encryption-global-events - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Capabilities: - CAPABILITY_NAMED_IAM Description: !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml index 65a4b21e..1d8ea4e9 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml @@ -23,6 +23,12 @@ Metadata: - pRootOrganizationalUnitId - pSRAAlarmEmail + - Label: + default: IAM Properties + Parameters: + - pStackSetAdminRole + - pStackExecutionRole + - Label: default: EC2 Default EBS Encryption Properties Parameters: @@ -45,6 +51,10 @@ Metadata: - pComplianceFrequency ParameterLabels: + pStackSetAdminRole: + default: Stack Set Role + pStackExecutionRole: + default: Stack execution role pComplianceFrequency: default: Frequency to Check for Organizational Compliance pControlTowerRegionsOnly: @@ -75,6 +85,16 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: + pStackSetAdminRole: + AllowedValues: [sra-stackset] + Default: sra-stackset + Description: The administration role name that is used in the stackset. + Type: String + pStackExecutionRole: + AllowedValues: [sra-execution] + Default: sra-execution + Description: The execution role name that is used in the stack. + Type: String pComplianceFrequency: ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. Default: 7 @@ -251,13 +271,13 @@ Resources: DependsOn: rEC2DefaultEBSEncryptionStack Properties: StackSetName: sra-ec2-default-ebs-encryption-global-events - AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} CallAs: SELF Capabilities: - CAPABILITY_NAMED_IAM Description: !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. - ExecutionRoleName: AWSControlTowerExecution + ExecutionRoleName: !Ref pStackExecutionRole ManagedExecution: Active: true OperationPreferences: diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml index 79d98390..72f49be6 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml @@ -326,6 +326,17 @@ Resources: Action: cloudformation:ListStackInstances Resource: !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/AWSControlTowerBP-* + - PolicyName: "ssm-access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Action: + - ssm:GetParameter + - ssm:GetParameters + Resource: + - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*" + - PolicyName: sra-ec2-default-ebs-encryption-policy-iam PolicyDocument: Version: 2012-10-17 @@ -483,7 +494,7 @@ Resources: source: - aws.organizations detail-type: - - AWS API Call via CloudTrail + - AWS Service Event via CloudTrail detail: eventSource: - organizations.amazonaws.com diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-configuration.yaml b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-configuration.yaml index 68d44d5f..80bd3df7 100644 --- a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-configuration.yaml +++ b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-configuration.yaml @@ -610,4 +610,15 @@ Resources: AlarmActions: - !Ref rGuardDutyOrgDLQAlarmTopic InsufficientDataActions: - - !Ref rGuardDutyOrgDLQAlarmTopic \ No newline at end of file + - !Ref rGuardDutyOrgDLQAlarmTopic + +Outputs: + oPublishingDestinationBucketName: + Description: Publishing Destination Bucket Name + Value: !Ref pPublishingDestinationBucketName + oPublishingDestinationBucketArn: + Description: Publishing Destination Bucket Name + Value: !Sub arn:${AWS::Partition}:s3:::${pPublishingDestinationBucketName} + oGuardDutyDeliveryKeyArn: + Description: GuardDuty Delivery KMS Key ARN + Value: !Ref pKMSKeyArn \ No newline at end of file diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml index 9252d23a..aa5f65f3 100644 --- a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml +++ b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml @@ -170,3 +170,5 @@ Outputs: oGuardDutyDeliveryKeyArn: Description: GuardDuty Delivery KMS Key ARN Value: !GetAtt rGuardDutyDeliveryKey.Arn + # Export: + # Name: eGuardDutyDeliveryKeyArn diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-main-ssm.yaml b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-main-ssm.yaml index df3e8b73..37e57f47 100644 --- a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-main-ssm.yaml @@ -457,3 +457,20 @@ Resources: Tags: - Key: sra-solution Value: !Ref pSRASolutionName + +Outputs: + oPublishingDestinationBucketName: + Description: Publishing Destination Bucket Name + Value: !GetAtt [rGuardDutyConfigurationStack, Outputs.oPublishingDestinationBucketName] + Export: + Name: ePublishingDestinationBucketName + oPublishingDestinationBucketArn: + Description: Publishing Destination Bucket Name + Value: !GetAtt [rGuardDutyConfigurationStack, Outputs.oPublishingDestinationBucketArn] + Export: + Name: ePublishingDestinationBucketArn + oGuardDutyDeliveryKeyArn: + Description: GuardDuty Delivery KMS Key ARN + Value: !GetAtt [rGuardDutyConfigurationStack, Outputs.oGuardDutyDeliveryKeyArn] + Export: + Name: eGuardDutyDeliveryKeyArn diff --git a/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py b/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py index abd2fff7..9c1ca976 100644 --- a/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py +++ b/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py @@ -86,7 +86,9 @@ def get_validated_parameters(event: CloudFormationCustomResourceEvent) -> dict: true_false_pattern = r"^true|false$" - parameter_pattern_validator("MAX_PASSWORD_AGE", params.get("MAX_PASSWORD_AGE", ""), pattern=r"^[0-9]$|^[0-9][0-9]$|^[0-9][0-2][0-8]$") + parameter_pattern_validator( + "MAX_PASSWORD_AGE", params.get("MAX_PASSWORD_AGE", ""), pattern=r"^[1-9]$|^[0-9][0-9]$|^[0-9][0-9][0-9]$|^[0-1][0]([0-8][0-9]|[9][0-5])$" + ) parameter_pattern_validator( "MINIMUM_PASSWORD_LENGTH", params.get("MINIMUM_PASSWORD_LENGTH", ""), pattern=r"^[6-9]$|^[0-9][0-9]$|^[0-9][0-2][0-8]$" ) diff --git a/aws_sra_examples/solutions/inspector/inspector_org/README.md b/aws_sra_examples/solutions/inspector/inspector_org/README.md index 1107b218..b963c8f0 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/README.md +++ b/aws_sra_examples/solutions/inspector/inspector_org/README.md @@ -85,7 +85,7 @@ The Inspector Organization solution will automate enabling Amazon Inspector by d #### 1.10 Inspector - The Inspector delegated administrator is registered within organizations in the `management account` using the Inspector APIs within each provided region. -- EC2, ECR, and Lambda function scanning is set to be auto-enabled for all associated member accounts (newly associated and newly created accounts) +- EC2, ECR, Lambda standard and Lambda code scanning is set to be auto-enabled for all associated member accounts (newly associated and newly created accounts) #### 1.11 Lambda Layer @@ -112,7 +112,7 @@ populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-B #### 2.3 Inspector (Delegated admin) - Inspector is enabled in the delegated admin account within each provided region. -- EC2, ECR, and Lambda function scanning is enabled. +- EC2, ECR, Lambda standard and Lambda code scanning is enabled. --- @@ -129,7 +129,7 @@ populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-B #### 3.3 Inspector (Members) - Inspector is enabled from the delegated administrator account. -- EC2, ECR, and Lambda function scanning is enabled. +- EC2, ECR, Lambda standard and Lambda code scanning is enabled. --- @@ -171,9 +171,9 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* 1. Verify that the delegated admin account is set for each region 2. Log into the Audit account and navigate to the Inspector page 1. Verify the Inspector service is enabled in each region - 2. Verify the auto-enable ec2, ecr, and lambda scanning for new accounts is ON in each region - 3. Verify all existing member accounts have inspector ec2, ecr, and lambda scanning enabled in each region -3. Log into a member account and verify the inspector is enabled and configured to scan ec2, ecr, and lambda functions + 2. Verify the auto-enable ec2, ecr and lambda standard scanning for new accounts is ON in each region, and lambda code scanning in supported regions + 3. Verify all existing member accounts have inspector ec2, ecr, and lambda standard scanning enabled in each region, and lambda code scanning in supported regions +3. Log into a member account and verify the inspector is enabled and configured to scan ec2, ecr, lambda functions and lambda code #### Solution Update Instructions @@ -205,3 +205,4 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* - [Managing AWS SDKs in Lambda Functions](https://docs.aws.amazon.com/lambda/latest/operatorguide/sdks-functions.html) - [Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) - [Python Boto3 SDK changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) +- [AWS Regions where Lambda code scanning is currently available](https://docs.aws.amazon.com/inspector/latest/user/inspector_regions.html) diff --git a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/manifest-v2.yaml b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/manifest-v2.yaml index f4cb49d5..dee25919 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/manifest-v2.yaml +++ b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/manifest-v2.yaml @@ -30,7 +30,7 @@ resources: - parameter_key: pSRASolutionVersion parameter_value: 'v1.0' - parameter_key: pScanComponents - parameter_value: EC2, ECR, LAMBDA + parameter_value: EC2, ECR, LAMBDA, LAMBDA_CODE - parameter_key: pEcrRescanDuration parameter_value: 'LIFETIME' deploy_method: stack_set diff --git a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main-ssm.json b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main-ssm.json index 9936812f..120034dd 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main-ssm.json +++ b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main-ssm.json @@ -37,7 +37,7 @@ }, { "ParameterKey": "pScanComponents", - "ParameterValue": "EC2, ECR, LAMBDA" + "ParameterValue": "EC2, ECR, LAMBDA, LAMBDA_CODE" }, { "ParameterKey": "pEcrRescanDuration", diff --git a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main.json b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main.json index 2ed05a30..208d10da 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main.json +++ b/aws_sra_examples/solutions/inspector/inspector_org/customizations_for_aws_control_tower/parameters/sra-inspector-org-main.json @@ -53,7 +53,7 @@ }, { "ParameterKey": "pScanComponents", - "ParameterValue": "EC2, ECR, LAMBDA" + "ParameterValue": "EC2, ECR, LAMBDA, LAMBDA_CODE" }, { "ParameterKey": "pEcrRescanDuration", diff --git a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py index 64680bc3..30fa87c9 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py @@ -36,7 +36,7 @@ UNEXPECTED = "Unexpected!" SERVICE_NAME = "inspector2.amazonaws.com" SNS_PUBLISH_BATCH_MAX = 10 -ALL_INSPECTOR_SCAN_COMPONENTS = ["EC2", "ECR", "LAMBDA"] +ALL_INSPECTOR_SCAN_COMPONENTS = ["EC2", "ECR", "LAMBDA", "LAMBDA_CODE"] helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120) @@ -172,7 +172,9 @@ def get_validated_parameters(event: Dict[str, Any]) -> dict: params.update(parameter_pattern_validator("SNS_TOPIC_ARN", os.environ.get("SNS_TOPIC_ARN"), pattern=sns_topic_pattern)) params.update( parameter_pattern_validator( - "SCAN_COMPONENTS", os.environ.get("SCAN_COMPONENTS"), pattern=r"(?i)^((ec2|ecr|lambda),?){0,2}(ec2|ecr|lambda){1}$" + "SCAN_COMPONENTS", + os.environ.get("SCAN_COMPONENTS"), + pattern=r"(?i)^((ec2|ecr|lambda|lambda_code),?){0,3}(ec2|ecr|lambda|lambda_code){1}$", ) ) params.update(parameter_pattern_validator("ECR_SCAN_DURATION", os.environ.get("ECR_SCAN_DURATION"), pattern=r"^(LIFETIME|DAYS_30|DAYS_180){1}$")) @@ -374,22 +376,17 @@ def setup_inspector_in_region( scan_components: list of components to scan ecr_scan_duration: ecr scan duration """ - scan_component_dict: AutoEnableTypeDef = {"ec2": False, "ecr": False, "lambda": False} + scan_component_dict: AutoEnableTypeDef = {"ec2": False, "ecr": False, "lambda": False, "lambdaCode": False} for scan_component in scan_components: - if scan_component.lower() == "ec2": - scan_component_dict["ec2"] = True - elif scan_component.lower() == "ecr": - scan_component_dict["ecr"] = True - elif scan_component.lower() == "lambda": - scan_component_dict["lambda"] = True + scan_component_dict[common.snake_to_camel(scan_component)] = True # type: ignore + + if scan_component_dict["lambdaCode"] and not scan_component_dict["lambda"]: + scan_component_dict["lambda"] = True disabled_components: list = [] - if scan_component_dict["ec2"] is False: - disabled_components.append("ec2") - if scan_component_dict["ecr"] is False: - disabled_components.append("ecr") - if scan_component_dict["lambda"] is False: - disabled_components.append("lambda") + for scan_component in scan_component_dict: + if scan_component_dict[scan_component] is False: # type: ignore + disabled_components.append(scan_component) LOGGER.info(f"setup_inspector_in_region: scan_components - ({scan_components}) in {region}") LOGGER.info(f"setup_inspector_in_region: created scan_component_dict as ({scan_component_dict})") diff --git a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/common.py b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/common.py index cbc2d4c2..dbb3ad3b 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/common.py +++ b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/common.py @@ -206,3 +206,30 @@ def create_service_linked_role( LOGGER.info(api_call_details) except iam_client.exceptions.NoSuchEntityException: iam_client.create_service_linked_role(AWSServiceName=service_name, Description=description) + + +def snake_to_camel(snake_str: str) -> str: + """Convert snake case to camel case. + + Args: + snake_str: String to convert + + Returns: + Camel case string + """ + camel_str = snake_str.title().replace("_", "") + return camel_str[0].lower() + camel_str[1:] + + +def camel_to_snake_upper(camel_str: str) -> str: + """Concert camel case to snake upper case. + + Args: + camel_str: String to convert + + Returns: + Snake upper case string + """ + snake_chars = ["_" + x.lower() if x.isupper() else x for x in camel_str] + snake_str = "".join(snake_chars).lstrip("_") + return snake_str.upper() diff --git a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/inspector.py b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/inspector.py index 91a51a26..3bd16520 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/inspector.py +++ b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/inspector.py @@ -246,6 +246,7 @@ def check_inspector_org_auto_enabled(inspector2_delegated_admin_client: Inspecto org_config_ec2_auto_enabled = 0 org_config_ecr_auto_enabled = 0 org_config_lambda_auto_enabled = 0 + org_config_lambda_code_auto_enabled = 0 if "ec2" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["ec2"] is True: org_config_ec2_auto_enabled = 1 LOGGER.info("Organization inspector scanning for ec2 is already configured to be auto-enabled") @@ -255,11 +256,14 @@ def check_inspector_org_auto_enabled(inspector2_delegated_admin_client: Inspecto if "lambda" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["lambda"] is True: org_config_lambda_auto_enabled = 1 LOGGER.info("Organization inspector scanning for lambda is already configured to be auto-enabled") - return org_config_ec2_auto_enabled + org_config_ecr_auto_enabled + org_config_lambda_auto_enabled + if "lambdaCode" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["lambdaCode"] is True: + org_config_lambda_code_auto_enabled = 1 + LOGGER.info("Organization inspector scanning for lambda code is already configured to be auto-enabled") + return org_config_ec2_auto_enabled + org_config_ecr_auto_enabled + org_config_lambda_auto_enabled + org_config_lambda_code_auto_enabled def disable_auto_scanning_in_org(delegated_admin_account_id: str, configuration_role_name: str, regions: list) -> None: - """Disable auto-enable setting in org for ec2, ec2, and lambda. + """Disable auto-enable setting in org for ec2, ec2, lambda and lambdaCode. Args: regions: AWS Region List @@ -273,7 +277,7 @@ def disable_auto_scanning_in_org(delegated_admin_account_id: str, configuration_ if check_inspector_org_auto_enabled(inspector_delegated_admin_region_client) > 0: LOGGER.info(f"disabling inspector scanning auto-enable in region {region}") update_organization_configuration_response = inspector_delegated_admin_region_client.update_organization_configuration( - autoEnable={"ec2": False, "ecr": False, "lambda": False} + autoEnable={"ec2": False, "ecr": False, "lambda": False, "lambdaCode": False} ) api_call_details = {"API_Call": "inspector:UpdateOrganizationConfiguration", "API_Response": update_organization_configuration_response} LOGGER.info(api_call_details) @@ -301,8 +305,8 @@ def get_inspector_status(inspector2_client: Inspector2Client, account_id: str, s if status["state"]["status"] == "ENABLED": LOGGER.info(f"Status: {status['state']['status']}") for scan_component in scan_components: - LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component.lower()]['status']}") # type: ignore - if status["resourceState"][scan_component.lower()]["status"] != "ENABLED": # type: ignore + LOGGER.info(f"{scan_component} status: {status['resourceState'][common.snake_to_camel(scan_component)]['status']}") # type: ignore + if status["resourceState"][common.snake_to_camel(scan_component)]["status"] != "ENABLED": # type: ignore LOGGER.info(f"{scan_component} scan component is disabled...") else: LOGGER.info(f"{scan_component} scan component is enabled...") @@ -358,15 +362,17 @@ def check_for_updates_to_scan_components(inspector2_client: Inspector2Client, ac if status["state"]["status"] == "ENABLED": LOGGER.info(f"Status: {status['state']['status']}") for scan_component in disabled_components: - LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component.lower()]['status']}") # type: ignore - if status["resourceState"][scan_component.lower()]["status"] != "ENABLED": # type: ignore + LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component]['status']}") # type: ignore + if status["resourceState"][scan_component]["status"] != "ENABLED": # type: ignore LOGGER.info(f"{scan_component} scan component is disabled...") else: LOGGER.info(f"{scan_component} scan component is enabled (disablement required)...") disablement = True if disablement is True: LOGGER.info("Disabling some scan components...") - disable_inspector2(inspector2_client, account_id, [disabled_component.upper() for disabled_component in disabled_components]) + disable_inspector2( + inspector2_client, account_id, [common.camel_to_snake_upper(disabled_component) for disabled_component in disabled_components] + ) def enable_inspector2_in_mgmt_and_delegated_admin( @@ -490,12 +496,9 @@ def set_auto_enable_inspector_in_org( scan_component_dict: dictionary of scan components with true/false enable value """ enabled_component_count: int = 0 - if scan_component_dict["ec2"] is True: - enabled_component_count = enabled_component_count + 1 - if scan_component_dict["ecr"] is True: - enabled_component_count = enabled_component_count + 1 - if scan_component_dict["lambda"] is True: - enabled_component_count = enabled_component_count + 1 + for scan_component in scan_component_dict: + if scan_component_dict[scan_component] is True: # type: ignore + enabled_component_count = enabled_component_count + 1 LOGGER.info(f"set_auto_enable_inspector_in_org: scan_component_dict - ({scan_component_dict})") delegated_admin_session = common.assume_role(configuration_role_name, "sra-enable-inspector", delegated_admin_account_id) @@ -503,7 +506,7 @@ def set_auto_enable_inspector_in_org( inspector_delegated_admin_region_client: Inspector2Client = delegated_admin_session.client("inspector2", region) if check_inspector_org_auto_enabled(inspector_delegated_admin_region_client) != enabled_component_count: - LOGGER.info(f"configuring aut-enable inspector via update_organization_configuration in region {region}") + LOGGER.info(f"configuring auto-enable inspector via update_organization_configuration in region {region}") update_organization_configuration_response = inspector_delegated_admin_region_client.update_organization_configuration( autoEnable=scan_component_dict ) diff --git a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-configuration.yaml b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-configuration.yaml index 3a83ed50..dbd17300 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-configuration.yaml +++ b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-configuration.yaml @@ -88,7 +88,7 @@ Metadata: pInspectorConfigurationRoleName: default: Inspector Configuration Role Name pScanComponents: - default: Comma separated list of scan components (EC2, ECR, LAMBDA) + default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE) pEcrRescanDuration: default: ECR Rescan Duration @@ -195,8 +195,8 @@ Parameters: numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String pScanComponents: - AllowedValues: [EC2, ECR, LAMBDA] - Default: EC2, ECR, LAMBDA + AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE] + Default: EC2, ECR, LAMBDA, LAMBDA_CODE Description: Lambda Function Logging Level Type: CommaDelimitedList pEcrRescanDuration: diff --git a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main-ssm.yaml b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main-ssm.yaml index a4e60dbf..edcb6762 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main-ssm.yaml @@ -89,7 +89,7 @@ Metadata: pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name pScanComponents: - default: Comma separated list of scan components (EC2, ECR, LAMBDA) + default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE) pEcrRescanDuration: default: ECR Rescan Duration @@ -202,8 +202,8 @@ Parameters: Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String pScanComponents: - AllowedValues: [EC2, ECR, LAMBDA] - Default: EC2, ECR, LAMBDA + AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE] + Default: EC2, ECR, LAMBDA, LAMBDA_CODE Description: Lambda Function Logging Level Type: CommaDelimitedList pEcrRescanDuration: diff --git a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main.yaml b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main.yaml index 48774890..fa809463 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main.yaml +++ b/aws_sra_examples/solutions/inspector/inspector_org/templates/sra-inspector-org-main.yaml @@ -92,7 +92,7 @@ Metadata: pSRASolutionVersion: default: SRA Solution Version pScanComponents: - default: Comma separated list of scan components (EC2, ECR, LAMBDA) + default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE) pEcrRescanDuration: default: ECR Rescan Duration @@ -200,8 +200,8 @@ Parameters: Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String pScanComponents: - AllowedValues: [EC2, ECR, LAMBDA] - Default: EC2, ECR, LAMBDA + AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE] + Default: EC2, ECR, LAMBDA, LAMBDA_CODE Description: Lambda Function Logging Level Type: CommaDelimitedList pEcrRescanDuration: diff --git a/aws_sra_examples/solutions/macie/macie_org/README.md b/aws_sra_examples/solutions/macie/macie_org/README.md index fe298907..aa51dd26 100644 --- a/aws_sra_examples/solutions/macie/macie_org/README.md +++ b/aws_sra_examples/solutions/macie/macie_org/README.md @@ -74,7 +74,7 @@ The Lambda function is required to register the Macie delegated administrator ac #### 2.3 Macie -- See [1.5 Macie](#15-macie) +- See [1.8 Macie](#18-macie) --- @@ -96,7 +96,7 @@ The example solutions use `Audit Account` instead of `Security Tooling Account` #### 3.4 Macie -- See [1.5 Macie](#15-macie) +- See [1.8 Macie](#18-macie) --- @@ -104,7 +104,7 @@ The example solutions use `Audit Account` instead of `Security Tooling Account` #### 4.1 Macie -- See [1.5 Macie](#15-macie) +- See [1.8 Macie](#18-macie) #### 4.2 Disable Macie Role