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
This commit is contained in:
parent
238493a7d4
commit
c16094e04b
|
@ -20,6 +20,8 @@ import java.io.Closeable;
|
|||
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 @@ class Lifecycle implements Closeable {
|
|||
else {
|
||||
phase.withBinding(Binding.from(DOMAIN_SOCKET_PATH, DOMAIN_SOCKET_PATH));
|
||||
}
|
||||
if (!Platform.isWindows()) {
|
||||
phase.withSecurityOption("label=disable");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isVerboseLogging() {
|
||||
|
|
|
@ -47,6 +47,8 @@ class Phase {
|
|||
|
||||
private final Map<String, String> env = new LinkedHashMap<>();
|
||||
|
||||
private final List<String> securityOptions = new ArrayList<>();
|
||||
|
||||
private String networkMode;
|
||||
|
||||
/**
|
||||
|
@ -110,6 +112,14 @@ class Phase {
|
|||
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 @@ class Phase {
|
|||
if (this.networkMode != null) {
|
||||
update.withNetworkMode(this.networkMode);
|
||||
}
|
||||
this.securityOptions.forEach(update::withSecurityOption);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,7 +48,8 @@ public class ContainerConfig {
|
|||
private final String json;
|
||||
|
||||
ContainerConfig(String user, ImageReference image, String command, List<String> args, Map<String, String> labels,
|
||||
List<Binding> bindings, Map<String, String> env, String networkMode) throws IOException {
|
||||
List<Binding> bindings, Map<String, String> env, String networkMode, List<String> 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 class ContainerConfig {
|
|||
|
||||
private String networkMode;
|
||||
|
||||
private final List<String> securityOptions = new ArrayList<>();
|
||||
|
||||
Update(ImageReference image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
@ -128,7 +135,7 @@ public class ContainerConfig {
|
|||
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 class ContainerConfig {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -143,4 +143,18 @@ class PhaseTests {
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,12 +61,13 @@ class ContainerConfigTests extends AbstractJsonTests {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"build-volume:/cache",
|
||||
"launch-volume:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@
|
|||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=disable"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@
|
|||
"Binds": [
|
||||
"bind-source:bind-dest"
|
||||
],
|
||||
"NetworkMode": "test"
|
||||
"NetworkMode": "test",
|
||||
"SecurityOpt": [
|
||||
"option=value"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue