Skip to content

Commit 9e9106e

Browse files
authored
feat: 🚀 Created cloudformation-stackset workflow and readme (#95)
1 parent ba5eb58 commit 9e9106e

File tree

5 files changed

+252
-3
lines changed

5 files changed

+252
-3
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
---
2+
name: Cloudformation stack-set & stack-set-instances
3+
on:
4+
workflow_call:
5+
inputs:
6+
aws-region:
7+
description: 'Aws region (in this region stackset enabled)'
8+
required: false
9+
default: 'us-east-2'
10+
type: string
11+
stackset-instance-region:
12+
description: 'Stackset-instance regions where you need cloudformation stacks'
13+
required: false
14+
default: 'us-east-2'
15+
type: string
16+
stack-set-name:
17+
description: 'Stack-set name defined here'
18+
required: true
19+
type: string
20+
template-url:
21+
description: 'Cloudformation template path add here (S3 Object URL)'
22+
required: true
23+
type: string
24+
OrganizationalUnitIds:
25+
description: 'Organization unit ID for deployment in target accounts when service_managed permission added'
26+
required: false
27+
type: string
28+
account-ids:
29+
description: 'account ids for self_managed permission added'
30+
required: false
31+
type: string
32+
parameter-overrides:
33+
description: 'The parameters to override in the stack inputs. You can pass a comma-delimited list or a file URL. The comma-delimited list has each entry formatted as <ParameterName>=<ParameterValue> or <ParameterName>="<ParameterValue>,<ParameterValue>".'
34+
required: false
35+
type: string
36+
permission-model:
37+
description: 'IAM role permission SERVICE_MANAGED/SELF_MANAGED choose one'
38+
required: false
39+
type: string
40+
auto-deployment-enabled:
41+
description: 'true or false (true when Service_managed policy enable else false for Self_managed)'
42+
required: true
43+
type: string
44+
RetainStacksOnAccountRemoval:
45+
description: 'true or false (true when Service_managed policy enable else false for Self_managed)'
46+
required: true
47+
type: string
48+
administration-role-arn:
49+
description: 'Administrator role arn add here for trust relation on admin and child account'
50+
required: false
51+
type: string
52+
execution-role-name:
53+
description: 'execution-role-name add here for trust relation in child account'
54+
required: false
55+
type: string
56+
secrets:
57+
AWS_ACCESS_KEY_ID:
58+
required: false
59+
description: 'AWS Access Key ID to install AWS CLI.'
60+
AWS_SECRET_ACCESS_KEY:
61+
required: false
62+
description: 'AWS Secret access key to install AWS CLI'
63+
AWS_SESSION_TOKEN:
64+
required: false
65+
description: 'AWS Session Token to install AWS CLI'
66+
AWS_ROLE_TO_ASSUME:
67+
required: false
68+
description: 'AWS Role ARN defined'
69+
GITHUB:
70+
required: false
71+
description: 'GitHub token'
72+
73+
jobs:
74+
deploy-cf-stackset:
75+
runs-on: ubuntu-latest
76+
steps:
77+
- name: Checkout code from master branch
78+
uses: actions/checkout@v4
79+
80+
- name: Configure AWS Credentials
81+
uses: aws-actions/configure-aws-credentials@v4
82+
with:
83+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID}}
84+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
85+
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
86+
aws-region: ${{ inputs.aws-region }}
87+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
88+
89+
- name: Check if StackSet exists or not-exist then create/update stack-set
90+
id: check-stackset
91+
run: |
92+
set +e
93+
result=$(aws cloudformation describe-stack-set --stack-set-name "${{ inputs.stack-set-name }}" 2>&1)
94+
RC=$?
95+
set -e
96+
if [ "${{ inputs.permission-model }}" = "SERVICE_MANAGED" ]; then
97+
if [ $RC -eq 0 ]; then
98+
echo "StackSet exists, updating..."
99+
aws cloudformation update-stack-set \
100+
--stack-set-name ${{ inputs.stack-set-name }} \
101+
--template-url ${{ inputs.template-url }} \
102+
--parameters ${{ inputs.parameter-overrides }} \
103+
--capabilities CAPABILITY_NAMED_IAM \
104+
--permission-model ${{ inputs.permission-model }} \
105+
--auto-deployment Enabled=${{ inputs.auto-deployment-enabled }},RetainStacksOnAccountRemoval=${{ inputs.RetainStacksOnAccountRemoval }}
106+
elif [ $RC -eq 254 ]; then
107+
if echo "$result" | grep -q "StackSetNotFoundException"; then
108+
echo "StackSet does not exist, creating..."
109+
aws cloudformation create-stack-set \
110+
--stack-set-name ${{ inputs.stack-set-name }} \
111+
--template-url ${{ inputs.template-url }} \
112+
--parameters ${{ inputs.parameter-overrides }} \
113+
--capabilities CAPABILITY_NAMED_IAM \
114+
--permission-model ${{ inputs.permission-model }} \
115+
--auto-deployment Enabled=${{ inputs.auto-deployment-enabled }},RetainStacksOnAccountRemoval=${{ inputs.RetainStacksOnAccountRemoval }}
116+
else
117+
exit $RC
118+
fi
119+
else
120+
exit $RC
121+
fi
122+
else
123+
if [ $RC -eq 0 ]; then
124+
echo "StackSet exists, updating..."
125+
aws cloudformation update-stack-set \
126+
--stack-set-name ${{ inputs.stack-set-name }} \
127+
--template-url ${{ inputs.template-url }} \
128+
--capabilities CAPABILITY_NAMED_IAM \
129+
--parameters ${{ inputs.parameter-overrides }} \
130+
--administration-role-arn ${{ inputs.administration-role-arn }}
131+
elif [ $RC -eq 254 ]; then
132+
if echo "$result" | grep -q "StackSetNotFoundException"; then
133+
echo "StackSet does not exist, creating..."
134+
aws cloudformation create-stack-set \
135+
--stack-set-name ${{ inputs.stack-set-name }} \
136+
--template-url ${{ inputs.template-url }} \
137+
--capabilities CAPABILITY_NAMED_IAM \
138+
--parameters ${{ inputs.parameter-overrides }} \
139+
--administration-role-arn ${{ inputs.administration-role-arn }} \
140+
--execution-role-name AWSControlTowerExecution
141+
else
142+
exit $RC
143+
fi
144+
else
145+
exit $RC
146+
fi
147+
sleep 50s
148+
fi
149+
150+
- name: Create or Update StackSet-instance
151+
run: |
152+
stack_instance_list=$(aws cloudformation list-stack-instances --region ${{ inputs.stackset-instance-region }} --stack-set-name ${{ inputs.stack-set-name }})
153+
if [ "${{ inputs.permission-model }}" == "SERVICE_MANAGED" ]; then
154+
if [[ "$stack_instance_list" == *'"Summaries": []'* ]]; then
155+
echo "StackSet-instance, creating..."
156+
aws cloudformation create-stack-instances \
157+
--stack-set-name ${{ inputs.stack-set-name }} \
158+
--deployment-targets OrganizationalUnitIds='["${{ inputs.OrganizationalUnitIds }}"]' \
159+
--parameter-overrides ${{ inputs.parameter-overrides }} \
160+
--regions ${{ inputs.stackset-instance-region }}
161+
else
162+
echo "StackSet-instance, updating..."
163+
aws cloudformation update-stack-instances \
164+
--stack-set-name ${{ inputs.stack-set-name }} \
165+
--deployment-targets OrganizationalUnitIds='["${{ inputs.OrganizationalUnitIds }}"]' \
166+
--parameter-overrides ${{ inputs.parameter-overrides }} \
167+
--regions ${{ inputs.stackset-instance-region }}
168+
fi
169+
else
170+
if [[ "$stack_instance_list" == *'"Summaries": []'* ]]; then
171+
echo "StackSet-instance, creating..."
172+
aws cloudformation create-stack-instances \
173+
--stack-set-name ${{ inputs.stack-set-name }} \
174+
--parameter-overrides ${{ inputs.parameter-overrides }} \
175+
--accounts ${{ inputs.account-ids }} \
176+
--regions ${{ inputs.stackset-instance-region }} \
177+
--operation-preferences FailureToleranceCount=1,MaxConcurrentCount=2
178+
else
179+
echo "StackSet-instance, updating..."
180+
aws cloudformation update-stack-instances \
181+
--stack-set-name ${{ inputs.stack-set-name }} \
182+
--parameter-overrides ${{ inputs.parameter-overrides }} \
183+
--accounts ${{ inputs.account-ids }} \
184+
--regions ${{ inputs.stackset-instance-region }} \
185+
--operation-preferences MaxConcurrentPercentage=1
186+
fi
187+
fi
188+
...

