Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Salsa framework during release to increase the supply-chain security #966

Merged
merged 3 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ on:
jobs:
release:
runs-on: ubuntu-20.04
outputs:
container_tags: ${{ steps.container_info.outputs.container_tags }}
container_info: ${{ steps.container_info.outputs.container_info }}
env:
DOCKER_CLI_EXPERIMENTAL: "enabled"
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -32,6 +36,15 @@ jobs:
compareLink: true
filterByMilestone: true
unreleased: true
- name: Install Cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.12.1'
- name: Install Syft
uses: anchore/sbom-action/download-syft@v0.12.0
- name: Install signing key
run: |
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
- name: Set up Go
uses: actions/setup-go@v3
with:
Expand All @@ -48,3 +61,205 @@ jobs:
args: release --rm-dist --release-notes=changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get container info
id: container_info
run: |
function digest_tags {
while IFS= read -r line ; do
jq -n "{digest: \"$line\", tags: \$ARGS.positional}" --args $(docker inspect docker.io/absaoss/k8gb@$line --format '{{ join .RepoTags "\n" }}' | sed 's/.*://' | awk '!_[$0]++')
done <<< "$(docker manifest inspect docker.io/absaoss/k8gb:${{ github.ref_name }} | grep digest | cut -d '"' -f 4)"
}
CONTAINER_INFO="$(digest_tags | jq --slurp . -c)"
CONTAINER_DIGEST="$(echo ${CONTAINER_INFO} | jq --raw-output '.[0].digest')"
CONTAINER_TAGS=$(echo ${CONTAINER_INFO} | jq --raw-output '[.[].tags[]] | join(" ")')
set | grep 'CONTAINER_'
echo "container_info=$CONTAINER_INFO" >> $GITHUB_ENV
echo "container_tags=$CONTAINER_TAGS" >> $GITHUB_ENV
- name: Cleanup signing keys
if: ${{ always() }}
run: rm -f cosign.key

sbom:
name: sbom
needs: [release]
runs-on: ubuntu-20.04
env:
TAGS: "${{ needs.release.outputs.container_tags }}"

steps:
- name: Install cosign
uses: sigstore/cosign-installer@v2.7.0
with:
cosign-release: 'v1.12.1'

- name: Install Syft
uses: anchore/sbom-action/download-syft@v0.12.0
- name: Login to Dockerhub
uses: docker/login-action@v2.1.0
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Attach SBOM
env:
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
echo '${{ secrets.COSIGN_PUBLIC_KEY }}' > cosign.pub
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
for t in `echo ${TAGS}`; do
cosign verify --key cosign.pub docker.io/absaoss/k8gb:${t}
syft docker.io/absaoss/k8gb:${t} -o spdx-json > sbom-spdx.json
cosign attest --predicate sbom-spdx.json --type spdx --key cosign.key docker.io/absaoss/k8gb:${t}
cosign verify-attestation -o verified-sbom-spdx.json --type spdx --key cosign.pub docker.io/absaoss/k8gb:${t}
done
- name: Clean up
if: ${{ always() }}
run: |
rm -f cosign.key

provenance:
name: provenance
needs: [release]
runs-on: ubuntu-20.04
steps:
- name: Generate provenance for Release
uses: philips-labs/slsa-provenance-action@v0.8.0
id: provenance-step
with:
command: generate
subcommand: github-release
arguments: --artifact-path release-assets --output-path provenance.att --tag-name ${{ github.ref_name }}
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

- name: Check if uploading provenance failed
if: ${{ always() }}
run: |
[ "x${{steps.provenance-step.outcome}}" == "xfailure" ] && echo ":x: Uploading provenance for release failed, make sure to delete all the previous releases in GitHub web api before releasing." > "$GITHUB_STEP_SUMMARY" || true

- name: Install cosign
uses: sigstore/cosign-installer@v2.7.0
with:
cosign-release: 'v1.12.1'

