Skip to content

Commit

Permalink
(psa) make workloads compatible with psa:restricted profile
Browse files Browse the repository at this point in the history
With the introduction of [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/#pod-security-admission-labels-for-namespaces), the reccomeneded
best practice is to enforce the Restricted policy of admission (see [1] for more details).
This PR
*) Lables the olm namespace as `enforce:restricted`
*) updates the securityContext of olm workload pods(olm-operator, catalog-operator,
and CatalogSource registry pods) to adhere to the `Restricted` policy.
*) updates the bundle unpacking job to create a pod that adheres to the `Restricted` policy,
so that bundles can be unpacked in the `Restricted` namespace.

[1] https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
  • Loading branch information
anik120 committed Jul 26, 2022
1 parent 6c4e779 commit e4a9a66
Show file tree
Hide file tree
Showing 23 changed files with 193 additions and 112 deletions.
1 change: 1 addition & 0 deletions cmd/catalog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func (o *options) run(ctx context.Context, logger *logrus.Logger) error {
k8sscheme.Scheme,
o.installPlanTimeout,
o.bundleUnpackTimeout,
o.workloadUserID,
)
if err != nil {
return fmt.Errorf("error configuring catalog operator: %s", err.Error())
Expand Down
2 changes: 2 additions & 0 deletions cmd/catalog/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type options struct {
tlsKeyPath string
tlsCertPath string
clientCAPath string
workloadUserID int64

installPlanTimeout time.Duration
bundleUnpackTimeout time.Duration
Expand Down Expand Up @@ -66,6 +67,7 @@ func newRootCmd() *cobra.Command {
cmd.Flags().StringVar(&o.opmImage, "opmImage", defaultOPMImage, "the image to use for unpacking bundle content with opm")
cmd.Flags().StringVar(&o.utilImage, "util-image", defaultUtilImage, "an image containing custom olm utilities")
cmd.Flags().StringVar(&o.writeStatusName, "writeStatusName", defaultOperatorName, "ClusterOperator name in which to write status, set to \"\" to disable.")
cmd.Flags().Int64Var(&o.workloadUserID, "workload-user-id", 0, "The non-root user ID that registry pods will run as.")

cmd.Flags().BoolVar(&o.debug, "debug", false, "use debug log level")
cmd.Flags().BoolVar(&o.version, "version", false, "displays the olm version")
Expand Down
4 changes: 4 additions & 0 deletions deploy/chart/templates/0000_50_olm_00-namespace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.namespace }}
labels:
pod-security.kubernetes.io/enforce: restricted

---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.operator_namespace }}
labels:
pod-security.kubernetes.io/enforce: restricted
11 changes: 11 additions & 0 deletions deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ spec:
labels:
app: olm-operator
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
{{- if eq .Values.installType "upstream" }}
runAsUser: {{ .Values.package.securityContext.runAsUser }}
{{- end }}
serviceAccountName: olm-operator-serviceaccount
{{- if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}
volumes:
Expand All @@ -33,6 +40,10 @@ spec:
{{- end }}
containers:
- name: olm-operator
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ "ALL" ]
{{- if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}
volumeMounts:
{{- end }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ spec:
labels:
app: catalog-operator
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
{{- if eq .Values.installType "upstream" }}
runAsUser: {{ .Values.package.securityContext.runAsUser }}
{{- end }}
serviceAccountName: olm-operator-serviceaccount
{{- if or .Values.catalog.tlsSecret .Values.catalog.clientCASecret }}
volumes:
Expand All @@ -33,6 +40,10 @@ spec:
{{- end }}
containers:
- name: catalog-operator
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ "ALL" ]
{{- if or .Values.catalog.tlsSecret .Values.catalog.clientCASecret }}
volumeMounts:
{{- end }}
Expand Down Expand Up @@ -76,6 +87,8 @@ spec:
- --client-ca
- /profile-collector-cert/tls.crt
{{- end }}
- --workload-user-id
- "1001"
image: {{ .Values.catalog.image.ref }}
imagePullPolicy: {{ .Values.catalog.image.pullPolicy }}
ports:
Expand Down
15 changes: 11 additions & 4 deletions deploy/chart/templates/_packageserver.deployment-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ spec:
labels:
app: packageserver
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
{{- if eq .Values.installType "upstream" }}
runAsUser: {{ .Values.package.securityContext.runAsUser }}
{{- end }}
serviceAccountName: olm-operator-serviceaccount
{{- if .Values.package.nodeSelector }}
nodeSelector:
Expand All @@ -25,6 +32,10 @@ spec:
{{- end }}
containers:
- name: packageserver
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ "ALL" ]
command:
- /bin/package-server
- -v=4
Expand Down Expand Up @@ -61,10 +72,6 @@ spec:
resources:
{{ toYaml .Values.package.resources | indent 10 }}
{{- end }}
{{- if .Values.package.securityContext }}
securityContext:
runAsUser: {{ .Values.package.securityContext.runAsUser }}
{{- end }}
volumeMounts:
- name: tmpfs
mountPath: /tmp
Expand Down
2 changes: 2 additions & 0 deletions deploy/chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ package:
internalPort: 5443
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsUser: 1001
resources:
requests:
cpu: 10m
Expand Down
11 changes: 7 additions & 4 deletions pkg/controller/operators/catalog/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,13 @@ type Operator struct {
clientFactory clients.Factory
muInstallPlan sync.Mutex
sourceInvalidator *resolver.RegistrySourceProvider
workloadUserID int64
}

