Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Restricted PSS security context work together with agent injection #1624

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(ignore WS)

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);
Comment on lines +30 to +33
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected and actual were inverted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe clearer to use assertThat(actual, is(expected))

}

@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"
Loading