role-secrets-access
Reading Secrets exposes the credentials they hold in the namespace, including service account tokens, TLS private keys and registry passwords, and the write verbs let those values be replaced with attacker-controlled ones.
!has(object.rules) || object.rules.all(r,
!(r.apiGroups.exists(ag, ag == "") &&
r.resources.exists(res, res == "secrets") &&
r.verbs.exists(v, variables.secretVerbs.exists(sv, sv == v))
)
)
Roles must not grant read or write access to Secrets without tight scoping.
secretVerbs
["get","list","watch","create","update","patch","delete"]
Remove get, list, watch, create, update, patch and delete from every rule covering secrets in the core API group, and deliver credentials through a projected volume or an external secret store instead. Fields: rules[*].apiGroups, rules[*].resources, rules[*].verbs.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: role-secrets-access
annotations:
kubeapt.io/uuid: "f2cdf998-1fbc-40e6-9602-1a721388f40f"
security.kubeapt.io/displayName: "Grants Access to Secrets"
security.kubeapt.io/description: "Reading Secrets exposes the credentials they hold in the namespace, including service account tokens, TLS private keys and registry passwords, and the write verbs let those values be replaced with attacker-controlled ones."
security.kubeapt.io/resource: "Roles"
security.kubeapt.io/severity: "Critical"
security.kubeapt.io/remediation: "Remove get, list, watch, create, update, patch and delete from every rule covering secrets in the core API group, and deliver credentials through a projected volume or an external secret store instead. 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:
- roles
variables:
- name: secretVerbs
expression: |
["get","list","watch","create","update","patch","delete"]
validations:
- expression: |
!has(object.rules) || object.rules.all(r,
!(r.apiGroups.exists(ag, ag == "") &&
r.resources.exists(res, res == "secrets") &&
r.verbs.exists(v, variables.secretVerbs.exists(sv, sv == v))
)
)
message: |
Roles must not grant read or write access to Secrets without tight scoping.Save it as role-secrets-access.yaml — the commands below assume that name.
Check a workload against this one policy, before anything is installed on a cluster.
$ kubeapt validate -p ./role-secrets-access.yaml -r ./workload.yamlOr without the file, from the published policy set — -r takes a directory too:
$ kubeapt policies download && kubeapt validate --policy-name role-secrets-access -r ./manifestsOr against every namespace in the cluster your kubeconfig points at:
$ kubeapt validate --policy-name role-secrets-access -A