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
+ partition : ${{ format('{0}{1}', steps.regions_china.outputs.partition, steps.regions_govcloud.outputs.partition) }}
52
+ aud : ${{ format('{0}{1}', steps.regions_china.outputs.aud, steps.regions_govcloud.outputs.aud) }}
53
+ steps :
54
+ - id : regions_china
55
+ name : Partition (China)
56
+ if : ${{ inputs.partition == 'China' }}
57
+ run : |
58
+ echo regions='["cn-north-1"]'>> "$GITHUB_OUTPUT"
59
+ echo partition='aws-cn'>> "$GITHUB_OUTPUT"
60
+ echo aud='sts.amazonaws.com.cn'>> "$GITHUB_OUTPUT"
61
+ - id : regions_govcloud
62
+ name : Partition (GovCloud)
63
+ if : ${{ inputs.partition == 'GovCloud' }}
64
+ run : |
65
+ echo regions='["us-gov-east-1", "us-gov-west-1"]'>> "$GITHUB_OUTPUT"
66
+ echo partition='aws-us-gov'>> "$GITHUB_OUTPUT"
67
+ echo aud='sts.amazonaws.com'>> "$GITHUB_OUTPUT"
68
+ download :
69
+ runs-on : ubuntu-latest
70
+ permissions :
71
+ id-token : write
72
+ contents : read
73
+ environment : Prod (Readonly)
74
+ strategy :
75
+ matrix :
76
+ layer :
77
+ - AWSLambdaPowertoolsPythonV3-python39
78
+ - AWSLambdaPowertoolsPythonV3-python310
79
+ - AWSLambdaPowertoolsPythonV3-python311
80
+ - AWSLambdaPowertoolsPythonV3-python312
81
+ - AWSLambdaPowertoolsPythonV3-python313
82
+ arch :
83
+ - arm64
84
+ - x86_64
85
+ steps :
86
+ - name : Configure AWS Credentials
87
+ uses : aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
88
+ with :
89
+ role-to-assume : ${{ secrets.AWS_IAM_ROLE }}
90
+ aws-region : us-east-1
91
+ mask-aws-account-id : true
92
+ - name : Grab Zip
93
+ run : |
94
+ aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o ${{ matrix.layer }}_${{ matrix.arch }}.zip
95
+ aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} > ${{ matrix.layer }}_${{ matrix.arch }}.json
96
+ - name : Store Zip
97
+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
98
+ with :
99
+ name : ${{ matrix.layer }}_${{ matrix.arch }}.zip
100
+ path : ${{ matrix.layer }}_${{ matrix.arch }}.zip
101
+ retention-days : 1
102
+ if-no-files-found : error
103
+ - name : Store Metadata
104
+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
105
+ with :
106
+ name : ${{ matrix.layer }}_${{ matrix.arch }}.json
107
+ path : ${{ matrix.layer }}_${{ matrix.arch }}.json
108
+ retention-days : 1
109
+ if-no-files-found : error
110
+
111
+ copy :
112
+ name : Copy
113
+ needs :
114
+ - setup
115
+ - download
116
+ runs-on : ubuntu-latest
117
+ permissions :
118
+ id-token : write
119
+ contents : read
120
+ # Environment should interperlate as "GovCloud Prod" or "China Beta"
121
+ environment : ${{ inputs.partition }} ${{ inputs.environment }}
122
+ strategy :
123
+ matrix :
124
+ region : ${{ fromJson(needs.setup.outputs.regions) }}
125
+ layer :
126
+ - AWSLambdaPowertoolsPythonV3-python39
127
+ - AWSLambdaPowertoolsPythonV3-python310
128
+ - AWSLambdaPowertoolsPythonV3-python311
129
+ - AWSLambdaPowertoolsPythonV3-python312
130
+ - AWSLambdaPowertoolsPythonV3-python313
131
+ arch :
132
+ - arm64
133
+ - x86_64
134
+ steps :
135
+ - name : Download Zip
136
+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
137
+ with :
138
+ name : ${{ matrix.layer }}_${{ matrix.arch }}.zip
139
+ - name : Download Metadata
140
+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
141
+ with :
142
+ name : ${{ matrix.layer }}_${{ matrix.arch }}.json
143
+ - name : Verify Layer Signature
144
+ run : |
145
+ SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}_${{ matrix.arch }}.json')
146
+ test "$(openssl dgst -sha256 -binary ${{ matrix.layer }}_${{ matrix.arch }}.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
147
+ - id : transform
148
+ run : |
149
+ echo 'CONVERTED_REGION=${{ matrix.region }}' | tr 'a-z\-' 'A-Z_' >> "$GITHUB_OUTPUT"
150
+ - name : Configure AWS Credentials
151
+ uses : aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
152
+ with :
153
+ role-to-assume : ${{ secrets[format('IAM_ROLE_{0}', steps.transform.outputs.CONVERTED_REGION)] }}
154
+ aws-region : ${{ matrix.region}}
155
+ mask-aws-account-id : true
156
+ audience : ${{ needs.setup.outputs.aud }}
157
+ - name : Create Layer
158
+ id : create-layer
159
+ run : |
160
+ cat '${{ matrix.layer }}-${{ matrix.arch }}.json' | jq '{"LayerName": "${{ matrix.layer }}-${{ matrix.arch }}", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "CompatibleArchitectures": .CompatibleArchitectures, "LicenseInfo": .LicenseInfo}' > input.json
161
+
162
+ LAYER_VERSION=$(aws --region ${{ matrix.region}} lambda publish-layer-version \
163
+ --zip-file 'fileb://./${{ matrix.layer }}-${{ matrix.arch }}.zip' \
164
+ --cli-input-json file://./input.json \
165
+ --query 'Version' \
166
+ --output text)
167
+
168
+ echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT"
169
+
170
+ aws --region ${{ matrix.region}} lambda add-layer-version-permission \
171
+ --layer-name ${{ matrix.layer }}-${{ matrix.arch }} \
172
+ --statement-id 'PublicLayer' \
173
+ --action lambda:GetLayerVersion \
174
+ --principal '*' \
175
+ --version-number "$LAYER_VERSION"
176
+ - name : Verify Layer
177
+ env :
178
+ LAYER_VERSION : ${{ steps.create-layer.outputs.LAYER_VERSION }}
179
+ run : |
180
+ export layer_output='${{ matrix.layer }}-${{ matrix.arch }}-${{matrix.region}}.json'
181
+ aws --region ${{ matrix.region}} lambda get-layer-version-by-arn --arn 'arn:${{ needs.setup.outputs.partition }}:lambda:${{ matrix.region}}:${{ secrets[format('AWS_ACCOUNT_{0}', steps.transform.outputs.CONVERTED_REGION)] }}:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ env.LAYER_VERSION }}' > $layer_output
182
+ REMOTE_SHA=$(jq -r '.Content.CodeSha256' $layer_output)
183
+ LOCAL_SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}-${{ matrix.arch }}.json')
184
+ test "$REMOTE_SHA" == "$LOCAL_SHA" && echo "SHA OK: ${LOCAL_SHA}" || exit 1
185
+ jq -s -r '["Layer Arn", "Runtimes", "Version", "Description", "SHA256"], ([.[0], .[1]] | .[] | [.LayerArn, (.CompatibleRuntimes | join("/")), .Version, .Description, .Content.CodeSha256]) |@tsv' '${{ matrix.layer }}-${{ matrix.arch }}.json' $layer_output | column -t -s $'\t'
186
+
187
+ - name : Store Metadata - ${{ matrix.region }}
188
+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
189
+ with :
190
+ name : ${{ matrix.layer }}-${{ matrix.arch }}-${{ matrix.region }}.json
191
+ path : ${{ matrix.layer }}-${{ matrix.arch }}-${{ matrix.region }}.json
192
+ retention-days : 1
193
+ if-no-files-found : error
0 commit comments