consolidation of some of the modules, localization fixes, product advisories work, qa work

This commit is contained in:
master
2026-03-05 03:54:22 +02:00
parent 7bafcc3eef
commit 8e1cb9448d
3878 changed files with 72600 additions and 46861 deletions

View File

@@ -1,101 +1,19 @@
# StellaOps Signer
# StellaOps Signer (Relocated)
Signer validates callers, enforces Proof-of-Entitlement, and produces signed DSSE bundles for SBOMs, reports, and exports.
> **Sprint 204 (2026-03-04):** The Signer module source has been consolidated under the Attestor trust domain.
> Source code is now at `src/Attestor/StellaOps.Signer/`.
> Architecture documentation is now in the [Attestor architecture dossier](../attestor/architecture.md#trust-domain-model-sprint-204----2026-03-04).
> Archived standalone docs are in `docs-archived/modules/signer/`.
## Latest updates (Sprint 0186/0401 · 2025-11-26)
- **CryptoDsseSigner** implemented with ICryptoProviderRegistry integration (SIGN-CORE-186-004), enabling keyless + KMS signing modes with cosign-compatible DSSE output.
- **SignerStatementBuilder** refactored to support StellaOps predicate types (`stella.ops/promotion@v1`, `stella.ops/sbom@v1`, `stella.ops/vex@v1`, etc.) with CanonicalJson canonicalization (SIGN-CORE-186-005).
- **PredicateTypes catalog** extended with `stella.ops/vexDecision@v1` and `stella.ops/graph@v1` for reachability evidence chain (SIGN-VEX-401-018).
- **Helper methods** added: `IsVexRelatedType`, `IsReachabilityRelatedType`, `GetAllowedPredicateTypes`, `IsAllowedPredicateType` for predicate type validation.
- **Integration tests** upgraded with real crypto abstraction, fixture predicates (promotion, SBOM, VEX, replay, policy, evidence, graph), and deterministic test data (SIGN-TEST-186-006). All 102 Signer tests passing.
## Runtime Identity (unchanged)
## Previous updates (Sprint 11 · 2025-10-21)
- `/sign/dsse` pipeline landed with Authority OpTok + PoE enforcement, Fulcio/KMS signing modes, and deterministic DSSE bundles ready for Attestor logging.
- `/verify/referrers` endpoint exposes release-integrity checks against scanner OCI referrers so callers can confirm digests before requesting signatures.
- Plan quota enforcement (QPS/concurrency/artifact size) and audit/metrics wiring now align with the Sprint11 signing-chain release.
- Docker image: `stellaops/signer:dev`
- API base path: `/api/v1/signer/`
- DSSE signing endpoint: `POST /api/v1/signer/sign/dsse`
- Database schemas: `signer`, `key_management` (isolated from Attestor schema by design)
## Responsibilities
- Enforce Proof-of-Entitlement and plan quotas before signing artifacts.
- Support keyless (Fulcio) and keyful (KMS/HSM) signing backends.
- Verify scanner release integrity via OCI referrers prior to issuing signatures.
- Emit DSSE payloads consumed by Attestor/Export Center and maintain comprehensive audit trails.
## Why the move
## Key components
- `StellaOps.Signer` service host with `SignerPipeline` orchestrating the signing flow.
- `CryptoDsseSigner` for ES256 signature generation via `ICryptoProviderRegistry`.
- `SignerStatementBuilder` for in-toto statement creation with `PredicateTypes` catalog.
- `DefaultSigningKeyResolver` for tenant-aware key resolution (keyless/KMS modes).
- Crypto providers under `StellaOps.Cryptography.*`.
Signer, Attestor, and Provenance form the trust domain -- the set of services responsible for cryptographic evidence production, transparency logging, and verification. Consolidating source ownership under `src/Attestor/` makes trust-boundary responsibilities explicit while preserving runtime isolation and database schema separation.
## Integrations & dependencies
- Authority for OpTok + PoE validation.
- Licensing Service for entitlement introspection.
- OCI registries (Referrers API) for scanner release verification.
- Attestor for transparency logging and Rekor ingestion.
- Export Center and CLI for artifact signing flows.
## API quick reference
- `POST /api/v1/signer/sign/dsse` — validate OpTok/PoE, enforce quotas, return DSSE bundle with signing identity metadata.
- `GET /api/v1/signer/verify/referrers` — report scanner release signer and trust verdict for a supplied image digest.
## Operational notes
- Key management via Authority/DevOps runbooks.
- Metrics for signing latency/throttle states.
- Offline kit integration for signature verification.
## Backlog references
- Sprint 0186: `docs/implplan/SPRINT_0186_0001_0001_record_deterministic_execution.md` (SIGN-CORE-186-004, SIGN-CORE-186-005, SIGN-TEST-186-006 DONE; SIGN-REPLAY-186-003 blocked on upstream).
- Sprint 0401: `docs/implplan/SPRINT_0401_0001_0001_reachability_evidence_chain.md` (SIGN-VEX-401-018 DONE; AUTH-REACH-401-005 TODO).
- SIG docs/tasks in ../../TASKS.md (e.g., DOCS-SIG-26-006).
## Implementation Status
### Phase 1 Core service & PoE (Complete)
- OpTok validation with Authority DPoP/mTLS tokens and signer.sign scope
- Proof-of-Entitlement (PoE) introspection with cloud licensing integration
- Scanner release verification via OCI referrers
- DSSE signing pipeline: keyless (Fulcio) and keyful (KMS/HSM/FIDO2)
- KMS key management foundations (KMSI-73-001, KMSI-73-002)
- DSSE/SLSA BuildDefinition models with canonical JSON (PROV-OBS-53-001/002)
### Phase 2 Export Center integration (In Progress)
- CryptoDsseSigner with ICryptoProviderRegistry (keyless + KMS modes)
- SignerStatementBuilder refactored for StellaOps predicate types
- PromotionAttestationBuilder with canonicalized payloads (PROV-OBS-53-003)
- Cosign-compatible DSSE output with provenance manifests
- Blocking: SIGN-CORE-186-004/005 crypto provider refactoring, replay manifest support
### Phase 3 Attestor alignment (Not Started)
- DSSE envelope metadata for Attestor ingestion
- Extended predicate catalog: stella.ops/vexDecision@v1, stella.ops/graph@v1 (SIGN-VEX-401-018 complete)
- Helper methods: IsVexRelatedType, IsReachabilityRelatedType, predicate validation
- Blocking: AUTH-REACH-401-005 predicate definitions, verification library (PROV-OBS-54-001/002)
### Phase 4 Observability & resilience (Not Started)
- Metrics: signing latency, PoE failures, quota hits, key usage distribution
- Structured logs with trace IDs, subject digests, issuer mode, decision outcomes
- Alerts for PoE outages, key exhaustion, quota breaches, failure spikes
- CLI commands: stella promotion attest/verify, stella forensic attest show
### Key Acceptance Criteria
- Signs only requests satisfying OpTok, PoE, quota, scanner provenance checks
- DSSE outputs verify with standard cosign tooling
- Export Center receives signed bundles with provenance manifests
- Audit logs capture every request with tenant, issuer, subject digest, PoE state
- CLI/Offline workflows verify signatures using Offline Kit trust roots
### Technical Decisions & Risks
- PoE/entitlement outages: cache last-known entitlement within TTL, emergency bypass with audit
- Key compromise: hardware-backed keys, rotation cadence, immediate revocation, incident runbook
- Release verification failures: allowlist for trusted scanner digests, manual approval fallback
- Determinism: canonicalize JSON, lock timestamp sources, regression tests for DSSE hashing
### Recent Updates (Sprint 0186/0401 · 2025-11-26)
- CryptoDsseSigner with ES256 signature generation via ICryptoProviderRegistry
- PredicateTypes catalog extended with VEX/graph predicates
- Integration tests upgraded with real crypto, fixture predicates (102 tests passing)
- CryptoPro signer plugin in progress (SEC-CRYPTO-90-020)
## Epic alignment
- **Epic 10 Export Center:** provide signing pipelines, cosign interoperability, and provenance manifests for bundle promotion.
- **Epic 19 Attestor Console:** supply DSSE payloads and Proof-of-Entitlement enforcement feeding attestation workflows described in `docs/modules/attestor/`.
See the [Trust Domain Model ADR](../attestor/architecture.md#security-boundary-no-merge-decision-adr) for the no-merge rationale.

View File

@@ -1,450 +0,0 @@
# component_architecture_signer.md — **StellaOps Signer** (2025Q4)
> Supports deliverables from Epic10 Export Center and Epic19 Attestor Console.
> **Scope.** Implementationready architecture for the **Signer**: the *only* service allowed to produce **StellaOpsverified** signatures over SBOMs and reports. It enforces **entitlement** (PoE), **release integrity** (scanner provenance), **senderconstrained auth** (DPoP/mTLS), and emits **intoto/DSSE** bundles suitable for **Rekor v2** logging by the Attestor. Includes APIs, data flow, storage, quotas, security, and test matrices.
---
## 0) Mission & boundaries
**Mission.** Convert authenticated signing requests from trusted StellaOps services into **verifiable** DSSE bundles while enforcing **license policy** and **supplychain integrity**.
**Boundaries.**
* **Signer does not push to Rekor** — it returns DSSE to the caller; **Attestor** logs to **Rekor v2**.
* **Signer does not compute PASS/FAIL** — it signs SBOMs/reports produced by Scanner/WebService after backend evaluation.
* **Signer is stateless for hot path** — longterm storage is limited to audit events; all secrets/keys live in KMS/HSM or are ephemeral (keyless).
---
## 1) Responsibilities (contract)
1. **Authenticate** caller with **OpTok** (Authority OIDC, DPoP or mTLSbound).
2. **Authorize** scopes (`signer.sign`) + audience (`aud=signer`) + tenant/installation.
3. **Validate entitlement** via **PoE** (ProofofEntitlement) against Cloud Licensing `/license/introspect`.
4. **Verify release integrity** of the **scanner** image digest presented in the request: must be **cosignsigned** by StellaOps release key, discoverable via **OCI Referrers API**.
5. **Enforce plan & quotas** (concurrency/QPS/artifact size/rate caps).
6. **Mint signing identity**:
* **Keyless** (default): get a shortlived X.509 cert from **Fulcio** using the Signers OIDC identity and sign the DSSE.
* **Keyful** (optional): sign with an HSM/KMS key.
7. **Return DSSE bundle** (subject digests + predicate + cert chain or KMS key id).
8. **Audit** every decision; expose metrics.
---
## 2) External dependencies
* **Authority** (onprem OIDC): validates OpToks (JWKS/introspection) and DPoP/mTLS.
* **Licensing Service (cloud)**: `/license/introspect` to verify PoE (active, claims, expiry, revocation).
* **Fulcio** (Sigstore) *or* **KMS/HSM**: to obtain certs or perform signatures.
* **OCI Registry (Referrers API)**: to verify **scanner** image release signature.
* **Attestor**: downstream service that writes DSSE bundles to **Rekor v2**.
* **Config/state stores**: Valkey (caches, rate buckets), PostgreSQL (audit log).
---
## 3) API surface (mTLS; DPoP supported)
Base path: `/api/v1/signer`. **All endpoints require**:
* Access token (JWT) from **Authority** with `aud=signer`, `scope=signer.sign`.
* **Sender constraint**: DPoP proof per request or mTLS client cert.
* **PoE** presented as either:
* **Client TLS cert** (if PoE is mTLSstyle) chained to Licensing CA, *or*
* **PoE JWT** (DPoP/mTLSbound) in `X-PoE` header or request body.
### 3.1 `POST /sign/dsse`
Request (JSON):
```json
{
"subject": [
{ "name": "s3://stellaops/images/sha256:.../inventory.cdx.pb",
"digest": { "sha256": "..." } }
],
"predicateType": "https://stella-ops.org/attestations/sbom/1",
"predicate": {
"image_digest": "sha256:...",
"stellaops_version": "2.3.1 (2027.04)",
"license_id": "LIC-9F2A...",
"customer_id": "CUST-ACME",
"plan": "pro",
"policy_digest": "sha256:...", // optional for final reports
"views": ["inventory", "usage"],
"created": "2025-10-17T12:34:56Z"
},
"scannerImageDigest": "sha256:sc-web-or-worker-digest",
"poe": {
"format": "jwt", // or "mtls"
"value": "eyJhbGciOi..." // PoE JWT when not using mTLS PoE
},
"options": {
"signingMode": "keyless", // "keyless" | "kms"
"expirySeconds": 600, // cert lifetime hint (keyless)
"returnBundle": "dsse+cert" // dsse (default) | dsse+cert
}
}
```
Response 200:
```json
{
"bundle": {
"dsse": { "payloadType": "application/vnd.in-toto+json", "payload": "<base64>", "signatures": [ ... ] },
"certificateChain": [ "-----BEGIN CERTIFICATE-----...", "... root ..." ],
"mode": "keyless",
"signingIdentity": { "issuer": "https://fulcio.internal", "san": "urn:stellaops:signer", "certExpiry": "2025-10-17T12:44:56Z" }
},
"policy": { "plan": "pro", "maxArtifactBytes": 104857600, "qpsRemaining": 97 },
"auditId": "a7c9e3f2-1b7a-4e87-8c3a-90d7d2c3ad12"
}
```
Errors (RFC7807):
* `401 invalid_token` (JWT/DPoP/mTLS failure)
* `403 entitlement_denied` (PoE invalid/revoked/expired; release year mismatch)
* `403 release_untrusted` (scanner image not Stellasigned)
* `429 plan_throttled` (license plan caps)
* `413 artifact_too_large` (size cap)
* `400 invalid_request` (schema/predicate/type invalid)
* `500 signing_unavailable` (Fulcio/KMS outage)
### 3.2 `GET /verify/referrers?imageDigest=<sha256>`
Checks whether the **image** at digest is signed by **StellaOps release key**.
Response:
```json
{ "trusted": true, "signatures": [ { "type": "cosign", "digest": "sha256:...", "signedBy": "StellaOps Release 2027 Q2" } ] }
```
> **Note:** This endpoint is also used internally by Signer before issuing signatures.
### 3.3 Predicate catalog (Sprint401 update)
Signer now enforces an allowlist of predicate identifiers:
| Predicate | Description | Producer |
|-----------|-------------|----------|
| `stella.ops/sbom@v1` | SBOM/report attestation (existing). | Scanner WebService. |
| `stella.ops/promotion@v1` | Promotion evidence (see `docs/release/promotion-attestations.md`). | DevOps/Export Center. |
| `stella.ops/vexDecision@v1` | OpenVEX decision for a single `(cve, product)` pair, including reachability evidence references. | Policy Engine / VEXer. |
Requests with unknown predicates receive `400 predicate_not_allowed`. Policy Engine must supply the OpenVEX JSON as the `predicate` body; Signer preserves payload bytes verbatim so DSSE digest = OpenVEX digest.
---
### KMS drivers (keyful mode)
Signer now ships five deterministic KMS adapters alongside the default keyless flow:
- `services.AddFileKms(...)` stores encrypted ECDSA material on disk for air-gapped or lab installs.
- `services.AddAwsKms(options => { options.Region = "us-east-1"; /* optional: options.Endpoint, UseFipsEndpoint */ });` delegates signing to AWS KMS, caches metadata/public keys offline, and never exports the private scalar. Rotation/revocation still run through AWS tooling (this library intentionally throws for those APIs so we do not paper over operator approvals).
- `services.AddGcpKms(options => { options.Endpoint = "kms.googleapis.com"; });` integrates with Google Cloud KMS asymmetric keys, auto-resolves the primary key version when callers omit a version, and verifies signatures locally with exported PEM material.
- `services.AddPkcs11Kms(options => { options.LibraryPath = "/opt/hsm/libpkcs11.so"; options.PrivateKeyLabel = "stella-attestor"; });` loads a PKCS#11 module, opens read-only sessions, signs digests via HSM mechanisms, and never hoists the private scalar into process memory.
- `services.AddFido2Kms(options => { options.CredentialId = "<base64url>"; options.PublicKeyPem = "-----BEGIN PUBLIC KEY-----..."; options.AuthenticatorFactory = sp => new WebAuthnAuthenticator(); });` routes signing to a WebAuthn/FIDO2 authenticator for dual-control or air-gap scenarios. The authenticator must supply the CTAP/WebAuthn plumbing; the library handles digesting, key material caching, and verification.
Cloud & hardware-backed drivers share a few invariants:
1. Hash payloads server-side (SHA-256) before invoking provider APIs signatures remain reproducible and digest inputs are observable in structured audit logs.
2. Cache metadata for the configurable window (default 5min) and subject-public-key-info blobs for 10min; tune these per sovereignty policy when running in sealed/offline environments.
3. Only expose public coordinates (`Qx`, `Qy`) to the host ― `KmsKeyMaterial.D` is blank for non-exportable keys so downstream code cannot accidentally persist secrets.
> **Security review checkpoint:** rotate/destroy remains an administrative action in the provider. Document those runbooks per tenant, and gate AWS/GCP traffic in sealed-mode via the existing egress allowlist. PKCS#11 loads native code, so keep library paths on the allowlist and validate HSM policies separately. FIDO2 authenticators expect an operator in the loop; plan for session timeouts and explicit audit fields when enabling interactive signing.
## 4) Validation pipeline (hot path)
```mermaid
sequenceDiagram
autonumber
participant Client as Scanner.WebService
participant Auth as Authority (OIDC)
participant Sign as Signer
participant Lic as Licensing Service (cloud)
participant Reg as OCI Registry (Referrers)
participant Ful as Fulcio/KMS
Client->>Sign: POST /sign/dsse (OpTok + DPoP/mTLS, PoE, request)
Note over Sign: 1) Validate OpTok, audience, scope, DPoP/mTLS binding
Sign->>Lic: /license/introspect(PoE)
Lic-->>Sign: { active, claims: {license_id, plan, valid_release_year, max_version}, exp }
Note over Sign: 2) Enforce plan/version window and revocation
Sign->>Reg: Verify scannerImageDigest signed (Referrers + cosign)
Reg-->>Sign: OK with signer identity
Note over Sign: 3) Enforce release integrity
Note over Sign: 4) Enforce quotas (QPS/concurrency/size)
Sign->>Ful: Mint cert (keyless) or sign via KMS
Ful-->>Sign: Cert or signature
Sign-->>Client: DSSE bundle (+cert chain), policy counters, auditId
```
**DPoP nonce dance (when enabled for highvalue ops):**
* If DPoP proof lacks a valid nonce, Signer replies `401` with `WWW-Authenticate: DPoP error="use_dpop_nonce", dpop_nonce="<nonce>"`.
* Client retries with new proof including the nonce; Signer validates nonce and `jti` uniqueness (Valkey TTL cache).
---
## 5) Entitlement enforcement (PoE)
* **Accepted forms**:
* **mTLS PoE**: client presents a **PoE client cert** at TLS handshake; Signer validates chain to **Licensing CA** (CA bundle configured) and calls `/license/introspect` with cert thumbprint + serial.
* **JWT PoE**: `X-PoE` bearer token (DPoP/mTLSbound) is validated (sig + `cnf`) locally (Licensing JWKS) and then **introspected** for status and claims.
* **Claims required**:
* `license_id`, `plan` (free|pro|enterprise|gov), `valid_release_year`, `max_version`, `exp`.
* Optional: `tenant_id`, `customer_id`, `entitlements[]`.
* **Enforcements**:
* Reject if **revoked**, **expired**, **plan mismatch** or **release outside window** (`stellaops_version` in predicate exceeds `max_version` or release date beyond `valid_release_year`).
* Apply plan **throttles** (QPS/concurrency/artifact bytes) via tokenbucket in Valkey keyed by `license_id`.
---
## 6) Release integrity (scanner provenance)
* **Input**: `scannerImageDigest` representing the actual Scanner component that produced the artifact.
* **Check**:
1. Use **OCI Referrers API** to enumerate signatures of that digest.
2. Verify **cosign** signatures against the configured **StellaOps Release** keyring (keyless Fulcio roots *or* keyful public keys).
3. Optionally require Rekor inclusion for those signatures.
* **Policy**:
* If not signed by an authorized **StellaOps Release** identity → **deny**.
* If signed but **release year** > PoE `valid_release_year`**deny**.
* **Cache**: LRU of digest → verification result (TTL 1030min) to avoid registry thrash.
---
## 7) Signing modes
### 7.1 Keyless (default; Sigstore Fulcio)
* Signer authenticates to **Fulcio** using its onprem OIDC identity (client credentials) and requests a **shortlived cert** (510min).
* Generates **ephemeral keypair**, gets cert for the public key, signs DSSE with the **private key**.
* DSSE **bundle** includes **certificate chain**; verifiers validate to Fulcio root.
### 7.2 Keyful (optional; KMS/HSM)
* Signer uses a configured **KMS** key (AWS KMS, GCP KMS, Azure Key Vault, Vault Transit, or HSM).
* DSSE bundle includes **key metadata** (kid, cert chain if x509).
* Recommended for FIPS/sovereign environments.
---
## 8) Predicates & schema
Supported **predicate types** (extensible):
* `https://stella-ops.org/attestations/sbom/1` (SBOM emissions)
* `https://stella-ops.org/attestations/report/1` (final PASS/FAIL reports)
* `https://stella-ops.org/attestations/vex-export/1` (Excititor exports; optional)
**Validation**:
* JSONSchema per predicate type; **canonical property order**.
* `subject[*].digest` must include `sha256`.
* `predicate.stellaops_version` must parse and match policy windows.
---
## 9) Quotas & throttling
Per `license_id` (from PoE):
* **QPS** (token bucket), **concurrency** (semaphore), **artifact bytes** (sliding window).
* On exceed → `429 plan_throttled` with `Retry-After`.
* Free/community plan may also receive **randomized delay** to disincentivize farmed signing.
---
## 10) Storage & caches
* **Valkey**:
* DPoP nonce & `jti` replay cache (TTL ≤ 10min).
* PoE introspection cache (short TTL, e.g., 60120s).
* Releaseverify cache (`scannerImageDigest` → { trusted, ts }).
* **Audit store** (PostgreSQL): `signer.audit_events`
```
{ _id, ts, tenantId, installationId, licenseId, customerId,
plan, actor{sub,cnf}, request{predicateType, subjectSha256[], imageDigest},
poe{type, thumbprint|jwtKid, exp, introspectSnapshot},
release{digest, signerId, policy},
mode: "keyless"|"kms",
result: "success"|"deny:<reason>"|"error:<reason>",
bundleSha256? }
```
* **Config**: StellaOps release signing keyring, Fulcio roots, Licensing CA bundle.
---
## 11) Security & privacy
* **mTLS** on all Signer endpoints.
* **No bearer fallbacks** — DPoP/mTLS enforced for `aud=signer`.
* **PoE** is never persisted beyond audit snapshots (minimized fields).
* **Secrets**: no longlived private keys on disk (keyless) or handled via KMS APIs.
* **Input hardening**: schemavalidate predicates; cap payload sizes; zstd/gzip decompression bombs guarded.
* **Logging**: redact PoE JWTs, access tokens, DPoP proofs; log only hashes and identifiers.
---
## 12) Metrics & observability
* `signer.requests_total{result}`
* `signer.latency_seconds{stage=auth|introspect|release_verify|sign}`
* `signer.poe_failures_total{reason}`
* `signer.release_verify_failures_total{reason}`
* `signer.plan_throttle_total{license_id}`
* `signer.bundle_bytes_total`
* `signer.keyless_certs_issued_total` / `signer.kms_sign_total`
* OTEL traces across stages; correlation id (`auditId`) returned to client.
---
## 13) Configuration (YAML)
```yaml
signer:
listen: "https://0.0.0.0:8443"
authority:
issuer: "https://authority.internal"
jwksUrl: "https://authority.internal/jwks"
require: "dpop" # "dpop" | "mtls"
poe:
mode: "both" # "jwt" | "mtls" | "both"
licensing:
introspectUrl: "https://www.stella-ops.org/api/v1/license/introspect"
caBundle: "/etc/ssl/licensing-ca.pem"
cacheTtlSeconds: 90
release:
referrers:
allowRekorVerified: true
keyrings:
- type: "cosign-keyless"
fulcioRoots: ["/etc/fulcio/root.pem"]
identities:
- san: "mailto:release@stella-ops.org"
- san: "https://sigstore.dev/oidc/stellaops"
signing:
mode: "keyless" # "keyless" | "kms"
fulcio:
issuer: "https://fulcio.internal"
oidcClientId: "signer"
oidcClientSecretRef: "env:FULCIO_CLIENT_SECRET"
certTtlSeconds: 600
kms:
provider: "aws-kms"
keyId: "arn:aws:kms:...:key/..."
quotas:
default:
qps: 100
concurrency: 20
maxArtifactBytes: 104857600
free:
qps: 5
concurrency: 1
maxArtifactBytes: 1048576
```
---
## 14) Testing matrix
* **Auth & DPoP**: bad `aud`, wrong `jkt`, replayed `jti`, missing nonce, mTLS mismatch.
* **PoE**: expired, revoked, plan mismatch, release year gate, max_version gate.
* **Release verify**: unsigned digest, wrong signer, Rekorabsent (when required), referrers unreachable.
* **Signing**: Fulcio outage; KMS timeouts; bundle correctness (verifier harness).
* **Quotas**: burst above QPS, artifact over size, concurrency overflow.
* **Schema**: invalid predicate types/required fields.
* **Determinism**: same request → identical DSSE (aside from cert validity period).
* **Perf**: P95 endtoend under 120ms with caches warm (excluding network to Fulcio).
---
## 15) Failure modes & responses
| Failure | HTTP | Problem type | Notes |
| ----------------------- | ---- | --------------------- | -------------------------------------------- |
| Invalid OpTok / DPoP | 401 | `invalid_token` | `WWW-Authenticate` with DPoP nonce if needed |
| PoE invalid/revoked | 403 | `entitlement_denied` | Include `license_id` (hashed) and reason |
| Scanner image untrusted | 403 | `release_untrusted` | Include digest and required identity |
| Plan throttle | 429 | `plan_throttled` | Include limits and `Retry-After` |
| Artifact too large | 413 | `artifact_too_large` | Include cap |
| Fulcio/KMS down | 503 | `signing_unavailable` | RetryAfter with jitter |
---
## 16) Deployment & HA
* Run ≥ 2 replicas; front with L7 LB; **sticky** not required.
* Valkey for replay/quota caches (HA).
* Audit sink (PostgreSQL) in primary region; asynchronous write with local fallback buffer.
* Fulcio/KMS clients configured with retries/backoff; circuit breakers.
---
## 17) Implementation notes
* **.NET 10** minimal API + Kestrel mTLS; custom DPoP middleware; JWT/JWKS cache.
* **Cosign verification** via sigstore libraries; Referrers queries over registry API with retries.
* **DSSE** via intoto libs; canonical JSON writer for predicates.
* **Backpressure** paths: refuse at auth/quota stages before any expensive network calls.
---
## 18) Examples (wire)
**Request (free plan; expect throttle if burst):**
```http
POST /api/v1/signer/sign/dsse HTTP/1.1
Authorization: DPoP <JWT>
DPoP: <proof>
Content-Type: application/json
```
**Error (release untrusted):**
```json
{
"type": "https://stella-ops.org/problems/release_untrusted",
"title": "Scanner image not signed by StellaOps",
"status": 403,
"detail": "sha256:abcd... not in trusted keyring",
"instance": "urn:audit:a7c9e3f2-..."
}
```
---
## 19) Roadmap
* **Key Transparency**: optional publication of Signers *own* certs to a KT log.
* **Attested Build**: SLSAstyle provenance for Signer container itself, checked at startup.
* **FIPS mode**: enforce `ES256` + KMS/HSM only; disallow Ed25519.
* **Dual attestation**: optional immediate push to **Attestor** (sync mode) with timeout budget, returning Rekor UUID inline.

View File

@@ -1,247 +0,0 @@
# Keyless Signing Quick Start
Get keyless signing working in your CI/CD pipeline in under 5 minutes.
## Overview
Keyless signing uses your CI platform's OIDC identity to sign artifacts without managing private keys. The signature is bound to your repository, branch, and workflow identity.
```
┌─────────────┐ ┌─────────┐ ┌───────────────┐
│ CI Platform │────▶│ Fulcio │────▶│ Signed Artifact│
│ OIDC Token │ │ Sigstore│ │ + Rekor Entry │
└─────────────┘ └─────────┘ └───────────────┘
```
## GitHub Actions (Fastest)
### Step 1: Add the workflow
Create `.github/workflows/sign.yml`:
```yaml
name: Build and Sign
on:
push:
branches: [main]
jobs:
build-and-sign:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Build container
run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Install StellaOps CLI
run: curl -sL https://get.stella-ops.org/cli | sh
- name: Get OIDC Token
id: oidc
run: |
TOKEN=$(curl -sLS "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore" \
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
| jq -r '.value')
echo "::add-mask::${TOKEN}"
echo "token=${TOKEN}" >> $GITHUB_OUTPUT
- name: Sign container
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
DIGEST=$(docker inspect ghcr.io/${{ github.repository }}:${{ github.sha }} \
--format='{{index .RepoDigests 0}}' | cut -d@ -f2)
stella attest sign --keyless --artifact "$DIGEST"
```
### Step 2: Push and verify
```bash
git add .github/workflows/sign.yml
git commit -m "Add keyless signing"
git push
```
Check Actions tab - your container is now signed!
---
## GitLab CI (5 minutes)
### Step 1: Update `.gitlab-ci.yml`
```yaml
stages:
- build
- sign
build:
stage: build
image: docker:24
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- echo "ARTIFACT_DIGEST=$(docker inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --format='{{index .RepoDigests 0}}' | cut -d@ -f2)" >> build.env
artifacts:
reports:
dotenv: build.env
sign:
stage: sign
image: stella-ops/cli:latest
id_tokens:
STELLAOPS_OIDC_TOKEN:
aud: sigstore
needs:
- build
script:
- stella attest sign --keyless --artifact "$ARTIFACT_DIGEST"
only:
- main
```
### Step 2: Push
```bash
git add .gitlab-ci.yml
git commit -m "Add keyless signing"
git push
```
---
## Verification Gate
Add verification before deployment:
### GitHub Actions
```yaml
deploy:
needs: [build-and-sign]
runs-on: ubuntu-latest
environment: production
steps:
- name: Verify before deploy
run: |
stella attest verify \
--artifact "${{ needs.build-and-sign.outputs.digest }}" \
--certificate-identity "repo:${{ github.repository }}:ref:refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--require-rekor
- name: Deploy
run: kubectl set image deployment/app app=$IMAGE
```
### GitLab CI
```yaml
deploy:
stage: deploy
environment: production
needs:
- sign
script:
- |
stella attest verify \
--artifact "$ARTIFACT_DIGEST" \
--certificate-identity "project_path:$CI_PROJECT_PATH:ref_type:branch:ref:main" \
--certificate-oidc-issuer "https://gitlab.com" \
--require-rekor
- kubectl set image deployment/app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
```
---
## Identity Patterns Cheat Sheet
### GitHub Actions
| Pattern | Example |
|---------|---------|
| Any branch | `repo:org/repo:.*` |
| Main only | `repo:org/repo:ref:refs/heads/main` |
| Tags only | `repo:org/repo:ref:refs/tags/v.*` |
| Environment | `repo:org/repo:environment:production` |
**OIDC Issuer:** `https://token.actions.githubusercontent.com`
### GitLab CI
| Pattern | Example |
|---------|---------|
| Any ref | `project_path:group/project:.*` |
| Main only | `project_path:group/project:ref_type:branch:ref:main` |
| Tags only | `project_path:group/project:ref_type:tag:.*` |
| Protected | `project_path:group/project:ref_protected:true` |
**OIDC Issuer:** `https://gitlab.com` (or self-hosted URL)
---
## Using Reusable Workflows
For cleaner pipelines, use StellaOps reusable workflows:
### GitHub Actions
```yaml
jobs:
sign:
uses: stella-ops/workflows/.github/workflows/stellaops-sign.yml@v1
with:
artifact-digest: sha256:abc123...
artifact-type: image
permissions:
id-token: write
verify:
needs: [sign]
uses: stella-ops/workflows/.github/workflows/stellaops-verify.yml@v1
with:
artifact-digest: sha256:abc123...
certificate-identity: "repo:${{ github.repository }}:ref:refs/heads/main"
certificate-oidc-issuer: "https://token.actions.githubusercontent.com"
```
### GitLab CI
```yaml
include:
- project: 'stella-ops/templates'
file: '.gitlab-ci-stellaops.yml'
sign-container:
extends: .stellaops-sign
variables:
ARTIFACT_DIGEST: sha256:abc123...
ARTIFACT_TYPE: image
```
---
## What's Next?
- [Identity Constraints Guide](./identity-constraints.md) - Secure verification patterns
- [Troubleshooting Guide](./keyless-signing-troubleshooting.md) - Common issues and fixes
- [Offline Verification](../airgap/offline-verification.md) - Air-gapped environments
## Need Help?
- Documentation: https://docs.stella-ops.org/
- Issues: https://github.com/stella-ops/stellaops/issues
- Slack: https://stellaops.slack.com/

View File

@@ -1,399 +0,0 @@
# Keyless Signing Troubleshooting Guide
This guide covers common issues when integrating StellaOps keyless signing into CI/CD pipelines.
## Common Errors
### OIDC Token Acquisition Failures
#### Error: "Unable to get OIDC token"
**Symptoms:**
```
Error: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL
```
**Cause:** The workflow doesn't have `id-token: write` permission.
**Solution:**
```yaml
# GitHub Actions
permissions:
id-token: write
contents: read
# GitLab CI
job:
id_tokens:
STELLAOPS_OIDC_TOKEN:
aud: sigstore
```
#### Error: "Token audience mismatch"
**Symptoms:**
```
Error: Token audience 'api://default' does not match expected 'sigstore'
```
**Cause:** OIDC token was requested with wrong audience.
**Solution:**
```yaml
# GitHub Actions
OIDC_TOKEN=$(curl -sLS "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore" \
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}")
# GitLab CI
id_tokens:
STELLAOPS_OIDC_TOKEN:
aud: sigstore # Must be 'sigstore' for Fulcio
```
---
### Fulcio Certificate Errors
#### Error: "Failed to get certificate from Fulcio"
**Symptoms:**
```
Error: error getting certificate from Fulcio: 401 Unauthorized
```
**Causes:**
1. OIDC token expired (tokens are short-lived, typically 5-10 minutes)
2. Fulcio doesn't recognize the OIDC issuer
3. Network connectivity issues to Fulcio
**Solutions:**
1. **Token expiry:** Request token immediately before signing:
```yaml
- name: Get OIDC Token
id: oidc
run: |
# Get fresh token right before signing
OIDC_TOKEN=$(curl -sLS "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore" \
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
| jq -r '.value')
echo "token=${OIDC_TOKEN}" >> $GITHUB_OUTPUT
- name: Sign (immediately after)
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: stella attest sign --keyless --artifact "$DIGEST"
```
2. **Unknown issuer:** Ensure your CI platform is supported:
- GitHub Actions: `https://token.actions.githubusercontent.com`
- GitLab.com: `https://gitlab.com`
- Self-hosted GitLab: Must be configured in Fulcio
3. **Network issues:** Check connectivity:
```bash
curl -v https://fulcio.sigstore.dev/api/v2/signingCert
```
#### Error: "Certificate identity not found in token"
**Symptoms:**
```
Error: no matching subject or SAN found in OIDC token
```
**Cause:** Token claims don't include expected identity fields.
**Solution:** Verify token contents:
```bash
# Decode and inspect token (don't do this in production logs)
echo $OIDC_TOKEN | cut -d. -f2 | base64 -d | jq .
```
Expected claims for GitHub Actions:
```json
{
"sub": "repo:org/repo:ref:refs/heads/main",
"iss": "https://token.actions.githubusercontent.com",
"repository": "org/repo",
"ref": "refs/heads/main"
}
```
---
### Rekor Transparency Log Errors
#### Error: "Failed to upload to Rekor"
**Symptoms:**
```
Error: error uploading entry to Rekor: 500 Internal Server Error
```
**Causes:**
1. Rekor service temporarily unavailable
2. Entry too large
3. Network issues
**Solutions:**
1. **Retry with backoff:**
```yaml
- name: Sign with retry
run: |
for i in 1 2 3; do
stella attest sign --keyless --artifact "$DIGEST" && break
echo "Attempt $i failed, retrying in 30s..."
sleep 30
done
```
2. **Check Rekor status:** https://status.sigstore.dev/
3. **Use offline bundle (air-gapped):**
```bash
stella attest sign --keyless --artifact "$DIGEST" --offline-bundle
```
#### Error: "Rekor entry not found"
**Symptoms:**
```
Error: entry not found in transparency log
```
**Cause:** Verification requiring Rekor but entry wasn't logged (offline signing).
**Solution:** Either:
- Sign with Rekor enabled (default)
- Verify without Rekor requirement:
```bash
stella attest verify --artifact "$DIGEST" --skip-rekor
```
---
### Verification Failures
#### Error: "Certificate identity mismatch"
**Symptoms:**
```
Error: certificate identity 'repo:org/repo:ref:refs/heads/feature'
does not match expected 'repo:org/repo:ref:refs/heads/main'
```
**Cause:** Artifact was signed from a different branch/ref than expected.
**Solutions:**
1. **Use regex for flexibility:**
```bash
stella attest verify \
--artifact "$DIGEST" \
--certificate-identity "repo:org/repo:.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
```
2. **Verify expected signing context:**
```bash
# Check what identity was actually used
stella attest inspect --artifact "$DIGEST" --show-identity
```
#### Error: "Certificate OIDC issuer mismatch"
**Symptoms:**
```
Error: certificate issuer 'https://gitlab.com'
does not match expected 'https://token.actions.githubusercontent.com'
```
**Cause:** Artifact was signed by a different CI platform.
**Solution:** Update verification to accept correct issuer:
```bash
# For GitLab-signed artifacts
stella attest verify \
--artifact "$DIGEST" \
--certificate-identity "project_path:org/repo:.*" \
--certificate-oidc-issuer "https://gitlab.com"
```
#### Error: "Signature expired"
**Symptoms:**
```
Error: certificate validity period has expired
```
**Cause:** Fulcio certificates are short-lived (10 minutes). Verification after expiry requires Rekor proof.
**Solution:** Ensure Rekor verification is enabled:
```bash
stella attest verify \
--artifact "$DIGEST" \
--require-rekor \
--certificate-identity "..." \
--certificate-oidc-issuer "..."
```
---
### Platform-Specific Issues
#### GitHub Actions: "Resource not accessible by integration"
**Symptoms:**
```
Error: Resource not accessible by integration
```
**Cause:** GitHub App or token lacks required permissions.
**Solution:** Ensure workflow has correct permissions:
```yaml
permissions:
id-token: write # For OIDC token
contents: read # For checkout
packages: write # If pushing to GHCR
attestations: write # For GitHub attestations
```
#### GitLab CI: "id_tokens not available"
**Symptoms:**
```
Error: STELLAOPS_OIDC_TOKEN variable not set
```
**Cause:** GitLab version doesn't support `id_tokens` or feature is disabled.
**Solutions:**
1. Check GitLab version (requires 15.7+)
2. Enable CI/CD OIDC in project settings:
- Settings > CI/CD > Token Access
- Enable "Allow CI job tokens from the following projects"
3. Use service account as fallback:
```yaml
sign:
script:
- |
if [ -z "$STELLAOPS_OIDC_TOKEN" ]; then
# Fallback to service account
stella attest sign --key "$SIGNING_KEY" --artifact "$DIGEST"
else
stella attest sign --keyless --artifact "$DIGEST"
fi
```
#### Gitea: OIDC Token Format
**Symptoms:**
```
Error: Invalid OIDC token format
```
**Cause:** Gitea Actions uses different token acquisition method.
**Solution:**
```yaml
- name: Get OIDC Token
run: |
# Gitea provides token directly in environment
if [ -n "$ACTIONS_ID_TOKEN" ]; then
echo "token=$ACTIONS_ID_TOKEN" >> $GITHUB_OUTPUT
else
echo "::error::OIDC token not available"
exit 1
fi
```
---
### Network and Connectivity
#### Error: "Connection refused" to Sigstore services
**Symptoms:**
```
Error: dial tcp: connection refused
```
**Cause:** Firewall blocking outbound connections.
**Required endpoints:**
| Service | URL | Purpose |
|---------|-----|---------|
| Fulcio | `https://fulcio.sigstore.dev` | Certificate issuance |
| Rekor | `https://rekor.sigstore.dev` | Transparency log |
| TUF | `https://tuf-repo-cdn.sigstore.dev` | Trust root |
| OIDC | CI platform URL | Token validation |
**Solution:** Allow outbound HTTPS to these endpoints, or use self-hosted Sigstore.
#### Proxy Configuration
```yaml
- name: Sign with proxy
env:
HTTPS_PROXY: http://proxy.internal:8080
NO_PROXY: internal.corp.com
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: stella attest sign --keyless --artifact "$DIGEST"
```
---
## Debugging Commands
### Inspect OIDC Token
```bash
# Decode token payload (never log in production)
echo $OIDC_TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | jq .
```
### Verify Fulcio Connectivity
```bash
curl -v https://fulcio.sigstore.dev/api/v2/configuration
```
### Check Rekor Entry
```bash
# Search by artifact hash
rekor-cli search --sha "sha256:abc123..."
# Get entry details
rekor-cli get --uuid "24296fb24b8ad77a..."
```
### Inspect Attestation
```bash
stella attest inspect \
--artifact "$DIGEST" \
--show-certificate \
--show-rekor-entry
```
### Verbose Signing
```bash
STELLAOPS_LOG_LEVEL=debug stella attest sign --keyless --artifact "$DIGEST"
```
---
## Getting Help
1. **Check service status:** https://status.sigstore.dev/
2. **StellaOps documentation:** https://docs.stella-ops.org/
3. **Sigstore documentation:** https://docs.sigstore.dev/
4. **File an issue:** https://github.com/stella-ops/stellaops/issues
When reporting issues, include:
- CI platform and version
- StellaOps CLI version (`stella --version`)
- Sanitized error output (remove tokens/secrets)
- Relevant workflow configuration

View File

@@ -1,230 +0,0 @@
# Keyless Signing Guide
This guide explains how to configure and use keyless signing with Sigstore Fulcio for CI/CD pipelines.
## Overview
Keyless signing eliminates the need to manage long-lived signing keys by using short-lived X.509 certificates (~10 minute TTL) issued by Fulcio based on OIDC identity tokens. This approach:
- **Zero key management**: No secrets to rotate or protect
- **Identity-bound signatures**: Signatures are cryptographically tied to the CI/CD identity
- **Non-repudiation**: Audit trail via Rekor transparency log
- **Industry standard**: Compatible with Sigstore ecosystem (cosign, gitsign, etc.)
## How It Works
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CI Runner │────▶│ OIDC Token │────▶│ Fulcio │────▶│ Ephemeral │
│ (GitHub/GL) │ │ Provider │ │ CA │ │ Cert │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
┌─────────────┐
│ Sign DSSE │
│ Envelope │
└─────────────┘
```
1. **CI runner provides OIDC token** - GitHub Actions, GitLab CI, etc. provide ambient identity tokens
2. **Token exchanged for certificate** - Fulcio validates the OIDC token and issues a short-lived certificate
3. **Ephemeral key generation** - A new ECDSA P-256 or Ed25519 key is generated per signing operation
4. **DSSE signing** - The payload is signed using the ephemeral key
5. **Certificate attached** - The Fulcio certificate is included in the signed bundle for verification
## Configuration
### Basic Configuration
```yaml
# etc/signer.yaml
signer:
signing:
mode: "keyless"
keyless:
enabled: true
fulcio:
url: "https://fulcio.sigstore.dev"
timeout: 30s
retries: 3
oidc:
useAmbientToken: true
```
### Private Fulcio Instance
For air-gapped or private deployments:
```yaml
signer:
signing:
keyless:
fulcio:
url: "https://fulcio.internal.example.com"
certificate:
rootBundlePath: "/etc/stellaops/fulcio-roots.pem"
additionalRoots:
- |
-----BEGIN CERTIFICATE-----
MIIBjzCCATSgAwIBAgIRANZl...
-----END CERTIFICATE-----
```
### Identity Constraints
Restrict which identities are allowed to sign:
```yaml
signer:
signing:
keyless:
identity:
expectedIssuers:
- "https://token.actions.githubusercontent.com"
- "https://gitlab.com"
expectedSubjectPatterns:
- "^https://github\.com/myorg/.*$"
- "^project_path:mygroup/myproject:.*$"
```
## CI/CD Integration
### GitHub Actions
```yaml
name: Sign Artifacts
on: [push]
jobs:
sign:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC token
contents: read
steps:
- uses: actions/checkout@v4
- name: Install StellaOps CLI
run: |
curl -sSL https://get.stella-ops.io | bash
- name: Sign with keyless mode
run: |
stella sign --mode keyless \
--image ghcr.io/${{ github.repository }}:${{ github.sha }}
```
### GitLab CI
```yaml
sign:
image: registry.stella-ops.io/cli:latest
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- stella sign --mode keyless --image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
```
## Algorithm Support
| Algorithm | Status | Use Case |
|-----------|--------|----------|
| ECDSA P-256 | Preferred | Default, widest compatibility |
| Ed25519 | Supported | Better performance, growing adoption |
Configure preferred algorithm:
```yaml
signer:
signing:
keyless:
algorithms:
preferred: "ECDSA_P256"
allowed: ["ECDSA_P256", "Ed25519"]
```
## Signed Bundle Format
The keyless signing produces a DSSE envelope with embedded certificate:
```json
{
"payloadType": "application/vnd.in-toto+json",
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEi...",
"signatures": [
{
"keyid": "",
"sig": "MEUCIQD..."
}
],
"certificateChain": [
"-----BEGIN CERTIFICATE-----\nMIIC...",
"-----BEGIN CERTIFICATE-----\nMIIB..."
],
"signingMode": "keyless",
"signingIdentity": {
"issuer": "https://token.actions.githubusercontent.com",
"subject": "https://github.com/org/repo/.github/workflows/ci.yml@refs/heads/main"
}
}
```
## Verification
Bundles signed with keyless mode can be verified using:
```bash
# Verify a signed bundle
stella verify --bundle verdict.json \
--expected-issuer "https://token.actions.githubusercontent.com" \
--expected-subject "https://github.com/myorg/myrepo/*"
```
The verification process:
1. Validates the certificate chain to Fulcio roots
2. Verifies the signature using the certificate's public key
3. Checks identity claims match expectations
4. Optionally validates SCT (Signed Certificate Timestamp)
## Troubleshooting
### Common Issues
**OIDC token not available**
- Ensure id-token: write permission in GitHub Actions
- Ensure id_tokens is configured in GitLab CI
- Check ACTIONS_ID_TOKEN_REQUEST_URL environment variable
**Fulcio returns 401**
- OIDC token may have expired (default 5-10 min validity)
- Audience mismatch - ensure token is for sigstore
- Issuer not trusted by Fulcio instance
**Certificate chain validation failed**
- Root certificate bundle may be outdated
- Private Fulcio instance roots not configured
- Certificate expired (Fulcio certs are ~10 min TTL)
### Debug Logging
Enable verbose logging:
```bash
STELLAOPS_LOG_LEVEL=debug stella sign --mode keyless ...
```
## Security Considerations
1. **Ephemeral keys never persist** - Keys exist only in memory during signing
2. **Short-lived certificates** - ~10 minute validity limits exposure window
3. **Identity verification** - Always configure expectedIssuers and expectedSubjectPatterns in production
4. **SCT validation** - Enable requireSct: true for public Fulcio instances
## Related Documentation
- [Signer Architecture](../architecture.md)
- [DSSE Envelope Format](../dsse-format.md)
- [CI/CD Gate Integration](../../policy/guides/cicd-gates.md)
- [Sigstore Documentation](https://docs.sigstore.dev/)

View File

@@ -1,30 +0,0 @@
# Signer Implementation Plan
## Purpose
Define a concise, living plan for Signer DSSE signing, predicate registry, and attestor alignment.
## Active work
- `docs/implplan/SPRINT_20260112_015_SIGNER_path_witness_predicate.md`
## Near-term deliverables
- Register canonical path-witness predicate `https://stella.ops/predicates/path-witness/v1` with alias support.
- Update predicate classification helpers and allowlists for reachability types.
- Expand predicate allowlist tests and integration coverage for DSSE signing.
- Maintain cosign-compatible DSSE outputs with deterministic canonical JSON.
## Dependencies
- Authority for OpTok and Proof-of-Entitlement checks.
- Crypto provider registry and keyless or KMS backends.
- Attestor and Policy verification rules for accepted predicate types.
- Path witness contract updates in `docs/contracts/witness-v1.md`.
## Evidence of completion
- Predicate catalog updates in `src/Signer/StellaOps.Signer/StellaOps.Signer.Core/PredicateTypes.cs`.
- Tests updated under `src/Signer/__Tests`.
- DSSE bundles for path witness validate under Signer allowlist rules.
## Reference docs
- `docs/modules/signer/README.md`
- `docs/modules/signer/architecture.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/contracts/witness-v1.md`