Skip to content

Commit

Permalink
UPSTREAM: <carry>: make the PSA workload admission warnings honor the…
Browse files Browse the repository at this point in the history
… changes that SCC will eventually make to the pod

UPSTREAM: <carry>: pod-security: don't fail on SCC admission error

If we propagate SCC admission error during pod extraction to PodSecurity
admission, the latter will log the error instead of continuing with
unmutated pod spec, and so we will not get a validation error in
either the audit logs or as a warning.

OpenShift-Rebase-Source: 6fe5c8f
OpenShift-Rebase-Source: b4e019f

UPSTREAM: <carry>: SCC pod extractor: assume default SA if SA is empty
  • Loading branch information
deads2k authored and sairameshv committed Dec 4, 2023
1 parent 3c6b7aa commit 88f2997
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 1 deletion.
7 changes: 7 additions & 0 deletions openshift-kube-apiserver/enablement/intialization.go
Expand Up @@ -4,9 +4,12 @@ import (
"io/ioutil"
"path"

"k8s.io/kubernetes/plugin/pkg/admission/security/podsecurity"

configv1 "github.com/openshift/api/config/v1"
kubecontrolplanev1 "github.com/openshift/api/kubecontrolplane/v1"
osinv1 "github.com/openshift/api/osin/v1"
"github.com/openshift/apiserver-library-go/pkg/securitycontextconstraints/sccadmission"
"github.com/openshift/library-go/pkg/config/helpers"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -74,6 +77,8 @@ func ForceGlobalInitializationForOpenShift() {
},
})

podsecurity.SCCMutatingPodSpecExtractorInstance.SetSCCAdmission(SCCAdmissionPlugin)

// add permissions we require on our kube-apiserver
// TODO, we should scrub these out
bootstrappolicy.ClusterRoles = bootstrappolicy.OpenshiftClusterRoles
Expand All @@ -83,3 +88,5 @@ func ForceGlobalInitializationForOpenShift() {
// SkipSystemMastersAuthorizer disable implicitly added system/master authz, and turn it into another authz mode "SystemMasters", to be added via authorization-mode
authorizer.SkipSystemMastersAuthorizer()
}

var SCCAdmissionPlugin = sccadmission.NewConstraint()
6 changes: 6 additions & 0 deletions openshift-kube-apiserver/openshiftkubeapiserver/patch.go
Expand Up @@ -80,6 +80,12 @@ func OpenShiftKubeAPIServerConfigPatch(genericConfig *genericapiserver.Config, k
managementcpusoverride.NewInitializer(openshiftInformers.getOpenshiftInfraInformers().Config().V1().Infrastructures()),
managednode.NewInitializer(openshiftInformers.getOpenshiftInfraInformers().Config().V1().Infrastructures()),
)

// This is needed in order to have the correct initializers for the SCC admission plugin which is used to mutate
// PodSpecs for PodSpec-y workload objects in the pod security admission plugin.
enablement.SCCAdmissionPlugin.SetAuthorizer(genericConfig.Authorization.Authorizer)
enablement.SCCAdmissionPlugin.SetSecurityInformers(openshiftInformers.getOpenshiftSecurityInformers().Security().V1().SecurityContextConstraints())
enablement.SCCAdmissionPlugin.SetExternalKubeInformerFactory(kubeInformers)
// END ADMISSION

// HANDLER CHAIN (with oauth server and web console)
Expand Down
2 changes: 1 addition & 1 deletion plugin/pkg/admission/security/podsecurity/admission.go
Expand Up @@ -115,7 +115,7 @@ func newPlugin(reader io.Reader) (*Plugin, error) {
Configuration: config,
Evaluator: evaluator,
Metrics: getDefaultRecorder(),
PodSpecExtractor: podsecurityadmission.DefaultPodSpecExtractor{},
PodSpecExtractor: SCCMutatingPodSpecExtractorInstance,
},
}, nil
}
Expand Down
111 changes: 111 additions & 0 deletions plugin/pkg/admission/security/podsecurity/patch_podspecextractor.go
@@ -0,0 +1,111 @@
package podsecurity

