Skip to content

Commit

Permalink
[artemiscloud#799] Restrict security context of pods by default
Browse files Browse the repository at this point in the history
The operator pod and the broker pods can run with a safer and restricted
security context without issues. Restricting the security context of the pods
by default allows to deploy a cluster of brokers also in Kubernetes namespaces
with the restricted policy.
  • Loading branch information
brusdev committed Feb 19, 2024
1 parent bd045cd commit eb41468
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2725,8 +2725,15 @@ spec:
resources: {}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
serviceAccountName: activemq-artemis-controller-manager
terminationGracePeriodSeconds: 10
permissions:
Expand Down
7 changes: 7 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ spec:
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- command:
- /home/activemq-artemis-operator/bin/entrypoint
Expand Down Expand Up @@ -66,6 +68,11 @@ spec:
name: manager
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
seccompProfile:
type: RuntimeDefault
livenessProbe:
httpGet:
path: /healthz
Expand Down
27 changes: 25 additions & 2 deletions controllers/activemqartemis_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1710,6 +1710,17 @@ func (reconciler *ActiveMQArtemisReconcilerImpl) NewPodTemplateSpecForCR(customR

podSpec.ImagePullSecrets = customResource.Spec.DeploymentPlan.ImagePullSecrets

allowPrivilegeEscalation := false
runAsNonRoot := true
capabilities := corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}
seccompProfile := corev1.SeccompProfile{Type: "RuntimeDefault"}
securityContext := corev1.SecurityContext{
AllowPrivilegeEscalation: &allowPrivilegeEscalation,
Capabilities: &capabilities,
SeccompProfile: &seccompProfile,
RunAsNonRoot: &runAsNonRoot,
}

container := containers.MakeContainer(podSpec, customResource.Name, common.ResolveImage(customResource, common.BrokerImageKey), MakeEnvVarArrayForCR(customResource, namer))

container.Resources = customResource.Spec.DeploymentPlan.Resources
Expand Down Expand Up @@ -1743,6 +1754,8 @@ func (reconciler *ActiveMQArtemisReconcilerImpl) NewPodTemplateSpecForCR(customR
container.LivenessProbe = reconciler.configureLivenessProbe(container, customResource.Spec.DeploymentPlan.LivenessProbe)
container.ReadinessProbe = reconciler.configureReadinessProbe(container, customResource.Spec.DeploymentPlan.ReadinessProbe)

container.SecurityContext = &securityContext

if len(customResource.Spec.DeploymentPlan.NodeSelector) > 0 {
reqLogger.V(1).Info("Adding Node Selectors", "len", len(customResource.Spec.DeploymentPlan.NodeSelector))
podSpec.NodeSelector = customResource.Spec.DeploymentPlan.NodeSelector
Expand Down Expand Up @@ -1811,6 +1824,7 @@ func (reconciler *ActiveMQArtemisReconcilerImpl) NewPodTemplateSpecForCR(customR
reqLogger.V(2).Info("Creating init container for broker configuration")
initContainer := containers.MakeInitContainer(podSpec, customResource.Name, common.ResolveImage(customResource, common.InitImageKey), MakeEnvVarArrayForCR(customResource, namer))
initContainer.Resources = customResource.Spec.DeploymentPlan.Resources
initContainer.SecurityContext = &securityContext

var initCmds []string
var initCfgRootDir = "/init_cfg_root"
Expand Down Expand Up @@ -2330,7 +2344,12 @@ func (r *ActiveMQArtemisReconcilerImpl) configurePodSecurityContext(podSpec *cor
podSpec.SecurityContext = podSecurityContext
} else {
r.log.V(2).Info("Incoming podSecurityContext is nil, creating with default values")
podSpec.SecurityContext = &corev1.PodSecurityContext{}
runAsNonRoot := true
seccompProfile := corev1.SeccompProfile{Type: "RuntimeDefault"}
podSpec.SecurityContext = &corev1.PodSecurityContext{
RunAsNonRoot: &runAsNonRoot,
SeccompProfile: &seccompProfile,
}
}
}

Expand Down Expand Up @@ -2361,8 +2380,12 @@ func (r *ActiveMQArtemisReconcilerImpl) configPodSecurity(podSpec *corev1.PodSpe
if podSecurity.RunAsUser != nil {
r.log.V(2).Info("Pod runAsUser specified", "runAsUser", *podSecurity.RunAsUser)
if podSpec.SecurityContext == nil {
runAsNonRoot := true
seccompProfile := corev1.SeccompProfile{Type: "RuntimeDefault"}
secCtxt := corev1.PodSecurityContext{
RunAsUser: podSecurity.RunAsUser,
RunAsUser: podSecurity.RunAsUser,
RunAsNonRoot: &runAsNonRoot,
SeccompProfile: &seccompProfile,
}
podSpec.SecurityContext = &secCtxt
} else {
Expand Down
49 changes: 44 additions & 5 deletions controllers/controllermanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,37 @@ var _ = Describe("tests regarding controller manager", func() {
})
})

It("test watching restricted namespace", func() {
testWatchNamespace("restricted", Default, func(g Gomega) {
By("deploying broker in to target namespace")
cr, createdCr := DeployCustomBroker(restrictedNamespace, nil)

By("check statefulset get created")
createdSs := &appsv1.StatefulSet{}
Eventually(func(g Gomega) {
key := types.NamespacedName{Name: namer.CrToSS(cr.Name), Namespace: restrictedNamespace}
err := k8sClient.Get(ctx, key, createdSs)
g.Expect(err).To(Succeed(), "expect to get ss for cr "+cr.Name)
}, timeout, interval).Should(Succeed())

if os.Getenv("USE_EXISTING_CLUSTER") == "true" {

// with kube, deleting while initialising leads to long delays on terminating the namespace..

By("verifying started")
deployedCrd := brokerv1beta1.ActiveMQArtemis{}
key := types.NamespacedName{Name: createdCr.Name, Namespace: createdCr.Namespace}

Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, key, &deployedCrd)).Should(Succeed())
g.Expect(len(deployedCrd.Status.PodStatus.Ready)).Should(BeEquivalentTo(1))
}, existingClusterTimeout, existingClusterInterval).Should(Succeed())
}

CleanResource(createdCr, cr.Name, restrictedNamespace)
})
})

