Integrate AWS CloudFormation StackSets for AWS Organizations as part of `cdk deploy`
cynicaljoy opened this issue ยท 5 comments
I'd like to be able to configure Stacks to be part of a StackSet that is deployed to my AWS Organization.
Use Case
I want to make use of CloudFormation features provided by the AWS team rather than attempting to roll my own CodePipeline to address the rollout of CloudFormation templates generated from CDK.
Proposed Solution
const stackSet = new cloudformation.StackSet(this, 'MyStackSet', {
permissionModel: 'SERVICE_MANGED',
autoDeployment: true,
retainStacksOnAccountRemoval: true,
deploymentTargets: {
organizationalUnitIds: ["ou-rcuk-1x5j1lwo", "ou-rcuk-slr5lh0a"]
},
regions: ["eu-west-1"]
});
const stack = new cdk.Stack(app, 'MultipleAccountsStack');
stackSet.add(stack);
This is a ๐ Feature Request
Having this would be a nice feature! I ended up creating a StackSet
construct with custom resources. I believe CDK will also have to implement something similar (i.e. consume Cloudformation stack set API directly) to add this feature..
import * as cdk from "@aws-cdk/core";
import { Construct, CfnOutput, Stack } from "@aws-cdk/core";
import * as cloudtrail from "@aws-cdk/aws-cloudtrail";
import * as sns from "@aws-cdk/aws-sns";
import {
Bucket,
BucketPolicy,
BlockPublicAccess,
BucketAccessControl,
} from "@aws-cdk/aws-s3";
import {
PolicyStatement,
Effect,
} from "@aws-cdk/aws-iam";
import { ITopic } from "@aws-cdk/aws-sns";
import {
AwsCustomResource,
PhysicalResourceId,
AwsCustomResourcePolicy,
} from "@aws-cdk/custom-resources";
interface StackSetProps extends cdk.StackProps {
templateURL: string;
orgUnitIds: string[];
regions: string[]
name: string;
}
export class StackSet extends Construct {
constructor(scope: Construct, id: string, props: StackSetProps) {
super(scope, id);
const rolePolicy = AwsCustomResourcePolicy.fromStatements([
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["s3:ListBucket"],
resources: ["arn:aws:s3:::cdktoolkit-stagingbucket*"],
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["s3:GetObject"],
resources: ["arn:aws:s3:::cdktoolkit-stagingbucket*/*"],
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["cloudformation:*"],
resources: ["*"],
}),
]);
const stackSet = new AwsCustomResource(this, props.name, {
onCreate: {
service: "CloudFormation",
action: "createStackSet",
physicalResourceId: PhysicalResourceId.of(props.name),
parameters: {
StackSetName: props.name,
TemplateURL: props.templateURL,
PermissionModel: "SERVICE_MANAGED",
AutoDeployment: {
Enabled: true,
RetainStacksOnAccountRemoval: true,
},
},
},
onDelete: {
service: "CloudFormation",
action: "deleteStackSet",
parameters: {
StackSetName: props.name,
},
},
policy: rolePolicy,
});
const stackInstancesName = `${props.name}-Instances`;
const stackInstances = new AwsCustomResource(this, stackInstancesName, {
onCreate: {
service: "CloudFormation",
action: "createStackInstances",
physicalResourceId: PhysicalResourceId.of(stackInstancesName),
parameters: {
Regions: [Stack.of(this).region],
StackSetName: props.name,
DeploymentTargets: {
OrganizationalUnitIds: props.orgUnitIds,
},
OperationPreferences: {
MaxConcurrentCount: 4,
FailureTolerancePercentage: 100,
},
},
},
onUpdate: {
service: "CloudFormation",
action: "updateStackInstances",
physicalResourceId: PhysicalResourceId.of(stackInstancesName),
parameters: {
Regions: props.regions,
StackSetName: props.name,
DeploymentTargets: {
OrganizationalUnitIds: props.orgUnitIds,
},
OperationPreferences: {
MaxConcurrentCount: 4,
FailureTolerancePercentage: 100,
},
},
},
onDelete: {
service: "CloudFormation",
action: "deleteStackInstances",
parameters: {
Regions: props.regions,
StackSetName: props.name,
DeploymentTargets: {
OrganizationalUnitIds: props.orgUnitIds,
},
RetainStacks: false,
},
},
policy: rolePolicy,
});
stackInstances.node.addDependency(stackSet);
}
}
I can see how the above works ๐. How does it differ to using new cdk.CfnStackSet
(plus a couple of hack lines) like here? #66 (comment)
I can see how the above works ๐. How does it differ to using
new cdk.CfnStackSet
(plus a couple of hack lines) like here? #66 (comment)
Don't think cdk.CfnStackSet
existed at that time. I used above only due to the lack of built-in support at the time.
I don't believe this to be a duplicate as it's completely reasonable for the team to build out StackSet Support without building in the support for AWS Organizations.