- name: Sign provenance
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
SIGNATURE: provenance.att.sig
run: |
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
cosign sign-blob --key cosign.key --output-signature "${SIGNATURE}" provenance.att
cat "${SIGNATURE}"
curl_args=(-s -H "Authorization: token ${GITHUB_TOKEN}")
curl_args+=(-H "Accept: application/vnd.github.v3+json")
release_id="$(curl "${curl_args[@]}" "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases?per_page=10" | jq "map(select(.name == \"${GITHUB_REF_NAME}\"))" | jq -r '.[0].id')"
echo "Upload ${SIGNATURE} to release with id ${release_id}…"
curl_args+=(-H "Content-Type: $(file -b --mime-type "${SIGNATURE}")")
curl "${curl_args[@]}" \
--data-binary @"${SIGNATURE}" \
"https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=${SIGNATURE}"

container-provenance:
name: container-provenance
needs: [release]
runs-on: ubuntu-20.04

strategy:
matrix:
container: ${{ fromJSON(needs.release.outputs.container_info) }}

steps:
- name: Install cosign
uses: sigstore/cosign-installer@v2.7.0
with:
cosign-release: 'v1.12.1'

- name: Generate provenance for container image
uses: philips-labs/slsa-provenance-action@v0.8.0
with:
command: generate
subcommand: container
arguments: --repository docker.io/absaoss/k8gb --output-path provenance.att --digest ${{ matrix.container.digest }} --tags ${{ join(matrix.container.tags, ',') }} }}
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

- name: Get slsa-provenance predicate
run: |
cat provenance.att | jq .predicate > provenance-predicate.att
- name: Login to Dockerhub
uses: docker/login-action@v2.1.0
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Attach provenance to image
run: |
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
cosign attest --predicate provenance-predicate.att --type slsaprovenance --key cosign.key docker.io/absaoss/k8gb@${{ matrix.container.digest }}
env:
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

- name: Verify attestation
run: |
echo '${{ secrets.COSIGN_PUBLIC_KEY }}' > cosign.pub
cosign verify-attestation --key cosign.pub --type slsaprovenance docker.io/absaoss/k8gb@${{ matrix.container.digest }}
- name: Cleanup
if: ${{ always() }}
run: |
rm -f cosign.key

