Skip to content

Commit 5a0fac4

Browse files
gnufiedbertinatto
authored andcommitted
UPSTREAM: <carry>: Add plugin for storage performant security policy
Add featuregate for performantsecuritypolicy for storage
1 parent 3500f94 commit 5a0fac4

File tree

4 files changed

+416
-4
lines changed

4 files changed

+416
-4
lines changed

openshift-kube-apiserver/admission/admissionenablement/register.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
projectnodeenv "k8s.io/kubernetes/openshift-kube-apiserver/admission/scheduler/nodeenv"
2525
schedulerpodnodeconstraints "k8s.io/kubernetes/openshift-kube-apiserver/admission/scheduler/podnodeconstraints"
2626
"k8s.io/kubernetes/openshift-kube-apiserver/admission/storage/csiinlinevolumesecurity"
27+
"k8s.io/kubernetes/openshift-kube-apiserver/admission/storage/performantsecuritypolicy"
2728
)
2829

2930
func RegisterOpenshiftKubeAdmissionPlugins(plugins *admission.Plugins) {
@@ -44,6 +45,7 @@ func RegisterOpenshiftKubeAdmissionPlugins(plugins *admission.Plugins) {
4445
externalipranger.RegisterExternalIP(plugins)
4546
restrictedendpoints.RegisterRestrictedEndpoints(plugins)
4647
csiinlinevolumesecurity.Register(plugins)
48+
performantsecuritypolicy.Register(plugins)
4749
}
4850

4951
var (
@@ -73,10 +75,11 @@ var (
7375
"security.openshift.io/SecurityContextConstraint",
7476
"security.openshift.io/SCCExecRestrictions",
7577
"route.openshift.io/IngressAdmission",
76-
hostassignment.PluginName, // "route.openshift.io/RouteHostAssignment"
77-
csiinlinevolumesecurity.PluginName, // "storage.openshift.io/CSIInlineVolumeSecurity"
78-
managednode.PluginName, // "autoscaling.openshift.io/ManagedNode"
79-
mixedcpus.PluginName, // "autoscaling.openshift.io/MixedCPUs"
78+
hostassignment.PluginName, // "route.openshift.io/RouteHostAssignment"
79+
csiinlinevolumesecurity.PluginName, // "storage.openshift.io/CSIInlineVolumeSecurity"
80+
managednode.PluginName, // "autoscaling.openshift.io/ManagedNode"
81+
mixedcpus.PluginName, // "autoscaling.openshift.io/MixedCPUs"
82+
performantsecuritypolicy.PluginName, // "storage.openshift.io/PerformantSecurityPolicy"
8083
}
8184

8285
// openshiftAdmissionPluginsForKubeAfterResourceQuota are the plugins to add after ResourceQuota plugin
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package performantsecuritypolicy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
8+
openshiftfeatures "github.com/openshift/api/features"
9+
corev1 "k8s.io/api/core/v1"
10+
"k8s.io/apiserver/pkg/admission"
11+
"k8s.io/apiserver/pkg/admission/initializer"
12+
"k8s.io/apiserver/pkg/audit"
13+
"k8s.io/apiserver/pkg/warning"
14+
"k8s.io/client-go/informers"
15+
corev1listers "k8s.io/client-go/listers/core/v1"
16+
"k8s.io/component-base/featuregate"
17+
"k8s.io/klog/v2"
18+
kapi "k8s.io/kubernetes/pkg/apis/core"
19+
)
20+
21+
const (
22+
PluginName = "storage.openshift.io/PerformantSecurityPolicy"
23+
fsGroupChangePolicyLabel = "storage.openshift.io/fsgroup-change-policy"
24+
selinuxChangePolicyLabel = "storage.openshift.io/selinux-change-policy"
25+
26+
warningFormat = "found %s label with invalid %s: %s on %s namespace"
27+
)
28+
29+
var (
30+
_ = initializer.WantsExternalKubeInformerFactory(&performantSecurityPolicy{})
31+
_ = admission.MutationInterface(&performantSecurityPolicy{})
32+
_ = initializer.WantsFeatures(&performantSecurityPolicy{})
33+
34+
fsGroupPolicyPodAuditLabel = fmt.Sprintf("%s-pod", fsGroupChangePolicyLabel)
35+
selinuxPolicyPodAuditLabel = fmt.Sprintf("%s-pod", selinuxChangePolicyLabel)
36+
)
37+
38+
func Register(plugins *admission.Plugins) {
39+
plugins.Register(PluginName,
40+
func(config io.Reader) (admission.Interface, error) {
41+
return &performantSecurityPolicy{
42+
Handler: admission.NewHandler(admission.Create),
43+
}, nil
44+
})
45+
}
46+
47+
// performantSecurityPolicy checks and applies if a default FSGroupChangePolicy and SELinuxChangePolicy
48+
// should be applied to the pod.
49+
type performantSecurityPolicy struct {
50+
*admission.Handler
51+
storagePerformantSecurityPolicyFeatureEnabled bool
52+
nsLister corev1listers.NamespaceLister
53+
}
54+
55+
// SetExternalKubeInformerFactory registers an informer
56+
func (c *performantSecurityPolicy) SetExternalKubeInformerFactory(kubeInformers informers.SharedInformerFactory) {
57+
c.nsLister = kubeInformers.Core().V1().Namespaces().Lister()
58+
c.SetReadyFunc(func() bool {
59+
return kubeInformers.Core().V1().Namespaces().Informer().HasSynced()
60+
})
61+
}
62+
63+
func (c *performantSecurityPolicy) InspectFeatureGates(featureGates featuregate.FeatureGate) {
64+
c.storagePerformantSecurityPolicyFeatureEnabled = featureGates.Enabled(featuregate.Feature(openshiftfeatures.FeatureGateStoragePerformantSecurityPolicy))
65+
}
66+
67+
func (c *performantSecurityPolicy) ValidateInitialization() error {
68+
if c.nsLister == nil {
69+
return fmt.Errorf("%s plugin needs a namespace lister", PluginName)
70+
}
71+
return nil
72+
}
73+
74+
func (c *performantSecurityPolicy) Admit(ctx context.Context, attributes admission.Attributes, _ admission.ObjectInterfaces) error {
75+
if !c.storagePerformantSecurityPolicyFeatureEnabled {
76+
return nil
77+
}
78+
79+
if !c.WaitForReady() {
80+
return admission.NewForbidden(attributes, fmt.Errorf("not yet ready to handle request"))
81+
}
82+
83+
if attributes.GetResource().GroupResource() != kapi.Resource("pods") ||
84+
len(attributes.GetSubresource()) > 0 {
85+
return nil
86+
}
87+
88+
pod, ok := attributes.GetObject().(*kapi.Pod)
89+
if !ok {
90+
return admission.NewForbidden(attributes, fmt.Errorf("unexpected object: %#v", attributes.GetObject()))
91+
}
92+
93+
ns, err := c.nsLister.Get(pod.Namespace)
94+
if err != nil {
95+
return fmt.Errorf("error listing pod namespace: %v", err)
96+
}
97+
podNameKey := fmt.Sprintf("%s/%s", attributes.GetName(), attributes.GetNamespace())
98+
99+
currentFSGroupChangePolicy := extractCurrentFSGroupChangePolicy(pod)
100+
if currentFSGroupChangePolicy == nil {
101+
currentFSGroupChangePolicy = getDefaultFSGroupChangePolicy(ctx, ns)
102+
if currentFSGroupChangePolicy != nil {
103+
klog.V(4).Infof("Setting default FSGroupChangePolicy %s for pod %s", *currentFSGroupChangePolicy, podNameKey)
104+
audit.AddAuditAnnotations(ctx, fsGroupChangePolicyLabel, string(*currentFSGroupChangePolicy), fsGroupPolicyPodAuditLabel, podNameKey)
105+
if pod.Spec.SecurityContext != nil {
106+
pod.Spec.SecurityContext.FSGroupChangePolicy = currentFSGroupChangePolicy
107+
} else {
108+
pod.Spec.SecurityContext = &kapi.PodSecurityContext{
109+
FSGroupChangePolicy: currentFSGroupChangePolicy,
110+
}
111+
}
112+
}
113+
}
114+
115+
currentSELinuxChangePolicy := extractCurrentSELinuxChangePolicy(pod)
116+
if currentSELinuxChangePolicy == nil {
117+
currentSELinuxChangePolicy = getDefaultSELinuxChangePolicy(ctx, ns)
118+
if currentSELinuxChangePolicy != nil {
119+
klog.V(4).Infof("Setting default SELinuxChangePolicy %s for pod %s", *currentSELinuxChangePolicy, podNameKey)
120+
audit.AddAuditAnnotations(ctx, selinuxChangePolicyLabel, string(*currentSELinuxChangePolicy), selinuxPolicyPodAuditLabel, podNameKey)
121+
if pod.Spec.SecurityContext != nil {
122+
pod.Spec.SecurityContext.SELinuxChangePolicy = currentSELinuxChangePolicy
123+
} else {
124+
pod.Spec.SecurityContext = &kapi.PodSecurityContext{
125+
SELinuxChangePolicy: currentSELinuxChangePolicy,
126+
}
127+
}
128+
}
129+
}
130+
return nil
131+
}
132+
133+
func extractCurrentSELinuxChangePolicy(pod *kapi.Pod) *kapi.PodSELinuxChangePolicy {
134+
if pod.Spec.SecurityContext != nil {
135+
return pod.Spec.SecurityContext.SELinuxChangePolicy
136+
}
137+
138+
return nil
139+
}
140+
141+
func extractCurrentFSGroupChangePolicy(pod *kapi.Pod) *kapi.PodFSGroupChangePolicy {
142+
if pod.Spec.SecurityContext != nil {
143+
return pod.Spec.SecurityContext.FSGroupChangePolicy
144+
}
145+
return nil
146+
}
147+
148+
func getDefaultFSGroupChangePolicy(ctx context.Context, ns *corev1.Namespace) *kapi.PodFSGroupChangePolicy {
149+
fsGroupPolicy, ok := ns.Labels[fsGroupChangePolicyLabel]
150+
if !ok {
151+
return nil
152+
}
153+
policy := kapi.PodFSGroupChangePolicy(fsGroupPolicy)
154+
155+
if policy == kapi.FSGroupChangeOnRootMismatch || policy == kapi.FSGroupChangeAlways {
156+
return &policy
157+
}
158+
klog.Warningf("found %s label with invalid fsGroupPolicy: %s", fsGroupChangePolicyLabel, fsGroupPolicy)
159+
warning.AddWarning(ctx, "", fmt.Sprintf(warningFormat, fsGroupChangePolicyLabel, "fsGroupPolicy", fsGroupPolicy, ns.Name))
160+
return nil
161+
}
162+
163+
func getDefaultSELinuxChangePolicy(ctx context.Context, ns *corev1.Namespace) *kapi.PodSELinuxChangePolicy {
164+
selinuxChangePolicy, ok := ns.Labels[selinuxChangePolicyLabel]
165+
if !ok {
166+
return nil
167+
}
168+
169+
policy := kapi.PodSELinuxChangePolicy(selinuxChangePolicy)
170+
171+
if policy == kapi.SELinuxChangePolicyMountOption || policy == kapi.SELinuxChangePolicyRecursive {
172+
return &policy
173+
}
174+
175+
klog.Warningf("found %s label with invalid selinuxPolicy: %s", selinuxChangePolicyLabel, selinuxChangePolicy)
176+
warning.AddWarning(ctx, "", fmt.Sprintf(warningFormat, selinuxChangePolicyLabel, "selinuxPolicy", selinuxChangePolicy, ns.Name))
177+
return nil
178+
179+
}

0 commit comments

Comments
 (0)