1+ # Partitioned Layer Publish
2+ # ---
3+ # This workflow publishes a specific layer version in an AWS account based on the environment input.
4+ #
5+ # We pull each the version of the layer and store them as artifacts, the we upload them to each of the Partitioned AWS accounts.
6+ #
7+ # A number of safety checks are performed to ensure safety.
8+
9+ on :
10+ workflow_dispatch :
11+ inputs :
12+ environment :
13+ description : Deployment environment
14+ type : choice
15+ options :
16+ - Gamma
17+ - Prod
18+ required : true
19+ version :
20+ description : Layer version to duplicate
21+ type : string
22+ required : true
23+ partition :
24+ description : Partition to deploy to
25+ type : choice
26+ options :
27+ - China
28+ - GovCloud
29+ workflow_call :
30+ inputs :
31+ environment :
32+ description : Deployment environment
33+ type : string
34+ required : true
35+ version :
36+ description : Layer version to duplicate
37+ type : string
38+ required : true
39+
40+ name : Layer Deployment (Partitions)
41+ run-name : Layer Deployment (${{ inputs.partition }}) - ${{ inputs.environment }} / Version - ${{ inputs.version }}
42+
43+ permissions :
44+ contents : read
45+
46+ jobs :
47+ setup :
48+ runs-on : ubuntu-latest
49+ outputs :
50+ regions : ${{ format('{0}{1}', steps.regions_china.outputs.regions, steps.regions_govcloud.outputs.regions) }}
51+ parition : ${{ format('{0}{1}', steps.regions_china.outputs.partition, steps.regions_govcloud.outputs.parition) }}
52+ steps :
53+ - id : regions_china
54+ name : Parition (China)
55+ if : ${{ inputs.partition == 'China' }}
56+ run : |
57+ echo regions='["cn-north-1", "cn-northwest-1"]'>> "$GITHUB_OUTPUT"
58+ echo partition='aws-cn'>> "$GITHUB_OUTPUT"
59+ - id : regions_govcloud
60+ name : Partition (GovCloud)
61+ if : ${{ inputs.partition == 'GovCloud' }}
62+ run : |
63+ echo regions='["us-gov-east-1", "us-gov-west-1"]'>> "$GITHUB_OUTPUT"
64+ echo partition='aws-us-gov'>> "$GITHUB_OUTPUT"
65+ download :
66+ runs-on : ubuntu-latest
67+ permissions :
68+ id-token : write
69+ contents : read
70+ environment : Prod (Readonly)
71+ steps :
72+ - name : Configure AWS Credentials
73+ uses : aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
74+ with :
75+ role-to-assume : ${{ secrets.AWS_IAM_ROLE }}
76+ aws-region : us-east-1
77+ mask-aws-account-id : true
78+ - name : Grab Zip
79+ run : |
80+ aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o AWSLambdaPowertoolsTypeScriptV2.zip
81+ aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} > AWSLambdaPowertoolsTypeScriptV2.json
82+ - name : Store Zip
83+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
84+ with :
85+ name : AWSLambdaPowertoolsTypeScriptV2.zip
86+ path : AWSLambdaPowertoolsTypeScriptV2.zip
87+ retention-days : 1
88+ if-no-files-found : error
89+ - name : Store Metadata
90+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
91+ with :
92+ name : AWSLambdaPowertoolsTypeScriptV2.json
93+ path : AWSLambdaPowertoolsTypeScriptV2.json
94+ retention-days : 1
95+ if-no-files-found : error
96+
97+ copy :
98+ name : Copy
99+ needs :
100+ - setup
101+ - download
102+ runs-on : ubuntu-latest
103+ permissions :
104+ id-token : write
105+ contents : read
106+ # Environment should interperlate as "GovCloud Prod" or "China Beta"
107+ environment : ${{ inputs.partition }} ${{ inputs.environment }}
108+ strategy :
109+ matrix :
110+ region : ${{ fromJson(needs.setup.outputs.regions) }}
111+ steps :
112+ - name : Download Zip
113+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
114+ with :
115+ name : AWSLambdaPowertoolsTypeScriptV2.zip
116+ - name : Download Metadata
117+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
118+ with :
119+ name : AWSLambdaPowertoolsTypeScriptV2.json
120+ - name : Verify Layer Signature
121+ run : |
122+ SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json')
123+ test "$(openssl dgst -sha256 -binary AWSLambdaPowertoolsTypeScriptV2.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
124+ - id : transform
125+ run : |
126+ echo 'CONVERTED_REGION=${{ matrix.region }}' | tr 'a-z\-' 'A-Z_' >> "$GITHUB_OUTPUT"
127+ - name : Configure AWS Credentials
128+ uses : aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
129+ with :
130+ role-to-assume : ${{ secrets[format('IAM_ROLE_{0}', steps.transform.outputs.CONVERTED_REGION)] }}
131+ aws-region : ${{ matrix.region}}
132+ mask-aws-account-id : true
133+ - name : Create Layer
134+ id : create-layer
135+ run : |
136+ cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json
137+
138+ LAYER_VERSION=$(aws --region ${{ matrix.region}} lambda publish-layer-version \
139+ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \
140+ --cli-input-json file://./input.json \
141+ --query 'Version' \
142+ --output text)
143+
144+ echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT"
145+
146+ aws --region ${{ matrix.region}} lambda add-layer-version-permission \
147+ --layer-name 'AWSLambdaPowertoolsTypeScriptV2' \
148+ --statement-id 'PublicLayer' \
149+ --action lambda:GetLayerVersion \
150+ --principal '*' \
151+ --version-number "$LAYER_VERSION"
152+ - name : Verify Layer
153+ env :
154+ LAYER_VERSION : ${{ steps.create-layer.outputs.LAYER_VERSION }}
155+ run : |
156+ export layer_output='AWSLambdaPowertoolsTypeScriptV2-${{matrix.region}}.json'
157+ aws --region ${{ matrix.region}} lambda get-layer-version-by-arn --arn 'arn:${{ needs.setup.outputs.parition }}:lambda:${{ matrix.region}}:${{ secrets[format('AWS_ACCOUNT_{0}', steps.transform.outputs.CONVERTED_REGION)] }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > $layer_output
158+ REMOTE_SHA=$(jq -r '.Content.CodeSha256' $layer_output)
159+ LOCAL_SHA=$(jq -r '.Content.CodeSha256' AWSLambdaPowertoolsTypeScriptV2.json)
160+ test "$REMOTE_SHA" == "$LOCAL_SHA" && echo "SHA OK: ${LOCAL_SHA}" || exit 1
161+ jq -s -r '["Layer Arn", "Runtimes", "Version", "Description", "SHA256"], ([.[0], .[1]] | .[] | [.LayerArn, (.CompatibleRuntimes | join("/")), .Version, .Description, .Content.CodeSha256]) |@tsv' AWSLambdaPowertoolsTypeScriptV2.json $layer_output | column -t -s $'\t'
162+
163+ - name : Store Metadata - ${{ matrix.region }}
164+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
165+ with :
166+ name : AWSLambdaPowertoolsTypeScriptV2-${{ matrix.region }}.json
167+ path : AWSLambdaPowertoolsTypeScriptV2-${{ matrix.region }}.json
168+ retention-days : 1
169+ if-no-files-found : error
0 commit comments