AWSTemplateFormatVersion: "2010-09-09" Parameters: AccountId: Type: String Description: CodeShield account ID to connect to. ExternalId: Type: String Description: External ID created for this connection for additional security. SnsTopicArn: Type: String Description: Arn of the CodeShield SNS topic that get's notified after the Role was created. ConnectionName: Type: String Description: Arbitrary name used to identify the connection in the CodeShield dashboard. Default: "" TemplateUrl: Type: String Description: Url to this template to restrict created StackSets of the multi-account-connector to this template. Resources: CodeShieldCrossAccountRole: Type: 'AWS::IAM::Role' Description: Role with necessary permissions for CodeShield to operate Properties: AssumeRolePolicyDocument: Statement: - Action: 'sts:AssumeRole' Effect: Allow Principal: AWS: !Ref AccountId Condition: StringEquals: sts:ExternalId: !Ref ExternalId Sid: '' Version: '2012-10-17' ManagedPolicyArns: - arn:aws:iam::aws:policy/SecurityAudit - !Ref CodeShieldSecurityAuditAdditions - !Ref CodeShieldMaintenancePolicy CodeShieldSecurityAuditAdditions: Type: 'AWS::IAM::ManagedPolicy' Properties: Description: Additional required permissions not in SecurityAudit Path: / PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: # Further required and not in SecurityAudit - "apigateway:GET" - "cloudformation:ListExports" - "audit-manager:ListAssessments" - "amplify:ListApps" - "backup:ListBackupVaults" - "backup:ListBackupPlans" - "detective:ListInvitations" - "ecr:DescribeRegistry" - "ecr:GetRegistryPolicy" - "ecr:GetRegistryScanningConfiguration" - "kafka:ListClusters" - "inspector:DescribeFindings" - "inspector:ListFindings" - "inspector2:DescribeFindings" - "inspector2:ListFindings" - "inspector2:ListCoverage" - "inspector2:ListCoverageStatistics" - "inspector2:ListFindingAggregations" - "lambda:GetFunction" - "memorydb:DescribeACLs" - "memorydb:DescribeClusters" - "memorydb:DescribeParameterGroups" - "memorydb:DescribeSubnetGroups" - "memorydb:DescribeUsers" - "network-firewall:ListFirewallPolicies" - "network-firewall:ListRuleGroups" - "resource-groups:ListGroups" - "route53resolver:ListFirewallDomains" - "s3outposts:ListEndpoints" - "serverlessrepo:CreateCloudFormationTemplate" - "ses:ListTemplates" - "ses:ListConfigurationSets" - "ses:ListCustomVerificationEmailTemplates" - "ses:ListIdentityPolicies" - "ses:ListIdentities" - "sns:ListTagsForResource" - "sns:ListPhoneNumbersOptedOut" - "sns:GetEndpointAttributes" - "sns:GetTopicAttributes" - "sns:GetSMSSandboxAccountStatus" - "sns:GetPlatformApplicationAttributes" - "sns:GetSubscriptionAttributes" - "sns:GetSMSAttributes" - "sns:CheckIfPhoneNumberIsOptedOut" - "ssm-incidents:ListReplicationSets" - "ssm-incidents:ListResponsePlans" - "sso:ListInstances" - "states:ListStateMachines" - "states:DescribeStateMachine" - "states:ListActivities" - "states:DescribeActivity" - "waf:ListByteMatchSets" - "waf:ListIPSets" - "waf:ListRules" - "waf:ListSizeConstraintSets" - "waf:ListSqlInjectionMatchSets" - "waf:ListXssMatchSets" - "waf-regional:ListByteMatchSets" - "waf-regional:ListGeoMatchSets" - "waf-regional:ListIPSets" - "waf-regional:ListRateBasedRules" - "waf-regional:ListRegexPatternSets" - "waf-regional:ListRules" - "waf-regional:ListSizeConstraintSets" - "waf-regional:ListSqlInjectionMatchSets" - "waf-regional:ListXssMatchSets" # Further required for CSPM - "ses:DescribeActiveReceiptRuleSet" - "athena:GetWorkGroup" - "logs:DescribeLogGroups" - "logs:DescribeMetricFilters" - "elastictranscoder:ListPipelines" - "elasticfilesystem:DescribeFileSystems" - "servicequotas:ListServiceQuotas" # required to analyze SCPs - "organizations:DescribePolicy" - "organizations:ListPolicies" - "organizations:ListTargetsForPolicy" - "organizations:ListPoliciesForTarget" Resource: - "*" CodeShieldMaintenancePolicy: Type: 'AWS::IAM::ManagedPolicy' Properties: Description: Permissions required to maintain the connection Path: / PolicyDocument: Version: "2012-10-17" Statement: - Sid: SelfDeleteAndUpdateProposal Effect: Allow Action: # Required to propose updates to this stack - "cloudformation:CreateChangeSet" # Required to automatically disconnect this stack - "cloudformation:DeleteStack" Resource: - !Ref AWS::StackId - Sid: SelfDeleteDetachPolicies Effect: Allow Action: # Required to detach the created policies from the created role on stack delete - "iam:DetachRolePolicy" Resource: arn:aws:iam::*:role/CodeShieldAwsConnector-* Condition: ArnLike: iam:PolicyARN: - arn:aws:iam::*:policy/*-CodeShieldMaintenancePolicy-* - arn:aws:iam::*:policy/*-CodeShieldSecurityAuditAdditions-* - arn:aws:iam::aws:policy/SecurityAudit - Sid: SelfDeleteDeleteRoleAndPolicies Effect: Allow Action: # Required to delete the created role and its policies on stack delete - "iam:DeletePolicy" - "iam:DeletePolicyVersion" - "iam:DeleteRole" - "iam:DeleteRolePolicy" Resource: - arn:aws:iam::*:policy/*-CodeShieldMaintenancePolicy-* - arn:aws:iam::*:policy/*-CodeShieldSecurityAuditAdditions-* - arn:aws:iam::*:role/CodeShieldAwsConnector-* - Sid: MultiAccountConnectorPolicy Effect: Allow Action: # Required to connect multiple accounts automatically - "cloudformation:CreateStackSet" - "cloudformation:DeleteStackSet" - "cloudformation:DescribeStackSet" - "cloudformation:UpdateStackSet" - "cloudformation:CreateStackInstances" - "cloudformation:ListStackInstances" - "cloudformation:DeleteStackInstances" - "cloudformation:DescribeStackSetOperation" - "cloudformation:ListStackSetOperation" - "cloudformation:TagResource" - "cloudformation:UntagResource" - "s3:GetObject" Resource: - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/CodeShield-MultiConnect*:* - !Sub arn:aws:cloudformation:*::type/resource/* - !Sub arn:aws:cloudformation::${AWS::AccountId}:stackset-target/CodeShield-MultiConnect*:* - arn:aws:s3:::codeshield-public-templates-* Condition: StringEqualsIfExists: # Only allow CreateStackSet and UpdateStackSet with our template. Actions that do not care for the template, and thus do not have it in their context (e.g., CreateStackInstances), will still work due to the "IfExists" operator. "cloudformation:TemplateUrl": !Ref TemplateUrl - Sid: OrganizationsPolicy Effect: Allow Action: # required to analyze account structure for cross-account scanning and multi account connections - "organizations:DescribeOrganization" - "organizations:ListRoots" - "organizations:ListOrganizationalUnitsForParent" - "organizations:ListAccountsForParent" - "organizations:DescribeAccount" Resource: "*" # Custom resource that registers the Arn of the created role to CodeShield NotifyRoleArn: Description: Custom resource that registers the Arn of the created role to CodeShield Type: Custom::NotifyRoleArn Version: '1.0' DependsOn: CodeShieldCrossAccountRole Properties: ServiceToken: !Ref SnsTopicArn RoleArn: !GetAtt CodeShieldCrossAccountRole.Arn CredentialsId: !Ref ExternalId ConnectionName: !Ref ConnectionName