Skip to content

How do I use CodePipeline to deploy a service-managed CloudFormation StackSet in a delegated administrator account?

5 minute read
0

I want to use AWS CodePipeline to deploy an AWS CloudFormation StackSet to target organizational units (OUs) in AWS Organizations. I want to use service-managed permissions to deploy the stack in a delegated administrator account.

Resolution

Note: If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshooting errors for the AWS CLI. Also, make sure that you're using the most recent AWS CLI version.

Prerequisite: Activate trusted access between AWS CloudFormation StackSets and Organizations. For permissions, see Permissions required to enable trusted access. You must be an administrator user in the management account to activate trusted access.

Register the delegated administrator account

To delegate a member account as an administrator account, run the following register-delegated-administrator AWS CLI command:

aws organizations register-delegated-administrator \
  --service-principal=member.org.stacksets.cloudformation.amazonaws.com \
  --account-id="111122223333"

Note: Replace 111122223333 with your account ID.

To verify the registration, run the following list-delegated-administrators CLI command:

aws organizations list-delegated-administrators \
    --service-principal=member.org.stacksets.cloudformation.amazonaws.com

Set up the pipeline

To create a pipeline that allows CloudFormation actions, you can use the Codepipeline console or AWS CLI.

Use the console

To use the CodePipeline console to create a pipeline, see Create a pipeline from static templates. For Configure template, add the following cp-template.yaml template:

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  TargetRegions:
    Type: String

Resources:
  Bucket:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Retain
    Properties:
      VersioningConfiguration:
        Status: Enabled

  ServiceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codepipeline.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: CodePipelinePermissions
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketVersioning
                  - s3:PutObject
                  - s3:PutObjectAcl
                Resource:
                  - !Sub arn:aws:s3:::${Bucket}
                  - !Sub arn:aws:s3:::${Bucket}/*
              - Effect: Allow
                Action:
                  - cloudformation:CreateStackSet
                  - cloudformation:UpdateStackSet
                  - cloudformation:DeleteStackSet
                  - cloudformation:DescribeStackSet
                  - cloudformation:DescribeStackSetOperation
                  - cloudformation:ListStackInstances
                  - cloudformation:CreateStackInstances
                Resource: "*"
              - Effect: Allow
                Action:
                  - organizations:ListDelegatedAdministrators
                Resource: "*"

  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt ServiceRole.Arn
      ArtifactStore:
        Type: S3
        Location: !Ref Bucket
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: S3
                Version: "1"
              Configuration:
                S3Bucket: !Ref Bucket
                S3ObjectKey: "source.zip"
                PollForSourceChanges: false
              OutputArtifacts:
                - Name: SourceArtifact
        - Name: Deploy
          Actions:
            - Name: ServiceManaged-SS
              RunOrder: "1"
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Provider: CloudFormationStackSet
                Version: "1"
              Configuration:
                PermissionModel: SERVICE_MANAGED
                CallAs: DELEGATED_ADMIN
                OrganizationsAutoDeployment: Enabled
                Regions: !Ref TargetRegions
                StackSetName: !Sub codepipeline-deployed-cfn-${AWS::AccountId}-stackset
                MaxConcurrentPercentage: "50"
                FailureTolerancePercentage: "100"
                ConcurrencyMode: SOFT_FAILURE_TOLERANCE
                Capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
                DeploymentTargets: "SourceArtifact::ou.txt"
                TemplatePath: "SourceArtifact::template.yaml"
                Parameters: "SourceArtifact::parameters.txt"
              InputArtifacts:
                - Name: SourceArtifact

Note: The AWS Identity and Access Management (IAM) service role that you specified for CallAs must have the organizations:ListDelegatedAdministrators permission.

Use AWS CLI

To use the AWS CLI to create the pipeline, see Create a pipeline (CLI).

(Optional) Create a stack

If you don't use a template to create your pipeline, then you must create a stack in CloudFormation for your pipeline.

Use the console

To use the CloudFormation console to create a stack, see Creating a stack. In the Parameters section, add the AWS Regions that the StackSet instances deploy to. For example, include aa-example-1, aa-example-2 in TargetRegions. Make sure that the IAM service role that you specified for CallAs has the organizations:ListDelegatedAdministrators permission.

Note: After you create the stack, it's expected that the pipeline fails because you didn't upload the source .zip file. You upload the .zip file after you prepare the source files.

Use AWS CLI

Use the same file path that you used for cp-template.yaml, and then run the following create-stack AWS CLI command:

aws cloudformation create-stack \
  --stack-name stack-name \
  --capabilities CAPABILITY_NAMED_IAM \
  --template-body file://cp-template.yaml \
  --parameters ParameterKey=TargetRegions,ParameterValue=aa-example-1\\,aa-example-2

Note: Replace stack-name with your stack's name, //./cp-template.yaml with your file path and aa-example-1 and aa-example-2 with your Regions.

Upload source files to your Amazon S3 bucket

Prepare the source files

To define deployment targets, create a .txt file and name it ou.txt. Add the following code to the .txt file:

["ou-xrop-xxxxxxxx","ou-xrop-yyyyyyyy"]

To define the CloudFormation template parameters, create a .txt file and name it parameters.txt. Add the following code to the .txt file:

[
  {
    "ParameterKey": "VersioningStatus",
    "ParameterValue": "Enabled"
  }
]

To create the StackSet template, create a .txt file and name it template.yaml. Add the following code to the .txt file:

AWSTemplateFormatVersion: 2010-09-09

Parameters:
  VersioningStatus:
    Type: String
    Default: Suspended
    AllowedValues:
      - Enabled
      - Suspended

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Delete
    Properties:
      VersioningConfiguration: 
        Status: !Ref VersioningStatus

Deploy the source files

Compress the three files into source.zip, and then upload the .zip file to the root directory of the source Amazon Simple Storage Service (Amazon S3) bucket. If the pipeline fails and you get the "Account used is not a delegated administrator" error, then confirm that you registered the account as a delegated administrator.

Related information

AWS CloudFormation StackSets deploy action reference

How do I resolve the error "Account used is not a delegated administrator" when I run the ListStackSets operation?

AWS OFFICIALUpdated a year ago