# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 AWSTemplateFormatVersion: 2010-09-09 Description: Configure the AWSCloudFormationStackSetAdministrationRole to enable use of AWS CloudFormation StackSets. Metadata: TemplateVersion: '{{.TemplateVersion}}' Parameters: AdminRoleName: Type: String ExecutionRoleName: Type: String DNSDelegationRoleName: Type: String Default: "" AppDNSDelegatedAccounts: Type: CommaDelimitedList Default: "" AppDomainName: Type: String Default: "" AppDomainHostedZoneID: Type: String Default: "" AppName: Type: String Conditions: DelegateDNS: !Not [!Equals [ !Ref AppDomainName, "" ]] Resources: AdministrationRole: Metadata: 'aws:copilot:description': 'A StackSet admin role {{- if .PermissionsBoundary}} with permissions boundary {{.PermissionsBoundary}} {{- end}} assumed by CloudFormation to manage regional stacks' Type: AWS::IAM::Role Properties: RoleName: !Ref AdminRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: cloudformation.amazonaws.com Action: - sts:AssumeRole {{- if .PermissionsBoundary}} PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/{{.PermissionsBoundary}}' {{- end}} Path: / Policies: - PolicyName: AssumeRole-AWSCloudFormationStackSetExecutionRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - sts:AssumeRole Resource: - !Sub 'arn:${AWS::Partition}:iam::*:role/${ExecutionRoleName}' ExecutionRole: Metadata: 'aws:copilot:description': 'An IAM role {{- if .PermissionsBoundary}} with permissions boundary {{.PermissionsBoundary}} {{- end}} assumed by the admin role to create ECR repositories, KMS keys, and S3 buckets' Type: AWS::IAM::Role Properties: RoleName: !Ref ExecutionRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !GetAtt AdministrationRole.Arn Action: - sts:AssumeRole {{- if .PermissionsBoundary}} PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/{{.PermissionsBoundary}}' {{- end}} Path: / Policies: - PolicyName: ExecutionRolePolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: StackSetRequiredPermissions # https://go.aws/3Sa5Tcf Effect: Allow Action: - cloudformation:* - s3:* - sns:* Resource: "*" - Sid: KeyAdminPermissions # https://go.aws/3BIqf7a Effect: Allow Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:TagResource - kms:UntagResource - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion Resource: "*" - Sid: ManageECRRepos Effect: Allow Action: - ecr:DescribeImageScanFindings - ecr:GetLifecyclePolicyPreview - ecr:CreateRepository - ecr:GetDownloadUrlForLayer - ecr:GetAuthorizationToken - ecr:ListTagsForResource - ecr:ListImages - ecr:DeleteLifecyclePolicy - ecr:DeleteRepository - ecr:SetRepositoryPolicy - ecr:BatchGetImage - ecr:DescribeImages - ecr:DescribeRepositories - ecr:BatchCheckLayerAvailability - ecr:GetRepositoryPolicy - ecr:GetLifecyclePolicy - ecr:TagResource Resource: "*" DNSDelegationRole: Metadata: 'aws:copilot:description': 'A DNS delegation role {{- if .PermissionsBoundary}} with permissions boundary {{.PermissionsBoundary}} {{- end}} to allow accounts: {{join .AppDNSDelegatedAccounts ", "}} to manage your domain' Type: AWS::IAM::Role Condition: DelegateDNS Properties: RoleName: !Ref DNSDelegationRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root Action: - sts:AssumeRole - Effect: Allow Principal: AWS: {{- range $account := .AppDNSDelegatedAccounts}} - !Sub arn:${AWS::Partition}:iam::{{$account}}:root {{- end}} Action: - sts:AssumeRole {{- if .PermissionsBoundary}} PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/{{.PermissionsBoundary}}' {{- end}} Path: / Policies: - PolicyName: DNSDelegationPolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: HostedZoneReadRecords Effect: Allow Action: - route53:Get* - route53:List* Resource: "*" - Sid: HostedZoneUpdate Effect: Allow Action: - route53:ChangeResourceRecordSets Resource: - !Sub arn:${AWS::Partition}:route53:::hostedzone/${AppHostedZone} - !Sub arn:${AWS::Partition}:route53:::hostedzone/${AppDomainHostedZoneID} AppHostedZone: Metadata: 'aws:copilot:description': 'A hosted zone for {{.Name}}.{{.Domain}}' Type: AWS::Route53::HostedZone Condition: DelegateDNS Properties: HostedZoneConfig: Comment: !Sub "Hosted zone for copilot application ${AppName}: ${AppName}.${AppDomainName}" Name: !Sub ${AppName}.${AppDomainName} AppDomainDelegationRecordSet: Metadata: 'aws:copilot:description': 'Add NS records to delegate responsibility to the {{.Name}}.{{.Domain}} subdomain' Type: AWS::Route53::RecordSet Condition: DelegateDNS Properties: HostedZoneName: !Sub ${AppDomainName}. Comment: !Sub "Record for copilot domain delegation for application ${AppDomainName}" Name: !Sub ${AppName}.${AppDomainName}. Type: NS TTL: '900' ResourceRecords: !GetAtt AppHostedZone.NameServers Outputs: ExecutionRoleARN: Description: ExecutionRole used by this application to set up ECR Repos, KMS Keys and S3 buckets Value: !GetAtt ExecutionRole.Arn AdministrationRoleARN: Description: AdministrationRole used by this application to manage this application's StackSet Value: !GetAtt AdministrationRole.Arn TemplateVersion: Description: Required output to force the stack to update if mutating version. Value: {{.TemplateVersion}}