up
This commit is contained in:
@@ -10,6 +10,12 @@ passwordPolicy:
|
||||
requireDigit: true
|
||||
requireSymbol: true
|
||||
|
||||
passwordHashing:
|
||||
algorithm: "Argon2id"
|
||||
memorySizeInKib: 19456
|
||||
iterations: 2
|
||||
parallelism: 1
|
||||
|
||||
lockout:
|
||||
enabled: true
|
||||
maxAttempts: 5
|
||||
|
||||
@@ -23,6 +23,25 @@ storage:
|
||||
# databaseName: "stellaops_authority"
|
||||
commandTimeout: "00:00:30"
|
||||
|
||||
# Signing configuration for revocation bundles and JWKS.
|
||||
signing:
|
||||
enabled: true
|
||||
activeKeyId: "authority-signing-2025-dev"
|
||||
keyPath: "../certificates/authority-signing-2025-dev.pem"
|
||||
algorithm: "ES256"
|
||||
keySource: "file"
|
||||
# provider: "default"
|
||||
additionalKeys:
|
||||
- keyId: "authority-signing-dev"
|
||||
path: "../certificates/authority-signing-dev.pem"
|
||||
source: "file"
|
||||
# Rotation flow:
|
||||
# 1. Generate a new PEM under ./certificates (e.g. authority-signing-2026-dev.pem).
|
||||
# 2. Trigger the .gitea/workflows/authority-key-rotation.yml workflow (or run
|
||||
# ops/authority/key-rotation.sh) with the new keyId/keyPath.
|
||||
# 3. Update activeKeyId/keyPath above and move the previous key into additionalKeys
|
||||
# so restarts retain retired material for JWKS consumers.
|
||||
|
||||
# Bootstrap administrative endpoints (initial provisioning).
|
||||
bootstrap:
|
||||
enabled: false
|
||||
|
||||
165
etc/authority/revocation_bundle.schema.json
Normal file
165
etc/authority/revocation_bundle.schema.json
Normal file
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://stella-ops.org/schemas/revocation-bundle.json",
|
||||
"title": "StellaOps Authority Revocation Bundle",
|
||||
"description": "Canonical representation of revoked tokens, clients, and principals distributed to offline mirrors.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"issuer",
|
||||
"issuedAt",
|
||||
"sequence",
|
||||
"revocations"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "string",
|
||||
"pattern": "^1\\.0\\.[0-9]+$",
|
||||
"description": "SemVer of the bundle schema. Major version bumps indicate breaking changes."
|
||||
},
|
||||
"issuer": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Canonical issuer URL of the Authority instance producing the bundle."
|
||||
},
|
||||
"bundleId": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-f0-9]{16,64}$",
|
||||
"description": "Deterministic identifier for this bundle revision (e.g. SHA-256 hex)."
|
||||
},
|
||||
"issuedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp when the bundle was emitted."
|
||||
},
|
||||
"validFrom": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp when consumers should begin enforcing entries."
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Optional expiry after which consumers must fetch a newer bundle."
|
||||
},
|
||||
"sequence": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Monotonic sequence number. Consumers MUST ignore bundles with lower sequence values."
|
||||
},
|
||||
"signingKeyId": {
|
||||
"type": "string",
|
||||
"description": "Key identifier (kid) used for the detached JWS signature."
|
||||
},
|
||||
"revocations": {
|
||||
"type": "array",
|
||||
"description": "Deterministically sorted revocation entries.",
|
||||
"items": { "$ref": "#/$defs/revocationEntry" }
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"description": "Additional producer metadata (operator, environment, export job id).",
|
||||
"additionalProperties": {
|
||||
"type": ["string", "number", "boolean", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"revocationEntry": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "category", "revokedAt"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 4,
|
||||
"description": "Primary identifier for the revoked entity (token id, subject id, client id, or key id)."
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": ["token", "subject", "client", "key"],
|
||||
"description": "Scope of the revocation entry."
|
||||
},
|
||||
"tokenType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"access_token",
|
||||
"refresh_token",
|
||||
"authorization_code",
|
||||
"device_code"
|
||||
],
|
||||
"description": "Token type impacted by the revocation (required when category == 'token')."
|
||||
},
|
||||
"subjectId": {
|
||||
"type": "string",
|
||||
"description": "Subject identifier impacted (user, service account)."
|
||||
},
|
||||
"clientId": {
|
||||
"type": "string",
|
||||
"description": "OAuth client identifier impacted."
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9_.-]{1,64}$",
|
||||
"description": "Reason code (e.g. compromised, rotation, policy)."
|
||||
},
|
||||
"reasonDescription": {
|
||||
"type": "string",
|
||||
"maxLength": 256,
|
||||
"description": "Human-readable description for operator tooling."
|
||||
},
|
||||
"revokedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp when the entity was revoked."
|
||||
},
|
||||
"effectiveAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp when revocation becomes effective (defaults to revokedAt)."
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Optional expiry after which the revocation no longer applies."
|
||||
},
|
||||
"scopes": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"uniqueItems": true,
|
||||
"description": "Scoped permissions affected (for token revocations)."
|
||||
},
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Fa-f0-9]{64}$",
|
||||
"description": "SHA-256 hash of the revoked credential (optional)."
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"description": "Additional structured metadata to assist consumers (e.g. audit id).",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9_.-]{1,64}$": {
|
||||
"type": ["string", "number", "boolean", "null"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": { "properties": { "category": { "const": "token" } } },
|
||||
"then": { "required": ["tokenType", "clientId"] }
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "category": { "const": "subject" } } },
|
||||
"then": { "required": ["subjectId"] }
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "category": { "const": "client" } } },
|
||||
"then": { "required": ["clientId"] }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,27 @@ authority:
|
||||
clientSecretFile: ""
|
||||
clientScopes:
|
||||
- "feedser.jobs.trigger"
|
||||
resilience:
|
||||
# Enable deterministic retry/backoff when Authority is briefly unavailable.
|
||||
enableRetries: true
|
||||
retryDelays:
|
||||
- "00:00:01"
|
||||
- "00:00:02"
|
||||
- "00:00:05"
|
||||
# Allow stale discovery/JWKS responses when Authority is offline (extend tolerance as needed for air-gapped mirrors).
|
||||
allowOfflineCacheFallback: true
|
||||
offlineCacheTolerance: "00:10:00"
|
||||
# Networks allowed to bypass authentication (loopback by default for on-host cron jobs).
|
||||
bypassNetworks:
|
||||
- "127.0.0.1/32"
|
||||
- "::1/128"
|
||||
|
||||
sources:
|
||||
ghsa:
|
||||
apiToken: "${GITHUB_PAT}"
|
||||
pageSize: 50
|
||||
maxPagesPerFetch: 5
|
||||
requestDelay: "00:00:00.200"
|
||||
failureBackoff: "00:05:00"
|
||||
rateLimitWarningThreshold: 500
|
||||
secondaryRateLimitBackoff: "00:02:00"
|
||||
|
||||
Reference in New Issue
Block a user