Skip to content

Commit

Permalink
[JENKINS-73513] Fix inheritance of container capabilities and and pod…
Browse files Browse the repository at this point in the history
… shareProcessNamespace settings (#1592)
  • Loading branch information
cfraenkel committed Aug 12, 2024
1 parent abd0346 commit 0889b96
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import hudson.model.Label;
import hudson.model.Node;
import hudson.slaves.NodeProperty;
import io.fabric8.kubernetes.api.model.Capabilities;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.EnvFromSource;
Expand Down Expand Up @@ -184,6 +185,7 @@ public static Container combine(@CheckForNull Container parent, @NonNull Contain
: (parent.getSecurityContext() != null
? parent.getSecurityContext().getRunAsGroup()
: null);
Capabilities capabilities = combineCapabilities(parent, template);
String imagePullPolicy = isNullOrEmpty(template.getImagePullPolicy())
? parent.getImagePullPolicy()
: template.getImagePullPolicy();
Expand Down Expand Up @@ -219,12 +221,13 @@ public static Container combine(@CheckForNull Container parent, @NonNull Contain
.withEnv(combineEnvVars(parent, template)) //
.withEnvFrom(combinedEnvFromSources(parent, template))
.withVolumeMounts(new ArrayList<>(volumeMounts.values()));
if ((privileged != null && privileged) || runAsUser != null || runAsGroup != null) {
if ((privileged != null && privileged) || runAsUser != null || runAsGroup != null || capabilities != null) {
containerBuilder = containerBuilder
.withNewSecurityContext()
.withNewSecurityContextLike(parent.getSecurityContext())
.withPrivileged(privileged)
.withRunAsUser(runAsUser)
.withRunAsGroup(runAsGroup)
.withCapabilities(capabilities)
.endSecurityContext();
}
return containerBuilder.build();
Expand All @@ -245,6 +248,41 @@ private static Map<String, Quantity> combineResources(
);
}

private static Capabilities combineCapabilities(Container parent, Container template) {
Capabilities parentCapabilities = parent.getSecurityContext() != null
? parent.getSecurityContext().getCapabilities()
: null;
Capabilities templateCapabilities = template.getSecurityContext() != null
? template.getSecurityContext().getCapabilities()
: null;
if (parentCapabilities == null && templateCapabilities == null) {
return null;
}
if (parentCapabilities == null) {
return templateCapabilities;
}
if (templateCapabilities == null) {
return parentCapabilities;
}
Capabilities combined = new Capabilities();
combined.setAdd(combineCapabilities(parentCapabilities, templateCapabilities, Capabilities::getAdd));
combined.setDrop(combineCapabilities(parentCapabilities, templateCapabilities, Capabilities::getDrop));
return combined;
}

private static List<String> combineCapabilities(
Capabilities parentCapabilities,
Capabilities templateCapabilities,
Function<Capabilities, List<String>> capabilitiesListFunction) {
List<String> parentCapabilitiesList = capabilitiesListFunction.apply(parentCapabilities);
List<String> templateCapabilitiesList = capabilitiesListFunction.apply(templateCapabilities);
// override: template capabilities win
if (templateCapabilitiesList != null) {
return templateCapabilitiesList;
}
return parentCapabilitiesList;
}

/**
* Combines all given pods together in order.
* @param pods the pods to combine
Expand Down Expand Up @@ -293,6 +331,10 @@ public static Pod combine(Pod parent, Pod template) {
? template.getSpec().getHostNetwork()
: parent.getSpec().getHostNetwork();

Boolean shareProcessNamespace = template.getSpec().getShareProcessNamespace() != null
? template.getSpec().getShareProcessNamespace()
: parent.getSpec().getShareProcessNamespace();

Map<String, String> podAnnotations = mergeMaps(
parent.getMetadata().getAnnotations(), template.getMetadata().getAnnotations());
Map<String, String> podLabels = mergeMaps(
Expand Down Expand Up @@ -346,6 +388,7 @@ public static Pod combine(Pod parent, Pod template) {
.withServiceAccountName(serviceAccountName) //
.withSchedulerName(schedulerName)
.withHostNetwork(hostNetwork) //
.withShareProcessNamespace(shareProcessNamespace) //
.withContainers(combinedContainers) //
.withInitContainers(combinedInitContainers) //
.withVolumes(combinedVolumes) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,4 +982,137 @@ public void shouldSanitizeJenkinsLabel() {
"ylooooooooooooooooooooooooooooonglabelendinginunderscorex",
sanitizeLabel("label1 label2 verylooooooooooooooooooooooooooooonglabelendinginunderscore_"));
}

@Test
public void shouldCombineCapabilities() {
Container container1 = containerBuilder()
.withNewSecurityContext()
.withNewCapabilities()
.addToAdd("TO_ADD")
.withDrop((List<String>) null)
.endCapabilities()
.withRunAsUser(1000L)
.endSecurityContext()
.build();
Container container2 = containerBuilder()
.withNewSecurityContext()
.withNewCapabilities()
.addToDrop("TO_DROP")
.withAdd((List<String>) null)
.endCapabilities()
.endSecurityContext()
.build();
Container container3 = containerBuilder().build();

Container result = combine(container1, container3);
assertNotNull(result.getSecurityContext());
assertNotNull(result.getSecurityContext().getCapabilities());
assertTrue(result.getSecurityContext().getCapabilities().getAdd().contains("TO_ADD"));

result = combine(container3, container1);
assertNotNull(result.getSecurityContext());
assertNotNull(result.getSecurityContext().getCapabilities());
assertTrue(result.getSecurityContext().getCapabilities().getAdd().contains("TO_ADD"));

result = combine(container2, container3);
assertNotNull(result.getSecurityContext());
assertNotNull(result.getSecurityContext().getCapabilities());
assertTrue(result.getSecurityContext().getCapabilities().getDrop().contains("TO_DROP"));

result = combine(container1, container2);
assertNotNull(result.getSecurityContext());
assertNotNull(result.getSecurityContext().getCapabilities());
assertTrue(result.getSecurityContext().getCapabilities().getAdd().contains("TO_ADD"));
assertTrue(result.getSecurityContext().getCapabilities().getDrop().contains("TO_DROP"));
}

@Test
public void shouldOverrideCapabilitiesWithTemplate() {
Container container1 = containerBuilder()
.withNewSecurityContext()
.withNewCapabilities()
.addToAdd("CONTAINER1_ADD")
.addToDrop("CONTAINER1_DROP")
.endCapabilities()
.endSecurityContext()
.build();
Container container2 = containerBuilder()
.withNewSecurityContext()
.withNewCapabilities()
.addToAdd("CONTAINER2_ADD")
.addToDrop("CONTAINER2_DROP")
.endCapabilities()
.endSecurityContext()
.build();

Container result = combine(container1, container2);
assertNotNull(result.getSecurityContext());
assertNotNull(result.getSecurityContext().getCapabilities());
assertTrue(result.getSecurityContext().getCapabilities().getAdd().contains("CONTAINER2_ADD"));
assertTrue(result.getSecurityContext().getCapabilities().getDrop().contains("CONTAINER2_DROP"));
}

@Test
public void shouldRetainNullsWhenCombiningCapabilities() {

Container container1 = new ContainerBuilder().build();
Container container2 = new ContainerBuilder().build();
Container container3 = new ContainerBuilder()
.withNewSecurityContext()
.withPrivileged()
.endSecurityContext()
.build();

Container result = combine(container1, container2);
assertNull(result.getSecurityContext());

result = combine(container2, container3);
assertNotNull(result.getSecurityContext());
assertNull(result.getSecurityContext().getCapabilities());
}

@Test
public void shouldOverrideShareProcessNamespaceIfSpecified() {
Pod parent1 = new PodBuilder()
.withNewMetadata()
.endMetadata()
.withNewSpec()
.endSpec()
.build();

Pod parent2 = new PodBuilder()
.withNewMetadata()
.endMetadata()
.withNewSpec()
.withShareProcessNamespace()
.endSpec()
.build();

Pod child1 = new PodBuilder()
.withNewMetadata()
.endMetadata()
.withNewSpec()
.withShareProcessNamespace(false)
.endSpec()
.build();

Pod child2 = new PodBuilder()
.withNewMetadata()
.endMetadata()
.withNewSpec()
.endSpec()
.build();

Pod result1 = combine(parent1, child1);
assertFalse(result1.getSpec().getShareProcessNamespace());

Pod result2 = combine(parent1, child2);
assertNull(result2.getSpec().getShareProcessNamespace());

Pod result3 = combine(parent2, child1);
assertFalse(result3.getSpec().getShareProcessNamespace());

Pod result4 = combine(parent2, child2);
assertTrue(result4.getSpec().getShareProcessNamespace());
}
}

0 comments on commit 0889b96

Please sign in to comment.