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

Signed-off-by: Anik Bhattacharjee <anikbhattacharya93@gmail.com>
  • Loading branch information
anik120 committed Jul 27, 2022
1 parent 6c4e779 commit 19f2901
Show file tree
Hide file tree
Showing 26 changed files with 397 additions and 138 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", -1, "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
10 changes: 10 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,19 @@ apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.namespace }}
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest

---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.operator_namespace }}
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: baseline
pod-security.kubernetes.io/warn-version: latest
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
- "{{ .Values.package.securityContext.runAsUser }}"
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
41 changes: 34 additions & 7 deletions pkg/controller/bundle/bundle_unpacker.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
listersbatchv1 "k8s.io/client-go/listers/batch/v1"
listerscorev1 "k8s.io/client-go/listers/core/v1"
listersrbacv1 "k8s.io/client-go/listers/rbac/v1"
"k8s.io/utils/pointer"

"github.com/operator-framework/api/pkg/operators/reference"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
Expand Down Expand Up @@ -85,7 +86,7 @@ func newBundleUnpackResult(lookup *operatorsv1alpha1.BundleLookup) *BundleUnpack
}
}

func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, annotationUnpackTimeout time.Duration) *batchv1.Job {
func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, annotationUnpackTimeout time.Duration, runAsUser int64) *batchv1.Job {
job := &batchv1.Job{
Spec: batchv1.JobSpec{
//ttlSecondsAfterFinished: 0 // can use in the future to not have to clean up job
Expand All @@ -101,6 +102,12 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
// See: https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-backoff-failure-policy
RestartPolicy: corev1.RestartPolicyNever,
ImagePullSecrets: secrets,
SecurityContext: &corev1.PodSecurityContext{
RunAsNonRoot: pointer.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
},
Containers: []corev1.Container{
{
Name: "extract",
Expand Down Expand Up @@ -129,6 +136,12 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
corev1.ResourceMemory: resource.MustParse("50Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
},
},
InitContainers: []corev1.Container{
Expand All @@ -148,6 +161,12 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
corev1.ResourceMemory: resource.MustParse("50Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
},
{
Name: "pull",
Expand All @@ -170,6 +189,12 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
corev1.ResourceMemory: resource.MustParse("50Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
},
},
Volumes: []corev1.Volume{
Expand All @@ -193,7 +218,9 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
job.SetNamespace(cmRef.Namespace)
job.SetName(cmRef.Name)
job.SetOwnerReferences([]metav1.OwnerReference{ownerRef(cmRef)})

if runAsUser > 0 {
job.Spec.Template.Spec.SecurityContext.RunAsUser = &runAsUser
}
// By default the BackoffLimit is set to 6 which with exponential backoff 10s + 20s + 40s ...
// translates to ~10m of waiting time.
// We want to fail faster than that when we have repeated failures from the bundle unpack pod
Expand Down Expand Up @@ -229,7 +256,7 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Unpacker

type Unpacker interface {
UnpackBundle(lookup *operatorsv1alpha1.BundleLookup, timeout time.Duration) (result *BundleUnpackResult, err error)
UnpackBundle(lookup *operatorsv1alpha1.BundleLookup, timeout time.Duration, runAsUser int64) (result *BundleUnpackResult, err error)
}

type ConfigMapUnpacker struct {
Expand Down Expand Up @@ -383,7 +410,7 @@ const (
NotUnpackedMessage = "bundle contents have not yet been persisted to installplan status"
)

func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup, timeout time.Duration) (result *BundleUnpackResult, err error) {
func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup, timeout time.Duration, runAsUser int64) (result *BundleUnpackResult, err error) {
result = newBundleUnpackResult(lookup)

// if bundle lookup failed condition already present, then there is nothing more to do
Expand Down Expand Up @@ -445,7 +472,7 @@ func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup,
secrets = append(secrets, corev1.LocalObjectReference{Name: secretName})
}
var job *batchv1.Job
job, err = c.ensureJob(cmRef, result.Path, secrets, timeout)
job, err = c.ensureJob(cmRef, result.Path, secrets, timeout, runAsUser)
if err != nil || job == nil {
// ensureJob can return nil if the job present does not match the expected job (spec and ownerefs)
// The current job is deleted in that case so UnpackBundle needs to be retried
Expand Down Expand Up @@ -584,8 +611,8 @@ func (c *ConfigMapUnpacker) ensureConfigmap(csRef *corev1.ObjectReference, name
return
}

func (c *ConfigMapUnpacker) ensureJob(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, timeout time.Duration) (job *batchv1.Job, err error) {
fresh := c.job(cmRef, bundlePath, secrets, timeout)
func (c *ConfigMapUnpacker) ensureJob(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, timeout time.Duration, runAsUser int64) (job *batchv1.Job, err error) {
fresh := c.job(cmRef, bundlePath, secrets, timeout, runAsUser)
job, err = c.jobLister.Jobs(fresh.GetNamespace()).Get(fresh.GetName())
if err != nil {
if apierrors.IsNotFound(err) {
Expand Down

0 comments on commit 19f2901

Please sign in to comment.