adding ssh host signing
This commit is contained in:
@@ -8,19 +8,24 @@
|
||||
# shell-local post-processors extract artifacts, build the UKI (ukify), and
|
||||
# build+push the OCI release image.
|
||||
#
|
||||
# Signed when the SB_KEY/SB_CERT secrets are set; otherwise an UNSIGNED (lab)
|
||||
# build where build-oci.sh emits its loud unsigned-UKI warning. Signing runs
|
||||
# shell-local on the runner (not in the build VM); the key is staged to
|
||||
# RUNNER_TEMP and shredded after. See docs/secure-boot-keys.md.
|
||||
# This is the PRODUCTION build profile and it FAILS CLOSED (POA&M P-03): a
|
||||
# "Production build gate" step aborts the run unless SB_KEY, SB_CERT and FLEET_CA
|
||||
# are set — there is no unsigned fallback and no placeholder fleet CA. STIG
|
||||
# hardening is mandatory (enforced by the Packer template's variable validation).
|
||||
# Signing runs shell-local on the runner (not in the build VM); the key is staged
|
||||
# to RUNNER_TEMP and shredded after. See docs/secure-boot-keys.md.
|
||||
#
|
||||
# Required Gitea repo secrets:
|
||||
# REGISTRY_USERNAME - registry user for `oci_image` (oci_push=true)
|
||||
# REGISTRY_TOKEN - registry password/token
|
||||
# SSH_AUTHORIZED_KEY - public key for the sudo admin user; empty => no admin
|
||||
# user + root left unlocked (lab). Set it to lock root.
|
||||
# SB_KEY, SB_CERT - Secure Boot signing: the `db` PRIVATE key (PEM) + its
|
||||
# cert (PEM). Empty => unsigned lab build. PK/KEK are NOT
|
||||
# here (offline/HSM). Generate per docs/secure-boot-keys.md.
|
||||
# SB_KEY, SB_CERT - REQUIRED. Secure Boot signing: the `db` PRIVATE key (PEM)
|
||||
# + its cert (PEM). PK/KEK are NOT here (offline/HSM).
|
||||
# Generate per docs/secure-boot-keys.md. Missing => build fails.
|
||||
# FLEET_CA - REQUIRED. Real fleet step-ca root PEM baked to
|
||||
# radius-ca.pem (RADIUS EAP-TLS + fleet-agent verify).
|
||||
# Missing => build fails.
|
||||
#
|
||||
# Runner: needs KVM (qemu accelerator=kvm) and the build-host tooling installed
|
||||
# below (libguestfs, erofs-utils, cryptsetup, jq, ukify, buildah).
|
||||
@@ -147,6 +152,36 @@ jobs:
|
||||
echo "image_version=${version}" >> "$GITHUB_OUTPUT"
|
||||
echo "Building image_version=${version}"
|
||||
|
||||
-
|
||||
name: Production build gate (fail closed on missing security material)
|
||||
# POA&M P-03 / F-01 (poam-hardening): the pipeline is the production build
|
||||
# profile, so it FAILS CLOSED. There is no unsigned fallback and no
|
||||
# placeholder fleet CA — the three security-critical secrets MUST be set:
|
||||
# SB_KEY / SB_CERT Secure Boot `db` signing material (signed UKI)
|
||||
# FLEET_CA real fleet step-ca root baked to radius-ca.pem
|
||||
# (RADIUS EAP-TLS trust anchor + fleet-agent verify)
|
||||
# enable_stig is enforced true by the Packer template itself (variable
|
||||
# validation); it is asserted here too so a misconfigured ENABLE_STIG env
|
||||
# fails before the ~17-min VM build rather than during it.
|
||||
env:
|
||||
SB_KEY: ${{ secrets.SB_KEY }}
|
||||
SB_CERT: ${{ secrets.SB_CERT }}
|
||||
FLEET_CA: ${{ secrets.FLEET_CA }}
|
||||
run: |
|
||||
miss=0
|
||||
for v in SB_KEY SB_CERT FLEET_CA; do
|
||||
if [ -z "${!v}" ]; then
|
||||
echo "::error::required secret ${v} is empty — production builds are signed with a real fleet CA (no fallback). Set it in the Gitea repo secrets."
|
||||
miss=1
|
||||
fi
|
||||
done
|
||||
if [ "${ENABLE_STIG}" != "true" ]; then
|
||||
echo "::error::ENABLE_STIG must be 'true' — production builds are hardening-mandatory (POA&M P-03)."
|
||||
miss=1
|
||||
fi
|
||||
[ "$miss" = 0 ] || exit 1
|
||||
echo "Production gate passed: SB_KEY, SB_CERT, FLEET_CA present; STIG enabled."
|
||||
|
||||
-
|
||||
name: Install build-host tooling
|
||||
# Tools the shell-local post-processors run on the RUNNER (not the VM):
|
||||
@@ -197,7 +232,7 @@ jobs:
|
||||
go-version: '1.26.4'
|
||||
|
||||
-
|
||||
name: Build host Go binaries out-of-VM (fleet-enrol, fleet-hostapi, fleet-agent)
|
||||
name: Build host Go binaries out-of-VM (fleet-enrol, fleet-hostapi, fleet-agent, fleet-ssh-hostcert)
|
||||
# Built HERE on the runner, NOT inside the Packer VM, so the Rocky build
|
||||
# image never carries the Go toolchain or the go-tpm dep tree. Packer
|
||||
# file-provisions the resulting static binaries into the rootfs. Runs
|
||||
@@ -223,7 +258,11 @@ jobs:
|
||||
&& CGO_ENABLED=0 GOTOOLCHAIN=local \
|
||||
go build -trimpath -buildvcs=false -ldflags '-s -w -buildid=' -o bin/fleet-agent . \
|
||||
&& CGO_ENABLED=0 go vet ./... && CGO_ENABLED=0 go test ./... )
|
||||
file files/enrol/bin/fleet-enrol files/hostapi/bin/fleet-hostapi files/agent/bin/fleet-agent
|
||||
( cd files/ssh-hostcert \
|
||||
&& CGO_ENABLED=0 GOTOOLCHAIN=local \
|
||||
go build -trimpath -buildvcs=false -ldflags '-s -w -buildid=' -o bin/fleet-ssh-hostcert . \
|
||||
&& CGO_ENABLED=0 go vet ./... && CGO_ENABLED=0 go test ./... )
|
||||
file files/enrol/bin/fleet-enrol files/hostapi/bin/fleet-hostapi files/agent/bin/fleet-agent files/ssh-hostcert/bin/fleet-ssh-hostcert
|
||||
|
||||
-
|
||||
name: TPM ceremony + agent mTLS tests (go-tpm software simulator)
|
||||
@@ -265,9 +304,8 @@ jobs:
|
||||
# signing post-processor runs shell-local on THIS runner (not in the build
|
||||
# VM), so write the secrets to runner-temp files and pass their paths. The
|
||||
# `db` PRIVATE key is the only signing key here; PK/KEK stay offline (see
|
||||
# docs/secure-boot-keys.md). If SB_KEY is unset, this no-ops and the build
|
||||
# falls back to an UNSIGNED lab UKI (the loud warning stays).
|
||||
if: ${{ secrets.SB_KEY != '' }}
|
||||
# docs/secure-boot-keys.md). Presence is guaranteed by the Production build
|
||||
# gate above (fail-closed) — there is no unsigned fallback.
|
||||
env:
|
||||
SB_KEY: ${{ secrets.SB_KEY }} # db private key (PEM) — secret
|
||||
SB_CERT: ${{ secrets.SB_CERT }} # db cert (PEM) — public, kept as a secret for convenience
|
||||
@@ -284,10 +322,9 @@ jobs:
|
||||
name: Materialize fleet CA (radius-ca.pem trust anchor)
|
||||
# The real fleet step-ca root is baked to /etc/dot1x/radius-ca.pem (RADIUS
|
||||
# EAP-TLS + fleet-agent server-verify). Written to a runner-temp FILE and
|
||||
# passed as a build-host PATH (var.fleet_ca). If FLEET_CA is unset this
|
||||
# no-ops and the build falls back to the committed PLACEHOLDER (auth cannot
|
||||
# succeed — lab only). Never commit real internal CA material (CLAUDE.md).
|
||||
if: ${{ secrets.FLEET_CA != '' }}
|
||||
# passed as a build-host PATH (var.fleet_ca). Presence is guaranteed by the
|
||||
# Production build gate above (fail-closed) — the committed placeholder is
|
||||
# NOT a usable fallback here. Never commit real internal CA material (CLAUDE.md).
|
||||
env:
|
||||
FLEET_CA: ${{ secrets.FLEET_CA }} # fleet step-ca root PEM (root, or root+intermediate)
|
||||
run: |
|
||||
@@ -318,9 +355,10 @@ jobs:
|
||||
|
||||
-
|
||||
name: packer build (UKI + OCI release image)
|
||||
# Signed when SB_KEY/SB_CERT secrets are set (paths exported above);
|
||||
# UNSIGNED lab build (loud warning) when they're empty. sb_key/sb_cert are
|
||||
# PATHS, never values — see the materialize step and docs/secure-boot-keys.md.
|
||||
# Always a SIGNED build: SB_KEY/SB_CERT/FLEET_CA presence is enforced by the
|
||||
# Production build gate, and enable_stig=true is enforced by the template's
|
||||
# variable validation. sb_key/sb_cert are PATHS, never values — see the
|
||||
# materialize step and docs/secure-boot-keys.md.
|
||||
run: |
|
||||
packer build -color=false -on-error=abort \
|
||||
-var image_version="${{ steps.vars.outputs.image_version }}" \
|
||||
@@ -330,9 +368,9 @@ jobs:
|
||||
-var disable_dot1x=${{ env.DISABLE_DOT1X }} \
|
||||
-var nvmet_traddr="${{ env.NVMET_TRADDR }}" \
|
||||
-var ssh_authorized_key="${{ secrets.SSH_AUTHORIZED_KEY }}" \
|
||||
-var sb_key="${SB_KEY_FILE:-}" \
|
||||
-var sb_cert="${SB_CERT_FILE:-}" \
|
||||
-var fleet_ca="${FLEET_CA_FILE:-files/etc/dot1x/radius-ca.pem}" \
|
||||
-var sb_key="${SB_KEY_FILE}" \
|
||||
-var sb_cert="${SB_CERT_FILE}" \
|
||||
-var fleet_ca="${FLEET_CA_FILE}" \
|
||||
-var kiosk_url="${{ env.KIOSK_URL }}" \
|
||||
-var boot_splash=${{ env.BOOT_SPLASH }} \
|
||||
-var enable_stig=${{ env.ENABLE_STIG }} \
|
||||
|
||||
Reference in New Issue
Block a user