Skip to content

Commit

Permalink
(psa) allow legacy Catalogsources to run in non-restrcted namespaces …
Browse files Browse the repository at this point in the history
…(#2845)

* (chore) vendor in o-f/api v0.17.1

Signed-off-by: Anik Bhattacharjee <anikbhattacharya93@gmail.com>

* (psa) allow legacy Catalogsources to run in non-restrcted namespaces

This PR configures the Catalogsource reconciler to use the spec.GrpcPodConfig.SecurityContextConfig
field to determine if the pod.spec.securityContext and container[*].spec.SecurityContext for the registry
pod should be configured to be runnable in a PSA restrcited namespace or not, so that cluster admins can
indicate that they want to run legacy catalogsources in a non-resctricted (baseline/privileged) namespace.

This allows cluster admins to run catalogsources that are built with a version of opm that is less than
v1.23.2 (i.e a version of opm that does not contain [this commit](operator-framework/operator-registry#974)

Signed-off-by: Anik Bhattacharjee <anikbhattacharya93@gmail.com>

Signed-off-by: Anik Bhattacharjee <anikbhattacharya93@gmail.com>

Upstream-commit: edffd9c83c3065073e5f91ff0d7c7b78a5c77063
Upstream-repository: operator-lifecycle-manager
  • Loading branch information
anik120 authored and timflannagan committed Sep 15, 2022
1 parent b488a20 commit 6bdc9f8
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 32 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/mikefarah/yq/v3 v3.0.0-20201202084205-8846255d1c37
github.com/onsi/ginkgo/v2 v2.1.3
github.com/openshift/api v0.0.0-20220525145417-ee5b62754c68
github.com/operator-framework/api v0.16.0
github.com/operator-framework/api v0.17.1
github.com/operator-framework/operator-lifecycle-manager v0.0.0-00010101000000-000000000000
github.com/operator-framework/operator-registry v1.17.5
github.com/sirupsen/logrus v1.8.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ spec:
priorityClassName:
description: If specified, indicates the pod's priority. If not specified, the pod priority will be default or zero if there is no default.
type: string
securityContextConfig:
description: 'SecurityContextConfig can be one of `legacy` or `restricted`. The CatalogSource''s pod is either injected with the right pod.spec.securityContext and pod.spec.container[*].securityContext values to allow the pod to run in Pod Security Admission(PSA) controller''s `restricted` mode, or doesn''t set these values at all, in which case the pod can only be run in PSA `baseline` or `privileged` namespaces. By default, SecurityContextConfig is set to `restricted`. If the value is unspecified, the default value of `restricted` is used. Specifying any other value will result in a validation error. When using older catalog images, which could not be run in `restricted` mode, the SecurityContextConfig should be set to `legacy`. More information about PSA can be found here: https://kubernetes.io/docs/concepts/security/pod-security-admission/'''
type: string
default: restricted
enum:
- legacy
- restricted
tolerations:
description: Tolerations are the catalog source's pod's tolerations.
type: array
Expand Down
2 changes: 1 addition & 1 deletion staging/operator-lifecycle-manager/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/onsi/gomega v1.18.1
github.com/openshift/api v0.0.0-20220525145417-ee5b62754c68
github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a
github.com/operator-framework/api v0.16.0
github.com/operator-framework/api v0.17.1
github.com/operator-framework/operator-registry v1.17.5
github.com/otiai10/copy v1.2.0
github.com/pkg/errors v0.9.1
Expand Down
4 changes: 2 additions & 2 deletions staging/operator-lifecycle-manager/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1080,8 +1080,8 @@ github.com/openshift/cluster-policy-controller v0.0.0-20220825134653-523e4104074
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/operator-framework/api v0.7.1/go.mod h1:L7IvLd/ckxJEJg/t4oTTlnHKAJIP/p51AvEslW3wYdY=
github.com/operator-framework/api v0.16.0 h1:swUOhVv7QDszxBTwYM8QAtyeqI4EQHNVAiKMS+xjakY=
github.com/operator-framework/api v0.16.0/go.mod h1:kk8xJahHJR3bKqrA+A+1VIrhOTmyV76k+ARv+iV+u1Q=
github.com/operator-framework/api v0.17.1 h1:J/6+Xj4IEV8C7hcirqUFwOiZAU3PbnJhWvB0/bB51c4=
github.com/operator-framework/api v0.17.1/go.mod h1:kk8xJahHJR3bKqrA+A+1VIrhOTmyV76k+ARv+iV+u1Q=
github.com/operator-framework/operator-registry v1.17.5 h1:LR8m1rFz5Gcyje8WK6iYt+gIhtzqo52zMRALdmTYHT0=
github.com/operator-framework/operator-registry v1.17.5/go.mod h1:sRQIgDMZZdUcmHltzyCnM6RUoDF+WS8Arj1BQIARDS8=
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,7 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saN
},
},
SecurityContext: &corev1.SecurityContext{
ReadOnlyRootFilesystem: pointer.Bool(false),
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
ReadOnlyRootFilesystem: pointer.Bool(false),
},
ImagePullPolicy: pullPolicy,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
Expand All @@ -195,19 +191,18 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saN
NodeSelector: map[string]string{
"kubernetes.io/os": "linux",
},
SecurityContext: &corev1.PodSecurityContext{
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
},
ServiceAccountName: saName,
},
}

