Skip to content

Commit 61acd0a

Browse files
committed
(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 <[email protected]>
1 parent 1e69145 commit 61acd0a

File tree

2 files changed

+160
-13
lines changed

2 files changed

+160
-13
lines changed

pkg/controller/registry/reconciler/reconciler.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,7 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saN
182182
},
183183
},
184184
SecurityContext: &corev1.SecurityContext{
185-
ReadOnlyRootFilesystem: pointer.Bool(false),
186-
AllowPrivilegeEscalation: pointer.Bool(false),
187-
Capabilities: &corev1.Capabilities{
188-
Drop: []corev1.Capability{"ALL"},
189-
},
185+
ReadOnlyRootFilesystem: pointer.Bool(false),
190186
},
191187
ImagePullPolicy: pullPolicy,
192188
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
@@ -195,19 +191,26 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saN
195191
NodeSelector: map[string]string{
196192
"kubernetes.io/os": "linux",
197193
},
198-
SecurityContext: &corev1.PodSecurityContext{
199-
SeccompProfile: &corev1.SeccompProfile{
200-
Type: corev1.SeccompProfileTypeRuntimeDefault,
201-
},
202-
},
203194
ServiceAccountName: saName,
204195
},
205196
}
206197

207-
if runAsUser > 0 {
208-
pod.Spec.SecurityContext.RunAsUser = &runAsUser
209-
pod.Spec.SecurityContext.RunAsNonRoot = pointer.Bool(true)
198+
if source.Spec.GrpcPodConfig == nil || source.Spec.GrpcPodConfig.SecurityContextConfig != operatorsv1alpha1.Legacy {
199+
pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = pointer.Bool(false)
200+
pod.Spec.Containers[0].SecurityContext.Capabilities = &corev1.Capabilities{
201+
Drop: []corev1.Capability{"ALL"},
202+
}
203+
pod.Spec.SecurityContext = &corev1.PodSecurityContext{
204+
SeccompProfile: &corev1.SeccompProfile{
205+
Type: corev1.SeccompProfileTypeRuntimeDefault,
206+
},
207+
}
208+
if runAsUser > 0 {
209+
pod.Spec.SecurityContext.RunAsUser = &runAsUser
210+
pod.Spec.SecurityContext.RunAsNonRoot = pointer.Bool(true)
211+
}
210212
}
213+
211214
// Override scheduling options if specified
212215
if source.Spec.GrpcPodConfig != nil {
213216
grpcPodConfig := source.Spec.GrpcPodConfig

test/e2e/catalog_e2e_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,151 @@ var _ = Describe("Starting CatalogSource e2e tests", func() {
13961396
})
13971397
})
13981398
})
1399+
When("The namespace is labled as Pod Security Admission policy enforce:restricted", func() {
1400+
BeforeEach(func() {
1401+
var err error
1402+
testNS := &corev1.Namespace{}
1403+
Eventually(func() error {
1404+
testNS, err = c.KubernetesInterface().CoreV1().Namespaces().Get(context.TODO(), ns.GetName(), metav1.GetOptions{})
1405+
if err != nil {
1406+
return err
1407+
}
1408+
return nil
1409+
}).Should(BeNil())
1410+
1411+
testNS.ObjectMeta.Labels = map[string]string{
1412+
"pod-security.kubernetes.io/enforce": "restricted",
1413+
"pod-security.kubernetes.io/enforce-version": "latest",
1414+
}
1415+
1416+
Eventually(func() error {
1417+
_, err := c.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), testNS, metav1.UpdateOptions{})
1418+
if err != nil {
1419+
return err
1420+
}
1421+
return nil
1422+
}).Should(BeNil())
1423+
})
1424+
When("A CatalogSource built with opm v1.21.0 (<v1.23.2)is created without spec.GrpcPodConfig.SecurityContextConfig set to legacy", func() {
1425+
var sourceName string
1426+
BeforeEach(func() {
1427+
// In OPC, any namespace created that is not prefixed with openshift- is overriden to be PSA restricted.
1428+
// This test namespace needs to prefixed with openshift- so that the baseline enforcement is not overriden,
1429+
// and it passes in OCP.
1430+
// Change it only after https://github.com/operator-framework/operator-lifecycle-manager/issues/2859 is closed.
1431+
sourceName = genName("openshift-")
1432+
source := &v1alpha1.CatalogSource{
1433+
TypeMeta: metav1.TypeMeta{
1434+
Kind: v1alpha1.CatalogSourceKind,
1435+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
1436+
},
1437+
ObjectMeta: metav1.ObjectMeta{
1438+
Name: sourceName,
1439+
Namespace: ns.GetName(),
1440+
Labels: map[string]string{"olm.catalogSource": sourceName},
1441+
},
1442+
Spec: v1alpha1.CatalogSourceSpec{
1443+
SourceType: v1alpha1.SourceTypeGrpc,
1444+
Image: "quay.io/olmtest/old-opm-catsrc:v1.21.0",
1445+
},
1446+
}
1447+
1448+
Eventually(func() error {
1449+
_, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{})
1450+
return err
1451+
}).Should(Succeed())
1452+
})
1453+
It("The registry pod fails to become come up because of lack of permission", func() {
1454+
Eventually(func() (bool, error) {
1455+
podList, err := c.KubernetesInterface().CoreV1().Pods(ns.GetName()).List(context.TODO(), metav1.ListOptions{})
1456+
if err != nil {
1457+
return false, err
1458+
}
1459+
for _, pod := range podList.Items {
1460+
if pod.ObjectMeta.OwnerReferences != nil && pod.ObjectMeta.OwnerReferences[0].Name == sourceName {
1461+
if pod.Status.ContainerStatuses != nil && pod.Status.ContainerStatuses[0].State.Terminated != nil {
1462+
return true, nil
1463+
}
1464+
}
1465+
}
1466+
return false, nil
1467+
}).Should(BeTrue())
1468+
})
1469+
})
1470+
})
1471+
When("The namespace is labled as Pod Security Admission policy enforce:baseline", func() {
1472+
BeforeEach(func() {
1473+
var err error
1474+
testNS := &corev1.Namespace{}
1475+
Eventually(func() error {
1476+
testNS, err = c.KubernetesInterface().CoreV1().Namespaces().Get(context.TODO(), ns.GetName(), metav1.GetOptions{})
1477+
if err != nil {
1478+
return err
1479+
}
1480+
return nil
1481+
}).Should(BeNil())
1482+
1483+
testNS.ObjectMeta.Labels = map[string]string{
1484+
"pod-security.kubernetes.io/enforce": "baseline",
1485+
"pod-security.kubernetes.io/enforce-version": "latest",
1486+
}
13991487

1488+
Eventually(func() error {
1489+
_, err := c.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), testNS, metav1.UpdateOptions{})
1490+
if err != nil {
1491+
return err
1492+
}
1493+
return nil
1494+
}).Should(BeNil())
1495+
})
1496+
When("A CatalogSource built with opm v1.21.0 (<v1.23.2)is created with spec.GrpcPodConfig.SecurityContextConfig set to legacy", func() {
1497+
var sourceName string
1498+
BeforeEach(func() {
1499+
sourceName = genName("catalog-")
1500+
source := &v1alpha1.CatalogSource{
1501+
TypeMeta: metav1.TypeMeta{
1502+
Kind: v1alpha1.CatalogSourceKind,
1503+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
1504+
},
1505+
ObjectMeta: metav1.ObjectMeta{
1506+
Name: sourceName,
1507+
Namespace: ns.GetName(),
1508+
Labels: map[string]string{"olm.catalogSource": sourceName},
1509+
},
1510+
Spec: v1alpha1.CatalogSourceSpec{
1511+
GrpcPodConfig: &v1alpha1.GrpcPodConfig{
1512+
SecurityContextConfig: operatorsv1alpha1.Legacy,
1513+
},
1514+
SourceType: v1alpha1.SourceTypeGrpc,
1515+
Image: "quay.io/olmtest/old-opm-catsrc:v1.21.0",
1516+
},
1517+
}
1518+
1519+
Eventually(func() error {
1520+
_, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{})
1521+
return err
1522+
}).Should(Succeed())
1523+
})
1524+
It("The registry pod comes up successfully", func() {
1525+
Eventually(func() (bool, error) {
1526+
podList, err := c.KubernetesInterface().CoreV1().Pods(ns.GetName()).List(context.TODO(), metav1.ListOptions{})
1527+
if err != nil {
1528+
return false, err
1529+
}
1530+
for _, pod := range podList.Items {
1531+
if pod.ObjectMeta.OwnerReferences != nil && pod.ObjectMeta.OwnerReferences[0].Name == sourceName {
1532+
if pod.Status.ContainerStatuses != nil {
1533+
if *pod.Status.ContainerStatuses[0].Started == true {
1534+
return true, nil
1535+
}
1536+
}
1537+
}
1538+
}
1539+
return false, nil
1540+
}).Should(BeTrue())
1541+
})
1542+
})
1543+
})
14001544
})
14011545

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

0 commit comments

Comments
 (0)