Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1440 from stlaz/deads2k_featuresets_412_psa_enable
[4.12] OCPBUGS-6789: enable pod security admission for techpreview
- Loading branch information
Showing
77 changed files
with
11,515 additions
and
16,964 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
pkg/operator/configobservation/auth/podsecurityadmission.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package auth | ||
|
||
import ( | ||
"fmt" | ||
|
||
configv1 "github.com/openshift/api/config/v1" | ||
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" | ||
"github.com/openshift/library-go/pkg/operator/configobserver" | ||
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates" | ||
"github.com/openshift/library-go/pkg/operator/events" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/util/sets" | ||
) | ||
|
||
type FeatureGateLister interface { | ||
FeatureGateLister() configlistersv1.FeatureGateLister | ||
} | ||
|
||
var configPath = []string{"admission", "pluginConfig", "PodSecurity", "configuration", "defaults"} | ||
|
||
// We want this: | ||
/* | ||
admission: | ||
pluginConfig: | ||
PodSecurity: | ||
configuration: | ||
kind: PodSecurityConfiguration | ||
apiVersion: pod-security.admission.config.k8s.io/v1beta1 | ||
defaults: | ||
enforce: "restricted" | ||
enforce-version: "latest" | ||
*/ | ||
func SetPodSecurityAdmissionToEnforceRestricted(config map[string]interface{}) error { | ||
psaEnforceRestricted := map[string]interface{}{ | ||
"enforce": "restricted", | ||
"enforce-version": "latest", | ||
"audit": "restricted", | ||
"audit-version": "latest", | ||
"warn": "restricted", | ||
"warn-version": "latest", | ||
} | ||
|
||
unstructured.RemoveNestedField(config, configPath...) | ||
if err := unstructured.SetNestedMap(config, psaEnforceRestricted, configPath...); err != nil { | ||
return fmt.Errorf("failed to set PodSecurity to enforce restricted: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func SetPodSecurityAdmissionToEnforcePrivileged(config map[string]interface{}) error { | ||
psaEnforceRestricted := map[string]interface{}{ | ||
"enforce": "privileged", | ||
"enforce-version": "latest", | ||
"audit": "restricted", | ||
"audit-version": "latest", | ||
"warn": "restricted", | ||
"warn-version": "latest", | ||
} | ||
|
||
unstructured.RemoveNestedField(config, configPath...) | ||
if err := unstructured.SetNestedMap(config, psaEnforceRestricted, configPath...); err != nil { | ||
return fmt.Errorf("failed to set PodSecurity to enforce restricted: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// ObserveFeatureFlags fills in --feature-flags for the kube-apiserver | ||
func ObservePodSecurityAdmissionEnforcement(genericListers configobserver.Listers, recorder events.Recorder, existingConfig map[string]interface{}) (ret map[string]interface{}, _ []error) { | ||
listers := genericListers.(FeatureGateLister) | ||
errs := []error{} | ||
|
||
featureGate, err := listers.FeatureGateLister().Get("cluster") | ||
// if we have no featuregate, then the installer and MCO probably still have way to reconcile certain custom resources | ||
// we will assume that this means the same as default and hope for the best | ||
if apierrors.IsNotFound(err) { | ||
featureGate = &configv1.FeatureGate{ | ||
Spec: configv1.FeatureGateSpec{ | ||
FeatureGateSelection: configv1.FeatureGateSelection{ | ||
FeatureSet: configv1.Default, | ||
}, | ||
}, | ||
} | ||
} else if err != nil { | ||
return existingConfig, append(errs, err) | ||
} | ||
|
||
return observePodSecurityAdmissionEnforcement(featureGate, recorder, existingConfig) | ||
} | ||
|
||
func observePodSecurityAdmissionEnforcement(featureGate *configv1.FeatureGate, recorder events.Recorder, existingConfig map[string]interface{}) (ret map[string]interface{}, _ []error) { | ||
defer func() { | ||
ret = configobserver.Pruned(ret, configPath) | ||
}() | ||
|
||
errs := []error{} | ||
|
||
enabled, _, err := featuregates.FeaturesGatesFromFeatureSets(featureGate) | ||
if err != nil { | ||
return existingConfig, append(errs, err) | ||
} | ||
|
||
observedConfig := map[string]interface{}{} | ||
switch { | ||
case sets.NewString(enabled...).Has("OpenShiftPodSecurityAdmission"): | ||
if err := SetPodSecurityAdmissionToEnforceRestricted(observedConfig); err != nil { | ||
return existingConfig, append(errs, err) | ||
} | ||
default: | ||
if err := SetPodSecurityAdmissionToEnforcePrivileged(observedConfig); err != nil { | ||
return existingConfig, append(errs, err) | ||
} | ||
} | ||
|
||
return observedConfig, errs | ||
} |
118 changes: 118 additions & 0 deletions
118
pkg/operator/configobservation/auth/podsecurityadmission_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package auth | ||
|
||
import ( | ||
"encoding/json" | ||
"strings" | ||
"testing" | ||
|
||
utilerrors "k8s.io/apimachinery/pkg/util/errors" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/stretchr/testify/require" | ||
|
||
configv1 "github.com/openshift/api/config/v1" | ||
"github.com/openshift/library-go/pkg/operator/events" | ||
) | ||
|
||
func TestObservePodSecurityAdmissionEnforcement(t *testing.T) { | ||
privilegedMap := map[string]interface{}{} | ||
require.NoError(t, SetPodSecurityAdmissionToEnforcePrivileged(privilegedMap)) | ||
privilegedJSON, err := json.Marshal(privilegedMap) | ||
require.NoError(t, err) | ||
|
||
restrictedMap := map[string]interface{}{} | ||
require.NoError(t, SetPodSecurityAdmissionToEnforceRestricted(restrictedMap)) | ||
restrictedJSON, err := json.Marshal(restrictedMap) | ||
require.NoError(t, err) | ||
|
||
defaultFeatureSet := &configv1.FeatureGate{ | ||
Spec: configv1.FeatureGateSpec{ | ||
FeatureGateSelection: configv1.FeatureGateSelection{ | ||
FeatureSet: "", | ||
CustomNoUpgrade: nil, | ||
}, | ||
}, | ||
} | ||
|
||
corruptFeatureSet := &configv1.FeatureGate{ | ||
Spec: configv1.FeatureGateSpec{ | ||
FeatureGateSelection: configv1.FeatureGateSelection{ | ||
FeatureSet: "Bad", | ||
CustomNoUpgrade: nil, | ||
}, | ||
}, | ||
} | ||
|
||
disabledFeatureSet := &configv1.FeatureGate{ | ||
Spec: configv1.FeatureGateSpec{ | ||
FeatureGateSelection: configv1.FeatureGateSelection{ | ||
FeatureSet: "CustomNoUpgrade", | ||
CustomNoUpgrade: &configv1.CustomFeatureGates{ | ||
Enabled: []string{"OpenShiftPodSecurityAdmission"}, | ||
Disabled: nil, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range []struct { | ||
name string | ||
existingJSON string | ||
featureGate *configv1.FeatureGate | ||
expectedErr string | ||
expectedJSON string | ||
}{ | ||
{ | ||
name: "not enabled", | ||
existingJSON: string(privilegedJSON), | ||
featureGate: defaultFeatureSet, | ||
expectedErr: "", | ||
expectedJSON: string(privilegedJSON), | ||
}, | ||
{ | ||
name: "corrupt-1", | ||
existingJSON: string(privilegedJSON), | ||
featureGate: corruptFeatureSet, | ||
expectedErr: "not found", | ||
expectedJSON: string(privilegedJSON), | ||
}, | ||
{ | ||
name: "corrupt-2", | ||
existingJSON: string(restrictedJSON), | ||
featureGate: corruptFeatureSet, | ||
expectedErr: "not found", | ||
expectedJSON: string(restrictedJSON), | ||
}, | ||
{ | ||
name: "enabled", | ||
existingJSON: string(restrictedJSON), | ||
featureGate: disabledFeatureSet, | ||
expectedErr: "", | ||
expectedJSON: string(restrictedJSON), | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
testRecorder := events.NewInMemoryRecorder("SAIssuerTest") | ||
existingConfig := map[string]interface{}{} | ||
require.NoError(t, json.Unmarshal([]byte(tc.existingJSON), &existingConfig)) | ||
|
||
actual, errs := observePodSecurityAdmissionEnforcement(tc.featureGate, testRecorder, existingConfig) | ||
|
||
switch { | ||
case len(errs) == 0 && len(tc.expectedErr) == 0: | ||
case len(errs) == 0 && len(tc.expectedErr) > 0: | ||
t.Fatalf("missing err: %v", tc.expectedErr) | ||
|
||
case len(errs) > 0 && len(tc.expectedErr) == 0: | ||
t.Fatal(errs) | ||
case len(errs) > 0 && len(tc.expectedErr) > 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), tc.expectedErr): | ||
t.Fatalf("missing err: %v in \n%v", tc.expectedErr, errs) | ||
} | ||
|
||
actualJSON, err := json.Marshal(actual) | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, tc.expectedJSON, string(actualJSON), cmp.Diff(tc.expectedJSON, string(actualJSON))) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.