# ValidatingAdmissionPolicy to restrict images in dexorder-agents namespace # Requires Kubernetes 1.30+ (or 1.28+ with feature gate) # This is the critical security control that prevents arbitrary image execution # even if the gateway is compromised. --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: name: dexorder-agent-image-policy spec: failurePolicy: Fail matchConstraints: namespaceSelector: matchLabels: dexorder.io/type: agents resourceRules: - apiGroups: ["apps"] apiVersions: ["v1"] resources: ["deployments"] operations: ["CREATE", "UPDATE"] validations: # Only allow images from our approved registry with agent prefix - expression: | object.spec.template.spec.containers.all(c, c.image.startsWith('ghcr.io/dexorder/agent:') || c.image.startsWith('ghcr.io/dexorder/agent-')) message: "Only approved dexorder agent images are allowed in the agents namespace" reason: Forbidden # No privileged containers - expression: | object.spec.template.spec.containers.all(c, !has(c.securityContext) || !has(c.securityContext.privileged) || c.securityContext.privileged == false) message: "Privileged containers are not allowed" reason: Forbidden # No hostPath volumes - expression: | !has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(v, !has(v.hostPath)) message: "hostPath volumes are not allowed" reason: Forbidden # No hostNetwork - expression: | !has(object.spec.template.spec.hostNetwork) || object.spec.template.spec.hostNetwork == false message: "hostNetwork is not allowed" reason: Forbidden # No hostPID - expression: | !has(object.spec.template.spec.hostPID) || object.spec.template.spec.hostPID == false message: "hostPID is not allowed" reason: Forbidden # Containers must run as non-root - expression: | object.spec.template.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.runAsNonRoot) && c.securityContext.runAsNonRoot == true) message: "Containers must run as non-root" reason: Forbidden # Must drop all capabilities - expression: | object.spec.template.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.capabilities) && has(c.securityContext.capabilities.drop) && c.securityContext.capabilities.drop.exists(cap, cap == 'ALL')) message: "Containers must drop all capabilities" reason: Forbidden # Read-only root filesystem - expression: | object.spec.template.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.readOnlyRootFilesystem) && c.securityContext.readOnlyRootFilesystem == true) message: "Containers must have read-only root filesystem" reason: Forbidden # Resource limits must be set - expression: | object.spec.template.spec.containers.all(c, has(c.resources) && has(c.resources.limits) && has(c.resources.limits.memory) && has(c.resources.limits.cpu)) message: "Containers must have resource limits set" reason: Forbidden --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: name: dexorder-agent-image-policy-binding spec: policyName: dexorder-agent-image-policy validationActions: - Deny matchResources: namespaceSelector: matchLabels: dexorder.io/type: agents