diff --git a/.github/workflows/security-build.yml b/.github/workflows/security-build.yml index 3d04e5d..eb0d141 100644 --- a/.github/workflows/security-build.yml +++ b/.github/workflows/security-build.yml @@ -35,7 +35,7 @@ jobs: set -euo pipefail test "$(go env GOVERSION)" = go1.27.3 bash scripts/validate.sh - docker build --build-arg VERSION=0.1.2 --build-arg REVISION="$GITHUB_SHA" -f package/Dockerfile -t local/vault-secrets-bridge . + docker build --build-arg VERSION=0.1.3 --build-arg REVISION="$GITHUB_SHA" -f package/Dockerfile -t local/vault-secrets-bridge . - name: Retain the exact verified runtime shell: bash run: | @@ -52,14 +52,45 @@ jobs: scanner=aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 PYTHONDONTWRITEBYTECODE=1 python3 .github/scripts/test_runtime_vulnerability_policy.py docker pull "$scanner" + cache="$RUNNER_TEMP/ubuntu-backports-trivy-cache" + mkdir -p "$cache" + docker run --rm -v "$cache:/root/.cache/trivy" "$scanner" image --download-db-only for runtime in local/vault-secrets-bridge; do name=${runtime##*/}; name=${name%%:*} docker save "$runtime" --output "$RUNNER_TEMP/$name.tar" - docker run --rm -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --input /image.tar --scanners vuln,secret --list-all-pkgs --format json --output "/evidence/$name-security.json" - python3 .github/scripts/enforce-runtime-vulnerabilities.py --repository PastureStack/vault-secrets-bridge < "dist/security-runtime/$name-security.json" - docker run --rm -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --input /image.tar --format cyclonedx --output "/evidence/$name-sbom.cdx.json" + docker run --rm -v "$cache:/root/.cache/trivy" -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --skip-db-update --input /image.tar --scanners vuln,secret --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL --list-all-pkgs --format json --output "/evidence/$name-security.json" + docker run --rm -v "$cache:/root/.cache/trivy" -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --skip-db-update --input /image.tar --format cyclonedx --output "/evidence/$name-sbom.cdx.json" + mkdir -p dist/security-runtime + consumer_container=$(docker create "$runtime" /bin/true) + if docker cp "$consumer_container:/usr/share/pasturestack/security/ubuntu-backports" dist/security-runtime/ubuntu-backports; then + docker rm "$consumer_container" >/dev/null + else + docker rm "$consumer_container" >/dev/null + exit 1 + fi + (cd dist/security-runtime/ubuntu-backports && sha256sum --check SHA256SUMS) + bundle_image='ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a' + mkdir -p dist/security-runtime/bundle-tools + bundle_container=$(docker create "$bundle_image" unused) + if docker cp "$bundle_container:/out/verify-consumer-evidence.py" dist/security-runtime/bundle-tools/verify-consumer-evidence.py && \ + docker cp "$bundle_container:/out/SHA256SUMS" dist/security-runtime/bundle-tools/SHA256SUMS; then + docker rm "$bundle_container" >/dev/null + else + docker rm "$bundle_container" >/dev/null + exit 1 + fi + (cd dist/security-runtime/bundle-tools && \ + test "$(grep -Ec '^[0-9a-f]{64} verify-consumer-evidence\.py$' SHA256SUMS)" -eq 1 && \ + grep -E '^[0-9a-f]{64} verify-consumer-evidence\.py$' SHA256SUMS | sha256sum --check -) + python3 dist/security-runtime/bundle-tools/verify-consumer-evidence.py \ + --evidence-dir dist/security-runtime/ubuntu-backports --sbom "dist/security-runtime/$name-sbom.cdx.json" \ + --bundle-checksums dist/security-runtime/bundle-tools/SHA256SUMS \ + --expected-bundle-digest 'sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a' > dist/security-runtime/ubuntu-backports-validation.json + docker run --rm -v "$cache:/root/.cache/trivy" -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --skip-db-update --input /image.tar --scanners vuln,secret --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL --list-all-pkgs --vex /evidence/ubuntu-backports/openvex.json --format json --output "/evidence/$name-security-backports.json" + python3 .github/scripts/enforce-runtime-vulnerabilities.py --repository PastureStack/vault-secrets-bridge < "dist/security-runtime/$name-security-backports.json" + tar -cf dist/security-runtime/ubuntu-backports-evidence.tar -C dist/security-runtime ubuntu-backports ubuntu-backports-validation.json done - (cd dist/security-runtime && sha256sum -- *.json images.tar.gz source-revision.txt > SHA256SUMS) + (cd dist/security-runtime && sha256sum -- *.json *.tar images.tar.gz source-revision.txt > SHA256SUMS) - name: Upload verified runtime and checksums if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -80,7 +111,7 @@ jobs: packages: write env: GH_TOKEN: ${{ github.token }} - RELEASE_TAG: v0.1.2 + RELEASE_TAG: v0.1.3 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/README.md b/README.md index fd63f7c..d15938c 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,15 @@ PastureStack is an independent community effort to preserve, audit, and moderniz # Vault Secrets Bridge +Linux runtime **`v0.1.3`** integrates shared Ubuntu 26.04 security backports for already-installed packages while preserving the selected coreutils provider. + +The image retains bundle manifests, source inputs and installation receipts under `/usr/share/pasturestack/security/ubuntu-backports/`. + `vault-secrets-bridge` is the PastureStack host-authenticated broker for short-lived HashiCorp Vault leases. It accepts only fresh requests signed by an active host identity, enforces an explicit policy allowlist, asks Vault for a response-wrapped child token, encrypts that wrapping token to the requesting host, and tracks only the revocable accessor under a hashed host-and-volume key. -The current public release and Catalog image are `v0.1.2`. This repository does -not publish a mutable `latest` tag; future releases must use an unused pure -numeric version. +The Linux image is `ghcr.io/pasturestack/vault-secrets-bridge:v0.1.3`. +This repository uses unused pure numeric versions and does not publish a +mutable `latest` tag. The companion `secrets-flexvolume-plugin` runs as a separate host-local Docker volume driver with `--provider vault`. It verifies and decrypts the returned envelope, writes the wrapping token to a read-only file in an isolated `tmpfs`, and asks this bridge to revoke the lease after the final workload unmounts the volume. @@ -118,5 +122,4 @@ finding with an official fix blocks release, regardless of severity. Unknown findings block unless a separately reviewed, exact not-affected statement is proved by the actual product dependency graph. LOW/MEDIUM findings without an official fix require the repository's exact CVE/package/version/PURL review ledger; -new or changed findings fail closed. This policy-only update does not replace any -already published immutable artifact. +new or changed findings fail closed. Each release must pass this policy against its exact image and package versions. diff --git a/package/Dockerfile b/package/Dockerfile index cfe7a27..3918e0e 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -1,4 +1,5 @@ # syntax=docker/dockerfile:1.7 +FROM ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a AS ubuntu_security_backports FROM golang:1.27.3-bookworm@sha256:972b4110ba0f47539a975c31e52c64765e1ff19f2d74469ae4a595c6676e80a5 AS build ARG VERSION=dev @@ -55,6 +56,22 @@ RUN set -eux; \ COPY --from=build /out/vault-secrets-bridge /usr/local/bin/vault-secrets-bridge +# Install qualified backports only for packages already in this runtime. +# The immutable read-only build mount adds no installer or interpreter to it. +RUN --mount=from=ubuntu_security_backports,source=/out,target=/opt/pasturestack/ubuntu-security-backports,ro \ + set -eux; \ + evidence=/usr/share/pasturestack/security/ubuntu-backports; \ + mkdir -p "${evidence}"; \ + /opt/pasturestack/ubuntu-security-backports/install-existing-backports --install-in-docker-build > "${evidence}/install.json"; \ + /opt/pasturestack/ubuntu-security-backports/install-existing-backports --verify-installed > "${evidence}/verify.json"; \ + for document in manifest.json qualification.json openvex.json source-inputs.lock.json; do \ + cp "/opt/pasturestack/ubuntu-security-backports/${document}" "${evidence}/${document}"; \ + done; \ + printf '%s\n' 'ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a' > "${evidence}/bundle-image.txt"; \ + (cd "${evidence}" && sha256sum manifest.json qualification.json openvex.json source-inputs.lock.json install.json verify.json bundle-image.txt > SHA256SUMS); \ + dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort > /usr/share/pasturestack/ubuntu-security-packages.tsv; \ + rm -f /var/cache/ldconfig/aux-cache + USER 65532:65532 EXPOSE 8080 ENTRYPOINT ["/usr/local/bin/vault-secrets-bridge"]