Add Authority Advisory AI and API Lifecycle Configuration

- Introduced AuthorityAdvisoryAiOptions and related classes for managing advisory AI configurations, including remote inference options and tenant-specific settings.
- Added AuthorityApiLifecycleOptions to control API lifecycle settings, including legacy OAuth endpoint configurations.
- Implemented validation and normalization methods for both advisory AI and API lifecycle options to ensure proper configuration.
- Created AuthorityNotificationsOptions and its related classes for managing notification settings, including ack tokens, webhooks, and escalation options.
- Developed IssuerDirectoryClient and related models for interacting with the issuer directory service, including caching mechanisms and HTTP client configurations.
- Added support for dependency injection through ServiceCollectionExtensions for the Issuer Directory Client.
- Updated project file to include necessary package references for the new Issuer Directory Client library.
This commit is contained in:
master
2025-11-02 13:40:38 +02:00
parent 66cb6c4b8a
commit f98cea3bcf
516 changed files with 68157 additions and 24754 deletions

View File

@@ -152,13 +152,15 @@ clients:
tenants:
- name: "tenant-default"
roles:
orch-viewer:
scopes: [ "orch:read" ]
orch-operator:
scopes: [ "orch:read", "orch:operate" ]
export-viewer:
scopes: [ "export.viewer" ]
roles:
orch-viewer:
scopes: [ "orch:read" ]
orch-operator:
scopes: [ "orch:read", "orch:operate" ]
orch-admin:
scopes: [ "orch:read", "orch:operate", "orch:quota" ]
export-viewer:
scopes: [ "export.viewer" ]
export-operator:
scopes: [ "export.viewer", "export.operator" ]
export-admin:
@@ -169,10 +171,24 @@ tenants:
scopes: [ "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-approver:
scopes: [ "policy:approve", "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-operator:
scopes: [ "policy:operate", "policy:run", "policy:activate", "policy:read", "policy:simulate", "findings:read" ]
policy-auditor:
scopes: [ "policy:audit", "policy:read", "policy:simulate", "findings:read" ]
policy-operator:
scopes: [ "policy:operate", "policy:run", "policy:activate", "policy:read", "policy:simulate", "findings:read" ]
policy-auditor:
scopes: [ "policy:audit", "policy:read", "policy:simulate", "findings:read" ]
advisory-ai-viewer:
scopes: [ "advisory-ai:view" ]
advisory-ai-operator:
scopes: [ "advisory-ai:view", "advisory-ai:operate" ]
advisory-ai-admin:
scopes: [ "advisory-ai:view", "advisory-ai:operate", "advisory-ai:admin" ]
observability-viewer:
scopes: [ "obs:read", "timeline:read", "evidence:read", "attest:read" ]
observability-investigator:
scopes: [ "obs:read", "timeline:read", "timeline:write", "evidence:read", "evidence:create", "attest:read" ]
observability-legal:
scopes: [ "evidence:read", "evidence:hold" ]
observability-incident-commander:
scopes: [ "obs:read", "obs:incident", "timeline:read", "timeline:write", "evidence:create", "evidence:read", "attest:read" ]
security:
rateLimiting:
@@ -191,17 +207,23 @@ security:
memorySizeInKib: 19456
iterations: 2
parallelism: 1
senderConstraints:
dpop:
enabled: true
proofLifetime: "00:05:00"
allowedClockSkew: "00:00:10"
replayWindow: "00:10:00"
nonce:
enabled: false
mtls:
enabled: false
bypassNetworks:
- "127.0.0.1/32"
- "::1/128"
senderConstraints:
dpop:
enabled: true
proofLifetime: "00:05:00"
allowedClockSkew: "00:00:10"
replayWindow: "00:10:00"
nonce:
enabled: false
mtls:
enabled: false
advisoryAi:
remoteInference:
enabled: false
requireTenantConsent: true
allowedProfiles: []
bypassNetworks:
- "127.0.0.1/32"
- "::1/128"

View File

@@ -1,29 +1,29 @@
# StellaOps Authority configuration template.
# Copy to ../etc/authority.yaml (relative to the Authority content root)
# and adjust values to fit your environment. Environment variables
# prefixed with STELLAOPS_AUTHORITY_ override these values at runtime.
# Example: STELLAOPS_AUTHORITY__ISSUER=https://authority.example.com
schemaVersion: 1
# Absolute issuer URI advertised to clients. Use HTTPS for anything
# beyond loopback development.
issuer: "https://authority.stella-ops.local"
# Token lifetimes expressed as HH:MM:SS or DD.HH:MM:SS.
accessTokenLifetime: "00:02:00"
refreshTokenLifetime: "30.00:00:00"
identityTokenLifetime: "00:05:00"
authorizationCodeLifetime: "00:05:00"
deviceCodeLifetime: "00:15:00"
# MongoDB storage connection details.
storage:
connectionString: "mongodb://localhost:27017/stellaops-authority"
# databaseName: "stellaops_authority"
commandTimeout: "00:00:30"
# Signing configuration for revocation bundles and JWKS.
# StellaOps Authority configuration template.
# Copy to ../etc/authority.yaml (relative to the Authority content root)
# and adjust values to fit your environment. Environment variables
# prefixed with STELLAOPS_AUTHORITY_ override these values at runtime.
# Example: STELLAOPS_AUTHORITY__ISSUER=https://authority.example.com
schemaVersion: 1
# Absolute issuer URI advertised to clients. Use HTTPS for anything
# beyond loopback development.
issuer: "https://authority.stella-ops.local"
# Token lifetimes expressed as HH:MM:SS or DD.HH:MM:SS.
accessTokenLifetime: "00:02:00"
refreshTokenLifetime: "30.00:00:00"
identityTokenLifetime: "00:05:00"
authorizationCodeLifetime: "00:05:00"
deviceCodeLifetime: "00:15:00"
# MongoDB storage connection details.
storage:
connectionString: "mongodb://localhost:27017/stellaops-authority"
# databaseName: "stellaops_authority"
commandTimeout: "00:00:30"
# Signing configuration for revocation bundles and JWKS.
signing:
enabled: true
activeKeyId: "authority-signing-2025-dev"
@@ -36,303 +36,481 @@ signing:
- 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
apiKey: "change-me"
defaultIdentityProvider: "standard"
# Directories scanned for Authority plug-ins. Relative paths resolve
# against the application content root, enabling air-gapped deployments
# that package plug-ins alongside binaries.
pluginDirectories:
- "../StellaOps.Authority.PluginBinaries"
# "/var/lib/stellaops/authority/plugins"
# Plug-in manifests live in descriptors below; per-plugin settings are stored
# in the configurationDirectory (YAML files). Authority will load any enabled
# plugins and surface their metadata/capabilities to the host.
plugins:
configurationDirectory: "../etc/authority.plugins"
descriptors:
standard:
type: "standard"
assemblyName: "StellaOps.Authority.Plugin.Standard"
enabled: true
configFile: "standard.yaml"
capabilities:
- password
- bootstrap
- clientProvisioning
metadata:
defaultRole: "operators"
# Example for an external identity provider plugin. Leave disabled unless
# the plug-in package exists under StellaOps.Authority.PluginBinaries.
ldap:
type: "ldap"
assemblyName: "StellaOps.Authority.Plugin.Ldap"
enabled: false
configFile: "ldap.yaml"
capabilities:
- password
- mfa
# OAuth client registrations issued by Authority. These examples cover Notify WebService
# in dev (notify.dev audience) and production (notify audience). Replace the secret files
# with paths to your sealed credentials before enabling bootstrap mode.
clients:
- clientId: "notify-web-dev"
displayName: "Notify WebService (dev)"
grantTypes: [ "client_credentials" ]
audiences: [ "notify.dev" ]
scopes: [ "notify.read", "notify.admin" ]
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-web-dev.secret"
- clientId: "notify-web"
displayName: "Notify WebService"
grantTypes: [ "client_credentials" ]
audiences: [ "notify" ]
scopes: [ "notify.read", "notify.admin" ]
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-web.secret"
- clientId: "concelier-ingest"
displayName: "Concelier Ingestion"
grantTypes: [ "client_credentials" ]
audiences: [ "api://concelier" ]
scopes: [ "advisory:ingest", "advisory:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/concelier-ingest.secret"
- clientId: "excitor-ingest"
displayName: "Excititor VEX Ingestion"
grantTypes: [ "client_credentials" ]
audiences: [ "api://excitor" ]
scopes: [ "vex:ingest", "vex:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/excitor-ingest.secret"
- clientId: "aoc-verifier"
displayName: "AOC Verification Agent"
grantTypes: [ "client_credentials" ]
audiences: [ "api://concelier", "api://excitor" ]
scopes: [ "aoc:verify", "advisory:read", "vex:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/aoc-verifier.secret"
- clientId: "policy-engine"
displayName: "Policy Engine Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "policy:run", "findings:read", "effective:write" ]
tenant: "tenant-default"
properties:
serviceIdentity: "policy-engine"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/policy-engine.secret"
- clientId: "policy-cli"
displayName: "Policy Automation CLI"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "policy:read", "policy:author", "policy:review", "policy:simulate", "findings:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/policy-cli.secret"
- clientId: "exceptions-service"
displayName: "Policy Engine Exceptions Worker"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "exceptions:read", "exceptions:write" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/exceptions-service.secret"
- clientId: "console-web"
displayName: "StellaOps Console"
grantTypes: [ "authorization_code", "refresh_token" ]
audiences: [ "console" ]
scopes: [ "openid", "profile", "email", "ui.read", "authority:tenants.read", "advisory:read", "vex:read", "exceptions:read", "exceptions:approve", "aoc:verify", "findings:read", "orch:read", "vuln:read" ]
# exceptions:approve is elevated via fresh-auth and requires an MFA-capable identity provider.
tenant: "tenant-default"
senderConstraint: "dpop"
redirectUris:
- "https://console.stella-ops.local/oidc/callback"
postLogoutRedirectUris:
- "https://console.stella-ops.local/"
# Gateway must forward X-Stella-Tenant for /console endpoints; fresh-auth window (300s)
# returned by /console/profile governs admin actions in the Console UI.
auth:
type: "client_secret"
secretFile: "../secrets/console-web.secret"
- clientId: "cartographer-service"
displayName: "Cartographer Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://cartographer" ]
scopes: [ "graph:write", "graph:read" ]
tenant: "tenant-default"
properties:
serviceIdentity: "cartographer"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/cartographer-service.secret"
- clientId: "graph-api"
displayName: "Graph API Gateway"
grantTypes: [ "client_credentials" ]
audiences: [ "api://graph-api" ]
scopes: [ "graph:read", "graph:export", "graph:simulate" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/graph-api.secret"
- clientId: "export-center-operator"
displayName: "Export Center Operator"
grantTypes: [ "client_credentials" ]
audiences: [ "api://export-center" ]
scopes: [ "export.viewer", "export.operator" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/export-center-operator.secret"
- clientId: "export-center-admin"
displayName: "Export Center Admin"
grantTypes: [ "client_credentials" ]
audiences: [ "api://export-center" ]
scopes: [ "export.viewer", "export.operator", "export.admin" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/export-center-admin.secret"
- clientId: "vuln-explorer-ui"
displayName: "Vuln Explorer UI"
grantTypes: [ "client_credentials" ]
audiences: [ "api://vuln-explorer" ]
scopes: [ "vuln:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/vuln-explorer-ui.secret"
# Signals sensors must request aoc:verify alongside write scope.
- clientId: "signals-uploader"
displayName: "Signals Sensor"
grantTypes: [ "client_credentials" ]
audiences: [ "api://signals" ]
scopes: [ "signals:write", "signals:read", "aoc:verify" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/signals-uploader.secret"
tenants:
- name: "tenant-default"
roles:
orch-viewer:
scopes: [ "orch:read" ]
orch-operator:
scopes: [ "orch:read", "orch:operate" ]
policy-author:
scopes: [ "policy:author", "policy:read", "policy:simulate", "findings:read" ]
policy-reviewer:
scopes: [ "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-approver:
scopes: [ "policy:approve", "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-operator:
scopes: [ "policy:operate", "policy:run", "policy:activate", "policy:read", "policy:simulate", "findings:read" ]
policy-auditor:
scopes: [ "policy:audit", "policy:read", "policy:simulate", "findings:read" ]
export-viewer:
scopes: [ "export.viewer" ]
export-operator:
scopes: [ "export.viewer", "export.operator" ]
export-admin:
scopes: [ "export.viewer", "export.operator", "export.admin" ]
# Exception approval routing templates used by Policy Engine and Console.
exceptions:
routingTemplates:
- id: "secops"
authorityRouteId: "approvals/secops"
requireMfa: true
description: "Security Operations approval chain"
- id: "governance"
authorityRouteId: "approvals/governance"
requireMfa: false
description: "Governance review (non-production)"
# CIDR ranges that bypass network-sensitive policies (e.g. on-host cron jobs).
# Keep the list tight: localhost is sufficient for most air-gapped installs.
bypassNetworks:
- "127.0.0.1/32"
- "::1/128"
# Security posture (rate limiting + sender constraints).
security:
rateLimiting:
token:
enabled: true
permitLimit: 30
window: "00:01:00"
queueLimit: 0
authorize:
enabled: true
permitLimit: 60
window: "00:01:00"
queueLimit: 10
internal:
enabled: false
permitLimit: 5
window: "00:01:00"
queueLimit: 0
senderConstraints:
dpop:
enabled: true
allowedAlgorithms: [ "ES256", "ES384" ]
proofLifetime: "00:02:00"
allowedClockSkew: "00:00:30"
replayWindow: "00:05:00"
nonce:
enabled: true
ttl: "00:10:00"
maxIssuancePerMinute: 120
store: "memory" # Set to "redis" for multi-node Authority deployments.
requiredAudiences:
- "signer"
- "attestor"
# redisConnectionString: "redis://authority-redis:6379?ssl=false"
mtls:
enabled: false
requireChainValidation: true
rotationGrace: "00:15:00"
enforceForAudiences:
- "signer" # Requests for these audiences force mTLS sender constraints
allowedSanTypes:
- "dns"
- "uri"
allowedCertificateAuthorities: [ ]
allowedSubjectPatterns: [ ]
# 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.
notifications:
ackTokens:
enabled: true
payloadType: "application/vnd.stellaops.notify-ack-token+json"
defaultLifetime: "00:15:00"
maxLifetime: "00:30:00"
algorithm: "ES256"
keySource: "file"
activeKeyId: "notify-ack-2025-dev"
keyPath: "../certificates/notify-ack-2025-dev.pem"
keyUse: "notify-ack"
jwksCacheLifetime: "00:05:00"
additionalKeys: []
webhooks:
enabled: true
allowedHosts:
- "hooks.slack.com"
- "*.pagerduty.com"
escalation:
scope: "notify.escalate"
requireAdminScope: true
apiLifecycle:
legacyAuth:
enabled: true
deprecationDate: "2025-11-01T00:00:00Z"
sunsetDate: "2026-05-01T00:00:00Z"
documentationUrl: "https://docs.stella-ops.org/migrations/authority/legacy-auth-endpoints"
notificationTopic: "authority.api.deprecation"
advisoryAi:
remoteInference:
enabled: false
requireTenantConsent: true
allowedProfiles:
- "cloud-openai"
- "sovereign-local"
# Bootstrap administrative endpoints (initial provisioning).
bootstrap:
enabled: false
apiKey: "change-me"
defaultIdentityProvider: "standard"
# Directories scanned for Authority plug-ins. Relative paths resolve
# against the application content root, enabling air-gapped deployments
# that package plug-ins alongside binaries.
pluginDirectories:
- "../StellaOps.Authority.PluginBinaries"
# "/var/lib/stellaops/authority/plugins"
# Plug-in manifests live in descriptors below; per-plugin settings are stored
# in the configurationDirectory (YAML files). Authority will load any enabled
# plugins and surface their metadata/capabilities to the host.
plugins:
configurationDirectory: "../etc/authority.plugins"
descriptors:
standard:
type: "standard"
assemblyName: "StellaOps.Authority.Plugin.Standard"
enabled: true
configFile: "standard.yaml"
capabilities:
- password
- bootstrap
- clientProvisioning
metadata:
defaultRole: "operators"
# Example for an external identity provider plugin. Leave disabled unless
# the plug-in package exists under StellaOps.Authority.PluginBinaries.
ldap:
type: "ldap"
assemblyName: "StellaOps.Authority.Plugin.Ldap"
enabled: false
configFile: "ldap.yaml"
capabilities:
- password
- mfa
# OAuth client registrations issued by Authority. These examples cover Notify WebService
# in dev (notify.dev audience) and production (notify audience). Replace the secret files
# with paths to your sealed credentials before enabling bootstrap mode.
clients:
- clientId: "notify-web-dev"
displayName: "Notify WebService (dev)"
grantTypes: [ "client_credentials" ]
audiences: [ "notify.dev" ]
scopes: [ "notify.read", "notify.admin" ]
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-web-dev.secret"
- clientId: "notify-web"
displayName: "Notify WebService"
grantTypes: [ "client_credentials" ]
audiences: [ "notify" ]
scopes: [ "notify.read", "notify.admin" ]
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-web.secret"
- clientId: "concelier-ingest"
displayName: "Concelier Ingestion"
grantTypes: [ "client_credentials" ]
audiences: [ "api://concelier" ]
scopes: [ "advisory:ingest", "advisory:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/concelier-ingest.secret"
- clientId: "excitor-ingest"
displayName: "Excititor VEX Ingestion"
grantTypes: [ "client_credentials" ]
audiences: [ "api://excitor" ]
scopes: [ "vex:ingest", "vex:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/excitor-ingest.secret"
- clientId: "aoc-verifier"
displayName: "AOC Verification Agent"
grantTypes: [ "client_credentials" ]
audiences: [ "api://concelier", "api://excitor" ]
scopes: [ "aoc:verify", "advisory:read", "vex:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/aoc-verifier.secret"
- clientId: "airgap-operator"
displayName: "AirGap Operations CLI"
grantTypes: [ "client_credentials" ]
audiences: [ "api://airgap-controller", "api://airgap-importer" ]
scopes: [ "airgap:status:read", "airgap:import", "airgap:seal" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/airgap-operator.secret"
- clientId: "policy-engine"
displayName: "Policy Engine Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "policy:run", "findings:read", "effective:write" ]
tenant: "tenant-default"
properties:
serviceIdentity: "policy-engine"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/policy-engine.secret"
- clientId: "policy-cli"
displayName: "Policy Automation CLI"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "policy:read", "policy:author", "policy:review", "policy:simulate", "findings:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/policy-cli.secret"
- clientId: "exceptions-service"
displayName: "Policy Engine Exceptions Worker"
grantTypes: [ "client_credentials" ]
audiences: [ "api://policy-engine" ]
scopes: [ "exceptions:read", "exceptions:write" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/exceptions-service.secret"
- clientId: "console-web"
displayName: "StellaOps Console"
grantTypes: [ "authorization_code", "refresh_token" ]
audiences: [ "console" ]
scopes: [ "openid", "profile", "email", "ui.read", "authority:tenants.read", "advisory:read", "vex:read", "exceptions:read", "exceptions:approve", "aoc:verify", "findings:read", "airgap:status:read", "obs:read", "obs:incident", "timeline:read", "evidence:read", "attest:read", "orch:read", "vuln:read" ]
# exceptions:approve is elevated via fresh-auth and requires an MFA-capable identity provider.
tenant: "tenant-default"
senderConstraint: "dpop"
redirectUris:
- "https://console.stella-ops.local/oidc/callback"
postLogoutRedirectUris:
- "https://console.stella-ops.local/"
# Gateway must forward X-Stella-Tenant for /console endpoints; fresh-auth window (300s)
# returned by /console/profile governs admin actions in the Console UI.
auth:
type: "client_secret"
secretFile: "../secrets/console-web.secret"
- clientId: "cartographer-service"
displayName: "Cartographer Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://cartographer" ]
scopes: [ "graph:write", "graph:read" ]
tenant: "tenant-default"
properties:
serviceIdentity: "cartographer"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/cartographer-service.secret"
- clientId: "packs-registry"
displayName: "Packs Registry Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://packs-registry" ]
scopes: [ "packs.read", "packs.write" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/packs-registry.secret"
- clientId: "task-runner"
displayName: "Task Runner Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://task-runner" ]
scopes: [ "packs.run", "packs.read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/task-runner.secret"
- clientId: "pack-approver"
displayName: "Pack Approver Automation"
grantTypes: [ "client_credentials" ]
audiences: [ "api://task-runner" ]
scopes: [ "packs.approve", "packs.read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/pack-approver.secret"
- clientId: "graph-api"
displayName: "Graph API Gateway"
grantTypes: [ "client_credentials" ]
audiences: [ "api://graph-api" ]
scopes: [ "graph:read", "graph:export", "graph:simulate" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/graph-api.secret"
- clientId: "export-center-operator"
displayName: "Export Center Operator"
grantTypes: [ "client_credentials" ]
audiences: [ "api://export-center" ]
scopes: [ "export.viewer", "export.operator" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/export-center-operator.secret"
- clientId: "export-center-admin"
displayName: "Export Center Admin"
grantTypes: [ "client_credentials" ]
audiences: [ "api://export-center" ]
scopes: [ "export.viewer", "export.operator", "export.admin" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/export-center-admin.secret"
- clientId: "notify-service"
displayName: "Notify WebService"
grantTypes: [ "client_credentials" ]
audiences: [ "api://notify" ]
scopes: [ "notify.viewer", "notify.operator" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-service.secret"
- clientId: "notify-admin"
displayName: "Notify Admin Automation"
grantTypes: [ "client_credentials" ]
audiences: [ "api://notify" ]
scopes: [ "notify.viewer", "notify.operator", "notify.admin" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/notify-admin.secret"
- clientId: "observability-web"
displayName: "Observability Console Backend"
grantTypes: [ "client_credentials" ]
audiences: [ "api://observability" ]
scopes: [ "obs:read", "timeline:read", "evidence:read", "attest:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/observability-web.secret"
- clientId: "timeline-indexer"
displayName: "Timeline Indexer Worker"
grantTypes: [ "client_credentials" ]
audiences: [ "api://timeline" ]
scopes: [ "timeline:write", "timeline:read", "obs:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/timeline-indexer.secret"
- clientId: "evidence-locker"
displayName: "Evidence Locker Service"
grantTypes: [ "client_credentials" ]
audiences: [ "api://evidence" ]
scopes: [ "evidence:create", "evidence:read", "evidence:hold" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/evidence-locker.secret"
- clientId: "incident-bridge"
displayName: "Incident Bridge Automation"
grantTypes: [ "client_credentials" ]
audiences: [ "api://observability" ]
scopes: [ "obs:incident", "obs:read", "timeline:read", "timeline:write", "evidence:create" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/incident-bridge.secret"
- clientId: "vuln-explorer-ui"
displayName: "Vuln Explorer UI"
grantTypes: [ "client_credentials" ]
audiences: [ "api://vuln-explorer" ]
scopes: [ "vuln:read" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/vuln-explorer-ui.secret"
# Signals sensors must request aoc:verify alongside write scope.
- clientId: "signals-uploader"
displayName: "Signals Sensor"
grantTypes: [ "client_credentials" ]
audiences: [ "api://signals" ]
scopes: [ "signals:write", "signals:read", "aoc:verify" ]
tenant: "tenant-default"
senderConstraint: "dpop"
auth:
type: "client_secret"
secretFile: "../secrets/signals-uploader.secret"
tenants:
- name: "tenant-default"
roles:
orch-viewer:
scopes: [ "orch:read" ]
orch-operator:
scopes: [ "orch:read", "orch:operate" ]
orch-admin:
scopes: [ "orch:read", "orch:operate", "orch:quota" ]
policy-author:
scopes: [ "policy:author", "policy:read", "policy:simulate", "findings:read" ]
policy-reviewer:
scopes: [ "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-approver:
scopes: [ "policy:approve", "policy:review", "policy:read", "policy:simulate", "findings:read" ]
policy-operator:
scopes: [ "policy:operate", "policy:run", "policy:activate", "policy:read", "policy:simulate", "findings:read" ]
policy-auditor:
scopes: [ "policy:audit", "policy:read", "policy:simulate", "findings:read" ]
export-viewer:
scopes: [ "export.viewer" ]
export-operator:
scopes: [ "export.viewer", "export.operator" ]
export-admin:
scopes: [ "export.viewer", "export.operator", "export.admin" ]
notify-viewer:
scopes: [ "notify.viewer" ]
notify-operator:
scopes: [ "notify.viewer", "notify.operator" ]
notify-admin:
scopes: [ "notify.viewer", "notify.operator", "notify.admin" ]
observability-viewer:
scopes: [ "obs:read", "timeline:read", "evidence:read", "attest:read" ]
observability-investigator:
scopes: [ "obs:read", "timeline:read", "timeline:write", "evidence:read", "evidence:create", "attest:read" ]
observability-legal:
scopes: [ "evidence:read", "evidence:hold" ]
observability-incident-commander:
scopes: [ "obs:read", "obs:incident", "timeline:read", "timeline:write", "evidence:create", "evidence:read", "attest:read" ]
airgap-viewer:
scopes: [ "airgap:status:read" ]
airgap-operator:
scopes: [ "airgap:status:read", "airgap:import" ]
airgap-admin:
scopes: [ "airgap:status:read", "airgap:import", "airgap:seal" ]
advisory-ai-viewer:
scopes: [ "advisory-ai:view" ]
advisory-ai-operator:
scopes: [ "advisory-ai:view", "advisory-ai:operate" ]
advisory-ai-admin:
scopes: [ "advisory-ai:view", "advisory-ai:operate", "advisory-ai:admin" ]
advisoryAi:
remoteInference:
consentGranted: false
consentVersion: ""
consentedAt: ""
consentedBy: ""
# Exception approval routing templates used by Policy Engine and Console.
exceptions:
routingTemplates:
- id: "secops"
authorityRouteId: "approvals/secops"
requireMfa: true
description: "Security Operations approval chain"
- id: "governance"
authorityRouteId: "approvals/governance"
requireMfa: false
description: "Governance review (non-production)"
# CIDR ranges that bypass network-sensitive policies (e.g. on-host cron jobs).
# Keep the list tight: localhost is sufficient for most air-gapped installs.
bypassNetworks:
- "127.0.0.1/32"
- "::1/128"
# Security posture (rate limiting + sender constraints).
security:
rateLimiting:
token:
enabled: true
permitLimit: 30
window: "00:01:00"
queueLimit: 0
authorize:
enabled: true
permitLimit: 60
window: "00:01:00"
queueLimit: 10
internal:
enabled: false
permitLimit: 5
window: "00:01:00"
queueLimit: 0
senderConstraints:
dpop:
enabled: true
allowedAlgorithms: [ "ES256", "ES384" ]
proofLifetime: "00:02:00"
allowedClockSkew: "00:00:30"
replayWindow: "00:05:00"
nonce:
enabled: true
ttl: "00:10:00"
maxIssuancePerMinute: 120
store: "memory" # Set to "redis" for multi-node Authority deployments.
requiredAudiences:
- "signer"
- "attestor"
# redisConnectionString: "redis://authority-redis:6379?ssl=false"
mtls:
enabled: false
requireChainValidation: true
rotationGrace: "00:15:00"
enforceForAudiences:
- "signer" # Requests for these audiences force mTLS sender constraints
allowedSanTypes:
- "dns"
- "uri"
allowedCertificateAuthorities: [ ]
allowedSubjectPatterns: [ ]
advisoryAi:
remoteInference:
enabled: false
requireTenantConsent: true
allowedProfiles: []

View File

@@ -0,0 +1,22 @@
IssuerDirectory:
telemetry:
minimumLogLevel: Information
authority:
enabled: true
issuer: https://authority.example.com/realms/stellaops
requireHttpsMetadata: true
audiences:
- stellaops-platform
readScope: issuer-directory:read
writeScope: issuer-directory:write
adminScope: issuer-directory:admin
tenantHeader: X-StellaOps-Tenant
seedCsafPublishers: true
csafSeedPath: data/csaf-publishers.json
Mongo:
connectionString: mongodb://localhost:27017
database: issuer-directory
issuersCollection: issuers
issuerKeysCollection: issuer_keys
issuerTrustCollection: issuer_trust_overrides
auditCollection: issuer_audit

View File

@@ -14,10 +14,11 @@ authority:
allowAnonymousFallback: false
backchannelTimeoutSeconds: 30
tokenClockSkewSeconds: 60
audiences:
- notify.dev
readScope: notify.read
adminScope: notify.admin
audiences:
- notify.dev
viewerScope: notify.viewer
operatorScope: notify.operator
adminScope: notify.admin
api:
basePath: "/api/v1/notify"

View File

@@ -14,10 +14,11 @@ authority:
allowAnonymousFallback: false
backchannelTimeoutSeconds: 30
tokenClockSkewSeconds: 60
audiences:
- notify
readScope: notify.read
adminScope: notify.admin
audiences:
- notify
viewerScope: notify.viewer
operatorScope: notify.operator
adminScope: notify.admin
api:
basePath: "/api/v1/notify"

View File

@@ -14,10 +14,11 @@ authority:
allowAnonymousFallback: false
backchannelTimeoutSeconds: 30
tokenClockSkewSeconds: 60
audiences:
- notify
readScope: notify.read
adminScope: notify.admin
audiences:
- notify
viewerScope: notify.viewer
operatorScope: notify.operator
adminScope: notify.admin
api:
basePath: "/api/v1/notify"

View File

@@ -15,10 +15,11 @@ authority:
allowAnonymousFallback: false
backchannelTimeoutSeconds: 30
tokenClockSkewSeconds: 60
audiences:
- notify
readScope: notify.read
adminScope: notify.admin
audiences:
- notify
viewerScope: notify.viewer
operatorScope: notify.operator
adminScope: notify.admin
api:
basePath: "/api/v1/notify"

View File

@@ -0,0 +1,62 @@
# StellaOps Packs Registry configuration template.
# Copy to ../etc/packs-registry.yaml (relative to the Packs Registry content root)
# and adjust values as needed. Environment variables prefixed with
# STELLAOPS_PACKSREGISTRY_ override these settings at runtime.
schemaVersion: 1
telemetry:
enabled: true
serviceName: "stellaops-packs-registry"
exportConsole: true
minimumLogLevel: "Information"
otlpEndpoint: ""
resourceAttributes:
deployment.environment: "local"
authority:
issuer: "https://authority.stella-ops.local"
metadataAddress: ""
requireHttpsMetadata: true
audiences:
- "api://packs-registry"
tenant: "tenant-default"
# Client credentials for publishing packs into the registry.
publishClient:
clientId: "packs-registry"
clientSecret: ""
clientSecretFile: "../secrets/packs-registry.secret"
scopes:
- "packs.write"
- "packs.read"
# Optional read-only client for mirrors or offline tooling.
readerClient:
clientId: "packs-reader"
clientSecret: ""
clientSecretFile: "../secrets/packs-reader.secret"
scopes:
- "packs.read"
storage:
# Mongo database storing pack metadata and provenance.
mongoConnectionString: "mongodb://packs-registry:registry@mongo:27017/packs-registry?authSource=admin"
# Object storage bucket/container for pack bundles and signatures.
bundleStore: "s3://stellaops-packs"
signing:
# Trusted keys (PEM paths or Fulcio issuer URLs) used to validate inbound packs.
trustedKeys:
- "../certificates/packs-signing.pem"
# Enforce DSSE attestations for published packs.
requireDsse: true
mirroring:
enabled: false
# Remote registry or file share used to seed mirrors in offline deployments.
source: ""
schedule: "00:30:00"
offlineKit:
enabled: true
exportDirectory: "out/offline/packs"
provenanceManifest: "out/offline/packs/provenance.json"

View File

@@ -0,0 +1,69 @@
# StellaOps Task Runner configuration template.
# Copy to ../etc/task-runner.yaml (relative to the Task Runner content root)
# and adjust values for your environment. Environment variables prefixed with
# STELLAOPS_TASKRUNNER_ override these values at runtime.
schemaVersion: 1
telemetry:
enabled: true
serviceName: "stellaops-taskrunner"
exportConsole: true
minimumLogLevel: "Information"
otlpEndpoint: ""
resourceAttributes:
deployment.environment: "local"
authority:
issuer: "https://authority.stella-ops.local"
metadataAddress: ""
requireHttpsMetadata: true
audiences:
- "api://task-runner"
# Client credentials used for executing packs. Provide either clientSecret or
# clientSecretFile (preferred for production).
runnerClient:
clientId: "task-runner"
clientSecret: ""
clientSecretFile: "../secrets/task-runner.secret"
scopes:
- "packs.run"
- "packs.read"
# Client used to approve gates when automation workflows sign off on runs.
approvalsClient:
clientId: "pack-approver"
clientSecret: ""
clientSecretFile: "../secrets/pack-approver.secret"
scopes:
- "packs.approve"
- "packs.read"
# Optional secondary client used for registry interactions (promote/deprecate).
registryClient:
clientId: "packs-registry"
clientSecret: ""
clientSecretFile: "../secrets/packs-registry.secret"
scopes:
- "packs.write"
- "packs.read"
# Tenant context required for all Task Runner operations.
tenant: "tenant-default"
storage:
# Object storage bucket where run artifacts and evidence bundles are kept.
artifactsBucket: "s3://stellaops-taskrunner-artifacts"
# MongoDB stores run metadata and approval state; update connection string
# before deploying.
mongoConnectionString: "mongodb://taskrunner:taskrunner@mongo:27017/taskrunner?authSource=admin"
approvals:
# Default timeout before pending approvals auto-expire.
defaultExpiresAfter: "04:00:00"
# Notifications topic emitted when approvals are requested/resolved.
notifyTopic: "pack.run.approvals"
runner:
# Maximum concurrent steps Task Runner executes per worker.
maxParallelSteps: 8
# Allowlist of modules that can initiate network calls when sealed=false.
networkAllowlist:
- "*.internal.stella-ops.local"