AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Description: Sets up GuardDuty with a delegated administor and automatically enabled for all AWS accounts in the AWS Organization. (qs-1s3rsr7ln) Resources: LandingZoneSetupFinishedTrigger: Type: AWS::Events::Rule Properties: EventPattern: source: - superwerker detail: eventName: - LandingZoneSetupOrUpdateFinished State: ENABLED Targets: - Arn: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${EnableGuardDutyOrganizations} Id: EnableGuardDutyOrganizations RoleArn: !GetAtt SSMAutomationExecutionRoleforCWEvents.Arn SSMAutomationExecutionRoleforCWEvents: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: events.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: AllowStartAutomationExecution PolicyDocument: Statement: - Effect: Allow Action: - ssm:StartAutomationExecution Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${EnableGuardDutyOrganizations}:* EnableGuardDutyOrganizations: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: '0.3' assumeRole: !GetAtt EnableGuardDutyOrganizationsRole.Arn parameters: AuditAccountId: type: String default: '{{ssm:/superwerker/account_id_audit}}' LogArchiveAccountId: type: String default: '{{ssm:/superwerker/account_id_logarchive}}' mainSteps: - name: CheckIfOrganizationAdminAccountIsAlReadyRegistered action: aws:executeAwsApi inputs: Service: guardduty Api: ListOrganizationAdminAccounts outputs: - Name: AdminAccountId Selector: $.AdminAccounts[0].AdminAccountId nextStep: EnableOrganizationAdminAccountChoice - name: EnableOrganizationAdminAccountChoice action: aws:branch inputs: Choices: - NextStep: EnableGuardDutyInManagementAccount Variable: '{{ CheckIfOrganizationAdminAccountIsAlReadyRegistered.AdminAccountId }}' StringEquals: '{{ AuditAccountId }}' Default: EnableOrganizationAdminAccount - name: EnableOrganizationAdminAccount action: aws:executeAwsApi inputs: Service: guardduty Api: EnableOrganizationAdminAccount AdminAccountId: '{{ AuditAccountId }}' - name: WaitForEnableOrganizationAdminAccount timeoutSeconds: 60 action: aws:waitForAwsResourceProperty inputs: Service: organizations Api: ListDelegatedAdministrators ServicePrincipal: guardduty.amazonaws.com PropertySelector: $.DelegatedAdministrators[0].Status DesiredValues: - ACTIVE - name: EnableGuardDutyInManagementAccount action: aws:executeAwsApi inputs: Service: guardduty Api: CreateDetector Enable: true - name: SleepEnableGuardDutyExistingAccounts # GuardDuty Org Admin needs to settle first, give it some time action: aws:sleep inputs: Duration: PT120S - name: EnableGuardDutyS3DataProtectionForOrganization action: aws:executeAwsApi inputs: Service: ssm Api: StartAutomationExecution DocumentName: !Ref EnableGuardDutyS3DataProtectionForOrganization TargetLocations: - ExecutionRoleName: AWSControlTowerExecution Accounts: - '{{ AuditAccountId }}' Regions: - !Ref AWS::Region outputs: - Name: AutomationExecutionId Selector: $.AutomationExecutionId - name: WaitForEnableGuardDutyS3DataProtectionForOrganization timeoutSeconds: 60 action: aws:waitForAwsResourceProperty inputs: Service: ssm Api: DescribeAutomationExecutions Filters: - Key: ExecutionId Values: - '{{ EnableGuardDutyS3DataProtectionForOrganization.AutomationExecutionId }}' PropertySelector: $.AutomationExecutionMetadataList[0].AutomationExecutionStatus DesiredValues: - Success - name: EnableGuardDutyExistingAccounts action: aws:executeAwsApi inputs: Service: ssm Api: StartAutomationExecution DocumentName: !Ref EnableGuardDutyExistingAccounts TargetLocations: - ExecutionRoleName: AWSControlTowerExecution Accounts: - '{{ AuditAccountId }}' Regions: - !Ref AWS::Region Parameters: LogArchiveAWSAccountId: - '{{ LogArchiveAccountId }}' ManagementAWSAccountId: - !Sub "${AWS::AccountId}" outputs: - Name: AutomationExecutionId Selector: $.AutomationExecutionId - name: WaitForEnableGuardDutyExistingAccounts timeoutSeconds: 60 action: aws:waitForAwsResourceProperty inputs: Service: ssm Api: DescribeAutomationExecutions Filters: - Key: ExecutionId Values: - '{{ EnableGuardDutyExistingAccounts.AutomationExecutionId }}' PropertySelector: $.AutomationExecutionMetadataList[0].AutomationExecutionStatus DesiredValues: - Success EnableGuardDutyOrganizationsRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyWildcardResource Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: ssm.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: EnableAWSServiceAccess PolicyDocument: Statement: - Effect: Allow Action: - guardduty:EnableOrganizationAdminAccount - guardduty:ListOrganizationAdminAccounts - guardduty:CreateDetector - organizations:EnableAWSServiceAccess - organizations:ListAWSServiceAccessForOrganization - organizations:ListDelegatedAdministrators - organizations:RegisterDelegatedAdministrator - organizations:DescribeOrganization - ssm:DescribeAutomationExecutions Resource: '*' - PolicyName: AllowStartAutomationExecution PolicyDocument: Statement: - Effect: Allow Action: ssm:StartAutomationExecution Resource: - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${EnableGuardDutyExistingAccounts}:* - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${EnableGuardDutyS3DataProtectionForOrganization}:* - PolicyName: AllowCallCrossAccountAutomation PolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRole Resource: !Sub arn:${AWS::Partition}:iam::*:role/AWSControlTowerExecution - PolicyName: SSMParameters PolicyDocument: Statement: - Effect: Allow Action: ssm:GetParameters Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/superwerker/* - PolicyName: ServiceLinkedRole PolicyDocument: Statement: - Effect: Allow Action: iam:CreateServiceLinkedRole Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty EnableGuardDutyExistingAccounts: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: '0.3' parameters: LogArchiveAWSAccountId: type: String ManagementAWSAccountId: type: String mainSteps: - name: GetDetectorId action: aws:executeAwsApi inputs: Service: guardduty Api: ListDetectors outputs: - Name: DetectorId Selector: $.DetectorIds[0] - name: ManagementAWSAccount action: aws:executeAwsApi inputs: Service: organizations Api: DescribeAccount AccountId: '{{ ManagementAWSAccountId }}' outputs: - Name: EmailAddress Selector: $.Account.Email - name: LogArchiveAWSAccount action: aws:executeAwsApi inputs: Service: organizations Api: DescribeAccount AccountId: '{{ LogArchiveAWSAccountId }}' outputs: - Name: EmailAddress Selector: $.Account.Email - name: CreateMembers action: aws:executeAwsApi inputs: Service: guardduty Api: CreateMembers DetectorId: '{{ GetDetectorId.DetectorId }}' AccountDetails: - AccountId: '{{ ManagementAWSAccountId }}' Email: '{{ ManagementAWSAccount.EmailAddress }}' - AccountId: '{{ LogArchiveAWSAccountId }}' Email: '{{ LogArchiveAWSAccount.EmailAddress }}' - name: EnableGuardDutyExistingAccounts action: aws:executeAwsApi inputs: Service: guardduty Api: UpdateOrganizationConfiguration DetectorId: '{{ GetDetectorId.DetectorId }}' AutoEnable: true EnableGuardDutyS3DataProtectionForOrganization: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: '0.3' mainSteps: - name: GetDetectorId action: aws:executeAwsApi inputs: Service: guardduty Api: ListDetectors outputs: - Name: DetectorId Selector: $.DetectorIds[0] - name: EnableGuardDutyS3DataProtectionForOrganization action: aws:executeAwsApi inputs: Service: guardduty Api: UpdateOrganizationConfiguration AutoEnable: true DetectorId: '{{ GetDetectorId.DetectorId }}' DataSources: S3Logs: AutoEnable: true Metadata: SuperwerkerVersion: 0.13.2 cfn-lint: config: ignore_checks: - E9007