From 9bda8b5f248d2e020cec3503c3bcc78a188ea2b3 Mon Sep 17 00:00:00 2001 From: sjmiller609 <7516283+sjmiller609@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:27:33 +0000 Subject: [PATCH 1/3] Add shared Docker Hub credential lookup action --- .../actions/dockerhub-credentials/action.yml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/actions/dockerhub-credentials/action.yml diff --git a/.github/actions/dockerhub-credentials/action.yml b/.github/actions/dockerhub-credentials/action.yml new file mode 100644 index 00000000..2833a898 --- /dev/null +++ b/.github/actions/dockerhub-credentials/action.yml @@ -0,0 +1,61 @@ +name: Docker Hub credentials from SSM +description: Read the shared registry credential without replacing the caller's AWS credentials. +inputs: + role-arn: + description: Optional role to assume for the read; omit to use existing AWS credentials. + required: false + default: '' + role-chaining: + description: Assume the role using existing AWS credentials rather than GitHub OIDC. + required: false + default: 'false' +outputs: + username: + value: ${{ steps.read.outputs.username }} + password: + value: ${{ steps.read.outputs.password }} + credentials: + description: JSON username/password pair for Ansible. + value: ${{ steps.read.outputs.credentials }} +runs: + using: composite + steps: + - uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 + if: inputs.role-arn != '' + id: aws + with: + role-to-assume: ${{ inputs.role-arn }} + role-chaining: ${{ inputs.role-chaining }} + aws-region: us-east-1 + allowed-account-ids: '613957054632' + output-credentials: true + output-env-credentials: false + - id: read + shell: bash + env: + AWS_ACCESS_KEY_ID: ${{ steps.aws.outputs.aws-access-key-id || env.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.aws.outputs.aws-secret-access-key || env.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.aws.outputs.aws-session-token || env.AWS_SESSION_TOKEN }} + run: | + python3 - <<'PY' + import json, os, subprocess + raw = subprocess.check_output([ + "aws", "ssm", "get-parameter", "--name", "/kernel/dockerhub/credentials", + "--region", "us-east-1", "--with-decryption", "--output", "json", + ], text=True) + parameter = json.loads(raw)["Parameter"] + if parameter["Type"] != "SecureString": + raise ValueError("Docker Hub credentials must be stored as a SecureString") + credential = json.loads(parameter["Value"]) + for key in ("username", "password"): + value = credential.get(key) + if not isinstance(value, str) or not value or "\n" in value or "\r" in value: + raise ValueError("SSM must contain a nonempty, single-line username and password") + values = {key: credential[key] for key in ("username", "password")} + values["credentials"] = json.dumps(values) + for value in values.values(): + print("::add-mask::" + value.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A")) + with open(os.environ["GITHUB_OUTPUT"], "a") as output: + for key, value in values.items(): + output.write(f"{key}={value}\n") + PY From 8ef30f9f1e4e2c33533b1b4fc75734b79103efa6 Mon Sep 17 00:00:00 2001 From: sjmiller609 <7516283+sjmiller609@users.noreply.github.com> Date: Sat, 7 Nov 2026 16:05:31 +0000 Subject: [PATCH 2/3] Read Docker Hub credentials from SSM --- .github/workflows/chromium-headful-image.yaml | 17 +++++++++++------ .../workflows/chromium-headless-image.yaml | 17 +++++++++++------ .github/workflows/server-test.yaml | 19 ++++++++++++++++--- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/.github/workflows/chromium-headful-image.yaml b/.github/workflows/chromium-headful-image.yaml index 417126e6..cff51f5a 100644 --- a/.github/workflows/chromium-headful-image.yaml +++ b/.github/workflows/chromium-headful-image.yaml @@ -5,13 +5,12 @@ on: jobs: docker: - # Fork PRs get no secrets and now must not reach the self-hosted pool - # either: skipping here (rather than failing at registry login, as - # before) also skips the dependent e2e job via its needs chain. - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + # Credential-bearing builds run on trusted branch pushes, not PR merge refs. + if: github.repository == 'kernel/kernel-images' && github.event_name != 'pull_request' runs-on: [self-hosted, linux] permissions: contents: read + id-token: write steps: - name: Checkout uses: actions/checkout@v4 @@ -43,11 +42,17 @@ jobs: # that root-run CI from other repos clobbers to root-owned. echo "BUILDX_CONFIG=${HOME}/.docker/buildx-ci" >> "$GITHUB_ENV" + - name: Read Docker Hub credentials from SSM + id: dockerhub + uses: ./.github/actions/dockerhub-credentials + with: + role-arn: arn:aws:iam::613957054632:role/github-actions-kernel-images + - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ steps.dockerhub.outputs.username }} + password: ${{ steps.dockerhub.outputs.password }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/chromium-headless-image.yaml b/.github/workflows/chromium-headless-image.yaml index 26c6b64a..80008366 100644 --- a/.github/workflows/chromium-headless-image.yaml +++ b/.github/workflows/chromium-headless-image.yaml @@ -5,13 +5,12 @@ on: jobs: docker: - # Fork PRs get no secrets and now must not reach the self-hosted pool - # either: skipping here (rather than failing at registry login, as - # before) also skips the dependent e2e job via its needs chain. - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + # Credential-bearing builds run on trusted branch pushes, not PR merge refs. + if: github.repository == 'kernel/kernel-images' && github.event_name != 'pull_request' runs-on: [self-hosted, linux] permissions: contents: read + id-token: write steps: - name: Checkout uses: actions/checkout@v4 @@ -43,11 +42,17 @@ jobs: # that root-run CI from other repos clobbers to root-owned. echo "BUILDX_CONFIG=${HOME}/.docker/buildx-ci" >> "$GITHUB_ENV" + - name: Read Docker Hub credentials from SSM + id: dockerhub + uses: ./.github/actions/dockerhub-credentials + with: + role-arn: arn:aws:iam::613957054632:role/github-actions-kernel-images + - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ steps.dockerhub.outputs.username }} + password: ${{ steps.dockerhub.outputs.password }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/server-test.yaml b/.github/workflows/server-test.yaml index 0e92f023..facffc8e 100644 --- a/.github/workflows/server-test.yaml +++ b/.github/workflows/server-test.yaml @@ -2,7 +2,7 @@ name: Test for the server/ directory on: push: - branches: ["main"] + branches: ["**"] pull_request: branches: ["main"] workflow_dispatch: @@ -13,10 +13,16 @@ concurrency: jobs: build-headful: + permissions: + contents: read + id-token: write uses: ./.github/workflows/chromium-headful-image.yaml secrets: inherit build-headless: + permissions: + contents: read + id-token: write uses: ./.github/workflows/chromium-headless-image.yaml secrets: inherit @@ -67,6 +73,7 @@ jobs: needs: [build-headful, build-headless] permissions: contents: read + id-token: write steps: - name: Checkout code @@ -119,11 +126,17 @@ jobs: shell: bash run: echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + - name: Read Docker Hub credentials from SSM + id: dockerhub + uses: ./.github/actions/dockerhub-credentials + with: + role-arn: arn:aws:iam::613957054632:role/github-actions-kernel-images + - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ steps.dockerhub.outputs.username }} + password: ${{ steps.dockerhub.outputs.password }} - name: Pull e2e images shell: bash From 00132e625d389a25deaa4973abd1ba179f70219f Mon Sep 17 00:00:00 2001 From: sjmiller609 <7516283+sjmiller609@users.noreply.github.com> Date: Sat, 7 Nov 2026 16:22:44 +0000 Subject: [PATCH 3/3] Describe the credential action outputs --- .github/actions/dockerhub-credentials/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/dockerhub-credentials/action.yml b/.github/actions/dockerhub-credentials/action.yml index 2833a898..f65075d2 100644 --- a/.github/actions/dockerhub-credentials/action.yml +++ b/.github/actions/dockerhub-credentials/action.yml @@ -11,8 +11,10 @@ inputs: default: 'false' outputs: username: + description: Docker Hub username. value: ${{ steps.read.outputs.username }} password: + description: Docker Hub access token. value: ${{ steps.read.outputs.password }} credentials: description: JSON username/password pair for Ansible.