type CatalogSourceSyncFunc func(logger *logrus.Entry, in *v1alpha1.CatalogSource) (out *v1alpha1.CatalogSource, continueSync bool, syncError error)

// NewOperator creates a new Catalog Operator.
func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, opmImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration) (*Operator, error) {
func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, opmImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration, workloadUserID int64) (*Operator, error) {
resyncPeriod := queueinformer.ResyncWithJitter(resync, 0.2)
config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
if err != nil {
Expand Down Expand Up @@ -179,6 +180,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
client: crClient,
lister: lister,
namespace: operatorNamespace,
workloadUserID: workloadUserID,
recorder: eventRecorder,
catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(),
subQueueSet: queueinformer.NewEmptyResourceQueueSet(),
Expand Down Expand Up @@ -320,6 +322,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
subscription.WithAppendedReconcilers(subscription.ReconcilerFromLegacySyncHandler(op.syncSubscriptions, nil)),
subscription.WithRegistryReconcilerFactory(op.reconciler),
subscription.WithGlobalCatalogNamespace(op.namespace),
subscription.WithWorkloadUserID(workloadUserID),
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -704,15 +707,15 @@ func (o *Operator) syncRegistryServer(logger *logrus.Entry, in *v1alpha1.Catalog
out = in.DeepCopy()

sourceKey := registry.CatalogKey{Name: in.GetName(), Namespace: in.GetNamespace()}
srcReconciler := o.reconciler.ReconcilerForSource(in)
srcReconciler := o.reconciler.ReconcilerForSource(in, o.workloadUserID)
if srcReconciler == nil {
// TODO: Add failure status on catalogsource and remove from sources
syncError = fmt.Errorf("no reconciler for source type %s", in.Spec.SourceType)
out.SetError(v1alpha1.CatalogSourceRegistryServerError, syncError)
return
}

healthy, err := srcReconciler.CheckRegistryServer(in)
healthy, err := srcReconciler.CheckRegistryServer(in, o.workloadUserID)
if err != nil {
syncError = err
out.SetError(v1alpha1.CatalogSourceRegistryServerError, syncError)
Expand All @@ -733,7 +736,7 @@ func (o *Operator) syncRegistryServer(logger *logrus.Entry, in *v1alpha1.Catalog
// Registry pod hasn't been created or hasn't been updated since the last configmap update, recreate it
logger.Debug("ensuring registry server")

err = srcReconciler.EnsureRegistryServer(out)
err = srcReconciler.EnsureRegistryServer(out, o.workloadUserID)
if err != nil {
if _, ok := err.(reconciler.UpdateNotReadyErr); ok {
logger.Debug("requeueing registry server for catalog update check: update pod not yet ready")
Expand Down
8 changes: 5 additions & 3 deletions pkg/controller/operators/catalog/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1245,9 +1245,9 @@ func TestSyncResolvingNamespace(t *testing.T) {
require.NoError(t, err)

o.reconciler = &fakes.FakeRegistryReconcilerFactory{
ReconcilerForSourceStub: func(source *v1alpha1.CatalogSource) reconciler.RegistryReconciler {
ReconcilerForSourceStub: func(source *v1alpha1.CatalogSource, runAsUser int64) reconciler.RegistryReconciler {
return &fakes.FakeRegistryReconciler{
EnsureRegistryServerStub: func(source *v1alpha1.CatalogSource) error {
EnsureRegistryServerStub: func(source *v1alpha1.CatalogSource, runAsUser int64) error {
return nil
},
}
Expand Down Expand Up @@ -1439,6 +1439,7 @@ type fakeOperatorConfig struct {
recorder record.EventRecorder
reconciler reconciler.RegistryReconcilerFactory
sources []sourceAddress
// workloadUserID int64
}

// fakeOperatorOption applies an option to the given fake operator configuration.
Expand Down Expand Up @@ -1596,6 +1597,7 @@ func NewFakeOperator(ctx context.Context, namespace string, namespaces []string,
kubernetesClient: clientFake,
dynamicClient: dynamicClientFake,
},
workloadUserID: 1001,
}
op.sources = grpc.NewSourceStore(config.logger, 1*time.Second, 5*time.Second, op.syncSourceState)
if op.reconciler == nil {
Expand Down Expand Up @@ -1758,7 +1760,7 @@ func toManifest(t *testing.T, obj runtime.Object) string {
}

func pod(s v1alpha1.CatalogSource) *corev1.Pod {
pod := reconciler.Pod(&s, "registry-server", s.Spec.Image, s.GetName(), s.GetLabels(), s.GetAnnotations(), 5, 10)
pod := reconciler.Pod(&s, "registry-server", s.Spec.Image, s.GetName(), s.GetLabels(), s.GetAnnotations(), 5, 10, 1001)
ownerutil.AddOwner(pod, &s, false, false)
return pod
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/controller/operators/catalog/subscription/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type syncerConfig struct {
reconcilers kubestate.ReconcilerChain
registryReconcilerFactory reconciler.RegistryReconcilerFactory
globalCatalogNamespace string
workloadUserID int64
}

// SyncerOption is a configuration option for a subscription syncer.
Expand Down Expand Up @@ -128,6 +129,12 @@ func WithGlobalCatalogNamespace(namespace string) SyncerOption {
}
}

func WithWorkloadUserID(userID int64) SyncerOption {
return func(config *syncerConfig) {
config.workloadUserID = userID
}
}

func newInvalidConfigError(msg string) error {
return errors.Errorf("invalid subscription syncer config: %s", msg)
}
Expand Down
17 changes: 9 additions & 8 deletions pkg/controller/operators/catalog/subscription/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type catalogHealthReconciler struct {
catalogLister listers.CatalogSourceLister
registryReconcilerFactory reconciler.RegistryReconcilerFactory
globalCatalogNamespace string
workloadUserID int64
}

// Reconcile reconciles subscription catalog health conditions.
Expand All @@ -79,7 +80,7 @@ func (c *catalogHealthReconciler) Reconcile(ctx context.Context, in kubestate.St
// Gather catalog health and transition state
ns := s.Subscription().GetNamespace()
var catalogHealth []v1alpha1.SubscriptionCatalogHealth
if catalogHealth, err = c.catalogHealth(ns); err != nil {
if catalogHealth, err = c.catalogHealth(ns, c.workloadUserID); err != nil {
break
}

Expand Down Expand Up @@ -110,7 +111,7 @@ func (c *catalogHealthReconciler) Reconcile(ctx context.Context, in kubestate.St

// catalogHealth gets the health of catalogs that can affect Susbcriptions in the given namespace.
// This means all catalogs in the given namespace, as well as any catalogs in the operator's global catalog namespace.
func (c *catalogHealthReconciler) catalogHealth(namespace string) ([]v1alpha1.SubscriptionCatalogHealth, error) {
func (c *catalogHealthReconciler) catalogHealth(namespace string, userID int64) ([]v1alpha1.SubscriptionCatalogHealth, error) {
catalogs, err := c.catalogLister.CatalogSources(namespace).List(labels.Everything())
if err != nil {
return nil, err
Expand All @@ -134,7 +135,7 @@ func (c *catalogHealthReconciler) catalogHealth(namespace string) ([]v1alpha1.Su
now := c.now()
var errs []error
for i, catalog := range catalogs {
h, err := c.health(now, catalog)
h, err := c.health(now, catalog, userID)
if err != nil {
errs = append(errs, err)
continue
Expand All @@ -155,8 +156,8 @@ func (c *catalogHealthReconciler) catalogHealth(namespace string) ([]v1alpha1.Su
}

// health returns a SusbcriptionCatalogHealth for the given catalog with the given now.
func (c *catalogHealthReconciler) health(now *metav1.Time, catalog *v1alpha1.CatalogSource) (*v1alpha1.SubscriptionCatalogHealth, error) {
healthy, err := c.healthy(catalog)
func (c *catalogHealthReconciler) health(now *metav1.Time, catalog *v1alpha1.CatalogSource, userID int64) (*v1alpha1.SubscriptionCatalogHealth, error) {
healthy, err := c.healthy(catalog, userID)
if err != nil {
return nil, err
}
Expand All @@ -181,19 +182,19 @@ func (c *catalogHealthReconciler) health(now *metav1.Time, catalog *v1alpha1.Cat

// healthy returns true if the given catalog is healthy, false otherwise, and any error encountered
// while checking the catalog's registry server.
func (c *catalogHealthReconciler) healthy(catalog *v1alpha1.CatalogSource) (bool, error) {
func (c *catalogHealthReconciler) healthy(catalog *v1alpha1.CatalogSource, userID int64) (bool, error) {
if catalog.Status.Reason == v1alpha1.CatalogSourceSpecInvalidError {
// The catalog's spec is bad, mark unhealthy
return false, nil
}

// Check connection health
rec := c.registryReconcilerFactory.ReconcilerForSource(catalog)
rec := c.registryReconcilerFactory.ReconcilerForSource(catalog, userID)
if rec == nil {
return false, fmt.Errorf("could not get reconciler for catalog: %#v", catalog)
}

return rec.CheckRegistryServer(catalog)
return rec.CheckRegistryServer(catalog, userID)
}

// installPlanReconciler reconciles InstallPlan status for Subscriptions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1674,9 +1674,9 @@ func TestInstallPlanReconcile(t *testing.T) {

func fakeRegistryReconcilerFactory(healthy bool, err error) *olmfakes.FakeRegistryReconcilerFactory {
return &olmfakes.FakeRegistryReconcilerFactory{
ReconcilerForSourceStub: func(*v1alpha1.CatalogSource) registryreconciler.RegistryReconciler {
ReconcilerForSourceStub: func(*v1alpha1.CatalogSource, int64) registryreconciler.RegistryReconciler {
return &olmfakes.FakeRegistryReconciler{
CheckRegistryServerStub: func(*v1alpha1.CatalogSource) (bool, error) {
CheckRegistryServerStub: func(*v1alpha1.CatalogSource, int64) (bool, error) {
return healthy, err
},
}
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/operators/catalog/subscription/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func newSyncerWithConfig(ctx context.Context, config *syncerConfig) (kubestate.S
catalogLister: config.lister.OperatorsV1alpha1().CatalogSourceLister(),
registryReconcilerFactory: config.registryReconcilerFactory,
globalCatalogNamespace: config.globalCatalogNamespace,
workloadUserID: config.workloadUserID,
},
}
s.reconcilers = append(defaultReconcilers, s.reconcilers...)
Expand Down
8 changes: 4 additions & 4 deletions pkg/controller/operators/catalog/subscriptions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1020,9 +1020,9 @@ func TestSyncSubscriptions(t *testing.T) {
require.NoError(t, err)

o.reconciler = &fakes.FakeRegistryReconcilerFactory{
ReconcilerForSourceStub: func(source *v1alpha1.CatalogSource) reconciler.RegistryReconciler {
ReconcilerForSourceStub: func(source *v1alpha1.CatalogSource, runAsUser int64) reconciler.RegistryReconciler {
return &fakes.FakeRegistryReconciler{
EnsureRegistryServerStub: func(source *v1alpha1.CatalogSource) error {
EnsureRegistryServerStub: func(source *v1alpha1.CatalogSource, runAsUser int64) error {
return nil
},
}
Expand Down Expand Up @@ -1159,9 +1159,9 @@ func BenchmarkSyncResolvingNamespace(b *testing.B) {
},
},
reconciler: &fakes.FakeRegistryReconcilerFactory{
ReconcilerForSourceStub: func(*v1alpha1.CatalogSource) reconciler.RegistryReconciler {
ReconcilerForSourceStub: func(*v1alpha1.CatalogSource, int64) reconciler.RegistryReconciler {
return &fakes.FakeRegistryReconciler{
CheckRegistryServerStub: func(*v1alpha1.CatalogSource) (bool, error) {
CheckRegistryServerStub: func(*v1alpha1.CatalogSource, int64) (bool, error) {
return true, nil
},
}
Expand Down

0 comments on commit e4a9a66

Please sign in to comment.