if runAsUser > 0 {
pod.Spec.SecurityContext.RunAsUser = &runAsUser
pod.Spec.SecurityContext.RunAsNonRoot = pointer.Bool(true)
if source.Spec.GrpcPodConfig != nil {
if source.Spec.GrpcPodConfig.SecurityContextConfig == operatorsv1alpha1.Restricted {
addSecurityContext(pod, runAsUser)
}
} else {
addSecurityContext(pod, runAsUser)
}

// Override scheduling options if specified
if source.Spec.GrpcPodConfig != nil {
grpcPodConfig := source.Spec.GrpcPodConfig
Expand Down Expand Up @@ -256,3 +251,19 @@ func hashPodSpec(spec corev1.PodSpec) string {
hashutil.DeepHashObject(hasher, &spec)
return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
}

func addSecurityContext(pod *corev1.Pod, runAsUser int64) {
pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = pointer.Bool(false)
pod.Spec.Containers[0].SecurityContext.Capabilities = &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
}
pod.Spec.SecurityContext = &corev1.PodSecurityContext{
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
}
if runAsUser > 0 {
pod.Spec.SecurityContext.RunAsUser = &runAsUser
pod.Spec.SecurityContext.RunAsNonRoot = pointer.Bool(true)
}
}
146 changes: 145 additions & 1 deletion staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ var _ = Describe("Starting CatalogSource e2e tests", func() {
)

BeforeEach(func() {
namespaceName := genName("catsrc-e2e-")
// In OPC, PSA labels for any namespace created that is not prefixed with "openshift-" is overriden to enforce
// PSA restricted. This test namespace needs to prefixed with openshift- so that baseline/privileged enforcement
// for the PSA specific tests are not overridden,
// Change it only after https://github.com/operator-framework/operator-lifecycle-manager/issues/2859 is closed.
namespaceName := genName("openshift-catsrc-e2e-")
og := operatorsv1.OperatorGroup{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-operatorgroup", namespaceName),
Expand Down Expand Up @@ -1396,7 +1400,147 @@ var _ = Describe("Starting CatalogSource e2e tests", func() {
})
})
})
When("The namespace is labled as Pod Security Admission policy enforce:restricted", func() {
BeforeEach(func() {
var err error
testNS := &corev1.Namespace{}
Eventually(func() error {
testNS, err = c.KubernetesInterface().CoreV1().Namespaces().Get(context.TODO(), ns.GetName(), metav1.GetOptions{})
if err != nil {
return err
}
return nil
}).Should(BeNil())

testNS.ObjectMeta.Labels = map[string]string{
"pod-security.kubernetes.io/enforce": "restricted",
"pod-security.kubernetes.io/enforce-version": "latest",
}

Eventually(func() error {
_, err := c.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), testNS, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}).Should(BeNil())
})
When("A CatalogSource built with opm v1.21.0 (<v1.23.2)is created without spec.GrpcPodConfig.SecurityContextConfig set to legacy", func() {
var sourceName string
BeforeEach(func() {
sourceName = genName("catalog-")
source := &v1alpha1.CatalogSource{
TypeMeta: metav1.TypeMeta{
Kind: v1alpha1.CatalogSourceKind,
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: sourceName,
Namespace: ns.GetName(),
Labels: map[string]string{"olm.catalogSource": sourceName},
},
Spec: v1alpha1.CatalogSourceSpec{
SourceType: v1alpha1.SourceTypeGrpc,
Image: "quay.io/olmtest/old-opm-catsrc:v1.21.0",
},
}

Eventually(func() error {
_, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{})
return err
}).Should(Succeed())
})
It("The registry pod fails to become come up because of lack of permission", func() {
Eventually(func() (bool, error) {
podList, err := c.KubernetesInterface().CoreV1().Pods(ns.GetName()).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return false, err
}
for _, pod := range podList.Items {
if pod.ObjectMeta.OwnerReferences != nil && pod.ObjectMeta.OwnerReferences[0].Name == sourceName {
if pod.Status.ContainerStatuses != nil && pod.Status.ContainerStatuses[0].State.Terminated != nil {
return true, nil
}
}
}
return false, nil
}).Should(BeTrue())
})
})
})
When("The namespace is labled as Pod Security Admission policy enforce:baseline", func() {
BeforeEach(func() {
var err error
testNS := &corev1.Namespace{}
Eventually(func() error {
testNS, err = c.KubernetesInterface().CoreV1().Namespaces().Get(context.TODO(), ns.GetName(), metav1.GetOptions{})
if err != nil {
return err
}
return nil
}).Should(BeNil())

testNS.ObjectMeta.Labels = map[string]string{
"pod-security.kubernetes.io/enforce": "baseline",
"pod-security.kubernetes.io/enforce-version": "latest",
}

Eventually(func() error {
_, err := c.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), testNS, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}).Should(BeNil())
})
When("A CatalogSource built with opm v1.21.0 (<v1.23.2)is created with spec.GrpcPodConfig.SecurityContextConfig set to legacy", func() {
var sourceName string
BeforeEach(func() {
sourceName = genName("catalog-")
source := &v1alpha1.CatalogSource{
TypeMeta: metav1.TypeMeta{
Kind: v1alpha1.CatalogSourceKind,
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: sourceName,
Namespace: ns.GetName(),
Labels: map[string]string{"olm.catalogSource": sourceName},
},
Spec: v1alpha1.CatalogSourceSpec{
GrpcPodConfig: &v1alpha1.GrpcPodConfig{
SecurityContextConfig: operatorsv1alpha1.Legacy,
},
SourceType: v1alpha1.SourceTypeGrpc,
Image: "quay.io/olmtest/old-opm-catsrc:v1.21.0",
},
}

Eventually(func() error {
_, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{})
return err
}).Should(Succeed())
})
It("The registry pod comes up successfully", func() {
Eventually(func() (bool, error) {
podList, err := c.KubernetesInterface().CoreV1().Pods(ns.GetName()).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return false, err
}
for _, pod := range podList.Items {
if pod.ObjectMeta.OwnerReferences != nil && pod.ObjectMeta.OwnerReferences[0].Name == sourceName {
if pod.Status.ContainerStatuses != nil {
if *pod.Status.ContainerStatuses[0].Started == true {
return true, nil
}
}
}
}
return false, nil
}).Should(BeTrue())
})
})
})
})

func getOperatorDeployment(c operatorclient.ClientInterface, namespace string, operatorLabels labels.Set) (*appsv1.Deployment, error) {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ github.com/openshift/client-go/config/listers/config/v1
# github.com/openshift/cluster-policy-controller v0.0.0-20220825134653-523e4104074f
## explicit; go 1.18
github.com/openshift/cluster-policy-controller/pkg/psalabelsyncer/nsexemptions
# github.com/operator-framework/api v0.16.0 => ./staging/api
# github.com/operator-framework/api v0.17.1 => ./staging/api
## explicit; go 1.18
github.com/operator-framework/api/crds
github.com/operator-framework/api/pkg/constraints
Expand Down

0 comments on commit 6bdc9f8

Please sign in to comment.