######################################################################## # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 ######################################################################## AWSTemplateFormatVersion: 2010-09-09 Description: This template creates a custom resource Lambda to delegate administration and configure GuardDuty - 'guardduty_org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse4k) Metadata: SRA: Version: 1.1 Order: 6 AWS::CloudFormation::Interface: ParameterGroups: - Label: default: General Properties Parameters: - pSRASolutionName - pSRAStagingS3BucketName - pSRAAlarmEmail - Label: default: Lambda Function Properties Parameters: - pGuardDutyOrgLambdaRoleName - pGuardDutyOrgLambdaFunctionName - pOrganizationId - Label: default: Custom Resource Properties Parameters: - pDisableGuardDuty - pAutoEnableS3Logs - pAutoEnableKubernetesAuditLogs - pAutoEnableMalwareProtection - pEnableRdsLoginEvents - pEnableEksRuntimeMonitoring - pEnableEksAddonManagement - pEnableLambdaNetworkLogs - pControlTowerRegionsOnly - pGuardDutyOrgConfigurationRoleName - pDelegatedAdminAccountId - pDeleteDetectorRoleName - pEnabledRegions - pFindingPublishingFrequency - pKMSKeyArn - pPublishingDestinationBucketName - Label: default: General Lambda Function Properties Parameters: - pCreateLambdaLogGroup - pLambdaLogGroupRetention - pLambdaLogGroupKmsKey - pLambdaLogLevel ParameterLabels: pAutoEnableS3Logs: default: Auto Enable S3 Logs pAutoEnableKubernetesAuditLogs: default: Auto Enable Kubernetes Audit Logs pAutoEnableMalwareProtection: default: Auto Enable Malware Protection pEnableRdsLoginEvents: default: Auto enable RDS Login Events pEnableEksRuntimeMonitoring: default: Auto enable EKS Runtime Monitoring pEnableEksAddonManagement: default: Auto enable EKS Add-on Management pEnableLambdaNetworkLogs: default: Auto enable Lambda Network Logs pControlTowerRegionsOnly: default: Control Tower Regions Only pCreateLambdaLogGroup: default: Create Lambda Log Group pDelegatedAdminAccountId: default: Delegated Admin Account ID pDeleteDetectorRoleName: default: Delete Detector Role Name pDisableGuardDuty: default: Disable GuardDuty in All Accounts pEnabledRegions: default: Enabled Regions pFindingPublishingFrequency: default: Finding Publishing Frequency pGuardDutyOrgConfigurationRoleName: default: GuardDuty Configuration Role Name pGuardDutyOrgLambdaFunctionName: default: Lambda Function Name pGuardDutyOrgLambdaRoleName: default: Lambda Role Name pKMSKeyArn: default: KMS Key ARN pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: default: Lambda Log Group Retention pLambdaLogLevel: default: Lambda Log Level pOrganizationId: default: Organization ID pPublishingDestinationBucketName: default: Publishing Destination Bucket Name pSRAAlarmEmail: default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: 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 pControlTowerRegionsOnly: Type: String Description: Only enable in the Control Tower governed regions Default: 'true' AllowedValues: ['true', 'false'] pCreateLambdaLogGroup: AllowedValues: ['true', 'false'] Default: 'false' 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 pDelegatedAdminAccountId: AllowedPattern: '^\d{12}$' ConstraintDescription: Must be 12 digits Description: Delegated administrator account ID Type: String pDeleteDetectorRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] Default: sra-guardduty-delete-detector Description: GuardDuty IAM role to assume in each account to delete GuardDuty detectors Type: String pDisableGuardDuty: AllowedValues: ['true', 'false'] Default: 'false' Description: Update to 'true' to disable GuardDuty in all accounts and regions before deleting the stack. Type: String pEnabledRegions: AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$' ConstraintDescription: Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g. us-east-1,ap-southeast-2) Description: Enabled regions (AWS regions, separated by commas). Leave blank to enable all regions. Type: String pFindingPublishingFrequency: AllowedValues: [FIFTEEN_MINUTES, ONE_HOUR, SIX_HOURS] Default: FIFTEEN_MINUTES Description: Finding publishing frequency Type: String pGuardDutyOrgConfigurationRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] Default: sra-guardduty-org-configuration Description: GuardDuty Configuration role to assume in the delegated administrator account Type: String pGuardDutyOrgLambdaFunctionName: AllowedPattern: '^[\w-]{0,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] Default: sra-guardduty-org Description: Lambda function name Type: String pGuardDutyOrgLambdaRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] Default: sra-guardduty-org-lambda Description: GuardDuty configuration Lambda role name Type: String pKMSKeyArn: AllowedPattern: '^arn:(aws[a-zA-Z-]*)?: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' Description: Logging S3 bucket KMS Key ARN 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' 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 pOrganizationId: AllowedPattern: '^o-[a-z0-9]{10,32}$' ConstraintDescription: The Organization ID must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters Description: AWS Organizations ID Type: String pPublishingDestinationBucketName: 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 (-). Description: GuardDuty S3 bucket name Type: String pSRAAlarmEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Must be a valid email address. Description: (Optional) Email address for receiving DLQ alarms Type: String pSRASolutionName: AllowedValues: [sra-guardduty-org] Default: sra-guardduty-org Description: The SRA solution name. The default value is the folder name of the solution Type: String pSRAStagingS3BucketName: AllowedPattern: '^(?=^.{3,63}$)(?!.*[.-]{2})(?!.*[--]{2})(?!^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$)(^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$)' ConstraintDescription: SRA Staging S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Description: SRA Staging S3 bucket name for the artifacts relevant to solution. (e.g., lambda zips, CloudFormation templates) S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String Conditions: cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']] 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] Resources: rGuardDutyOrgLambdaLogGroup: Condition: cCreateLambdaLogGroup DeletionPolicy: Retain Type: AWS::Logs::LogGroup UpdateReplacePolicy: Retain Properties: LogGroupName: !Sub /aws/lambda/${pGuardDutyOrgLambdaFunctionName} KmsKeyId: !If - cUseKmsKey - !Ref pLambdaLogGroupKmsKey - !Ref AWS::NoValue RetentionInDays: !Ref pLambdaLogGroupRetention rGuardDutyOrgLambdaRole: Type: AWS::IAM::Role Metadata: cfn_nag: rules_to_suppress: - id: W11 reason: Actions require wildcard in resource - id: W28 reason: The role name is defined checkov: skip: - id: CKV_AWS_111 comment: IAM write actions require wildcard in resource Properties: RoleName: !Ref pGuardDutyOrgLambdaRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - lambda.amazonaws.com Path: '/' Policies: - PolicyName: sra-guardduty-org-policy-cloudformation PolicyDocument: Version: 2012-10-17 Statement: - Sid: CloudFormation Effect: Allow Action: cloudformation:ListStackInstances Resource: !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/AWSControlTowerBP-* - PolicyName: sra-guardduty-org-policy-guardduty PolicyDocument: Version: 2012-10-17 Statement: - Sid: GuardDutyNoResource Effect: Allow Action: - guardduty:DisableOrganizationAdminAccount - guardduty:EnableOrganizationAdminAccount - guardduty:ListDetectors - guardduty:ListOrganizationAdminAccounts Resource: '*' - Sid: GuardDutyWithResource Effect: Allow Action: - guardduty:DeleteDetector - guardduty:ListMembers Resource: - !Sub arn:${AWS::Partition}:guardduty:*:${AWS::AccountId}:detector/* - !Sub arn:${AWS::Partition}:guardduty:*:${AWS::AccountId}:/detector/* - PolicyName: sra-guardduty-org-policy-iam PolicyDocument: Version: 2012-10-17 Statement: - Sid: AllowReadIamActions Effect: Allow Action: iam:GetRole Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/* - Sid: AllowCreateServiceLinkedRole Effect: Allow Action: iam:CreateServiceLinkedRole Condition: StringLike: iam:AWSServiceName: - guardduty.amazonaws.com - malware-protection.guardduty.amazonaws.com Resource: - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/malware-protection.guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDutyMalwareProtection - Sid: AllowPolicyActions Effect: Allow Action: iam:PutRolePolicy Resource: - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/malware-protection.guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDutyMalwareProtection - Sid: AssumeRole Effect: Allow Action: sts:AssumeRole Condition: StringEquals: aws:PrincipalOrgId: !Ref pOrganizationId Resource: - !Sub arn:${AWS::Partition}:iam::*:role/${pDeleteDetectorRoleName} - !Sub arn:${AWS::Partition}:iam::*:role/${pGuardDutyOrgConfigurationRoleName} - PolicyName: sra-guardduty-org-policy-logs PolicyDocument: Version: 2012-10-17 Statement: - Sid: CreateLogGroupAndEvents Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pGuardDutyOrgLambdaFunctionName}:log-stream:* - PolicyName: sra-guardduty-org-policy-organizations PolicyDocument: Version: 2012-10-17 Statement: - Sid: OrganizationsReadAccess Effect: Allow Action: - organizations:DescribeOrganization - organizations:ListAWSServiceAccessForOrganization - organizations:ListAccounts - organizations:ListDelegatedAdministrators Resource: '*' - Sid: RegisterDeregisterDelegatedAdministrator Effect: Allow Action: - organizations:DeregisterDelegatedAdministrator - organizations:DisableAWSServiceAccess - organizations:EnableAWSServiceAccess - organizations:RegisterDelegatedAdministrator Condition: StringLikeIfExists: organizations:ServicePrincipal: - guardduty.amazonaws.com - malware-protection.guardduty.amazonaws.com Resource: '*' - PolicyName: sra-guardduty-org-policy-sns PolicyDocument: Version: 2012-10-17 Statement: - Sid: SNSPublish Effect: Allow Action: sns:Publish Resource: !Ref rGuardDutyOrgTopic - PolicyName: sra-guardduty-org-policy-sqs PolicyDocument: Version: 2012-10-17 Statement: - Sid: SQSSendMessage Effect: Allow Action: sqs:SendMessage Resource: !GetAtt rGuardDutyOrgDLQ.Arn Tags: - Key: sra-solution Value: !Ref pSRASolutionName rGuardDutyOrgLambdaFunction: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: CloudWatch access provided by the attached IAM role - id: W89 reason: Lambda is not deployed within a VPC - 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_117 comment: Lambda does not need to communicate with VPC resources. - id: CKV_AWS_173 comment: Environment variables are not sensitive. Properties: FunctionName: !Ref pGuardDutyOrgLambdaFunctionName Description: Configure GuardDuty for the Organization Architectures: !If - cUseGraviton - [arm64] - !Ref AWS::NoValue Handler: app.lambda_handler Role: !GetAtt rGuardDutyOrgLambdaRole.Arn MemorySize: 512 Runtime: python3.9 Timeout: 900 Code: S3Bucket: !Ref pSRAStagingS3BucketName S3Key: !Sub ${pSRASolutionName}/lambda_code/${pSRASolutionName}.zip Layers: - !Ref rGuardDutyOrgLambdaLayer DeadLetterConfig: TargetArn: !GetAtt rGuardDutyOrgDLQ.Arn Environment: Variables: LOG_LEVEL: !Ref pLambdaLogLevel Tags: - Key: sra-solution Value: !Ref pSRASolutionName rGuardDutyOrgLambdaLayer: Type: AWS::Lambda::LayerVersion Properties: Content: S3Bucket: !Ref pSRAStagingS3BucketName S3Key: !Sub ${pSRASolutionName}/layer_code/${pSRASolutionName}-layer.zip Description: Boto3 version 1.26.133 layer to enable newer API of GuardDuty LayerName: !Sub ${pGuardDutyOrgLambdaFunctionName}-updated-boto3-layer rGuardDutyOrgLambdaCustomResource: Type: Custom::LambdaCustomResource Version: '1.0' Properties: ServiceToken: !GetAtt rGuardDutyOrgLambdaFunction.Arn AUTO_ENABLE_S3_LOGS: !Ref pAutoEnableS3Logs AUTO_ENABLE_MALWARE_PROTECTION: !Ref pAutoEnableMalwareProtection ENABLE_EKS_AUDIT_LOGS: !Ref pAutoEnableKubernetesAuditLogs ENABLE_RDS_LOGIN_EVENTS: !Ref pEnableRdsLoginEvents ENABLE_EKS_RUNTIME_MONITORING: !Ref pEnableEksRuntimeMonitoring ENABLE_EKS_ADDON_MANAGEMENT: !Ref pEnableEksAddonManagement ENABLE_LAMBDA_NETWORK_LOGS: !Ref pEnableLambdaNetworkLogs CONFIGURATION_ROLE_NAME: !Ref pGuardDutyOrgConfigurationRoleName CONTROL_TOWER_REGIONS_ONLY: !Ref pControlTowerRegionsOnly DELEGATED_ADMIN_ACCOUNT_ID: !Ref pDelegatedAdminAccountId DELETE_DETECTOR_ROLE_NAME: !Ref pDeleteDetectorRoleName DISABLE_GUARD_DUTY: !Ref pDisableGuardDuty ENABLED_REGIONS: !Ref pEnabledRegions FINDING_PUBLISHING_FREQUENCY: !Ref pFindingPublishingFrequency KMS_KEY_ARN: !Ref pKMSKeyArn PUBLISHING_DESTINATION_BUCKET_ARN: !Sub arn:${AWS::Partition}:s3:::${pPublishingDestinationBucketName} SNS_TOPIC_ARN: !Ref rGuardDutyOrgTopic rGuardDutyOrgTopic: Type: AWS::SNS::Topic Properties: DisplayName: !Sub ${pSRASolutionName}-configuration KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns Tags: - Key: sra-solution Value: !Ref pSRASolutionName rGuardDutyOrgTopicLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !GetAtt rGuardDutyOrgLambdaFunction.Arn Principal: sns.amazonaws.com SourceArn: !Ref rGuardDutyOrgTopic rGuardDutyOrgTopicSubscription: Type: AWS::SNS::Subscription Properties: Endpoint: !GetAtt rGuardDutyOrgLambdaFunction.Arn Protocol: lambda TopicArn: !Ref rGuardDutyOrgTopic rGuardDutyOrgDLQ: Type: AWS::SQS::Queue Properties: KmsMasterKeyId: alias/aws/sqs QueueName: !Sub ${pSRASolutionName}-dlq Tags: - Key: sra-solution Value: !Ref pSRASolutionName rGuardDutyOrgDLQPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: - !Ref rGuardDutyOrgDLQ PolicyDocument: Statement: - Action: SQS:SendMessage Condition: ArnEquals: aws:SourceArn: - !GetAtt rGuardDutyOrgLambdaFunction.Arn Effect: Allow Principal: Service: events.amazonaws.com Resource: - !GetAtt rGuardDutyOrgDLQ.Arn rGuardDutyOrgDLQAlarmTopic: Condition: cCreateDLQAlarm Type: AWS::SNS::Topic Properties: DisplayName: !Sub ${pSRASolutionName}-dlq-alarm KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns TopicName: !Sub ${pSRASolutionName}-dlq-alarm Subscription: - Endpoint: !Ref pSRAAlarmEmail Protocol: email Tags: - Key: sra-solution Value: !Ref pSRASolutionName rGuardDutyOrgDLQAlarm: Condition: cCreateDLQAlarm Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: SRA DLQ alarm if the queue depth is 1 Namespace: AWS/SQS MetricName: ApproximateNumberOfMessagesVisible Dimensions: - Name: QueueName Value: !GetAtt rGuardDutyOrgDLQ.QueueName Statistic: Sum Period: 300 EvaluationPeriods: 1 Threshold: 1 ComparisonOperator: GreaterThanThreshold AlarmActions: - !Ref rGuardDutyOrgDLQAlarmTopic InsufficientDataActions: - !Ref rGuardDutyOrgDLQAlarmTopic