It("test watching all namespaces", func() {
testWatchNamespace("all", Default, func(g Gomega) {
By("deploying broker in to all namespaces")
Expand Down Expand Up @@ -274,14 +305,15 @@ var _ = Describe("tests regarding controller manager", func() {
})
})

func createNamespace(namespace string) error {
func createNamespace(namespace string, annotations map[string]string) error {
ns := corev1.Namespace{
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Name: namespace,
Annotations: annotations,
},
}

Expand Down Expand Up @@ -341,12 +373,18 @@ func testWatchNamespace(kind string, g Gomega, testFunc func(g Gomega)) {

shutdownControllerManager()

g.Expect(createNamespace(namespace1)).To(Succeed())
g.Expect(createNamespace(namespace2)).To(Succeed())
g.Expect(createNamespace(namespace3)).To(Succeed())
g.Expect(createNamespace(namespace1, map[string]string{})).To(Succeed())
g.Expect(createNamespace(namespace2, map[string]string{})).To(Succeed())
g.Expect(createNamespace(namespace3, map[string]string{})).To(Succeed())
g.Expect(createNamespace(restrictedNamespace, map[string]string{
"pod-security.kubernetes.io/enforce": "restricted",
"pod-security.kubernetes.io/enforce-version": "latest",
})).To(Succeed())

if kind == "single" {
createControllerManager(true, defaultNamespace)
} else if kind == "restricted" {
createControllerManager(true, restrictedNamespace)
} else if kind == "all" {
createControllerManager(true, "")
} else {
Expand All @@ -360,6 +398,7 @@ func testWatchNamespace(kind string, g Gomega, testFunc func(g Gomega)) {
deleteNamespace(namespace1, g)
deleteNamespace(namespace2, g)
deleteNamespace(namespace3, g)
deleteNamespace(restrictedNamespace, g)

createControllerManagerForSuite()
}
1 change: 1 addition & 0 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import (
const (
defaultNamespace = "default"
otherNamespace = "other"
restrictedNamespace = "restricted"
timeout = time.Second * 30
duration = time.Second * 10
interval = time.Millisecond * 500
Expand Down
7 changes: 7 additions & 0 deletions deploy/activemq-artemis-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5114,7 +5114,14 @@ spec:
periodSeconds: 10
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
serviceAccountName: activemq-artemis-controller-manager
terminationGracePeriodSeconds: 10
7 changes: 7 additions & 0 deletions deploy/operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,14 @@ spec:
periodSeconds: 10
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
serviceAccountName: activemq-artemis-controller-manager
terminationGracePeriodSeconds: 10

0 comments on commit eb41468

Please sign in to comment.