All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.cdklabs.cdk.stacksets.package-info Maven / Gradle / Ivy

There is a newer version: 0.0.150
Show newest version
/**
 * 

CDK StackSets Construct Library

*

* --- *

* cdk-constructs: Experimental *

*

*

* The APIs of higher level constructs in this module are experimental and under active development. * They are subject to non-backward compatible changes or removal in any future version. These are * not subject to the Semantic Versioning model and breaking changes will be * announced in the release notes. This means that while you may use them, you may need to update * your source code when upgrading to a newer version of this package. *

*

*

*


*

* *

* This construct library allows you to define AWS CloudFormation StackSets. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromAccounts(AccountsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .accounts(List.of("11111111111"))
 *                 .parameterOverrides(Map.of(
 *                         "SomeParam", "overrideValue"))
 *                 .build()))
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

*

Installing

*

*

TypeScript/JavaScript

*

*

 * npm install cdk-stacksets
 * 
*

*

Python

*

*

 * pip install cdk-stacksets
 * 
*

*

Java

*

*

 * // add this to your pom.xml
 * <dependency>
 *     <groupId>io.github.cdklabs</groupId>
 *     <artifactId>cdk-stacksets</artifactId>
 *     <version>0.0.0</version> // replace with version
 * </dependency>
 * 
*

*

.NET

*

*

 * dotnet add package CdklabsCdkStacksets --version X.X.X
 * 
*

*

Go

*

*

 * go get cdk-stacksets-go
 * 
*

*

Creating a StackSet Stack

*

* StackSets allow you to deploy a single CloudFormation template across multiple AWS accounts and regions. * Typically when creating a CDK Stack that will be deployed across multiple environments, the CDK will * synthesize separate Stack templates for each environment (account/region combination). Because of the * way that StackSets work, StackSet Stacks behave differently. For Stacks that will be deployed via StackSets * a single Stack is defined and synthesized. Any environmental differences must be encoded using Parameters. *

* A special class was created to handle the uniqueness of the StackSet Stack. * You declare a StackSetStack the same way that you declare a normal Stack, but there * are a couple of differences. StackSetStacks have a couple of special requirements/limitations when * compared to Stacks. *

* Requirements *

*

    *
  • Must be created in the scope of a Stack
  • *
  • Must be environment agnostic
  • *
*

* Limitations *

*

    *
  • Does not support Docker container assets
  • *
*

* Once you create a StackSetStack you can create resources within the stack. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "StackSet");
 * 
 * Role.Builder.create(stackSetStack, "MyRole")
 *         .assumedBy(new ServicePrincipal("myservice.amazonaws.com"))
 *         .build();
 * 
*

* Or *

*

 * public class MyStackSet extends StackSetStack {
 *     public MyStackSet(Construct scope, String id) {
 *         super(scope, id);
 * 
 *         Role.Builder.create(this, "MyRole")
 *                 .assumedBy(new ServicePrincipal("myservice.amazonaws.com"))
 *                 .build();
 *     }
 * }
 * 
*

*

Creating a StackSet

*

* AWS CloudFormation StackSets enable you to create, update, or delete stacks across multiple accounts and AWS Regions * with a single operation. Using an administrator account, you define and manage an AWS CloudFormation template, and use * the template as the basis for provisioning stacks into selected target accounts across specific AWS Regions. *

* There are two methods for defining where the StackSet should be deployed. You can either define individual accounts, or * you can define AWS Organizations organizational units. *

*

Deploying to individual accounts

*

* Deploying to individual accounts requires you to specify the account ids. If you want to later deploy to additional accounts, * or remove the stackset from accounts, this has to be done by adding/removing the account id from the list. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromAccounts(AccountsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .accounts(List.of("11111111111"))
 *                 .build()))
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

*

Deploying to organizational units

*

* AWS Organizations is an AWS service that enables you to centrally manage and govern multiple accounts. * AWS Organizations allows you to define organizational units (OUs) which are logical groupings of AWS accounts. * OUs enable you to organize your accounts into a hierarchy and make it easier for you to apply management controls. * For a deep dive on OU best practices you can read the Best Practices for Organizational Units with AWS Organizations blog post. *

* You can either specify the organization itself, or individual OUs. By default the StackSet will be deployed * to all AWS accounts that are part of the OU. If the OU is nested it will also deploy to all accounts * that are part of any nested OUs. *

* For example, given the following org hierarchy *

*

 * graph TD
 *   root-->ou-1;
 *   root-->ou-2;
 *   ou-1-->ou-3;
 *   ou-1-->ou-4;
 *   ou-3-->account-1;
 *   ou-3-->account-2;
 *   ou-4-->account-4;
 *   ou-2-->account-3;
 *   ou-2-->account-5;
 * 
*

* You could deploy to all AWS accounts under OUs ou-1, ou-3, ou-4 by specifying the following: *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .organizationalUnits(List.of("ou-1"))
 *                 .build()))
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

* This would deploy the StackSet to account-1, account-2, account-4. *

* If there are specific AWS accounts that are part of the specified OU hierarchy that you would like * to exclude, this can be done by specifying excludeAccounts. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .organizationalUnits(List.of("ou-1"))
 *                 .excludeAccounts(List.of("account-2"))
 *                 .build()))
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

* This would deploy only to account-1 & account-4, and would exclude account-2. *

* Sometimes you might have individual accounts that you would like to deploy the StackSet to, but * you do not want to include the entire OU. To do that you can specify additionalAccounts. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .organizationalUnits(List.of("ou-1"))
 *                 .additionalAccounts(List.of("account-5"))
 *                 .build()))
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

* This would deploy the StackSet to account-1, account-2, account-4 & account-5. *

*

StackSet permissions

*

* There are two modes for managing StackSet permissions (i.e. where StackSets can deploy & what resources they can create). * A StackSet can either be Service Managed or Self Managed. *

* You can control this through the deploymentType parameter. *

*

Service Managed

*

* When a StackSet is service managed, the permissions are managed by AWS Organizations. This allows the StackSet to deploy the Stack to any * account within the organization. In addition, the StackSet will be able to create any type of resource. *

*

 * Stack stack = new Stack();
 * StackSetStack stackSetStack = new StackSetStack(stack, "MyStackSet");
 * 
 * StackSet.Builder.create(stack, "StackSet")
 *         .target(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(List.of("us-east-1"))
 *                 .organizationalUnits(List.of("ou-1"))
 *                 .build()))
 *         .deploymentType(DeploymentType.serviceManaged())
 *         .template(StackSetTemplate.fromStackSetStack(stackSetStack))
 *         .build();
 * 
*

* When you specify serviceManaged deployment type, automatic deployments are enabled by default. * Automatic deployments allow the StackSet to be automatically deployed to or deleted from * AWS accounts when they are added or removed from the specified organizational units. *

*

Using File Assets

*

* You can use the StackSet's parent stack to facilitate file assets. Behind the scenes, * this is accomplished using the BucketDeployment construct from the * aws_s3_deployment module. You need to provide a bucket outside the scope of the CDK * managed asset buckets and ensure you have persmissions for the target accounts to pull * the artifacts from the supplied bucket. *

* As a basic example, if using a serviceManaged deployment, you just need to give read * access to the Organization. You can create the asset bucket in the parent stack, or another * stack in the same app and pass the object as a prop. Or, import an existing bucket as needed. *

* If creating in the parent or sibling stack you could create and export similar to this: *

*

 * Bucket bucket = Bucket.Builder.create(this, "Assets")
 *         .bucketName("cdkstacket-asset-bucket-xyz")
 *         .build();
 * 
 * bucket.addToResourcePolicy(
 * PolicyStatement.Builder.create()
 *         .actions(List.of("s3:Get*", "s3:List*"))
 *         .resources(List.of(bucket.arnForObjects("*"), bucket.getBucketArn()))
 *         .principals(List.of(new OrganizationPrincipal("o-xyz")))
 *         .build());
 * 
*

* Then pass as a prop to the StackSet stack: *

*

 * Bucket bucket;
 * 
 * Stack stack = new Stack();
 * StackSetStack stackSetStack = StackSetStack.Builder.create(stack, "MyStackSet")
 *         .assetBucket(bucket)
 *         .build();
 * 
*

* Then call new StackSet as described in the sections above. *

* You can use self-managed StackSet deployments with file assets too but will * need to ensure all target accounts roles will have access to the central asset * bucket you pass as the property. *

*

Deploying StackSets using CDK Pipelines

*

* You can also deploy StackSets using CDK Pipelines *

* Below is an example of a Pipeline that deploys from a central account. It also * defines separate stages for each "environment" so that you can first test out * the stackset in pre-prod environments. *

* This would be an automated way of deploying the bootstrap stack described in * this blog * post. *

*

 * App app;
 * 
 * public class BootstrapStageProps extends StageProps {
 *     private StackSetTarget initialBootstrapTarget;
 *     public StackSetTarget getInitialBootstrapTarget() {
 *         return this.initialBootstrapTarget;
 *     }
 *     public BootstrapStageProps initialBootstrapTarget(StackSetTarget initialBootstrapTarget) {
 *         this.initialBootstrapTarget = initialBootstrapTarget;
 *         return this;
 *     }
 *     private String stacksetName;
 *     public String getStacksetName() {
 *         return this.stacksetName;
 *     }
 *     public BootstrapStageProps stacksetName(String stacksetName) {
 *         this.stacksetName = stacksetName;
 *         return this;
 *     }
 * }
 * 
 * public class BootstrapStage extends Stage {
 *     public BootstrapStage(Construct scope, String id, BootstrapStageProps props) {
 *         super(scope, id, props);
 * 
 *         Stack stack = new Stack(this, "BootstrapStackSet");
 * 
 *         Bootstrap bootstrap = new Bootstrap(stack, "CDKToolkit");
 * 
 *         StackSet stackSet = StackSet.Builder.create(stack, "StackSet")
 *                 .template(StackSetTemplate.fromStackSetStack(bootstrap))
 *                 .target(props.getInitialBootstrapTarget())
 *                 .capabilities(List.of(Capability.NAMED_IAM))
 *                 .managedExecution(true)
 *                 .stackSetName(props.getStacksetName())
 *                 .deploymentType(DeploymentType.serviceManaged(ServiceManagedOptions.builder()
 *                         .delegatedAdmin(true)
 *                         .autoDeployEnabled(true)
 *                         .autoDeployRetainStacks(false)
 *                         .build()))
 *                 .operationPreferences(OperationPreferences.builder()
 *                         .regionConcurrencyType(RegionConcurrencyType.PARALLEL)
 *                         .maxConcurrentPercentage(100)
 *                         .failureTolerancePercentage(99)
 *                         .build())
 *                 .build();
 *     }
 * }
 * 
 * CodePipeline pipeline = CodePipeline.Builder.create(this, "BootstrapPipeline")
 *         .synth(ShellStep.Builder.create("Synth")
 *                 .commands(List.of("yarn install --frozen-lockfile", "npx cdk synth"))
 *                 .input(CodePipelineSource.connection("myorg/myrepo", "main", ConnectionSourceOptions.builder()
 *                         .connectionArn("arn:aws:codestar-connections:us-east-2:111111111111:connection/ca65d487-ca6e-41cc-aab2-645db37fdb2b")
 *                         .build()))
 *                 .build())
 *         .selfMutation(true)
 *         .build();
 * 
 * String[] regions = List.of("us-east-1", "us-east-2", "us-west-2", "eu-west-2", "eu-west-1", "ap-south-1", "ap-southeast-1");
 * 
 * pipeline.addStage(
 * new BootstrapStage(app, "DevBootstrap", new BootstrapStageProps()
 *         .env(Environment.builder()
 *                 .region("us-east-1")
 *                 .account("111111111111")
 *                 .build())
 *         .stacksetName("CDKToolkit-dev")
 *         .initialBootstrapTarget(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(regions)
 *                 .organizationalUnits(List.of("ou-hrza-ar333427"))
 *                 .build()))
 *         ));
 * 
 * pipeline.addStage(
 * new BootstrapStage(app, "ProdBootstrap", new BootstrapStageProps()
 *         .env(Environment.builder()
 *                 .region("us-east-1")
 *                 .account("111111111111")
 *                 .build())
 *         .stacksetName("CDKToolkit-prd")
 *         .initialBootstrapTarget(StackSetTarget.fromOrganizationalUnits(OrganizationsTargetOptions.builder()
 *                 .regions(regions)
 *                 .organizationalUnits(List.of("ou-hrza-bb999427", "ou-hraa-ar111127"))
 *                 .build()))
 *         ));
 * 
*/ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) package io.github.cdklabs.cdk.stacksets;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy