All Policies
Restrict Secrets by Label
Secrets often contain sensitive information and their access should be carefully controlled. Although Kubernetes RBAC can be effective at restricting them in several ways, it lacks the ability to use labels on referenced entities. This policy ensures that only Secrets not labeled with `status=protected` can be consumed by Pods.
Policy Definition
/other/restrict-secrets-by-label/restrict-secrets-by-label.yaml
1apiVersion: kyverno.io/v1
2kind: ClusterPolicy
3metadata:
4 name: restrict-secrets-by-label
5 annotations:
6 policies.kyverno.io/title: Restrict Secrets by Label
7 policies.kyverno.io/category: Other
8 policies.kyverno.io/severity: medium
9 policies.kyverno.io/minversion: 1.6.0
10 kyverno.io/kyverno-version: 1.6.0
11 kyverno.io/kubernetes-version: "1.23"
12 policies.kyverno.io/subject: Pod, Secret
13 policies.kyverno.io/description: >-
14 Secrets often contain sensitive information and their access should be carefully controlled.
15 Although Kubernetes RBAC can be effective at restricting them in several ways,
16 it lacks the ability to use labels on referenced entities. This policy ensures
17 that only Secrets not labeled with `status=protected` can be consumed by Pods.
18spec:
19 background: false
20 validationFailureAction: Audit
21 rules:
22 - name: secrets-lookup-from-env
23 match:
24 any:
25 - resources:
26 kinds:
27 - Pod
28 preconditions:
29 all:
30 # check if any secrets are in env statements
31 - key: "{{ request.object.spec.[containers, initContainers, ephemeralContainers][].env[].valueFrom.secretKeyRef || '' | length(@) }}"
32 operator: GreaterThanOrEquals
33 value: 1
34 - key: "{{request.operation || 'BACKGROUND'}}"
35 operator: NotEquals
36 value: DELETE
37 validate:
38 message: These Secrets are restricted.
39 foreach:
40 # get every secret, then do an API lookup on each one checking for the `status` label.
41 # deny the request if any of those secrets have `status=protected`.
42 - list: "request.object.spec.[containers, initContainers, ephemeralContainers][].env[].valueFrom.secretKeyRef"
43 context:
44 - name: status
45 apiCall:
46 jmesPath: "metadata.labels.status || ''"
47 urlPath: "/api/v1/namespaces/{{request.namespace}}/secrets/{{element.name}}"
48 deny:
49 conditions:
50 any:
51 - key: "{{ status }}"
52 operator: Equals
53 value: protected
54 - name: secrets-lookup-from-envfrom
55 match:
56 any:
57 - resources:
58 kinds:
59 - Pod
60 preconditions:
61 all:
62 # check if any secrets are in envfrom statements
63 - key: "{{ request.object.spec.[containers, initContainers, ephemeralContainers][].envFrom[].secretRef || '' | length(@) }}"
64 operator: GreaterThanOrEquals
65 value: 1
66 - key: "{{request.operation || 'BACKGROUND'}}"
67 operator: NotEquals
68 value: DELETE
69 validate:
70 message: These Secrets are restricted.
71 foreach:
72 # get every secret, then do an API lookup on each one checking for the `status` label.
73 # deny the request if any of those secrets have `status=protected`.
74 - list: "request.object.spec.[containers, initContainers, ephemeralContainers][].envFrom[].secretRef"
75 context:
76 - name: status
77 apiCall:
78 jmesPath: "metadata.labels.status || ''"
79 urlPath: "/api/v1/namespaces/{{request.namespace}}/secrets/{{element.name}}"
80 deny:
81 conditions:
82 any:
83 - key: "{{ status }}"
84 operator: AnyIn
85 value: protected
86 - name: secrets-lookup-from-volumes
87 match:
88 any:
89 - resources:
90 kinds:
91 - Pod
92 preconditions:
93 all:
94 # check if any secrets are in volume statements
95 - key: "{{ request.object.spec.volumes[].secret || '' | length(@) }}"
96 operator: GreaterThanOrEquals
97 value: 1
98 - key: "{{request.operation || 'BACKGROUND'}}"
99 operator: NotEquals
100 value: DELETE
101 validate:
102 message: These Secrets are restricted.
103 foreach:
104 # get every secret, then do an API lookup on each one checking for the `status` label.
105 # deny the request if any of those secrets have `status=protected`.
106 - list: "request.object.spec.volumes[].secret"
107 context:
108 - name: status
109 apiCall:
110 jmesPath: "metadata.labels.status || ''"
111 urlPath: "/api/v1/namespaces/{{request.namespace}}/secrets/{{element.secretName}}"
112 deny:
113 conditions:
114 any:
115 - key: "{{ status }}"
116 operator: Equals
117 value: protected