Stella Ops Trust Bootstrap Guide
Sprint: SPRINT_20260125_003 - WORKFLOW-001 Last updated: 2026-01-25 Status (2026-05-30 reconciliation): DRAFT / partially implemented. The bootstrap shell scripts (
devops/scripts/bootstrap-trust.sh,bootstrap-trust-offline.sh) exist and their flags match this guide, but thestella trust *CLI subcommands they orchestrate are not wired into the shipped CLI. TheTrustCommandGroupclass (src/Cli/StellaOps.Cli/Commands/Trust/TrustCommandGroup.cs) is fully written but itsBuildTrustCommandfactory is never registered in the root command (src/Cli/StellaOps.Cli/Commands/CommandFactory.cs), sostella trust init,stella trust status,stella trust import, etc. are not invocable today.stella trust snapshot exportis additionally a no-op stub that returnsNotImplemented. Sections below are annotated inline where the documented command does not match the code. Do not treat thestella trust/stella sign/stella keys generateexamples as working commands until the command group is registered.
Overview
Audience: operators standing up a new Stella Ops deployment who need to establish trust before signing or verifying any attestation.
This guide covers the initial trust setup for a new Stella Ops deployment. Trust bootstrap establishes the cryptographic foundations for secure attestation and verification — pinning a TUF root, importing trusted Rekor keys, and (optionally) provisioning a local signing key.
Prerequisites
- StellaOps CLI installed (
stellacommand available) - Network access to TUF repository (or offline trust bundle)
- Sufficient permissions to create keys in
/etc/stellaops/keys/ - For keyless mode: OIDC identity provider configured
Quick Start
The wrapper scripts below ship in
devops/scripts/and accept exactly the flags shown (verified against the script source). However, internally they callstella trust init/stella trust import(with no fallback), and that subcommand group is not currently registered in the CLI — so the scripts will fail at the TUF-init / import step untilBuildTrustCommandis wired intoCommandFactory. See the status banner at the top of this guide.
Online Bootstrap
# Initialize trust from organization's TUF repository
./devops/scripts/bootstrap-trust.sh \
--tuf-url https://trust.example.com/tuf/ \
--pin rekor-key-v1
Offline Bootstrap (Air-Gapped)
# Import pre-packaged trust bundle
./devops/scripts/bootstrap-trust-offline.sh \
/media/usb/trust-bundle-2026-01-25.tar.zst
Detailed Steps
Step 1: Generate Signing Keys (Optional)
If using local signing keys (not keyless/OIDC):
# Create key directory
mkdir -p /etc/stellaops/keys
chmod 700 /etc/stellaops/keys
# Generate an ECDSA P-256 signing key with OpenSSL.
# (This is what the bootstrap scripts actually use to produce a usable key.)
openssl ecparam -name prime256v1 -genkey -noout \
-out /etc/stellaops/keys/signing-key.pem
chmod 600 /etc/stellaops/keys/signing-key.pem
NOTE — CLI key generation: the documented
stella keys generate --type ecdsa-p256 --out ...form does not exist. There is no top-levelstella keyscommand at all — the only registered top-level key commands arestella key(singular; attestation signing-key rotation, fromProof.KeyRotationCommandGroup) andstella issuer keys(list/create/rotate/revoke, which today emit hard-coded mock JSON, not real key material —CommandFactory.BuildIssuerCommand). The crypto-provider key generator isstella crypto keys generate --algorithm {rsa|ecdsa|ed25519} [--size N] --output <prefix>(intended to write<prefix>.key/<prefix>.pub), but in the current build that handler is a stub — it prints the intended paths without producing real key material (src/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs,BuildKeysCommand). Use OpenSSL (above) for a real key until the stub is implemented.bootstrap-trust.shinvokesstella keys generate --type ecdsa-p256 --out ...first; because no such command exists (wrong group and wrong flag names — the real stub uses--algorithm/--output, not--type/--out), that call errors and is silently swallowed by the|| openssl …fallback, which is why the script still yields a working key.
Step 2: Initialize TUF Client
NOT WIRED:
stella trust initandstella trust statusare implemented inTrustCommandGroupbut the group is not registered in the CLI root, so these invocations currently fail with an unknown-command error. The option set shown (--tuf-url,--service-map,--pin, plus--cache-path,--offline,--force,--output) does match the code once the group is wired. NOTE: each--pinflag takes a single value; to pin multiple keys, repeat the flag (--pin rekor-key-v1 --pin rekor-key-v2) rather than listing them space-separated after one flag.
# Initialize with your organization's TUF repository
stella trust init \
--tuf-url https://trust.example.com/tuf/ \
--service-map sigstore-services-v1 \
--pin rekor-key-v1 --pin rekor-key-v2
# Verify initialization
stella trust status
The --pin option specifies which Rekor keys to trust. Pin multiple keys during rotation periods.
Step 3: Verify TUF Metadata
NOT WIRED: same caveat as Step 2 —
stella trust statusis not currently registered. The--show-keys/--show-endpointsflags match the code.
# Check trust status
stella trust status --show-keys --show-endpoints
# Expected output:
# TUF Repository: https://trust.example.com/tuf/
# Service Map: sigstore-services-v1
# Trusted Keys:
# - rekor-key-v1 (expires: 2027-01-01)
# - rekor-key-v2 (expires: 2028-01-01)
# Endpoints:
# - Rekor: https://rekor.sigstore.dev
# - Fulcio: https://fulcio.sigstore.dev
Step 4: Test Sign/Verify Cycle
INCORRECT (fixed below): there is no top-level
stella signcommand, and the top-levelstella verifycommand is a unified verifier for attestations/VEX/SBOMs/evidence bundles — not a<file> --sigsignature checker. The crypto-provider sign/verify commands arestella crypto sign --input <file> --output <sig>andstella crypto verify --input <file> --signature <sig>(src/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs).bootstrap-trust.shitself uses an OpenSSL fallback for this step, shown below.
# Create a test payload
echo "StellaOps bootstrap test" > /tmp/test-payload.txt
# Sign with your key via the crypto provider (DSSE format by default)
stella crypto sign \
--input /tmp/test-payload.txt \
--output /tmp/test.sig
# Verify the signature
stella crypto verify \
--input /tmp/test-payload.txt \
--signature /tmp/test.sig
# OpenSSL fallback (what bootstrap-trust.sh actually runs):
# openssl dgst -sha256 -sign /etc/stellaops/keys/signing-key.pem \
# -out /tmp/test.sig /tmp/test-payload.txt
# Clean up
rm /tmp/test-payload.txt /tmp/test.sig
Step 5: Test Attestation Sign/Verify (Online Only)
INCORRECT (fixed below): there is no
stella attest createsubcommand and no--rekor-submit/--check-inclusionflags. The real attestation commands (src/Cli/StellaOps.Cli/Commands/CommandFactory.cs,BuildAttestCommand) are:
stella attest sign— creates and signs a DSSE envelope; takes--predicate <file>,--predicate-type <uri>,--subject <name>,--digest <alg:hex>, optional--keyor--keyless.stella attest verify— verifies a DSSE envelope offline; takes--envelope <path>(required) plus--policy,--root,--transparency-checkpoint,--require-timestamp. There is no positional file argument and no--check-inclusion; transparency-log inclusion is checked by supplying a--transparency-checkpoint, andstella attest show --id <id> --include-proofsurfaces the Rekor inclusion proof.
# Create and sign a DSSE attestation for a subject
stella attest sign \
--predicate /tmp/predicate.json \
--predicate-type https://slsa.dev/provenance/v1 \
--subject test-payload \
--digest sha256:<hex>
# Verify the envelope (offline) against trust roots
stella attest verify \
--envelope /tmp/test.intoto.jsonl \
--transparency-checkpoint /path/to/checkpoint
Offline Bootstrap
For air-gapped deployments without network access:
Create Trust Bundle (Connected System)
On a system with network access, create a trust bundle:
NOT IMPLEMENTED + flag mismatch:
stella trust snapshot exportis currently a stub — the handler returnsNotImplementedand prints “No placeholder trust snapshot was created” (src/Cli/StellaOps.Cli/Commands/Trust/TrustCommandHandlers.cs,HandleSnapshotExportAsync). It also requires real TUF metadata, Rekor tiles, a signed checkpoint, and a manifest writer before it can emit a bundle. There is no--include-tilesflag; the real options are--out(required),--tiles <dir>(include a local tiles directory),--from-proxy,--include-entries <range>, and--depth <n>(default 10000). The example below reflects the actual flag names but will not produce a bundle until the handler is implemented.Note the related-but-distinct verb
stella trust export --out <dir> [--include-targets](TrustCommandHandlers.HandleExportAsync) is implemented — it copies the cached TUF metadata (root.json,snapshot.json,timestamp.json,targets.json,trust-config.json, plus thetargets/directory) into an output directory, not atar.zstarchive. It still lives in the same unregisteredtrustgroup, so it is not invocable today either, and it does not bundle Rekor tiles/checkpoints the waysnapshot exportis intended to.
stella trust snapshot export \
--out trust-bundle-$(date +%Y-%m-%d).tar.zst \
--depth 10000
Transfer and Import (Air-Gapped System)
# Transfer bundle via USB, DVD, or approved data diode
# Then import:
./devops/scripts/bootstrap-trust-offline.sh \
/media/usb/trust-bundle-2026-01-25.tar.zst
# Optional: Reject stale bundles
./devops/scripts/bootstrap-trust-offline.sh \
/media/usb/trust-bundle-2026-01-25.tar.zst \
--reject-if-stale 7d
Configuration Options
TUF Client Configuration
After bootstrap, TUF client configuration is stored under the local application data directory in StellaOps/TufCache/ (TrustCommandHandlers.GetDefaultCachePath → Environment.SpecialFolder.LocalApplicationData). On Linux this resolves to ~/.local/share/StellaOps/TufCache/; on Windows it is %LOCALAPPDATA%\StellaOps\TufCache\. Override it per-invocation with stella trust init --cache-path <dir> (the --cache-path option) — there is no environment variable for this (see the corrected list below).
Key files:
root.json- Root of trust (only updated via ceremony)targets.json- List of trusted targetssnapshot.json- Point-in-time snapshot of targetstimestamp.json- Freshness guarantee (regularly updated)
Environment Variables
ORPHANED / NOT IMPLEMENTED: none of
STELLAOPS_TUF_CACHE,STELLAOPS_LOG_LEVEL, orSTELLAOPS_OFFLINEis read by the CLI — they have no effect (verified: no references insrc/Cli/StellaOps.Cli). Use the equivalent command flags instead:
- Cache directory — pass
--cache-path <dir>tostella trust init(there is no env-var override).- Debug logging — pass the global
--verboseflag (or-v) to any command.- Offline mode — pass
--offlinetostella trust init/stella trust verify. (For offline content mirrors/kits, the CLI does readSTELLAOPS_OFFLINE_KITS_DIRECTORYandSTELLAOPS_OFFLINE_MIRROR_URL(src/Cli/StellaOps.Cli/Configuration/CliBootstrapper.cs), but those are unrelated to TUF trust state.)
# Override cache directory (per-invocation flag, not an env var)
stella trust init --tuf-url ... --cache-path /custom/path
# Enable debug logging
stella trust status --verbose
# Offline mode (no network calls)
stella trust init --tuf-url ... --offline
Troubleshooting
Error: “TUF metadata verification failed”
The TUF root key may have been rotated. Obtain the new root.json from your security team and re-bootstrap:
FLAG MISMATCH:
stella trust inithas no--root-jsonoption (its only flags are--tuf-url,--service-map,--pin,--cache-path,--offline,--force,--output; seeTrustCommandGroup.BuildInitCommand). To re-bootstrap against a rotated root, re-run with--force(which re-initializes even if already initialized) pointed at the repository serving the new root metadata.
stella trust init \
--tuf-url https://trust.example.com/tuf/ \
--force
Error: “Rekor connectivity check failed”
- Verify network access to Rekor endpoint
- Check firewall rules for HTTPS (port 443)
- Verify the Rekor URL in service map is correct
- Try forcing a sync:
stella trust sync --force
Error: “Key not found in trust store”
The pinned key may not exist in the TUF repository. Check available keys:
stella trust status --show-keys
Offline: “Bundle is stale”
The trust bundle exceeds the staleness threshold. Obtain a fresh bundle from a connected system:
NOT IMPLEMENTED: as noted under “Create Trust Bundle” above,
stella trust snapshot exportis a stub and will not produce a bundle in the current build. The--reject-if-staleimport-side check (and thebootstrap-trust-offline.sh --reject-if-stalewrapper) is implemented, so the staleness error is real even though regenerating the bundle from the CLI is not yet possible.
# On connected system (NOT IMPLEMENTED — see note above)
stella trust snapshot export --out fresh-bundle.tar.zst
# Transfer and import
./devops/scripts/bootstrap-trust-offline.sh fresh-bundle.tar.zst
Maintenance
Periodic Sync
Set up a cron job to keep TUF metadata fresh:
FLAG MISMATCH + NOT WIRED:
stella trust synchas no--quietflag (only--forceand--output {text|json}; use--output jsonif you want machine-parseable, low-noise output). And as noted in the status banner, thestella trustgroup is not currently registered in the CLI, so this cron job will not run untilBuildTrustCommandis wired in.
# Every 6 hours
0 */6 * * * /usr/local/bin/stella trust sync --output json
Updating Air-Gap Bundles
For air-gapped systems, schedule regular bundle updates based on your organization’s freshness requirements (typically 7-30 days).
Next Steps
- Configure CI/CD to use the signing key
- Set up key rotation procedures (see
key-rotation-runbook.md) - Configure monitoring for trust state freshness
- For air-gap: Establish bundle transfer schedule
Distinct from trust bootstrap: the master-key ceremony. This guide covers trust bootstrap (pinning a TUF root + Rekor keys). It is not the same as provisioning the installation’s master key (KEK) that seals secret values at rest. Every install must also complete the setup Master Key step (generate/import + seal/open probe) before storing connector credentials or deployment bundles — see the Secrets & Keys guide.
Related Documentation
- Secrets & Keys guide (master key ceremony, secret providers, secret-reference URLs)
- TUF Integration Guide
- Key Rotation Runbook
- Disaster Recovery