slsa-summary:
name: Release Summary
needs: [sbom, provenance, container-provenance, release]
runs-on: ubuntu-20.04
env:
TAGS: "${{ needs.release.outputs.container_tags }}"
CONTAINER_INFO: "${{ needs.release.outputs.container_info }}"
steps:
- name: Make summary for the release pipeline
run: |
{
echo "# :seedling: Release Summary"
echo "- version: [${{ github.ref_name }}](https://github.com/${GITHUB_REPOSITORY}/tree/${{ github.ref_name }})"
echo '- git sha: [`'$(echo ${GITHUB_SHA} | cut -c1-8)'`](https://github.com/'${GITHUB_REPOSITORY}'/commit/'${GITHUB_SHA}')'
echo '- SCM: [:octocat:`'${GITHUB_REPOSITORY}'`](https://github.com/'${GITHUB_REPOSITORY}')'
echo "- self reference: [action run #${{ github.run_id }}](https://github.com/'${GITHUB_REPOSITORY}'/actions/runs/${{ github.run_id }})"
echo "- release page: [${{ github.ref_name }}](https://github.com/'${GITHUB_REPOSITORY}'/releases/tag/${{ github.ref_name }})"
echo "- this github workflow (code): [ci.yaml](https://github.com/'${GITHUB_REPOSITORY}'/blob/${GITHUB_SHA}/.github/workflows/release.yaml)"
echo "- container images at dockerhub: [docker.io/absaoss/k8gb](https://hub.docker.com/r/absaoss/k8gb/tags)"
echo ""
echo "## :closed_lock_with_key: Secure Software Supply Chain"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
repo="docker.io/absaoss/k8gb"
for tag in `echo ${TAGS}`; do
img="${repo}:${tag}"
digest=$(echo $CONTAINER_INFO | jq "map(select(.tags[] | contains(\"${tag}\"))) | .[].digest")
{
echo '### Container image `'${img}'`'
echo ':lock: Image is signed. You can verify it with the following command:'
echo '```bash'
echo "cosign verify --key cosign.pub ${img}"
echo '```'
echo ":scroll: SBOM file is attested. You can verify it with the following command:"
echo '```bash'
echo "cosign verify-attestation --key cosign.pub --type spdx ${img} \\"
echo " | jq '.payload |= @base64d | .payload | fromjson | select( .predicateType==\"https://spdx.dev/Document\" ) | .predicate.Data | fromjson | .'"
echo '```'
echo ":green_book: SLSA Provenance file is attested. You can verify it with the following command:"
echo '```bash'
echo "cosign verify-attestation --key cosign.pub --type slsaprovenance ${repo}@${digest} \\"
echo " | jq '.payload |= @base64d | .payload | fromjson | select(.predicateType==\"https://slsa.dev/provenance/v0.2\" ) | .'"
echo '```'
echo "---"
} >> "$GITHUB_STEP_SUMMARY"
done
{
echo "**NOTE**"
echo
echo 'Instead of using `--key cosign.pub` that requires having the public key locally present, you can alternatively use:'
echo '```bash'
echo "cosign verify --key https://github.com/${GITHUB_REPOSITORY}/blob/${{ github.ref_name }}/cosign.pub \${image}"
echo '```'
echo
echo "---"
} >> "$GITHUB_STEP_SUMMARY"
2 changes: 1 addition & 1 deletion .github/workflows/terratest-more-clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
uses: goreleaser/goreleaser-action@v2
with:
version: v1.7.0
args: release --rm-dist --skip-publish --skip-validate --snapshot
args: release --rm-dist --skip-publish --skip-validate --snapshot --skip-sbom --skip-sign
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/terratest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
uses: goreleaser/goreleaser-action@v3
with:
version: v1.9.2
args: release --rm-dist --skip-publish --skip-validate --snapshot
args: release --rm-dist --skip-publish --skip-validate --snapshot --skip-sbom --skip-sign
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upgrade-testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
uses: goreleaser/goreleaser-action@v3
with:
version: v1.9.2
args: release --rm-dist --skip-publish --skip-validate --snapshot
args: release --rm-dist --skip-publish --skip-validate --snapshot --skip-sbom --skip-sign
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ k3d/test-gslb[!1-3].yaml

# Required by goreleaser
changes

# SLSA
cosign.key
*.sig
*.att
86 changes: 86 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ builds:
- -trimpath
ldflags:
- -s -w -X main.version={{ .Tag }} -X main.commit={{ .Commit }}
archives:
- id: binary
format: binary
name_template: "{{ .ProjectName }}_{{ .Os }}-{{ .Arch }}"
- id: archive
format: tar.gz
replacements:
darwin: macOS
files:
- LICENSE*
- README*
- cosign.pub
- dist/*.sig
format_overrides:
- goos: windows
format: zip
dockers:
- image_templates:
- "absaoss/k8gb:v{{ .Version }}-amd64"
Expand Down Expand Up @@ -43,9 +59,79 @@ docker_manifests:
image_templates:
- absaoss/k8gb:v{{ .Version }}-amd64
- absaoss/k8gb:v{{ .Version }}-arm64
sboms:
- id: archive-sbom
cmd: syft
args: ["${artifact}", "--file", "${artifact}.sbom.json", "--output", "spdx-json"]
documents:
- "${artifact}.sbom.json"
artifacts: archive
signs:
- id: checksums
cmd: cosign
stdin: '{{ .Env.COSIGN_PASSWORD }}'
output: true
artifacts: checksum
args:
- sign-blob
- --key
- cosign.key
- '--output-certificate=${certificate}'
- '--output-signature=${signature}'
- '${artifact}'
- id: binaries
cmd: cosign
stdin: '{{ .Env.COSIGN_PASSWORD }}'
output: true
artifacts: binary
args:
- sign-blob
- --key
- cosign.key
- '--output-certificate=${certificate}'
- '--output-signature=${signature}'
- '${artifact}'
- id: archives
cmd: cosign
stdin: '{{ .Env.COSIGN_PASSWORD }}'
output: true
artifacts: archive
args:
- sign-blob
- --key
- cosign.key
- '--output-certificate=${certificate}'
- '--output-signature=${signature}'
- '${artifact}'
- id: sboms
cmd: cosign
stdin: '{{ .Env.COSIGN_PASSWORD }}'
output: true
artifacts: sbom
args:
- sign-blob
- --key
- cosign.key
- '--output-certificate=${certificate}'
- '--output-signature=${signature}'
- '${artifact}'

docker_signs:
- cmd: cosign
artifacts: all
output: true
args:
- 'sign'
- --key
- cosign.key
- '${artifact}'
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Version }}-{{ .ShortCommit }}"
release:
draft: true
extra_files:
- glob: "./cosign.pub"
footer: |
:rocket:
Loading