checkId: check.agent.certificate.validity plugin: stellaops.doctor.agent severity: fail tags: [agent, certificate, security]

Agent Certificate Validity

This Stella Ops Doctor diagnostic proves that each registered agent presents a certificate that is not merely unexpired, but is also trusted, complete, and unrevoked. It is the chain-of-trust companion to check.agent.certificate.expiry, and is aimed at operators hardening agent-to-orchestrator mTLS.

What It Checks

Validates the trust anchor configuration, registered agent certificate thumbprints, and persisted per-agent certificate PEM bundles.

  1. Trust-anchor bundle health. When Doctor:Agent:TrustRootPath is configured, the check loads the file and verifies it parses as an X509 certificate, has not expired, and is not expiring within 30 days.
  2. Thumbprint hygiene. Every active (non-Inactive, non-Revoked) agent must have a registered SHA-256 (or legacy SHA-1) hex thumbprint, and no two agents may share the same thumbprint.
  3. Per-agent pinned chain validation. The ReleaseOrchestrator agent store retains the most recent issued certificate PEM or certificate bundle for each agent. Doctor loads that certificate material, matches it to the registered thumbprint, and builds an X509Chain with Doctor:Agent:TrustRootPath as the custom trust store. UntrustedRoot, PartialChain, NotTimeValid, and Revoked statuses fail the check.
  4. Per-agent revocation/identity probe. When IAgentCertificateService is resolvable, the check also calls ValidateAsync(thumbprint) for each registered thumbprint so orchestrator-local revocations remain visible.

In sealed or forced-offline mode (Doctor:OfflineProfile=true or AirGap sealed), the chain uses RevocationMode=NoCheck and does not fetch CRL/OCSP material from the network. In non-sealed mode it uses RevocationMode=Online, allowing the platform to consult OCSP/CRL endpoints when certificates expose them.

The persisted PEM is certificate material only. Private key PEM must never be stored; stores reject PEM that contains private key blocks. Treat the certificate bundle as controlled operational metadata because it identifies agent identities and issuing topology, even though it is not secret key material.

The check requires IAgentStore to be registered in DI; otherwise it will not run.

Evidence collected

Why It Matters

A valid certificate expiry date (checked by check.agent.certificate.expiry) is necessary but not sufficient. An agent could present a non-expired certificate that was signed by an untrusted CA, has a broken chain, or has been revoked. Any of these conditions would allow an impersonating agent to receive task dispatches or exfiltrate deployment secrets.

Common Causes

How to Fix

Docker Compose

# Inspect agent certificate chain
docker compose -f devops/compose/docker-compose.stella-ops.yml exec agent \
  openssl x509 -in /etc/stellaops/agent/tls.crt -text -noout

# Verify chain against CA bundle
docker compose -f devops/compose/docker-compose.stella-ops.yml exec agent \
  openssl verify -CAfile /etc/stellaops/ca/ca.crt /etc/stellaops/agent/tls.crt

Bare Metal / systemd

# Inspect agent certificate
openssl x509 -in /etc/stellaops/agent/tls.crt -text -noout

# Verify certificate chain
openssl verify -CAfile /etc/stellaops/ca/ca.crt -untrusted /etc/stellaops/ca/intermediate.crt \
  /etc/stellaops/agent/tls.crt

# Re-bootstrap if chain is broken
stella agent bootstrap --name <agent-name> --env <environment>

Kubernetes / Helm

# Check certificate in agent pod
kubectl exec -it deploy/stellaops-agent -n stellaops -- \
  openssl x509 -in /etc/stellaops/agent/tls.crt -text -noout

# If using cert-manager, check CertificateRequest status
kubectl get certificaterequest -n stellaops
kubectl describe certificaterequest <name> -n stellaops

Verification

stella doctor run --check check.agent.certificate.validity