diff --git a/.github/workflows/docker-build-cloud.yml b/.github/workflows/docker-build-cloud.yml index 0858331..ea03407 100644 --- a/.github/workflows/docker-build-cloud.yml +++ b/.github/workflows/docker-build-cloud.yml @@ -31,6 +31,10 @@ on: description: "Docker build arguments (multiline format: KEY1=value1\nKEY2=value2)" default: "" type: string + attest: + description: "Generate & sign a keyless SLSA build provenance attestation for the pushed image (the CALLER must grant id-token: write and attestations: write)" + default: false + type: boolean secrets: dockerhub-username: description: "Username for Docker Hub authentication" @@ -62,6 +66,7 @@ jobs: endpoint: ${{ inputs.cloud-builder-endpoint }} - name: Build and push multi-platform image + id: build uses: docker/build-push-action@v7 with: build-args: ${{ inputs.build-args }} @@ -70,3 +75,13 @@ jobs: platforms: ${{ inputs.platforms }} push: true tags: ${{ inputs.image-name }}:${{ inputs.image-tag }} + + # --- SLSA provenance attestation ----- + # Requires the permissions id-token: write + attestations: write. + - name: Generate & sign SLSA provenance (keyless) + if: ${{ inputs.attest }} + uses: actions/attest-build-provenance@v4 + with: + subject-name: ${{ inputs.image-name }} + subject-digest: ${{ steps.build.outputs.digest }} + push-to-registry: true` diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 703cb9e..157fa44 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -31,6 +31,10 @@ on: description: "Push Docker Image to Registry" default: false type: boolean + attest: + description: "Generate & sign a keyless SLSA build provenance attestation for the pushed image (the CALLER must grant id-token: write and attestations: write)" + default: false + type: boolean security-scan: description: "Enable Trivy Security Scan" default: true @@ -254,10 +258,21 @@ jobs: - name: Compute checksum of the Docker image id: checksum run: | - # Extract SHA256 digest and format as 0X... + # Extract SHA256 digest and expose it in both 0x... and sha256:... formats INSPECT=$(docker image inspect "$OCI_IMAGE") DIGEST=$(echo "$INSPECT" | jq -r 'if .[0].RepoDigests[0] then .[0].RepoDigests[0] | split("@sha256:")[1] else .[0].Id | split(":")[1] end') echo "checksum=0x${DIGEST}" >> "$GITHUB_OUTPUT" + echo "digest=sha256:${DIGEST}" >> "$GITHUB_OUTPUT" + + # --- SLSA provenance attestation ----- + # Requires the permissions id-token: write + attestations: write. + - name: Generate & sign SLSA provenance (keyless) + if: ${{ inputs.attest && inputs.push }} + uses: actions/attest-build-provenance@v4 + with: + subject-name: ${{ inputs.image-name }} + subject-digest: ${{ steps.checksum.outputs.digest }} + push-to-registry: true # Push attestation to registry - name: Cleanup files if: always() diff --git a/docker-build-cloud/README.md b/docker-build-cloud/README.md index e6371cd..2298bd9 100644 --- a/docker-build-cloud/README.md +++ b/docker-build-cloud/README.md @@ -10,6 +10,7 @@ This reusable GitHub Actions workflow builds and pushes a multi-platform Docker - ๐Ÿ” Authenticates to DockerHub for both registry push and DBC endpoint access - ๐Ÿท๏ธ Tags the image with `:` - ๐Ÿš€ No QEMU emulation, no native ARM runners โ€” DBC handles arch-specific builds +- ๐Ÿ“œ Generates & signs a keyless SLSA build provenance attestation (optional) > [!IMPORTANT] > Requires a Docker Build Cloud subscription and a builder configured in your DockerHub organization. The DockerHub PAT must have the **Build** scope to authenticate to the cloud endpoint. @@ -18,6 +19,7 @@ This reusable GitHub Actions workflow builds and pushes a multi-platform Docker | Name | Description | Required | Default | | ------------------------ | --------------------------------------------------------------------------------- | -------- | -------------- | +| `attest` | Generate & sign a keyless SLSA build provenance attestation for the pushed image (requires caller permissions, see notes) | No | `false` | | `build-args` | Docker build arguments (multiline format: `KEY1=value1\nKEY2=value2`) | No | `""` | | `cloud-builder-endpoint` | Docker Build Cloud endpoint, format `/` | Yes | - | | `context` | Path to Docker Build Context | No | `"."` | @@ -61,6 +63,12 @@ jobs: - ๐Ÿ”’ The DockerHub PAT must have the **Build** scope, not just Read/Write โ€” DBC endpoints will return `403 Forbidden` otherwise. - ๐Ÿชช The user owning the PAT must be a member of the cloud builder (Docker Hub โ†’ org โ†’ Build Cloud โ†’ builder โ†’ Members). - ๐Ÿ” Login to DockerHub MUST run before `setup-buildx-action` โ€” the cloud driver reads `~/.docker/config.json` at bootstrap. +- ๐Ÿ“œ When `attest: true`, the **caller** workflow must grant the following permissions: + ```yaml + permissions: + id-token: write + attestations: write + ``` ## ๐Ÿ› ๏ธ Troubleshooting diff --git a/docker-build/README.md b/docker-build/README.md index 4a647fc..108ca52 100644 --- a/docker-build/README.md +++ b/docker-build/README.md @@ -13,6 +13,7 @@ Perfect for teams looking to streamline their containerization workflow with min - ๐Ÿท๏ธ Intelligently tags and pushes images to a Docker Registry - ๐Ÿ”Ž Scan for vulnerabilities with Trivy - ๐Ÿ‘ Lint dockerfile +- ๐Ÿ“œ Generates & signs a keyless SLSA build provenance attestation (optional) - ๐Ÿ›ก๏ธ Handles authentication securely using GitHub Secrets - ๐Ÿš€ Optimizes build performance with layer caching - ๐Ÿ“ฆ Supports AMD64 and ARM64 platforms (one per workflow run) @@ -25,6 +26,7 @@ Perfect for teams looking to streamline their containerization workflow with min | Name | Description | Required | Default | | ----------------- | ---------------------------------------------------------------------------------- | -------- | ----------------- | +| `attest` | Generate & sign a keyless SLSA build provenance attestation for the pushed image (requires `push: true` and caller permissions, see notes) | No | `false` | | `build-args` | Docker build arguments (multiline format: `KEY1=value1\nKEY2=value2`) | No | `""` | | `context` | Path to Docker Build Context | No | `"."` | | `dockerfile` | Path to the Dockerfile to build (e.g., './Dockerfile', './docker/Dockerfile') | No | `"Dockerfile"` | @@ -90,6 +92,12 @@ jobs: - ๐Ÿท๏ธ You can specify any valid Docker tag format in the `tag` input - ๐Ÿ“… Consider using dynamic tags based on git tags, commit SHAs, or dates - ๐Ÿงช For testing purposes, you can use the `--dry-run` flag in your own implementation +- ๐Ÿ“œ When `attest: true`, the attestation is only generated if `push: true`, and the **caller** workflow must grant the following permissions: + ```yaml + permissions: + id-token: write + attestations: write + ``` ## ๐Ÿ› ๏ธ Troubleshooting