Skip to content

Commit

Permalink
(catsrc) allow catalogsource to be run as root
Browse files Browse the repository at this point in the history
This PR exposes a spec.runAsRoot field, so that cluster admins can
indicate that they want to run the catalogsource container as root
user.

This, along with the Pod Admission Controller enforce level `privileged`
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>
  • Loading branch information
anik120 committed Sep 1, 2022
1 parent d780d3c commit 16730df
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 16 deletions.
38 changes: 22 additions & 16 deletions pkg/controller/registry/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,32 +181,38 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saN
corev1.ResourceMemory: resource.MustParse("50Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
ReadOnlyRootFilesystem: pointer.Bool(false),
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
ImagePullPolicy: pullPolicy,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
},
},
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.RunAsRoot {
pod.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsUser: pointer.Int64(0),
RunAsNonRoot: pointer.Bool(false),
}
} else {
pod.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
ReadOnlyRootFilesystem: pointer.Bool(false),
AllowPrivilegeEscalation: pointer.Bool(false),
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)
}
}
// Override scheduling options if specified
if source.Spec.GrpcPodConfig != nil {
Expand Down
138 changes: 138 additions & 0 deletions test/e2e/catalog_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1396,7 +1396,145 @@ 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.RunAsRoot set to true", 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: "docker.io/anik120/ditto-index-opm: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:privileged", 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": "privileged",
"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.RunAsRoot set to true", 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{
RunAsRoot: true,
SourceType: v1alpha1.SourceTypeGrpc,
Image: "docker.io/anik120/ditto-index-opm: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

0 comments on commit 16730df

Please sign in to comment.