import (
"context"
"fmt"

utilruntime "k8s.io/apimachinery/pkg/util/runtime"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/apis/core"
v1 "k8s.io/kubernetes/pkg/apis/core/v1"
saadmission "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
podsecurityadmission "k8s.io/pod-security-admission/admission"
)

type SCCMutatingPodSpecExtractor struct {
sccAdmission admission.MutationInterface
delegate podsecurityadmission.PodSpecExtractor
}

var SCCMutatingPodSpecExtractorInstance = &SCCMutatingPodSpecExtractor{
delegate: podsecurityadmission.DefaultPodSpecExtractor{},
}

func (s *SCCMutatingPodSpecExtractor) SetSCCAdmission(sccAdmission admission.MutationInterface) {
s.sccAdmission = sccAdmission
}

func (s *SCCMutatingPodSpecExtractor) HasPodSpec(gr schema.GroupResource) bool {
return s.delegate.HasPodSpec(gr)
}

func (s *SCCMutatingPodSpecExtractor) ExtractPodSpec(obj runtime.Object) (*metav1.ObjectMeta, *corev1.PodSpec, error) {
if s.sccAdmission == nil {
return s.delegate.ExtractPodSpec(obj)
}

switch obj := obj.(type) {
case *corev1.Pod:
return s.delegate.ExtractPodSpec(obj)
}

podTemplateMeta, originalPodSpec, err := s.delegate.ExtractPodSpec(obj)
if err != nil {
return podTemplateMeta, originalPodSpec, err
}
if originalPodSpec == nil {
return nil, nil, nil
}
objectMeta, err := meta.Accessor(obj)
if err != nil {
return podTemplateMeta, originalPodSpec, fmt.Errorf("unable to get metadata for SCC mutation: %w", err)
}

pod := &corev1.Pod{
ObjectMeta: *podTemplateMeta.DeepCopy(),
Spec: *originalPodSpec.DeepCopy(),
}
if len(pod.Namespace) == 0 {
pod.Namespace = objectMeta.GetNamespace()
}
if len(pod.Name) == 0 {
pod.Name = "pod-for-container-named-" + objectMeta.GetName()
}
if len(pod.Spec.ServiceAccountName) == 0 {
pod.Spec.ServiceAccountName = saadmission.DefaultServiceAccountName
}
internalPod := &core.Pod{}
if err := v1.Convert_v1_Pod_To_core_Pod(pod, internalPod, nil); err != nil {
return nil, nil, err
}

admissionAttributes := admission.NewAttributesRecord(
internalPod,
nil,
corev1.SchemeGroupVersion.WithKind("Pod"),
pod.Namespace,
pod.Name,
corev1.SchemeGroupVersion.WithResource("pods"),
"",
admission.Create,
nil,
false,
&user.DefaultInfo{
Name: serviceaccount.MakeUsername(pod.Namespace, pod.Spec.ServiceAccountName),
UID: "",
Groups: append([]string{user.AllAuthenticated}, serviceaccount.MakeGroupNames(pod.Namespace)...),
Extra: nil,
})
if err := s.sccAdmission.Admit(context.Background(), admissionAttributes, nil); err != nil {
// don't fail the request, just warn if SCC will fail
klog.ErrorS(err, "failed to mutate object for PSA using SCC")
utilruntime.HandleError(fmt.Errorf("failed to mutate object for PSA using SCC: %w", err))
// TODO remove this failure we're causing when SCC fails, but for now we actually need to see our test fail because that was almost really bad.
return podTemplateMeta, originalPodSpec, nil
}

if err := v1.Convert_core_Pod_To_v1_Pod(internalPod, pod, nil); err != nil {
return nil, nil, err
}

return podTemplateMeta, &pod.Spec, nil
}

0 comments on commit 88f2997

Please sign in to comment.