.github/workflows/deploy-cloudformation.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ on:
5252
description: 'The parameters to override in the stack inputs. You can pass a comma-delimited list or a file URL. The comma-delimited list has each entry formatted as <ParameterName>=<ParameterValue> or <ParameterName>="<ParameterValue>,<ParameterValue>".'
5353
required: false
5454
type: string
55+
capabilities:
56+
description: "The comma-delimited list of stack template capabilities to acknowledge. Defaults to 'CAPABILITY_IAM'"
57+
required: false
58+
default: "CAPABILITY_IAM"
59+
type: string
60+
5561
secrets:
5662
AWS_ACCESS_KEY_ID:
5763
required: false
@@ -107,5 +113,6 @@ jobs:
107113
name: ${{ inputs.stack-name }}
108114
template: ${{ inputs.template-path }}
109115
no-fail-on-empty-changeset: "1"
110-
parameter-overrides: ${{ inputs.parameter-overrides}}
116+
parameter-overrides: ${{ inputs.parameter-overrides }}
117+
capabilities: ${{ inputs.capabilities }}
111118
...

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ Above example is just a simple example to call workflow from github shared workf
6363
7. [Checkov Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/checkov.md)
6464
8. [Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/terraform_workflow.md)
6565
9. [Infracost workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/infracost.md)
66-
10. [ Deploy Cloudformation workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/deploy-cloudformation.md)
66+
10. [ Deploy Cloudformation Stack workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/deploy-cloudformation.md)
67+
11. [ Deploy Cloudformation Stackset workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/deploy-cloudformation-stackset.md)
6768
6869
## Feedback
6970
If you come accross a bug or have any feedback, please log it in our [issue tracker](https://github.com/clouddrove/github-shared-workflows/issues), or feel free to drop us an email at [[email protected]](mailto:[email protected]).
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## [Deploy Cloudformation Stacket & Stackset-instances](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/deploy-cloudformation-stackset.yml)
2+
The process starts with the creation of a shared workflow template. This template contains CloudFormation resource definitions, parameter declarations, and other configuration settings that are commonly used across multiple projects or environments. It serves as a blueprint for the infrastructure you want to create. `.github/workflows/deploy-cloudformation-stackset.yml`
3+
4+
#### Usage
5+
6+
- In this workflow we added multiple parameters like S3 bucket for source code, stack-parameters, account-ids, stackset-name using parameters we overrides from called.yml as we defined below.
7+
- In this workflow we provide S3 Object URL where your code & template file located and deploy stackset and stackset-instances
8+
- Most important thing is we centrally manage stacks of every account's using stackset
9+
10+
#### Key Points:
11+
In this workflow we added steps like for the below conditions:
12+
13+
- If stackset are not-Exists then Create a new **stackset**
14+
- If stackset are Exist then Updating a **stackset**
15+
- If stackset-instance is not-Exist then Create a new **stackset-instance**
16+
- If stackset-instance is Exist then Updating a **stackset-instance**
17+
18+
#### Example
19+
20+
```yaml
21+
name: Cloudformation stack-set
22+
on:
23+
push:
24+
branches: main
25+
workflow_dispatch:
26+
27+
permissions:
28+
id-token: write
29+
contents: read
30+
31+
jobs:
32+
deploy-cf-stackset:
33+
uses: clouddrove/github-shared-workflows/.github/workflows/deploy-cloudformation-stackset.yml@master
34+
with:
35+
aws-region: # aws-configure region add, where you need stackset
36+
stackset-instance-region: # region add where you need stacks
37+
stack-set-name: # name of stack-set ( same name apply for stackset & instances )
38+
template-url: # S3 bucket Object URL add where template file is located
39+
OrganizationalUnitIds: "" # deployment targets OrganizationalUnitIds
40+
account-ids: # deployment targets add master account ids where you deploying stacksets
41+
parameter-overrides: # use this format (ParameterKey=ABC,ParameterValue=XXX ParameterKey=XYZ,ParameterValue=XXX)
42+
permission-model: # SELF_MANAGED & SERVICE_MANAGED add here
43+
auto-deployment-enabled: false # for SELF_MANAGED-false & SERVICE_MANAGED-true
44+
RetainStacksOnAccountRemoval: false # for SELF_MANAGED-false & SERVICE_MANAGED-true
45+
administration-role-arn: # administration AWSControlTowerStackSetRole ARN add here
46+
execution-role-name: # child account AWSControlTowerExecution role name add here
47+
48+
secrets:
49+
AWS_ROLE_TO_ASSUME: # Add AWS OIDC role ARN
50+
AWS_ACCESS_KEY_ID: # Add AWS credentials
51+
AWS_SECRET_ACCESS_KEY:
52+
AWS_SESSION_TOKEN:
53+
```

docs/deploy-cloudformation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## [Deploy Cloudformation Stack](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/infracost.yml)
1+
## [Deploy Cloudformation Stack](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/deploy-cloudformation.yml)
22
The process starts with the creation of a shared workflow template. This template contains CloudFormation resource definitions, parameter declarations, and other configuration settings that are commonly used across multiple projects or environments. It serves as a blueprint for the infrastructure you want to create. `.github/workflows/deploy-cloudformation.yml`
33

44
#### Usage

0 commit comments

Comments
 (0)