Skip to content

Commit 350c55e

Browse files
[Security Hardened Kubernetes Cluster] Add labelSelectors to rule options (#589)
* Add labelSelectors to all Hardened K8s rules * Adapt example files * Fix copy/paste typo * Return nil error on Errored check result
1 parent 79299d8 commit 350c55e

File tree

17 files changed

+328
-215
lines changed

17 files changed

+328
-215
lines changed

example/config/managedk8s.yaml

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -183,19 +183,22 @@ providers: # contains information about known providers
183183
# justification: "the whole rule is accepted for ... reasons"
184184
# args:
185185
# acceptedNamespaces:
186-
# - matchLabels:
187-
# foo: bar
186+
# - labelSelector:
187+
# matchLabels:
188+
# foo: bar
188189
# justification: "justification"
189190
# acceptedTraffic:
190191
# ingress: true
191192
# egress: true
192193
# - ruleID: "2001"
193194
# args:
194195
# acceptedPods:
195-
# - matchLabels:
196-
# foo: bar
197-
# namespaceMatchLabels:
198-
# foo: bar
196+
# - labelSelector:
197+
# matchLabels:
198+
# foo: bar
199+
# namespaceLabelSelector:
200+
# matchLabels:
201+
# foo: bar
199202
# justification: "justification"
200203
# - ruleID: "2002"
201204
# args:
@@ -207,28 +210,34 @@ providers: # contains information about known providers
207210
# - ruleID: "2003"
208211
# args:
209212
# acceptedPods:
210-
# - matchLabels:
211-
# foo: bar
212-
# namespaceMatchLabels:
213-
# foo: bar
213+
# - labelSelector:
214+
# matchLabels:
215+
# foo: bar
216+
# namespaceLabelSelector:
217+
# matchLabels:
218+
# foo: bar
214219
# justification: "justification"
215220
# volumeNames:
216221
# - "volume-a"
217222
# - "volume-b"
218-
# - matchLabels:
219-
# foo: baz
220-
# namespaceMatchLabels:
221-
# foo: baz
223+
# - labelSelector:
224+
# matchLabels:
225+
# foo: baz
226+
# namespaceLabelSelector:
227+
# matchLabels:
228+
# foo: baz
222229
# justification: "justification"
223230
# volumeNames:
224231
# - "*" # a wildcard can be used to match against all volumes in an accepted pod
225232
# - ruleID: "2004"
226233
# args:
227234
# acceptedServices:
228-
# - matchLabels:
229-
# foo: bar
230-
# namespaceMatchLabels:
231-
# foo: bar
235+
# - labelSelector:
236+
# matchLabels:
237+
# foo: bar
238+
# namespaceLabelSelector:
239+
# matchLabels:
240+
# foo: bar
232241
# justification: "justification"
233242
# - ruleID: "2005"
234243
# args:
@@ -237,42 +246,52 @@ providers: # contains information about known providers
237246
# - ruleID: "2006"
238247
# args:
239248
# acceptedRoles:
240-
# - matchLabels:
241-
# foo: bar
242-
# namespaceMatchLabels:
243-
# foo: bar
249+
# - labelSelector:
250+
# matchLabels:
251+
# foo: bar
252+
# namespaceLabelSelector:
253+
# matchLabels:
254+
# foo: bar
244255
# justification: "justification"
245256
# acceptedClusterRoles:
246-
# - matchLabels:
247-
# foo: bar
257+
# - labelSelector:
258+
# matchLabels:
259+
# foo: bar
248260
# justification: "justification"
249261
# - ruleID: "2007"
250262
# args:
251263
# acceptedRoles:
252-
# - matchLabels:
253-
# foo: bar
254-
# namespaceMatchLabels:
255-
# foo: bar
264+
# - labelSelector:
265+
# matchLabels:
266+
# foo: bar
267+
# namespaceLabelSelector:
268+
# matchLabels:
269+
# foo: bar
256270
# justification: "justification"
257271
# acceptedClusterRoles:
258-
# - matchLabels:
259-
# foo: bar
272+
# - labelSelector:
273+
# matchLabels:
274+
# foo: bar
260275
# justification: "justification"
261276
# - ruleID: "2008"
262277
# args:
263278
# acceptedPods:
264-
# - matchLabels:
265-
# foo: bar
266-
# namespaceMatchLabels:
267-
# foo: bar
279+
# - labelSelector:
280+
# matchLabels:
281+
# foo: bar
282+
# namespaceLabelSelector:
283+
# matchLabels:
284+
# foo: bar
268285
# justification: "justification"
269286
# volumeNames:
270287
# - "volume-a"
271288
# - "volume-b"
272-
# - matchLabels:
273-
# foo: baz
274-
# namespaceMatchLabels:
275-
# foo: baz
289+
# - labelSelector:
290+
# matchLabels:
291+
# foo: baz
292+
# namespaceLabelSelector:
293+
# matchLabels:
294+
# foo: baz
276295
# justification: "justification"
277296
# volumeNames:
278297
# - "*" # a wildcard can be used to match against all volumes in an accepted pod

example/guides/security-hardened-k8s-shoot.yaml

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,75 +14,92 @@ providers:
1414
- ruleID: "2000"
1515
args:
1616
acceptedNamespaces:
17-
- matchLabels:
18-
resources.gardener.cloud/managed-by: gardener
17+
- labelSelector:
18+
matchLabels:
19+
resources.gardener.cloud/managed-by: gardener
1920
justification: "Gardener managed namespaces are accepted to allow traffic by default."
2021
acceptedTraffic:
2122
ingress: true
2223
egress: true
2324
- ruleID: "2001"
2425
args:
2526
acceptedPods:
26-
- matchLabels:
27-
resources.gardener.cloud/managed-by: gardener
28-
namespaceMatchLabels:
29-
resources.gardener.cloud/managed-by: gardener
27+
- labelSelector:
28+
matchLabels:
29+
resources.gardener.cloud/managed-by: gardener
30+
namespaceLabelSelector:
31+
matchLabels:
32+
resources.gardener.cloud/managed-by: gardener
3033
justification: "Gardener managed resources are accepted to allow privilege escalation."
3134
- ruleID: "2003"
3235
args:
3336
acceptedPods:
34-
- matchLabels:
35-
resources.gardener.cloud/managed-by: gardener
36-
namespaceMatchLabels:
37-
resources.gardener.cloud/managed-by: gardener
37+
- labelSelector:
38+
matchLabels:
39+
resources.gardener.cloud/managed-by: gardener
40+
namespaceLabelSelector:
41+
matchLabels:
42+
resources.gardener.cloud/managed-by: gardener
3843
justification: "Gardener managed resources are accepted to use a wider range of volume types."
3944
volumeNames:
4045
- "*"
4146
- ruleID: "2004"
4247
args:
4348
acceptedServices:
44-
- matchLabels:
45-
resources.gardener.cloud/managed-by: gardener
46-
namespaceMatchLabels:
47-
resources.gardener.cloud/managed-by: gardener
49+
- labelSelector:
50+
matchLabels:
51+
resources.gardener.cloud/managed-by: gardener
52+
namespaceLabelSelector:
53+
matchLabels:
54+
resources.gardener.cloud/managed-by: gardener
4855
justification: "Gardener managed services are accepted to be of type NodePort."
4956
- ruleID: "2006"
5057
args:
5158
acceptedRoles:
52-
- matchLabels:
53-
resources.gardener.cloud/managed-by: gardener
54-
namespaceMatchLabels:
55-
resources.gardener.cloud/managed-by: gardener
59+
- labelSelector:
60+
matchLabels:
61+
resources.gardener.cloud/managed-by: gardener
62+
namespaceLabelSelector:
63+
matchLabels:
64+
resources.gardener.cloud/managed-by: gardener
5665
justification: "Roles managed by Gardener are accepted to use wildcards in RBAC resources."
5766
acceptedClusterRoles:
58-
- matchLabels:
59-
resources.gardener.cloud/managed-by: gardener
67+
- labelSelector:
68+
matchLabels:
69+
resources.gardener.cloud/managed-by: gardener
6070
justification: "ClusterRoles managed by Gardener are accepted to use wildcards in RBAC resources."
61-
- matchLabels:
62-
kubernetes.io/bootstrapping: rbac-defaults
71+
- labelSelector:
72+
matchLabels:
73+
kubernetes.io/bootstrapping: rbac-defaults
6374
justification: "Kubernetes default ClusterRoles are accepted to use wildcards in RBAC resources."
6475
- ruleID: "2007"
6576
args:
6677
acceptedRoles:
67-
- matchLabels:
68-
resources.gardener.cloud/managed-by: gardener
69-
namespaceMatchLabels:
70-
resources.gardener.cloud/managed-by: gardener
78+
- labelSelector:
79+
matchLabels:
80+
resources.gardener.cloud/managed-by: gardener
81+
namespaceLabelSelector:
82+
matchLabels:
83+
resources.gardener.cloud/managed-by: gardener
7184
justification: "Roles managed by Gardener are accepted to use wildcards in RBAC verbs."
7285
acceptedClusterRoles:
73-
- matchLabels:
86+
- labelSelector:
87+
matchLabels:
7488
resources.gardener.cloud/managed-by: gardener
7589
justification: "ClusterRoles managed by Gardener are accepted to use wildcards in RBAC verbs."
76-
- matchLabels:
77-
kubernetes.io/bootstrapping: rbac-defaults
90+
- labelSelector:
91+
matchLabels:
92+
kubernetes.io/bootstrapping: rbac-defaults
7893
justification: "Kubernetes default ClusterRoles are accepted to use wildcards in RBAC verbs."
7994
- ruleID: "2008"
8095
args:
8196
acceptedPods:
82-
- matchLabels:
83-
resources.gardener.cloud/managed-by: gardener
84-
namespaceMatchLabels:
85-
resources.gardener.cloud/managed-by: gardener
97+
- labelSelector:
98+
matchLabels:
99+
resources.gardener.cloud/managed-by: gardener
100+
namespaceLabelSelector:
101+
matchLabels:
102+
resources.gardener.cloud/managed-by: gardener
86103
justification: "Gardener managed resources are accepted to use a wider range of volume types."
87104
volumeNames:
88105
- "*"

pkg/provider/managedk8s/ruleset/securityhardenedk8s/rules/2000.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import (
88
"context"
99
"slices"
1010

11-
corev1 "k8s.io/api/core/v1"
1211
networkingv1 "k8s.io/api/networking/v1"
1312
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1413
"k8s.io/apimachinery/pkg/labels"
1514
"sigs.k8s.io/controller-runtime/pkg/client"
1615

17-
"github.com/gardener/diki/pkg/internal/utils"
1816
kubeutils "github.com/gardener/diki/pkg/kubernetes/utils"
1917
"github.com/gardener/diki/pkg/rule"
2018
"github.com/gardener/diki/pkg/shared/kubernetes/option"
@@ -127,7 +125,10 @@ func (r *Rule2000) Run(ctx context.Context) (rule.RuleResult, error) {
127125
if deniesAllIngress && !allowsAllIngress {
128126
checkResults = append(checkResults, rule.PassedCheckResult("Ingress traffic is denied by default.", deniesAllIngressTarget))
129127
} else {
130-
accepted, justification := r.acceptedIngress(namespace)
128+
accepted, justification, err := r.acceptedIngress(namespace.Labels)
129+
if err != nil {
130+
return rule.Result(r, rule.ErroredCheckResult(err.Error(), rule.NewTarget())), nil
131+
}
131132

132133
acceptedTarget := target
133134
msg := "Namespace is accepted to allow Ingress traffic by default."
@@ -152,7 +153,10 @@ func (r *Rule2000) Run(ctx context.Context) (rule.RuleResult, error) {
152153
if deniesAllEgress && !allowsAllEgress {
153154
checkResults = append(checkResults, rule.PassedCheckResult("Egress traffic is denied by default.", deniesAllEgressTarget))
154155
} else {
155-
accepted, justification := r.acceptedEgress(namespace)
156+
accepted, justification, err := r.acceptedEgress(namespace.Labels)
157+
if err != nil {
158+
return rule.Result(r, rule.ErroredCheckResult(err.Error(), rule.NewTarget())), nil
159+
}
156160

157161
acceptedTarget := target
158162
msg := "Namespace is accepted to allow Egress traffic by default."
@@ -178,33 +182,34 @@ func (r *Rule2000) Run(ctx context.Context) (rule.RuleResult, error) {
178182
return rule.Result(r, checkResults...), nil
179183
}
180184

181-
func (r *Rule2000) acceptedIngress(namespace corev1.Namespace) (bool, string) {
185+
func (r *Rule2000) acceptedIngress(namespaceLabels map[string]string) (bool, string, error) {
182186
if r.Options == nil {
183-
return false, ""
187+
return false, "", nil
184188
}
185189

186190
for _, acceptedNamespace := range r.Options.AcceptedNamespaces {
187-
188-
if utils.MatchLabels(namespace.Labels, acceptedNamespace.MatchLabels) &&
189-
acceptedNamespace.AcceptedTraffic.Ingress {
190-
return true, acceptedNamespace.Justification
191+
if matches, err := acceptedNamespace.Matches(namespaceLabels); err != nil {
192+
return false, "", err
193+
} else if matches && acceptedNamespace.AcceptedTraffic.Ingress {
194+
return true, acceptedNamespace.Justification, nil
191195
}
192196
}
193197

194-
return false, ""
198+
return false, "", nil
195199
}
196200

197-
func (r *Rule2000) acceptedEgress(namespace corev1.Namespace) (bool, string) {
201+
func (r *Rule2000) acceptedEgress(namespaceLabels map[string]string) (bool, string, error) {
198202
if r.Options == nil {
199-
return false, ""
203+
return false, "", nil
200204
}
201205

202206
for _, acceptedNamespace := range r.Options.AcceptedNamespaces {
203-
if utils.MatchLabels(namespace.Labels, acceptedNamespace.MatchLabels) &&
204-
acceptedNamespace.AcceptedTraffic.Egress {
205-
return true, acceptedNamespace.Justification
207+
if matches, err := acceptedNamespace.Matches(namespaceLabels); err != nil {
208+
return false, "", err
209+
} else if matches && acceptedNamespace.AcceptedTraffic.Egress {
210+
return true, acceptedNamespace.Justification, nil
206211
}
207212
}
208213

209-
return false, ""
214+
return false, "", nil
210215
}

0 commit comments

Comments
 (0)