Skip to content

Commit 4746a78

Browse files
committed
Add Hardened CI Release GitHub Action
- Seperate CI into several jobs to improve retry time - Use native runners (x86_64 and arm64) to improve base build time - Split E2E tests into parallel jobs - Use Distro Tool push-image action to support Rancher Prime - rename workflow to release.yml to comply with SLSA strategy Signed-off-by: Brooks Newberry <brooks@newberry.com> Signed-off-by: Derek Nola <derek.nola@suse.com>
1 parent 45a2789 commit 4746a78

1 file changed

Lines changed: 389 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 389 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,389 @@
1+
name: Hardened CI
2+
on:
3+
push:
4+
branches:
5+
- hardened-nginx-**
6+
pull_request:
7+
branches:
8+
- hardened-nginx-**
9+
release:
10+
types:
11+
- created
12+
workflow_dispatch: {}
13+
14+
permissions:
15+
contents: read
16+
17+
env:
18+
BASE_IMAGE_REPO: ${{ github.repository_owner }}/nginx
19+
20+
jobs:
21+
unit:
22+
permissions:
23+
contents: read
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Check out code
27+
uses: actions/checkout@v4
28+
29+
# Taken from the upstream ci.yaml action
30+
- name: Get go version
31+
run: echo "GOLANG_VERSION=$(cat GOLANG_VERSION)" >> $GITHUB_ENV
32+
33+
- name: Set up Go
34+
id: go
35+
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
36+
with:
37+
go-version: ${{ env.GOLANG_VERSION }}
38+
check-latest: true
39+
40+
- name: Run Unit Tests
41+
run: ./scripts/test
42+
43+
e2e-build:
44+
permissions:
45+
contents: read
46+
runs-on: ubuntu-latest
47+
steps:
48+
- name: Check out code
49+
uses: actions/checkout@v4
50+
51+
- name: Build E2E Base Image
52+
run: ./scripts/e2e-build
53+
54+
- name: Save Docker image
55+
run: docker save -o nginx-ingress-e2e.tar $(docker images --format "{{.Repository}}:{{.Tag}}" | grep "rancher/nginx")
56+
57+
- name: Upload Docker image
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: nginx-ingress-e2e
61+
path: nginx-ingress-e2e.tar
62+
retention-days: 1
63+
64+
e2e:
65+
needs: e2e-build
66+
permissions:
67+
contents: read
68+
runs-on: ubuntu-latest
69+
# Annotations and Settings have many checks, the rest of the focus groups only have 1-5 checks each
70+
# So they are combined in larger groups to reduce the number of jobs
71+
strategy:
72+
fail-fast: true
73+
matrix:
74+
focus:
75+
- Annotations
76+
- Settings
77+
- "Admission|Cgroups|Default Backend|Disable Leader|Endpointslices|Flag|TCP"
78+
- "Ingress|Lua|Memory Leak|metrics|Security|Service|Shutdown|SSL|Status|TopologyHints"
79+
steps:
80+
- name: Check out code
81+
uses: actions/checkout@v4
82+
83+
- name: Download Docker image
84+
uses: actions/download-artifact@v4
85+
with:
86+
name: nginx-ingress-e2e
87+
88+
- name: Load Docker image
89+
run: docker load -i nginx-ingress-e2e.tar
90+
91+
- name: Run E2E Tests with combined focus
92+
run: |
93+
# Add brackets around each focus area in the OR pattern
94+
FOCUS_PATTERN=$(echo "${{ matrix.focus }}" | sed -E 's/([^|]+)/\\[\1\\]/g')
95+
96+
FOCUS="$FOCUS_PATTERN" ./scripts/e2e-test
97+
98+
build-base-image-amd64:
99+
needs: e2e
100+
permissions:
101+
contents: read
102+
id-token: write # needed for the Vault authentication
103+
if: github.event_name == 'release' && github.event.action == 'created'
104+
runs-on: ubuntu-24.04
105+
env:
106+
REGISTRY: ${{ github.repository_owner }}
107+
steps:
108+
- name: Check out code
109+
uses: actions/checkout@v4
110+
111+
- name: Set up QEMU
112+
uses: docker/setup-qemu-action@v3
113+
114+
- name: Set up Docker Buildx
115+
uses: docker/setup-buildx-action@v3
116+
117+
# Only pull vault secrets if the repository is rancher
118+
- name: "Read secrets"
119+
if: github.repository_owner == 'rancher'
120+
uses: rancher-eio/read-vault-secrets@main
121+
with:
122+
secrets: |
123+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials username | DOCKER_USERNAME ;
124+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials password | DOCKER_TOKEN ;
125+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials registry | PRIME_REGISTRY ;
126+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials username | PRIME_REGISTRY_USERNAME ;
127+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials password | PRIME_REGISTRY_PASSWORD
128+
- name: Login to Container Registry with Rancher Secrets
129+
if: github.repository_owner == 'rancher'
130+
uses: docker/login-action@v3
131+
with:
132+
username: ${{ env.DOCKER_USERNAME }}
133+
password: ${{ env.DOCKER_TOKEN }}
134+
135+
# For forks, setup docker login with GHA secrets
136+
- name: Login to Container Registry
137+
if: github.repository_owner != 'rancher'
138+
uses: docker/login-action@v3
139+
with:
140+
username: ${{ secrets.DOCKER_USERNAME }}
141+
password: ${{ secrets.DOCKER_TOKEN }}
142+
143+
- name: Build and push by digest base image
144+
id: build
145+
uses: docker/build-push-action@v6
146+
with:
147+
platforms: linux/amd64
148+
outputs: type=image,"name=${{ env.BASE_IMAGE_REPO }}",push-by-digest=true,name-canonical=true,push=true
149+
context: ./images/nginx/rootfs
150+
151+
- name: Export digest
152+
run: |
153+
mkdir -p ${{ runner.temp }}/digests
154+
digest="${{ steps.build.outputs.digest }}"
155+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
156+
157+
- name: Upload digest
158+
uses: actions/upload-artifact@v4
159+
with:
160+
name: digests-amd64
161+
path: ${{ runner.temp }}/digests/*
162+
if-no-files-found: error
163+
retention-days: 1
164+
165+
build-base-image-arm64:
166+
needs: e2e
167+
permissions:
168+
contents: read
169+
id-token: write # needed for the Vault authentication
170+
if: github.event_name == 'release' && github.event.action == 'created'
171+
runs-on: ubuntu-24.04-arm
172+
env:
173+
REGISTRY: ${{ github.repository_owner }}
174+
steps:
175+
- name: Check out code
176+
uses: actions/checkout@v4
177+
178+
- name: Set up QEMU
179+
uses: docker/setup-qemu-action@v3
180+
181+
- name: Set up Docker Buildx
182+
uses: docker/setup-buildx-action@v3
183+
184+
# Only pull vault secrets if the repository is rancher
185+
- name: "Read secrets"
186+
if: github.repository_owner == 'rancher'
187+
uses: rancher-eio/read-vault-secrets@main
188+
with:
189+
secrets: |
190+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials username | DOCKER_USERNAME ;
191+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials password | DOCKER_TOKEN ;
192+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials registry | PRIME_REGISTRY ;
193+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials username | PRIME_REGISTRY_USERNAME ;
194+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials password | PRIME_REGISTRY_PASSWORD
195+
- name: Login to Container Registry with Rancher Secrets
196+
if: github.repository_owner == 'rancher'
197+
uses: docker/login-action@v3
198+
with:
199+
username: ${{ env.DOCKER_USERNAME }}
200+
password: ${{ env.DOCKER_TOKEN }}
201+
202+
# For forks, setup docker login with GHA secrets
203+
- name: Login to Container Registry
204+
if: github.repository_owner != 'rancher'
205+
uses: docker/login-action@v3
206+
with:
207+
username: ${{ secrets.DOCKER_USERNAME }}
208+
password: ${{ secrets.DOCKER_TOKEN }}
209+
210+
- name: Build and push by digest base image
211+
id: build
212+
uses: docker/build-push-action@v6
213+
with:
214+
platforms: linux/arm64
215+
outputs: type=image,"name=${{ env.BASE_IMAGE_REPO }}",push-by-digest=true,name-canonical=true,push=true
216+
context: ./images/nginx/rootfs
217+
218+
- name: Export digest
219+
run: |
220+
mkdir -p ${{ runner.temp }}/digests
221+
digest="${{ steps.build.outputs.digest }}"
222+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
223+
224+
- name: Upload digest
225+
uses: actions/upload-artifact@v4
226+
with:
227+
name: digests-arm64
228+
path: ${{ runner.temp }}/digests/*
229+
if-no-files-found: error
230+
retention-days: 1
231+
232+
merge-publish-base-image:
233+
runs-on: ubuntu-latest
234+
needs:
235+
- build-base-image-amd64
236+
- build-base-image-arm64
237+
238+
permissions:
239+
contents: read
240+
packages: write
241+
id-token: write # needed for the Vault authentication
242+
243+
steps:
244+
- name: Download digests
245+
uses: actions/download-artifact@v4
246+
with:
247+
path: ${{ runner.temp }}/digests
248+
pattern: digests-*
249+
merge-multiple: true
250+
251+
- name: "Read Vault secrets"
252+
if: github.repository_owner == 'rancher'
253+
uses: rancher-eio/read-vault-secrets@main
254+
with:
255+
secrets: |
256+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials username | DOCKER_USERNAME ;
257+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials password | DOCKER_TOKEN ;
258+
259+
- name: Login to DockerHub with Rancher Secrets
260+
if: github.repository_owner == 'rancher'
261+
uses: docker/login-action@v3
262+
with:
263+
username: ${{ env.DOCKER_USERNAME }}
264+
password: ${{ env.DOCKER_TOKEN }}
265+
266+
# For forks, setup DockerHub login with GHA secrets
267+
- name: Login to DockerHub with GHA Secrets
268+
if: github.repository_owner != 'rancher'
269+
uses: docker/login-action@v3
270+
with:
271+
username: ${{ secrets.DOCKER_USERNAME }}
272+
password: ${{ secrets.DOCKER_TOKEN }}
273+
274+
- name: Set up Docker Buildx
275+
uses: docker/setup-buildx-action@v3
276+
277+
- name: Docker meta
278+
id: meta
279+
uses: docker/metadata-action@v5
280+
with:
281+
images: |
282+
${{ env.BASE_IMAGE_REPO}}
283+
284+
- name: Create manifest list and push
285+
working-directory: ${{ runner.temp }}/digests
286+
run: |
287+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
288+
$(printf '${{ env.BASE_IMAGE_REPO }}@sha256:%s ' *)
289+
290+
- name: Inspect image
291+
run: docker buildx imagetools inspect ${{ env.BASE_IMAGE_REPO }}:${{ steps.meta.outputs.version }}
292+
293+
release-controller-image:
294+
needs: merge-publish-base-image
295+
permissions:
296+
contents: read
297+
id-token: write # needed for the Vault authentication
298+
if: github.event_name == 'release' && github.event.action == 'created'
299+
runs-on: ubuntu-22.04
300+
env:
301+
REGISTRY: ${{ github.repository_owner }}
302+
steps:
303+
304+
- name: Check out code
305+
uses: actions/checkout@v4
306+
307+
# Only pull vault secrets if the repository is rancher
308+
- name: "Read secrets"
309+
if: github.repository_owner == 'rancher'
310+
uses: rancher-eio/read-vault-secrets@main
311+
with:
312+
secrets: |
313+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials username | DOCKER_USERNAME ;
314+
secret/data/github/repo/${{ github.repository }}/dockerhub/${{ github.repository_owner }}/credentials password | DOCKER_TOKEN ;
315+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials registry | PRIME_REGISTRY ;
316+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials username | PRIME_REGISTRY_USERNAME ;
317+
secret/data/github/repo/${{ github.repository }}/rancher-prime-registry/credentials password | PRIME_REGISTRY_PASSWORD
318+
- name: Login to Container Registry with Rancher Secrets
319+
if: github.repository_owner == 'rancher'
320+
uses: docker/login-action@v3
321+
with:
322+
username: ${{ env.DOCKER_USERNAME }}
323+
password: ${{ env.DOCKER_TOKEN }}
324+
325+
# For forks, setup docker login with GHA secrets
326+
- name: Login to Container Registry
327+
if: github.repository_owner != 'rancher'
328+
uses: docker/login-action@v3
329+
with:
330+
username: ${{ secrets.DOCKER_USERNAME }}
331+
password: ${{ secrets.DOCKER_TOKEN }}
332+
333+
- name: Set up QEMU
334+
uses: docker/setup-qemu-action@v3
335+
336+
- name: Set up Docker Buildx
337+
uses: docker/setup-buildx-action@v3
338+
339+
- name: Build Binaries
340+
run: ./scripts/build-binary
341+
342+
- name: Setup tags
343+
run: |
344+
source ./scripts/version
345+
echo "TAG=$TAG" >> $GITHUB_ENV
346+
echo "PKG=$PKG" >> $GITHUB_ENV
347+
echo "NGINX_TAG=$NGINX_TAG" >> $GITHUB_ENV
348+
echo "BASE_IMAGE=$BASE_IMAGE" >> $GITHUB_ENV
349+
350+
- name: Setup Docker Credentials
351+
if: github.repository_owner != 'rancher'
352+
env:
353+
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
354+
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
355+
run: |
356+
echo "DOCKER_USERNAME=$DOCKER_USERNAME" >> $GITHUB_ENV
357+
echo "DOCKER_TOKEN=$DOCKER_TOKEN" >> $GITHUB_ENV
358+
359+
- name: Build and push controller image
360+
uses: rancher/ecm-distro-tools/actions/publish-image@master
361+
with:
362+
image: nginx-ingress-controller
363+
tag: ${{ github.event.release.tag_name }}
364+
make-target: push-image
365+
public-repo: ${{ env.REGISTRY }}
366+
public-username: ${{ env.DOCKER_USERNAME }}
367+
public-password: ${{ env.DOCKER_TOKEN }}
368+
369+
prime-repo: rancher
370+
prime-registry: ${{ env.PRIME_REGISTRY }}
371+
prime-username: ${{ env.PRIME_REGISTRY_USERNAME }}
372+
prime-password: ${{ env.PRIME_REGISTRY_PASSWORD }}
373+
push-to-prime: ${{ github.repository_owner == 'rancher' }}
374+
375+
- name: Build and push controller chroot image
376+
uses: rancher/ecm-distro-tools/actions/publish-image@master
377+
with:
378+
image: nginx-ingress-controller-chroot
379+
tag: ${{ github.event.release.tag_name }}
380+
make-target: push-chroot-image
381+
public-repo: ${{ env.REGISTRY }}
382+
public-username: ${{ env.DOCKER_USERNAME }}
383+
public-password: ${{ env.DOCKER_TOKEN }}
384+
385+
prime-repo: rancher
386+
prime-registry: ${{ env.PRIME_REGISTRY }}
387+
prime-username: ${{ env.PRIME_REGISTRY_USERNAME }}
388+
prime-password: ${{ env.PRIME_REGISTRY_PASSWORD }}
389+
push-to-prime: ${{ github.repository_owner == 'rancher' }}

0 commit comments

Comments
 (0)