From c16094e04b9ac2a336fa0125077154e374982d91 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Thu, 18 Aug 2022 15:41:58 -0500 Subject: [PATCH] Disable SELinux label security policy when building images When using the Gradle `bootBuildImage` task or Maven `spring-boot:build-image` goal on a Linux distribution with SELinux enabled, binding the Docker socket in the builder container might fail. This commit disables the `label` security policy in the builder container to prevent this type of failure. Fixes gh-32000 --- .../buildpack/platform/build/Lifecycle.java | 5 +++++ .../boot/buildpack/platform/build/Phase.java | 11 +++++++++++ .../platform/docker/type/ContainerConfig.java | 19 +++++++++++++++++-- .../buildpack/platform/build/PhaseTests.java | 14 ++++++++++++++ .../docker/type/ContainerConfigTests.java | 3 ++- .../build/lifecycle-creator-bindings.json | 3 +++ .../lifecycle-creator-cache-volumes.json | 3 +++ .../build/lifecycle-creator-clean-cache.json | 3 +++ .../lifecycle-creator-inherit-local.json | 3 +++ .../lifecycle-creator-inherit-remote.json | 3 +++ .../build/lifecycle-creator-network.json | 3 +++ .../lifecycle-creator-platform-api-0.3.json | 5 ++++- .../platform/build/lifecycle-creator.json | 3 +++ .../docker/type/container-config.json | 5 ++++- 14 files changed, 78 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index 75195e94e438..b787880b4a77 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.function.Consumer; +import com.sun.jna.Platform; + import org.springframework.boot.buildpack.platform.docker.DockerApi; import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent; import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost; @@ -201,6 +203,9 @@ private void configureDaemonAccess(Phase phase) { else { phase.withBinding(Binding.from(DOMAIN_SOCKET_PATH, DOMAIN_SOCKET_PATH)); } + if (!Platform.isWindows()) { + phase.withSecurityOption("label=disable"); + } } private boolean isVerboseLogging() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java index 20cf2fad1f85..80bacfad48a5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java @@ -47,6 +47,8 @@ class Phase { private final Map env = new LinkedHashMap<>(); + private final List securityOptions = new ArrayList<>(); + private String networkMode; /** @@ -110,6 +112,14 @@ void withNetworkMode(String networkMode) { this.networkMode = networkMode; } + /** + * Update this phase with a security option. + * @param option the security option + */ + void withSecurityOption(String option) { + this.securityOptions.add(option); + } + /** * Return the name of the phase. * @return the phase name @@ -138,6 +148,7 @@ void apply(ContainerConfig.Update update) { if (this.networkMode != null) { update.withNetworkMode(this.networkMode); } + this.securityOptions.forEach(update::withSecurityOption); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java index a411b49f2877..8e7585dba745 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java @@ -48,7 +48,8 @@ public class ContainerConfig { private final String json; ContainerConfig(String user, ImageReference image, String command, List args, Map labels, - List bindings, Map env, String networkMode) throws IOException { + List bindings, Map env, String networkMode, List securityOptions) + throws IOException { Assert.notNull(image, "Image must not be null"); Assert.hasText(command, "Command must not be empty"); ObjectMapper objectMapper = SharedObjectMapper.get(); @@ -70,6 +71,10 @@ public class ContainerConfig { } ArrayNode bindsNode = hostConfigNode.putArray("Binds"); bindings.forEach((binding) -> bindsNode.add(binding.toString())); + if (securityOptions != null && !securityOptions.isEmpty()) { + ArrayNode securityOptsNode = hostConfigNode.putArray("SecurityOpt"); + securityOptions.forEach(securityOptsNode::add); + } this.json = objectMapper.writeValueAsString(node); } @@ -120,6 +125,8 @@ public static class Update { private String networkMode; + private final List securityOptions = new ArrayList<>(); + Update(ImageReference image) { this.image = image; } @@ -128,7 +135,7 @@ private ContainerConfig run(Consumer update) { update.accept(this); try { return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings, - this.env, this.networkMode); + this.env, this.networkMode, this.securityOptions); } catch (IOException ex) { throw new IllegalStateException(ex); @@ -197,6 +204,14 @@ public void withNetworkMode(String networkMode) { this.networkMode = networkMode; } + /** + * Update the container config with a security option. + * @param option the security option + */ + public void withSecurityOption(String option) { + this.securityOptions.add(option); + } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java index 8ca4ba1883c4..7d5cd88cb0db 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java @@ -143,4 +143,18 @@ void applyWhenWithNetworkModeUpdatesConfigurationWithNetworkMode() { then(update).shouldHaveNoMoreInteractions(); } + @Test + void applyWhenWithSecurityOptionsUpdatesConfigurationWithSecurityOptions() { + Phase phase = new Phase("test", true); + phase.withSecurityOption("option1=value1"); + phase.withSecurityOption("option2=value2"); + Update update = mock(Update.class); + phase.apply(update); + then(update).should().withCommand("/cnb/lifecycle/test"); + then(update).should().withLabel("author", "spring-boot"); + then(update).should().withSecurityOption("option1=value1"); + then(update).should().withSecurityOption("option2=value2"); + then(update).shouldHaveNoMoreInteractions(); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java index a0b9292345c3..1457d498da71 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java @@ -61,12 +61,13 @@ void writeToWritesJson() throws Exception { update.withEnv("name1", "value1"); update.withEnv("name2", "value2"); update.withNetworkMode("test"); + update.withSecurityOption("option=value"); }); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); containerConfig.writeTo(outputStream); String actualJson = new String(outputStream.toByteArray(), StandardCharsets.UTF_8); String expectedJson = StreamUtils.copyToString(getContent("container-config.json"), StandardCharsets.UTF_8); - JSONAssert.assertEquals(expectedJson, actualJson, false); + JSONAssert.assertEquals(expectedJson, actualJson, true); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json index 2a2774f3ef61..85ac90ce4d8d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json @@ -33,6 +33,9 @@ "pack-cache-b35197ac41ea.launch:/launch-cache", "/host/src/path:/container/dest/path:ro", "volume-name:/container/volume/path:rw" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json index ae16fba38c26..7bd3d9a24ca0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json @@ -31,6 +31,9 @@ "pack-app-aaaaaaaaaa:/workspace", "build-volume:/cache", "launch-volume:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json index cfb41fe5bff9..1239aaa2f25c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json @@ -32,6 +32,9 @@ "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json index 9aea011de060..15ea893ce996 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json @@ -31,6 +31,9 @@ "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json index 52c999f54d25..55a7958b8b10 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json @@ -31,6 +31,9 @@ "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json index 868521e5c324..32169341c2a8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json @@ -32,6 +32,9 @@ "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json index d04ec56db362..38e6df207541 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json @@ -7,6 +7,9 @@ "author" : "spring-boot" }, "HostConfig" : { - "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ] + "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ], + "SecurityOpt" : [ + "label=disable" + ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json index 57adda7224af..5c85d04b8f0d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json @@ -31,6 +31,9 @@ "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" + ], + "SecurityOpt" : [ + "label=disable" ] } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json index 51780616f107..403a7d800a08 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json @@ -17,6 +17,9 @@ "Binds": [ "bind-source:bind-dest" ], - "NetworkMode": "test" + "NetworkMode": "test", + "SecurityOpt": [ + "option=value" + ] } }