Skip to content

Commit

Permalink
Make Restricted PSS security context work together with agent injecti…
Browse files Browse the repository at this point in the history
…on (#1624)
  • Loading branch information
Vlatombe authored Dec 2, 2024
1 parent 3fdd064 commit d82c569
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.csanchez.jenkins.plugins.kubernetes;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import io.fabric8.kubernetes.api.model.CapabilitiesBuilder;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.SeccompProfileBuilder;
import io.fabric8.kubernetes.api.model.SecurityContext;
Expand Down Expand Up @@ -45,35 +47,41 @@ public Pod decorate(@NonNull KubernetesCloud kubernetesCloud, @NonNull Pod pod)
LOGGER.warning("No spec found in the pod, skipping the security context update");
return pod;
}
var containers = spec.getContainers();
if (containers != null) {
for (var container : containers) {
var securityContext = container.getSecurityContext();
if (securityContext == null) {
securityContext = new SecurityContext();
container.setSecurityContext(securityContext);
}
if (securityContext.getAllowPrivilegeEscalation() == null) {
securityContext.setAllowPrivilegeEscalation(false);
}
if (securityContext.getRunAsNonRoot() == null) {
securityContext.setRunAsNonRoot(true);
}
var seccompProfile = securityContext.getSeccompProfile();
if (seccompProfile == null) {
securityContext.setSeccompProfile(new SeccompProfileBuilder()
.withType(SECCOMP_RUNTIME_DEFAULT)
.build());
}
var capabilities = securityContext.getCapabilities();
if (capabilities == null) {
securityContext.setCapabilities(new CapabilitiesBuilder()
.withDrop(List.of(CAPABILITIES_ALL))
.build());
}
}
}
secure(spec.getInitContainers());
secure(spec.getContainers());
}
return pod;
}

private static void secure(@CheckForNull List<Container> containers) {
if (containers != null) {
containers.forEach(RestrictedPssSecurityContextInjector::secure);
}
}

private static void secure(@NonNull Container container) {
var securityContext = container.getSecurityContext();
if (securityContext == null) {
securityContext = new SecurityContext();
container.setSecurityContext(securityContext);
}
if (securityContext.getAllowPrivilegeEscalation() == null) {
securityContext.setAllowPrivilegeEscalation(false);
}
if (securityContext.getRunAsNonRoot() == null) {
securityContext.setRunAsNonRoot(true);
}
var seccompProfile = securityContext.getSeccompProfile();
if (seccompProfile == null) {
securityContext.setSeccompProfile(new SeccompProfileBuilder()
.withType(SECCOMP_RUNTIME_DEFAULT)
.build());
}
var capabilities = securityContext.getCapabilities();
if (capabilities == null) {
securityContext.setCapabilities(new CapabilitiesBuilder()
.withDrop(List.of(CAPABILITIES_ALL))
.build());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public void setUpCloud() {
protected void test(String name) throws IOException {
var beforeYAML = loadFileAsStream(name + "-before.yaml");
var before = Serialization.unmarshal(beforeYAML, Pod.class);
assertEquals(name + "-before.yaml is not normalized", beforeYAML, Serialization.asYaml(before));
assertEquals(name + "-before.yaml is not normalized", Serialization.asYaml(before), beforeYAML);
var afterYAML = loadFileAsStream(name + "-after.yaml");
var after = decorator.decorate(cloud, before);
assertEquals(name + "-after.yaml processed", afterYAML, Serialization.asYaml(after));
assertEquals(name + "-after.yaml processed", Serialization.asYaml(after), afterYAML);
}

@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ public void multiContainer() throws IOException {
public void existingSecurityContext() throws IOException {
test("existingSecurityContext");
}

@Test
public void agentInjection() throws IOException {
test("agentInjection");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
apiVersion: "v1"
kind: "Pod"
metadata:
name: "simple"
namespace: "jenkins"
spec:
containers:
- env:
- name: "JENKINS_SECRET"
value: "my-little-secret"
- name: "JENKINS_AGENT_NAME"
value: "my-lovely-agent"
- name: "REMOTING_OPTS"
value: "-noReconnectAfter 1d"
- name: "JENKINS_NAME"
value: "my-lovely-agent"
- name: "JENKINS_AGENT_WORKDIR"
value: "/home/jenkins/agent"
- name: "JENKINS_URL"
value: "http://localhost/"
image: "jenkins/inbound-agent"
name: "maven"
resources:
limits:
cpu: "1"
memory: "768Mi"
requests:
cpu: "1"
memory: "768Mi"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
runAsNonRoot: true
seccompProfile:
type: "RuntimeDefault"
volumeMounts:
- mountPath: "/jenkins-agent"
name: "jenkins-agent"
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
initContainers:
- command:
- "/bin/sh"
- "-c"
- "cp $(command -v jenkins-agent) /jenkins-agent/jenkins-agent;cp /usr/share/jenkins/agent.jar\
\ /jenkins-agent/agent.jar;sed -i 's!-jar .*agent.jar!-jar /jenkins-agent\\\
/agent.jar!' /jenkins-agent/jenkins-agent"
image: "jenkins/inbound-agent:3261.v9c670a_4748a_9-1"
name: "set-up-jenkins-agent"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
runAsNonRoot: true
seccompProfile:
type: "RuntimeDefault"
volumeMounts:
- mountPath: "/jenkins-agent"
name: "jenkins-agent"
volumes:
- emptyDir:
medium: ""
name: "workspace-volume"
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
apiVersion: "v1"
kind: "Pod"
metadata:
name: "simple"
namespace: "jenkins"
spec:
containers:
- env:
- name: "JENKINS_SECRET"
value: "my-little-secret"
- name: "JENKINS_AGENT_NAME"
value: "my-lovely-agent"
- name: "REMOTING_OPTS"
value: "-noReconnectAfter 1d"
- name: "JENKINS_NAME"
value: "my-lovely-agent"
- name: "JENKINS_AGENT_WORKDIR"
value: "/home/jenkins/agent"
- name: "JENKINS_URL"
value: "http://localhost/"
image: "jenkins/inbound-agent"
name: "maven"
resources:
limits:
cpu: "1"
memory: "768Mi"
requests:
cpu: "1"
memory: "768Mi"
volumeMounts:
- mountPath: "/jenkins-agent"
name: "jenkins-agent"
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
initContainers:
- command:
- "/bin/sh"
- "-c"
- "cp $(command -v jenkins-agent) /jenkins-agent/jenkins-agent;cp /usr/share/jenkins/agent.jar\
\ /jenkins-agent/agent.jar;sed -i 's!-jar .*agent.jar!-jar /jenkins-agent\\\
/agent.jar!' /jenkins-agent/jenkins-agent"
image: "jenkins/inbound-agent:3261.v9c670a_4748a_9-1"
name: "set-up-jenkins-agent"
volumeMounts:
- mountPath: "/jenkins-agent"
name: "jenkins-agent"
volumes:
- emptyDir:
medium: ""
name: "workspace-volume"

0 comments on commit d82c569

Please sign in to comment.