apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: name: pharos-platform-route-writer spec: failurePolicy: Fail paramKind: apiVersion: v1 kind: ConfigMap matchConstraints: resourceRules: - apiGroups: - networking.istio.io - security.istio.io - networking.k8s.io apiVersions: - '*' operations: - CREATE - UPDATE - DELETE resources: - gateways - virtualservices - destinationrules - envoyfilters - authorizationpolicies - networkpolicies matchConditions: - name: catalogue-route expression: (object != null && has(object.metadata.labels) && 'pharos.platform/route' in object.metadata.labels) || (oldObject != null && has(oldObject.metadata.labels) && 'pharos.platform/route' in oldObject.metadata.labels) validations: - expression: params.data.routes == 'ansible' || params.data.routes == 'restoring' || request.userInfo.username == 'system:serviceaccount:argocd:argocd-application-controller' message: Catalogue routes are fenced for the Argo writer; suspend and record recovery before returning them to Helm --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: name: pharos-platform-route-writer spec: policyName: pharos-platform-route-writer validationActions: - Deny paramRef: name: pharos-platform-ownership namespace: istio-system parameterNotFoundAction: Deny --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: name: pharos-platform-project-writer spec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: - argoproj.io apiVersions: - '*' operations: - CREATE - UPDATE - DELETE resources: - appprojects matchConditions: - name: bootstrap-owned-project expression: (object != null && object.metadata.name in ['platform', 'default', 'services']) || (oldObject != null && oldObject.metadata.name in ['platform', 'default', 'services']) validations: - expression: '!request.userInfo.username.startsWith(''system:serviceaccount:argocd:'')' message: Platform project policy is owned by bootstrap administration, not Argo service accounts --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: name: pharos-platform-project-writer spec: policyName: pharos-platform-project-writer validationActions: - Deny --- # Deleting a Profile deletes its namespace with every volume, Job and retained account in it (ADR/DD-0067 §5.6). Only # the Site Agent may retire one it manages, and only after stamping the approval with the resource it belongs to; the # marker ties the approval to one resource, so a stale one cannot delete a different Project. apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: name: pharos-kubeflow-profile-retirement spec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: - kubeflow.org apiVersions: - v1 operations: - DELETE resources: - profiles # A DELETE request carries no object: the Profile being deleted is only in `oldObject`. Reading `object` here fails # the expression on every delete, including the agent's own. validations: - expression: >- oldObject.metadata.?labels.orValue({})[?'waldur.io/managed-by'].orValue('') != 'waldur-site-agent' || (oldObject.metadata.?labels.orValue({})[?'waldur.io/resource-uuid'].orValue('') != '' && oldObject.metadata.?annotations.orValue({})[?'execution.pharos.dev/retirement-approved'].orValue('') == oldObject.metadata.?labels.orValue({})[?'waldur.io/resource-uuid'].orValue('-') && request.userInfo.username == 'system:serviceaccount:waldur-site-agent:waldur-site-agent') message: >- A Site Agent Profile retires only with the agent's approval marker for its own resource, and only from the agent reason: Forbidden --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: name: pharos-kubeflow-profile-retirement spec: policyName: pharos-kubeflow-profile-retirement validationActions: - Deny --- # A Profile namespace is a Site Runtime namespace: the Site Agent keeps # `pod-security.kubernetes.io/enforce: restricted` on it and the guard pins the label (ADR/DD-0067 §3). Pod Security # admission runs before any ValidatingAdmissionPolicy, so in a correctly labelled namespace it is PSA that refuses an # incomplete pod; this policy is the safety net for a namespace that lost the label, and it states exactly PSA's # restricted profile so a pod it admits would also pass PSA: every container, init container and ephemeral container # declares allowPrivilegeEscalation false, drops ALL capabilities, adds at most NET_BIND_SERVICE, is not privileged, # runs as non-root and carries a RuntimeDefault or Localhost seccomp profile — each of the last two taken from the # container when it sets one and from the pod only when it does not, as PSA does. Nothing is rewritten, so an image # keeps the user it declares. It is validating and v1: MutatingAdmissionPolicy is beta and is served by neither the k3s # 1.34 development boxes nor the kubeadm 1.34/1.35 API server, so it would break their bootstrap. apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: name: pharos-kubeflow-restricted-pods spec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: - '' apiVersions: - v1 operations: - CREATE resources: - pods # An ephemeral container is added through its own subresource, which is an UPDATE of the pod. - apiGroups: - '' apiVersions: - v1 operations: - UPDATE resources: - pods/ephemeralcontainers namespaceSelector: matchLabels: app.kubernetes.io/part-of: kubeflow-profile variables: - name: podRunsNonRoot expression: >- has(object.spec.securityContext) && has(object.spec.securityContext.runAsNonRoot) && object.spec.securityContext.runAsNonRoot - name: podSeccomp expression: >- has(object.spec.securityContext) && has(object.spec.securityContext.seccompProfile) && has(object.spec.securityContext.seccompProfile.type) && object.spec.securityContext.seccompProfile.type in ['RuntimeDefault', 'Localhost'] - name: containers expression: >- object.spec.containers + (has(object.spec.initContainers) ? object.spec.initContainers : []) + (has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers : []) validations: - expression: >- variables.containers.all(c, has(c.securityContext) && (!has(c.securityContext.privileged) || !c.securityContext.privileged) && has(c.securityContext.allowPrivilegeEscalation) && c.securityContext.allowPrivilegeEscalation == false && has(c.securityContext.capabilities) && has(c.securityContext.capabilities.drop) && 'ALL' in c.securityContext.capabilities.drop && (!has(c.securityContext.capabilities.add) || c.securityContext.capabilities.add.all(a, a == 'NET_BIND_SERVICE')) && (!has(c.securityContext.runAsNonRoot) ? variables.podRunsNonRoot : c.securityContext.runAsNonRoot) && (!has(c.securityContext.seccompProfile) ? variables.podSeccomp : (has(c.securityContext.seccompProfile.type) && c.securityContext.seccompProfile.type in ['RuntimeDefault', 'Localhost']))) message: >- A Kubeflow Profile pod declares the restricted Pod Security profile on every container, init container and ephemeral container: an explicit allowPrivilegeEscalation false, capabilities drop ALL, runAsNonRoot, no capability added beyond NET_BIND_SERVICE and a RuntimeDefault seccomp profile. A container may not relax what the pod declares. reason: Forbidden --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: name: pharos-kubeflow-restricted-pods spec: policyName: pharos-kubeflow-restricted-pods validationActions: - Deny