Complete reference for all REST APIs exposed by the SCC Orchestration System.
The system exposes two API surfaces:
| Service | Default Port | Protocol | Description |
|---|---|---|---|
| Governance API | 3000 | HTTP/JSON | Policy evaluation, migration registry, audit, SCC version tracking |
| Admission Webhook | 8443 | HTTPS/JSON | Pod interception (K8s AdmissionReview) and per-pod mutation log |
The Governance API uses header-based RBAC (role-based access control). In production, an upstream API broker proxy or service mesh sets these headers after authenticating the caller.
| Header | Description | Example |
|---|---|---|
X-User-Role |
Caller's role. Controls endpoint access. | admin, operator, auditor, viewer |
X-Authenticated-User |
Authenticated username (for audit logging) | john.doe@example.com |
Role permissions:
| Role | /validate |
/admission/check |
/audit |
Other endpoints |
|---|---|---|---|---|
admin |
✅ | ✅ | ✅ | ✅ |
operator |
✅ | ✅ | ❌ | ✅ |
auditor |
❌ | ✅ | ✅ | ✅ |
viewer |
❌ | ✅ | ❌ | ✅ |
Note: RBAC enforcement is controlled by the
ENFORCE_RBAC=trueenvironment variable. When not set, all roles are allowed (development mode).
Base URL: http://<governance-api-host>:3000
Validate a migration plan against all governance policy rules. Called by the SCC Migration Controller during the Validating phase.
Authorization: admin, operator
Request Body:
{
"planName": "migrate-anyuid-to-restricted",
"namespace": "app-team-alpha",
"sourceSCC": "anyuid",
"targetSCC": "restricted",
"namespaces": ["app-team-alpha", "app-team-beta"]
}| Field | Type | Required | Description |
|---|---|---|---|
planName |
string | No | Name of the SCCMigrationPlan CR |
namespace |
string | No | Namespace of the CR |
sourceSCC |
string | Yes | Current SCC policy (e.g. anyuid) |
targetSCC |
string | Yes | Desired SCC policy (e.g. restricted) |
namespaces |
string[] | Yes | Namespaces affected by the migration |
Response — 200 OK:
{
"approved": true,
"violations": [],
"riskLevel": "low",
"recommendations": [
"[rule-001] Transition \"anyuid→restricted\" is explicitly approved by \"Allow privilege reduction\""
]
}| Field | Type | Description |
|---|---|---|
approved |
boolean | true if the plan passes all governance rules |
violations |
string[] | List of rule violations (empty when approved) |
riskLevel |
string | low, medium, or high |
recommendations |
string[] | Optional suggestions for the operator |
Response — 400 Bad Request:
{
"approved": false,
"violations": ["Missing required fields: sourceSCC, targetSCC, namespaces"]
}Real-time admission check for individual pod creation. Called by the Admission Webhook for every intercepted pod.
Authorization: All roles
Request Body:
{
"podName": "my-app-7d4b8c6f9-x2k5l",
"namespace": "app-team-alpha",
"currentSCC": "anyuid",
"requestedSCC": "anyuid",
"labels": {
"app": "my-app",
"version": "v2"
},
"serviceAccount": "my-app-sa",
"deploymentPhase": "stable",
"telemetrySignals": {
"scc.poc/error-rate": "low",
"scc.poc/cpu-usage": "normal"
}
}| Field | Type | Required | Description |
|---|---|---|---|
podName |
string | No | Name of the pod being admitted |
namespace |
string | No | Pod's namespace |
currentSCC |
string | No | SCC currently assigned to the pod |
requestedSCC |
string | No | SCC requested via annotations |
labels |
object | No | Pod labels for selector matching |
serviceAccount |
string | No | Pod's service account name |
deploymentPhase |
string | No | Inferred phase: canary, stable, etc. |
telemetrySignals |
object | No | Runtime telemetry hints from pod annotations |
Response — 200 OK (mutation approved):
{
"allow": true,
"mutateSCC": "restricted",
"reason": "Active migration \"migrate-anyuid-to-restricted\" in progress"
}Response — 200 OK (no mutation needed):
{
"allow": true,
"mutateSCC": "",
"reason": "No active migration for this namespace/SCC combination"
}| Field | Type | Description |
|---|---|---|
allow |
boolean | Always true (fail-open design) |
mutateSCC |
string | Target SCC to mutate to, or empty string if no mutation |
reason |
string | Human-readable explanation of the decision |
Context-aware skip conditions:
deploymentPhase: "canary"→ skips mutation for safetytelemetrySignals["scc.poc/error-rate"]: "high"→ defers mutation
List all governance policy rules.
Authorization: All roles
Response — 200 OK:
[
{
"id": "rule-001",
"name": "Allow privilege reduction",
"description": "Allows migration from more privileged to less privileged SCCs",
"enabled": true,
"allowedTransitions": [
"privileged→anyuid",
"privileged→restricted",
"anyuid→restricted",
"anyuid→nonroot",
"nonroot→restricted"
],
"blockedNamespaces": []
}
]List all currently active migrations.
Authorization: All roles
Response — 200 OK:
[
{
"planName": "migrate-anyuid-to-restricted",
"namespace": "app-team-alpha",
"sourceSCC": "anyuid",
"targetSCC": "restricted",
"namespaces": ["app-team-alpha"],
"phase": "Migrating",
"updatedAt": "2026-03-12T10:30:00.000Z"
}
]Register or update an active migration. Called by the controller when a migration enters the Migrating or Mirroring phase.
Authorization: All roles
Request Body:
{
"planName": "migrate-anyuid-to-restricted",
"namespace": "app-team-alpha",
"sourceSCC": "anyuid",
"targetSCC": "restricted",
"namespaces": ["app-team-alpha"],
"phase": "Migrating"
}| Field | Type | Required | Description |
|---|---|---|---|
planName |
string | Yes | Name of the migration plan |
namespace |
string | No | Namespace of the CR |
sourceSCC |
string | No | Source SCC being migrated from |
targetSCC |
string | No | Target SCC being migrated to |
namespaces |
string[] | No | Namespaces affected |
phase |
string | No | Current phase (default: Migrating) |
Response — 200 OK:
{
"status": "registered",
"key": "app-team-alpha/migrate-anyuid-to-restricted"
}Side effect: When a new migration is registered, SCC version
activatedevents are recorded in the SCC Version Registry for both source and target SCCs.
Remove an active migration. Called when a migration completes, fails, or is rolled back.
Authorization: All roles
Path Parameters:
| Parameter | Description |
|---|---|
namespace |
Namespace of the migration plan |
name |
Name of the migration plan |
Response — 200 OK:
{
"status": "removed",
"key": "app-team-alpha/migrate-anyuid-to-restricted"
}Response — 404 Not Found:
{
"error": "Migration not found",
"key": "app-team-alpha/migrate-anyuid-to-restricted"
}Side effect: Records SCC version
deactivatedevent for the source SCC.
Query the SCC Version Registry — a complete lifecycle history of SCC version activations and deactivations across all migrations.
Authorization: All roles
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
version |
string | — | Filter by SCC version name (e.g. restricted) |
action |
string | — | Filter by lifecycle action: activated or deactivated |
limit |
integer | 100 | Maximum entries to return |
Example: GET /api/v1/scc-versions?version=restricted&action=activated&limit=50
Response — 200 OK:
{
"total": 2,
"activeVersions": ["anyuid", "restricted"],
"entries": [
{
"timestamp": "2026-03-12T10:30:00.000Z",
"version": "restricted",
"role": "target",
"action": "activated",
"planName": "migrate-anyuid-to-restricted",
"namespace": "app-team-alpha"
}
]
}| Field | Type | Description |
|---|---|---|
total |
integer | Number of entries returned |
activeVersions |
string[] | SCC versions currently active (activated but not yet deactivated) |
entries |
object[] | Lifecycle event records |
Record a per-pod SCC migration event. Called by the webhook to push individual pod mutation decisions for centralised tracking.
Authorization: All roles
Request Body:
{
"podName": "my-app-7d4b8c6f9-x2k5l",
"namespace": "app-team-alpha",
"fromSCC": "anyuid",
"toSCC": "restricted",
"serviceAccount": "my-app-sa",
"deploymentPhase": "stable",
"status": "Mutated",
"reason": "Active migration in progress"
}| Field | Type | Required | Description |
|---|---|---|---|
podName |
string | Yes | Name of the pod |
namespace |
string | Yes | Pod's namespace |
fromSCC |
string | No | Source SCC |
toSCC |
string | No | Target SCC |
serviceAccount |
string | No | Pod's service account (default: default) |
deploymentPhase |
string | No | Deployment phase (default: stable) |
status |
string | No | Mutated, Skipped, or Failed |
reason |
string | No | Human-readable reason |
Response — 200 OK:
{
"status": "recorded",
"entry": {
"timestamp": "2026-03-12T10:35:00.000Z",
"podName": "my-app-7d4b8c6f9-x2k5l",
"namespace": "app-team-alpha",
"fromSCC": "anyuid",
"toSCC": "restricted",
"serviceAccount": "my-app-sa",
"deploymentPhase": "stable",
"status": "Mutated",
"reason": "Active migration in progress"
}
}Query per-pod SCC migration records with filtering support.
Authorization: All roles
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
namespace |
string | — | Filter by namespace |
status |
string | — | Filter by status: Mutated, Skipped, Failed |
fromSCC |
string | — | Filter by source SCC |
toSCC |
string | — | Filter by target SCC |
limit |
integer | 100 | Maximum entries to return |
Example: GET /api/v1/pod-migrations?namespace=app-team-alpha&status=Mutated&limit=50
Response — 200 OK:
{
"total": 3,
"summary": {
"totalRecords": 15,
"mutated": 10,
"skipped": 4,
"failed": 1
},
"entries": [
{
"timestamp": "2026-03-12T10:35:00.000Z",
"podName": "my-app-7d4b8c6f9-x2k5l",
"namespace": "app-team-alpha",
"fromSCC": "anyuid",
"toSCC": "restricted",
"serviceAccount": "my-app-sa",
"deploymentPhase": "stable",
"status": "Mutated",
"reason": "Active migration in progress"
}
]
}Retrieve audit log entries. Every governance API operation is recorded with timestamp, actor, role, action, and result.
Authorization: admin, auditor
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
action |
string | — | Filter by action type (e.g. validate, admission-check, migration-register) |
limit |
integer | 100 | Maximum entries to return |
Example: GET /api/v1/audit?action=validate&limit=50
Response — 200 OK:
{
"total": 2,
"entries": [
{
"timestamp": "2026-03-12T10:30:00.000Z",
"action": "validate",
"actor": "controller@scc-poc.svc",
"role": "operator",
"sourceIP": "10.0.0.15",
"userAgent": "scc-controller/1.0",
"details": {
"planName": "migrate-anyuid-to-restricted",
"sourceSCC": "anyuid",
"targetSCC": "restricted",
"namespaces": ["app-team-alpha"]
},
"result": "approved"
}
]
}Audit action types:
| Action | Triggered by |
|---|---|
validate |
Plan validation request |
admission-check |
Pod admission check |
migration-register |
Active migration registered |
migration-remove |
Active migration removed |
pod-migration |
Per-pod mutation recorded |
audit-read |
Audit log queried |
rbac-denied |
RBAC access denied |
Health check endpoint.
Authorization: None
Response — 200 OK:
{
"status": "healthy",
"timestamp": "2026-03-12T10:30:00.000Z",
"policyCount": 3,
"activeMigrations": 1,
"auditLogSize": 42,
"sccVersionRegistrySize": 4,
"podMigrationLogSize": 15
}Base URL: https://<webhook-host>:8443
The webhook communicates with Kubernetes via the standard AdmissionReview protocol. It also exposes a per-pod mutation log query endpoint.
Kubernetes Mutating Admission Webhook endpoint. Intercepts pod CREATE operations and optionally mutates the SCC annotation and security context.
Note: This endpoint is called by the Kubernetes API server, not directly by users. It is configured via a
MutatingWebhookConfigurationresource.
Request: Standard Kubernetes AdmissionReview (API version admission.k8s.io/v1)
Response: AdmissionReview with an AdmissionResponse containing:
allowed: true(always — fail-open design)- Optional JSON Patch (RFC 6902) that:
- Sets
openshift.io/sccannotation to the target SCC - Reconciles pod security context (privilege escalation, capabilities, SELinux, runAsNonRoot)
- Reconciles container-level security contexts for all containers and init containers
- Sets
Fail-open guarantee: The webhook never blocks pod creation. On any error (governance API unreachable, deserialization failure, patch build error), the pod is admitted unchanged.
Query the webhook's local per-pod mutation log. Returns recent SCC mutation decisions with filtering.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
namespace |
string | — | Filter by namespace |
status |
string | — | Filter by status: Mutated, Skipped, Failed |
limit |
integer | 100 | Maximum entries to return |
Example: GET /api/v1/pod-mutations?namespace=app-team-alpha&status=Mutated&limit=50
Response — 200 OK:
{
"total": 5,
"entries": [
{
"timestamp": "2026-03-12T10:35:00Z",
"podName": "my-app-7d4b8c6f9-x2k5l",
"namespace": "app-team-alpha",
"fromSCC": "anyuid",
"toSCC": "restricted",
"serviceAccount": "my-app-sa",
"deploymentPhase": "stable",
"status": "Mutated",
"reason": "Active migration in progress",
"telemetrySignals": {
"scc.poc/error-rate": "low"
}
}
],
"summary": {
"totalRecords": 20,
"mutated": 15,
"skipped": 4,
"failed": 1
}
}All endpoints return standard HTTP status codes:
| Status | Meaning |
|---|---|
200 |
Success |
400 |
Bad request — missing required fields |
403 |
Forbidden — insufficient RBAC role |
404 |
Resource not found |
500 |
Internal server error |
Error response format:
{
"error": "Forbidden",
"message": "Role \"viewer\" is not permitted. Required: admin, operator"
}{
"id": "string",
"name": "string",
"description": "string",
"enabled": "boolean",
"allowedTransitions": ["string"],
"blockedTransitions": ["string"],
"blockedNamespaces": ["string"]
}{
"planName": "string",
"namespace": "string",
"sourceSCC": "string",
"targetSCC": "string",
"namespaces": ["string"],
"phase": "string",
"updatedAt": "ISO 8601 timestamp"
}{
"timestamp": "ISO 8601 timestamp",
"version": "string",
"role": "source | target",
"action": "activated | deactivated",
"planName": "string",
"namespace": "string"
}{
"timestamp": "ISO 8601 timestamp",
"podName": "string",
"namespace": "string",
"fromSCC": "string",
"toSCC": "string",
"serviceAccount": "string",
"deploymentPhase": "string",
"status": "Mutated | Skipped | Failed",
"reason": "string",
"telemetrySignals": { "key": "value" }
}{
"timestamp": "ISO 8601 timestamp",
"action": "string",
"actor": "string",
"role": "string",
"sourceIP": "string",
"userAgent": "string",
"details": { },
"result": "string"
}| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server listen port |
LOG_LEVEL |
info |
Logging level |
ENFORCE_RBAC |
false |
Set to true to enforce RBAC role checks |
| Variable | Default | Description |
|---|---|---|
WEBHOOK_PORT |
8443 |
HTTPS listen port |
TLS_CERT_FILE |
/certs/tls.crt |
Path to TLS certificate |
TLS_KEY_FILE |
/certs/tls.key |
Path to TLS private key |
GOVERNANCE_API_URL |
http://governance-api:3000 |
Governance API base URL |