Doctor plugin checks: implement health check classes and documentation
Implement remediation-aware health checks across all Doctor plugin modules (Agent, Attestor, Auth, BinaryAnalysis, Compliance, Crypto, Environment, EvidenceLocker, Notify, Observability, Operations, Policy, Postgres, Release, Scanner, Storage, Vex) and their backing library counterparts (AI, Attestation, Authority, Core, Cryptography, Database, Docker, Integration, Notify, Observability, Security, ServiceGraph, Sources, Verification). Each check now emits structured remediation metadata (severity, category, runbook links, and fix suggestions) consumed by the Doctor dashboard remediation panel. Also adds: - docs/doctor/articles/ knowledge base for check explanations - Advisory AI search seed and allowlist updates for doctor content - Sprint plan for doctor checks documentation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
104
docs/doctor/articles/security/jwt-config.md
Normal file
104
docs/doctor/articles/security/jwt-config.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
checkId: check.security.jwt.config
|
||||
plugin: stellaops.doctor.security
|
||||
severity: fail
|
||||
tags: [security, jwt, authentication]
|
||||
---
|
||||
# JWT Configuration
|
||||
|
||||
## What It Checks
|
||||
Validates JWT token signing and validation configuration. The check only runs when a JWT configuration section exists (`Jwt` or `Authentication:Jwt`). It inspects:
|
||||
|
||||
| Setting | Threshold/Condition | Severity |
|
||||
|---|---|---|
|
||||
| `SigningKey` | Not configured | `fail` |
|
||||
| `SigningKey` | Shorter than 32 characters | `fail` |
|
||||
| `Issuer` | Not configured | `fail` |
|
||||
| `Audience` | Not configured | `fail` |
|
||||
| `ExpirationMinutes` | Greater than 1440 (24 hours) | `warn` |
|
||||
| `Algorithm` | `none` | `fail` — completely insecure |
|
||||
| `Algorithm` | `HS256` | `warn` — acceptable but RS256/ES256 recommended |
|
||||
|
||||
Default values if not explicitly set: `ExpirationMinutes` = 60, `Algorithm` = HS256.
|
||||
|
||||
Evidence collected includes: whether a signing key is configured, key length, issuer, audience, expiration minutes, and algorithm.
|
||||
|
||||
## Why It Matters
|
||||
JWT tokens are the primary authentication mechanism for API access. A missing or short signing key allows token forgery. The `none` algorithm disables signature verification entirely. Missing issuer or audience values disable critical validation claims, allowing tokens from other systems to be accepted. Long expiration times increase the window of opportunity if a token is compromised.
|
||||
|
||||
## Common Causes
|
||||
- JWT signing key is not configured in the deployment
|
||||
- JWT signing key is too short (fewer than 32 characters)
|
||||
- JWT issuer or audience not configured
|
||||
- JWT expiration time set too long (more than 24 hours)
|
||||
- Using algorithm `none` which disables all signature verification
|
||||
- Using HS256 symmetric algorithm when asymmetric (RS256/ES256) would be more secure
|
||||
|
||||
## How to Fix
|
||||
|
||||
### Docker Compose
|
||||
Set JWT configuration as environment variables:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
Jwt__SigningKey: "<generate-a-strong-key-at-least-32-chars>"
|
||||
Jwt__Issuer: "https://stella-ops.local"
|
||||
Jwt__Audience: "stellaops-api"
|
||||
Jwt__ExpirationMinutes: "60"
|
||||
Jwt__Algorithm: "RS256"
|
||||
```
|
||||
|
||||
Generate a strong signing key:
|
||||
```bash
|
||||
openssl rand -base64 48
|
||||
```
|
||||
|
||||
### Bare Metal / systemd
|
||||
Edit `appsettings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"Jwt": {
|
||||
"SigningKey": "<strong-key>",
|
||||
"Issuer": "https://stella-ops.yourdomain.com",
|
||||
"Audience": "stellaops-api",
|
||||
"ExpirationMinutes": 60,
|
||||
"Algorithm": "RS256"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For RS256, generate a key pair:
|
||||
```bash
|
||||
openssl genrsa -out jwt-private.pem 2048
|
||||
openssl rsa -in jwt-private.pem -pubout -out jwt-public.pem
|
||||
```
|
||||
|
||||
### Kubernetes / Helm
|
||||
Store the signing key as a Kubernetes Secret:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic stellaops-jwt \
|
||||
--from-literal=signing-key="$(openssl rand -base64 48)"
|
||||
```
|
||||
|
||||
Reference in Helm values:
|
||||
|
||||
```yaml
|
||||
jwt:
|
||||
issuer: "https://stella-ops.yourdomain.com"
|
||||
audience: "stellaops-api"
|
||||
expirationMinutes: 60
|
||||
algorithm: "RS256"
|
||||
signingKeySecret: "stellaops-jwt"
|
||||
```
|
||||
|
||||
## Verification
|
||||
```
|
||||
stella doctor run --check check.security.jwt.config
|
||||
```
|
||||
|
||||
## Related Checks
|
||||
- `check.core.auth.config` — validates broader authentication configuration including JWT
|
||||
- `check.security.secrets` — ensures the JWT signing key is not stored as plain text
|
||||
- `check.security.tls.certificate` — TLS protects JWT tokens in transit
|
||||
Reference in New Issue
Block a user