Skip to content

Commit 0ddbe7f

Browse files
authored
Security hardening (#7)
* Security hardening
1 parent 03a8969 commit 0ddbe7f

4 files changed

Lines changed: 216 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ concurrency:
1010
permissions:
1111
contents: write
1212
packages: write
13+
id-token: write # cosign keyless OIDC + SLSA provenance
1314

1415
jobs:
1516
release:
1617
runs-on: ubuntu-latest
1718
timeout-minutes: 20
19+
outputs:
20+
hashes: ${{ steps.hash.outputs.hashes }}
1821
steps:
1922
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2023
with:
@@ -28,13 +31,41 @@ jobs:
2831
username: ${{ github.actor }}
2932
password: ${{ secrets.GITHUB_TOKEN }}
3033
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
34+
- uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
35+
- uses: anchore/sbom-action/download-syft@55dc4ee22412511ee8c3142cbea40418e6cec693 # v0.17.8
3136
- uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
3237
with:
3338
version: "~> v2"
3439
args: release --clean
3540
env:
3641
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3742
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
43+
- name: Compute artifact hashes for SLSA provenance
44+
id: hash
45+
working-directory: dist
46+
run: |
47+
set -euo pipefail
48+
shopt -s nullglob
49+
subjects=(*.tar.gz *.zip *.deb *.rpm *.apk *.sbom.cdx.json checksums.txt)
50+
if [ ${#subjects[@]} -eq 0 ]; then
51+
echo "no release artifacts found in dist/" >&2
52+
exit 1
53+
fi
54+
echo "hashes=$(sha256sum -- "${subjects[@]}" | base64 -w0)" >> "$GITHUB_OUTPUT"
55+
56+
# SLSA Level 3 build provenance for binary release artifacts.
57+
# Reusable workflow MUST be referenced by tag (not commit SHA): the generator
58+
# verifies its own ref and rejects unpinned references at runtime.
59+
provenance:
60+
needs: [release]
61+
permissions:
62+
actions: read
63+
id-token: write
64+
contents: write
65+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
66+
with:
67+
base64-subjects: "${{ needs.release.outputs.hashes }}"
68+
upload-assets: true
3869

3970
verify:
4071
needs: release
@@ -56,6 +87,10 @@ jobs:
5687
method: homebrew
5788
- runner: ubuntu-latest
5889
method: go-install
90+
- runner: ubuntu-latest
91+
method: cosign-checksums
92+
- runner: ubuntu-latest
93+
method: cosign-image
5994
runs-on: ${{ matrix.runner }}
6095
timeout-minutes: 10
6196
steps:
@@ -113,10 +148,47 @@ jobs:
113148
augur --version
114149
115150
- name: Install from Homebrew
116-
if: matrix.method == 'homebrew'
151+
if: matrix.method == 'homebrew' && !contains(github.ref_name, '-')
117152
run: |
118153
brew install --cask starkross/tap/augur
119154
augur --version
120155
156+
- name: Skip Homebrew verify on pre-release
157+
if: matrix.method == 'homebrew' && contains(github.ref_name, '-')
158+
run: echo "Skipping Homebrew verify for pre-release ${GITHUB_REF_NAME} (tap is not updated for pre-releases by design)."
159+
160+
- name: Install cosign
161+
if: startsWith(matrix.method, 'cosign-')
162+
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
163+
164+
- name: Verify checksums.txt cosign signature
165+
if: matrix.method == 'cosign-checksums'
166+
env:
167+
IDENTITY_REGEX: https://github.com/${{ github.repository }}/.github/workflows/release.yml@refs/tags/v.*
168+
OIDC_ISSUER: https://token.actions.githubusercontent.com
169+
run: |
170+
set -euo pipefail
171+
base="https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}"
172+
curl -fsSL "${base}/checksums.txt" -o checksums.txt
173+
curl -fsSL "${base}/checksums.txt.sig" -o checksums.txt.sig
174+
curl -fsSL "${base}/checksums.txt.pem" -o checksums.txt.pem
175+
cosign verify-blob \
176+
--certificate checksums.txt.pem \
177+
--signature checksums.txt.sig \
178+
--certificate-identity-regexp "${IDENTITY_REGEX}" \
179+
--certificate-oidc-issuer "${OIDC_ISSUER}" \
180+
checksums.txt
181+
182+
- name: Verify container image cosign signature
183+
if: matrix.method == 'cosign-image'
184+
env:
185+
IDENTITY_REGEX: https://github.com/${{ github.repository }}/.github/workflows/release.yml@refs/tags/v.*
186+
OIDC_ISSUER: https://token.actions.githubusercontent.com
187+
run: |
188+
set -euo pipefail
189+
cosign verify "ghcr.io/starkross/augur:${{ steps.version.outputs.version }}" \
190+
--certificate-identity-regexp "${IDENTITY_REGEX}" \
191+
--certificate-oidc-issuer "${OIDC_ISSUER}"
192+
121193
- name: Verify version output
122194
run: echo "Successfully installed augur ${{ steps.version.outputs.version }} via ${{ matrix.method }}"

.goreleaser.yml

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ kos:
3232
repositories:
3333
- ghcr.io/starkross/augur
3434
platforms: [linux/amd64, linux/arm64]
35-
tags: ["{{ .Version }}", latest]
35+
tags:
36+
- "{{ .Version }}"
37+
- '{{ if not .Prerelease }}latest{{ end }}'
3638
bare: true
39+
sbom: cyclonedx
3740
ldflags: [-s, -w, "-X main.version={{.Version}}"]
3841
labels:
3942
org.opencontainers.image.title: "{{ .ProjectName }}"
@@ -50,10 +53,46 @@ homebrew_casks:
5053
homepage: https://github.com/starkross/augur
5154
description: Policy-driven linter for OpenTelemetry configurations
5255
license: Apache-2.0
56+
skip_upload: auto
57+
58+
release:
59+
prerelease: auto
5360

5461
checksum:
5562
name_template: checksums.txt
5663

64+
sboms:
65+
- id: archive
66+
artifacts: archive
67+
documents:
68+
- "${artifact}.sbom.cdx.json"
69+
cmd: syft
70+
args: [scan, "$artifact", --output, "cyclonedx-json=$document"]
71+
72+
signs:
73+
- id: checksums
74+
cmd: cosign
75+
certificate: "${artifact}.pem"
76+
signature: "${artifact}.sig"
77+
args:
78+
- sign-blob
79+
- "--yes"
80+
- "--output-certificate=${certificate}"
81+
- "--output-signature=${signature}"
82+
- "${artifact}"
83+
artifacts: checksum
84+
output: true
85+
86+
docker_signs:
87+
- id: images
88+
cmd: cosign
89+
args:
90+
- sign
91+
- "--yes"
92+
- "${artifact}"
93+
artifacts: manifests
94+
output: true
95+
5796
nfpms:
5897
- package_name: augur
5998
maintainer: starkross

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,21 @@ augur --policy ./my-policies config.yaml
162162
```
163163

164164
Custom policies are **merged** with the built-in rules — your rules run alongside all default checks.
165+
166+
## Security
167+
168+
Every release is reproducibly built and signed:
169+
170+
- **CycloneDX SBOMs** for every archive and every container image
171+
- **Cosign keyless signatures** (sigstore OIDC) on `checksums.txt` and on the published OCI image
172+
- **SLSA Level 3 build provenance** for binary artifacts
173+
174+
Quick verification of a release:
175+
176+
```sh
177+
cosign verify ghcr.io/starkross/augur:vX.Y.Z \
178+
--certificate-identity-regexp 'https://github.com/starkross/augur/\.github/workflows/release\.yml@refs/tags/v.*' \
179+
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
180+
```
181+
182+
See [SECURITY.md](SECURITY.md) for the full verification recipe (binaries, images, SLSA provenance, SBOMs) and the vulnerability disclosure process.

SECURITY.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Security
2+
3+
## Supply chain
4+
5+
Every tagged release of `augur` ships with the following supply-chain artifacts:
6+
7+
| Artifact | Format | Where |
8+
|----------|--------|-------|
9+
| Binary archives | `tar.gz` / `zip` | GitHub release page |
10+
| Linux packages | `deb`, `rpm`, `apk` | GitHub release page |
11+
| Container images | OCI (linux/amd64, linux/arm64) | `ghcr.io/starkross/augur` |
12+
| SBOM (per archive) | CycloneDX JSON | `<archive>.sbom.cdx.json` on the release page |
13+
| SBOM (per image) | CycloneDX, attached as OCI referrer | discoverable via `cosign download sbom` |
14+
| Checksums | SHA-256 | `checksums.txt` |
15+
| Cosign signature (checksums) | sigstore keyless | `checksums.txt.sig` + `checksums.txt.pem` |
16+
| Cosign signature (image) | sigstore keyless | OCI signature in registry |
17+
| SLSA build provenance | in-toto bundle | `multiple.intoto.jsonl` on the release page |
18+
19+
Signatures are produced with **cosign keyless** (sigstore OIDC). The signing identity is the release workflow itself — there is no long-lived signing key to leak or rotate.
20+
21+
## Verifying a release
22+
23+
You will need [`cosign`](https://docs.sigstore.dev/cosign/installation/) (≥ v2.0). Replace `vX.Y.Z` with the release tag you want to verify.
24+
25+
### 1. Verify `checksums.txt` and then verify your binary
26+
27+
```sh
28+
TAG=vX.Y.Z
29+
BASE="https://github.com/starkross/augur/releases/download/${TAG}"
30+
31+
curl -fsSLO "${BASE}/checksums.txt"
32+
curl -fsSLO "${BASE}/checksums.txt.sig"
33+
curl -fsSLO "${BASE}/checksums.txt.pem"
34+
35+
cosign verify-blob \
36+
--certificate checksums.txt.pem \
37+
--signature checksums.txt.sig \
38+
--certificate-identity-regexp 'https://github.com/starkross/augur/\.github/workflows/release\.yml@refs/tags/v.*' \
39+
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
40+
checksums.txt
41+
42+
# Now verify your downloaded binary matches the signed checksum
43+
curl -fsSLO "${BASE}/augur_${TAG#v}_linux_amd64.tar.gz"
44+
sha256sum --ignore-missing --check checksums.txt
45+
```
46+
47+
### 2. Verify the container image
48+
49+
```sh
50+
cosign verify ghcr.io/starkross/augur:vX.Y.Z \
51+
--certificate-identity-regexp 'https://github.com/starkross/augur/\.github/workflows/release\.yml@refs/tags/v.*' \
52+
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
53+
```
54+
55+
### 3. Verify SLSA build provenance
56+
57+
```sh
58+
# Install slsa-verifier: https://github.com/slsa-framework/slsa-verifier
59+
slsa-verifier verify-artifact \
60+
--provenance-path multiple.intoto.jsonl \
61+
--source-uri github.com/starkross/augur \
62+
--source-tag vX.Y.Z \
63+
augur_${TAG#v}_linux_amd64.tar.gz
64+
```
65+
66+
### 4. Inspect the SBOM
67+
68+
```sh
69+
# For an archive: download <archive>.sbom.cdx.json from the release page.
70+
71+
# For a container image:
72+
cosign download sbom ghcr.io/starkross/augur:vX.Y.Z > augur.sbom.cdx.json
73+
```
74+
75+
The SBOM is in [CycloneDX 1.5+](https://cyclonedx.org/) JSON. Feed it to your scanner of choice (`grype`, `trivy sbom`, Dependency-Track, etc.).
76+
77+
## Reporting a vulnerability
78+
79+
Please **do not open a public GitHub issue** for security vulnerabilities. Instead, use GitHub's private vulnerability reporting:
80+
81+
1. Go to https://github.com/starkross/augur/security/advisories
82+
2. Click **Report a vulnerability**
83+
3. Provide a description, reproduction steps, and the affected versions
84+
85+
We will acknowledge the report within a few working days and coordinate disclosure.

0 commit comments

Comments
 (0)