← Policy catalog
</> ValidatingAdmissionPolicy · Apache-2.0

Grants Approval of Certificate Signing Requests

clusterrole-cert-auth-review

severityCritical resourceClusterRoles productKubernetes bundles1

Write access to certificate signing requests and to the authorization and authentication review APIs lets the holder issue client certificates and use the API server to test which permissions a stolen credential carries.

Rejects unless

!has(object.rules) || object.rules.all(r,
  !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
    r.apiGroups.exists(ag, ag == "certificates.k8s.io") &&
    r.resources.exists(res, variables.certResources.exists(cr, cr == res)) &&
    r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v))) &&
  !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
    r.apiGroups.exists(ag, ag == "authorization.k8s.io") &&
    r.resources.exists(res, variables.authzResources.exists(ar, ar == res)) &&
    r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v))) &&
  !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
    r.apiGroups.exists(ag, ag == "authentication.k8s.io") &&
    r.resources.exists(res, variables.authnResources.exists(anr, anr == res)) &&
    r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v)))
)

ClusterRoles must not grant write/approve access to CSRs, authz/authn review APIs.

Variables

certResources

["certificatesigningrequests","certificatesigningrequests/approval","certificatesigningrequests/status"]

authzResources

["subjectaccessreviews","selfsubjectaccessreviews"]

authnResources

["tokenreviews"]

writeVerbs

["create","update","patch","approve"]

Remediation

Drop create, update, patch and approve on certificatesigningrequests and its approval and status subresources, and on subjectaccessreviews, selfsubjectaccessreviews and tokenreviews. Fields: rules[*].apiGroups, rules[*].resources, rules[*].verbs.

Applies to

  • clusterroles · rbac.authorization.k8s.io/v1 · CREATE, UPDATE

Manifest

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: clusterrole-cert-auth-review
  annotations:
    kubeapt.io/uuid: "09b595b5-1df6-4303-9adb-447f7183a174"
    security.kubeapt.io/displayName: "Grants Approval of Certificate Signing Requests"
    security.kubeapt.io/description: "Write access to certificate signing requests and to the authorization and authentication review APIs lets the holder issue client certificates and use the API server to test which permissions a stolen credential carries."
    security.kubeapt.io/resource: "ClusterRoles"
    security.kubeapt.io/severity: "Critical"
    security.kubeapt.io/remediation: "Drop create, update, patch and approve on certificatesigningrequests and its approval and status subresources, and on subjectaccessreviews, selfsubjectaccessreviews and tokenreviews. Fields: rules[*].apiGroups, rules[*].resources, rules[*].verbs."
    security.kubeapt.io/product: "Kubernetes"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:
      - rbac.authorization.k8s.io
      apiVersions:
      - v1
      operations:
      - CREATE
      - UPDATE
      resources:
      - clusterroles
  variables:
  - name: certResources
    expression: |
      ["certificatesigningrequests","certificatesigningrequests/approval","certificatesigningrequests/status"]
  - name: authzResources
    expression: |
      ["subjectaccessreviews","selfsubjectaccessreviews"]
  - name: authnResources
    expression: |
      ["tokenreviews"]
  - name: writeVerbs
    expression: |
      ["create","update","patch","approve"]
  validations:
  - expression: |
      !has(object.rules) || object.rules.all(r,
        !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
          r.apiGroups.exists(ag, ag == "certificates.k8s.io") &&
          r.resources.exists(res, variables.certResources.exists(cr, cr == res)) &&
          r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v))) &&
        !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
          r.apiGroups.exists(ag, ag == "authorization.k8s.io") &&
          r.resources.exists(res, variables.authzResources.exists(ar, ar == res)) &&
          r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v))) &&
        !(has(r.apiGroups) && has(r.resources) && has(r.verbs) &&
          r.apiGroups.exists(ag, ag == "authentication.k8s.io") &&
          r.resources.exists(res, variables.authnResources.exists(anr, anr == res)) &&
          r.verbs.exists(v, variables.writeVerbs.exists(wv, wv == v)))
      )
    message: |
      ClusterRoles must not grant write/approve access to CSRs, authz/authn review APIs.

Save it as clusterrole-cert-auth-review.yaml — the commands below assume that name.

Validate with kubeapt

Check a workload against this one policy, before anything is installed on a cluster.

$ kubeapt validate -p ./clusterrole-cert-auth-review.yaml -r ./workload.yaml

Or without the file, from the published policy set — -r takes a directory too:

$ kubeapt policies download && kubeapt validate --policy-name clusterrole-cert-auth-review -r ./manifests

Or against every namespace in the cluster your kubeconfig points at:

$ kubeapt validate --policy-name clusterrole-cert-auth-review -A