# Facet Seal Admission Webhook Configuration **Sprint:** SPRINT_20260105_002_004_CLI **Task:** CLI-017 - Admission webhook configuration documentation ## Overview The StellaOps Zastava admission webhook validates facet seals during Kubernetes pod admission. When enabled, it ensures that container images have valid facet seals and that any drift from the baseline is within acceptable quotas. ## Prerequisites - Kubernetes cluster with admission webhook support - StellaOps Zastava webhook deployed - Certificate management for webhook TLS - Network access from API server to webhook endpoint ## Enabling Facet Validation Facet seal validation is opt-in per namespace using annotations. ### Namespace Annotation Add the following annotation to enable facet validation: ```yaml apiVersion: v1 kind: Namespace metadata: name: production annotations: stellaops.io/facet-seal-required: "true" ``` ### Annotation Values | Value | Behavior | |-------|----------| | `"true"` | Facet seal validation enabled | | `"false"` | Facet seal validation disabled | | (not set) | Facet seal validation disabled | ## Validation Behavior When facet validation is enabled, the webhook performs these checks: 1. **Seal Lookup**: Load the facet seal for the image digest 2. **Signature Verification**: Verify the seal's DSSE signature (if present) 3. **Drift Computation**: Compare current image state against baseline seal 4. **Quota Evaluation**: Check drift against configured quotas ### Verdict Outcomes | Verdict | Result | Description | |---------|--------|-------------| | `Ok` | Allow | Drift within quotas | | `Warning` | Allow (with warning) | Approaching quota limits | | `Blocked` | Deny | Quota exceeded | | `RequiresVex` | Deny | Requires VEX authorization | ## Configuration Options ### Webhook Deployment ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: zastava-webhook namespace: stellaops-system spec: replicas: 3 selector: matchLabels: app: zastava-webhook template: metadata: labels: app: zastava-webhook spec: containers: - name: webhook image: stellaops/zastava-webhook:latest ports: - containerPort: 8443 env: - name: STELLAOPS_BACKEND_URL value: "https://api.stellaops.internal" - name: STELLAOPS_FACET_SEAL_STORE value: "remote" volumeMounts: - name: webhook-certs mountPath: /etc/webhook/certs readOnly: true volumes: - name: webhook-certs secret: secretName: zastava-webhook-certs ``` ### ValidatingWebhookConfiguration ```yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: stellaops-facet-admission webhooks: - name: facet.admission.stellaops.io clientConfig: service: name: zastava-webhook namespace: stellaops-system path: /validate caBundle: ${CA_BUNDLE} rules: - operations: ["CREATE", "UPDATE"] apiGroups: [""] apiVersions: ["v1"] resources: ["pods"] namespaceSelector: matchExpressions: - key: stellaops.io/facet-seal-required operator: In values: ["true"] failurePolicy: Fail sideEffects: None admissionReviewVersions: ["v1"] ``` ## Quota Configuration Facet drift quotas can be configured per namespace or globally. ### Global Quotas (ConfigMap) ```yaml apiVersion: v1 kind: ConfigMap metadata: name: stellaops-facet-quotas namespace: stellaops-system data: default.yaml: | quotas: runtime: warningThreshold: 10 blockThreshold: 25 vexThreshold: 50 config: warningThreshold: 20 blockThreshold: 40 vexThreshold: 60 static: warningThreshold: 30 blockThreshold: 50 vexThreshold: 75 ``` ### Per-Namespace Overrides ```yaml apiVersion: v1 kind: Namespace metadata: name: staging annotations: stellaops.io/facet-seal-required: "true" stellaops.io/facet-quota-runtime-warn: "20" stellaops.io/facet-quota-runtime-block: "50" ``` ## Troubleshooting ### Common Issues #### Seal Not Found ``` Admission denied: facet.seal.missing No facet seal found for image sha256:abc123... ``` **Resolution**: Ensure the image was sealed before deployment: ```bash stella seal sha256:abc123 --store ``` #### Invalid Signature ``` Admission denied: facet.seal.invalid_signature Facet seal signature verification failed ``` **Resolution**: Verify the seal was signed with a trusted key and the trust roots are configured. #### Quota Exceeded ``` Admission denied: facet.quota.exceeded Facet quota exceeded: runtime(45.2%) ``` **Resolution**: Either: 1. Re-seal the image with current state 2. Generate and approve a VEX authorization 3. Adjust quota thresholds ### Debugging Enable verbose logging: ```yaml env: - name: STELLAOPS_LOG_LEVEL value: "Debug" ``` View webhook logs: ```bash kubectl logs -n stellaops-system -l app=zastava-webhook ``` ## Metrics The webhook exposes Prometheus metrics: | Metric | Type | Description | |--------|------|-------------| | `stellaops_facet_admission_total` | Counter | Total admission requests | | `stellaops_facet_admission_allowed` | Counter | Allowed admissions | | `stellaops_facet_admission_denied` | Counter | Denied admissions | | `stellaops_facet_drift_percent` | Histogram | Drift percentage distribution | | `stellaops_facet_validation_duration_seconds` | Histogram | Validation latency | ## Related Documentation - [stella seal Command](../commands/seal.md) - [stella vex gen --from-drift](../commands/vex.md#stella-vex-gen---from-drift) - [Facet Drift Analysis](../commands/facet-drift.md)