Skip to content

Commit 3f55e01

Browse files
feature: Add the possibility to give secret to buildx build (#1798) (#1799)
Signed-off-by: Kevin Leturc <kevinleturc@users.noreply.github.com> Co-authored-by: Rohan Kumar <rohaan@redhat.com>
1 parent 7971f73 commit 3f55e01

File tree

11 files changed

+259
-20
lines changed

11 files changed

+259
-20
lines changed

doc/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Automatically create parent directories of portPropertyFile path
44
- Added support for `platform` attribute of a container in the docker-compose configuration.
55
- `docker:push` failed with build `ARG` in `FROM` ([1778](https://github.com/fabric8io/docker-maven-plugin/issues/1778))
6+
- Add the possibility to give secret to buildx build ([1798](https://github.com/fabric8io/docker-maven-plugin/issues/1798)
67
- `FROM` can reference `ARG` that references other `ARG` ([1800](https://github.com/fabric8io/docker-maven-plugin/issues/1800))
78

89
* **0.44.0** (2024-02-17):
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>io.fabric8.dmp.itests</groupId>
7+
<artifactId>dmp-it-parent</artifactId>
8+
<version>0.45-SNAPSHOT</version>
9+
<relativePath>../pom.xml</relativePath>
10+
</parent>
11+
12+
<artifactId>dmp-it-buildx-dockerfile-secret</artifactId>
13+
14+
<build>
15+
<plugins>
16+
<plugin>
17+
<groupId>io.fabric8</groupId>
18+
<artifactId>docker-maven-plugin</artifactId>
19+
<configuration>
20+
<images>
21+
<image>
22+
<name>dmp/alpine:${project.version}</name>
23+
<build>
24+
<dockerFile>${project.basedir}/src/main/docker/Dockerfile</dockerFile>
25+
<buildx>
26+
<secret>
27+
<envs>
28+
<myEnvVar>something</myEnvVar>
29+
</envs>
30+
<files>
31+
<myFile>${project.basedir}/../README.md</myFile>
32+
</files>
33+
</secret>
34+
</buildx>
35+
</build>
36+
</image>
37+
</images>
38+
</configuration>
39+
<executions>
40+
<execution>
41+
<id>default</id>
42+
<goals>
43+
<goal>build</goal>
44+
</goals>
45+
<phase>package</phase>
46+
</execution>
47+
</executions>
48+
</plugin>
49+
</plugins>
50+
</build>
51+
</project>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM alpine
2+
3+
RUN --mount=type=secret,id=myEnvVar cat /run/secrets/myEnvVar
4+
RUN --mount=type=secret,id=myFile cat /run/secrets/myFile

it/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<module>buildx-contextdir</module>
2626
<module>buildx-dependencyset</module>
2727
<module>buildx-dockerfile</module>
28+
<module>buildx-dockerfile-secret</module>
2829
<module>buildx-dockerfile_and_contextdir</module>
2930
<module>buildx-push</module>
3031
<module>docker-compose</module>

src/main/asciidoc/inc/build/_buildx.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ element defaults to `min` and the `<sbom>` element defaults to `false`.
6060
| A value to be passed through to the `--cache-from` option of `docker buildx build`. See https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-from[docker buildx reference docs].
6161
| *cacheTo*
6262
| A value to be passed through to the `--cache-to` option of `docker buildx build`. See https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-to[docker buildx reference docs].
63+
| *secret*
64+
| Two Maps, under `envs` and `files` of `<ID>VALUE</id>` elements specifying the values of https://docs.docker.com/reference/cli/docker/buildx/build/#secret[Docker Buildx secret] to give to the build as `--secret id=ID[,[env\|src]=VALUE]`.
6365
|===
6466

6567
.Examples

src/main/java/io/fabric8/maven/docker/config/BuildXConfiguration.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ public class BuildXConfiguration implements Serializable {
6161
@Parameter
6262
private Map<String, String> driverOpts;
6363

64+
/**
65+
* Secret to expose to the build
66+
*/
67+
@Parameter
68+
private SecretConfiguration secret;
69+
6470
public String getBuilderName() {
6571
return builderName;
6672
}
@@ -86,7 +92,7 @@ public String getCacheTo() {
8692
}
8793

8894
public boolean isBuildX() {
89-
return !getPlatforms().isEmpty();
95+
return !getPlatforms().isEmpty() || hasSecret();
9096
}
9197

9298
@Nonnull
@@ -102,6 +108,14 @@ public Map<String, String> getDriverOpts() {
102108
return driverOpts;
103109
}
104110

111+
public boolean hasSecret() {
112+
return secret != null;
113+
}
114+
115+
public SecretConfiguration getSecret() {
116+
return secret;
117+
}
118+
105119
public static class Builder {
106120

107121
private final BuildXConfiguration config = new BuildXConfiguration();
@@ -159,7 +173,6 @@ public Builder attestations(AttestationConfiguration attestations) {
159173
return this;
160174
}
161175

162-
163176
public Builder cacheFrom(String cacheFrom) {
164177
config.cacheFrom = cacheFrom;
165178
if (cacheFrom != null) {
@@ -183,5 +196,13 @@ public Builder cacheTo(String cacheTo) {
183196
}
184197
return this;
185198
}
199+
200+
public Builder secret(SecretConfiguration secret) {
201+
config.secret = secret;
202+
if (secret != null) {
203+
isEmpty = false;
204+
}
205+
return this;
206+
}
186207
}
187208
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.fabric8.maven.docker.config;
2+
3+
import org.apache.maven.plugins.annotations.Parameter;
4+
5+
import java.io.Serializable;
6+
import java.util.Map;
7+
8+
/**
9+
* @since 15/07/24
10+
*/
11+
public class SecretConfiguration implements Serializable {
12+
13+
@Parameter
14+
private Map<String, String> envs;
15+
16+
@Parameter
17+
private Map<String, String> files;
18+
19+
public Map<String, String> getEnvs() {
20+
return envs;
21+
}
22+
23+
public Map<String, String> getFiles() {
24+
return files;
25+
}
26+
27+
public static class Builder {
28+
29+
private final SecretConfiguration config = new SecretConfiguration();
30+
private boolean isEmpty = true;
31+
32+
public SecretConfiguration build() {
33+
return isEmpty ? null : config;
34+
}
35+
36+
public SecretConfiguration.Builder envs(Map<String, String> envs) {
37+
config.envs = envs;
38+
if (envs != null && !envs.isEmpty()) {
39+
isEmpty = false;
40+
}
41+
return this;
42+
}
43+
44+
public SecretConfiguration.Builder files(Map<String, String> files) {
45+
config.files = files;
46+
if (files != null && !files.isEmpty()) {
47+
isEmpty = false;
48+
}
49+
return this;
50+
}
51+
}
52+
}

src/main/java/io/fabric8/maven/docker/config/handler/property/ConfigKey.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public enum ConfigKey {
5050
BUILDX_ATTESTATION_SBOM("buildx.attestations.sbom"),
5151
BUILDX_CACHE_FROM("buildx.cacheFrom"),
5252
BUILDX_CACHE_TO("buildx.cacheTo"),
53+
BUILDX_SECRET_ENVS("buildx.secret.envs", ValueCombinePolicy.Merge),
54+
BUILDX_SECRET_FILES("buildx.secret.files", ValueCombinePolicy.Merge),
5355
CAP_ADD,
5456
CAP_DROP,
5557
SYSCTLS,

src/main/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandler.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import io.fabric8.maven.docker.config.RestartPolicy;
3737
import io.fabric8.maven.docker.config.RunImageConfiguration;
3838
import io.fabric8.maven.docker.config.RunVolumeConfiguration;
39+
import io.fabric8.maven.docker.config.SecretConfiguration;
3940
import io.fabric8.maven.docker.config.UlimitConfig;
4041
import io.fabric8.maven.docker.config.WaitConfiguration;
4142
import io.fabric8.maven.docker.config.WatchImageConfiguration;
@@ -342,6 +343,7 @@ private BuildXConfiguration extractBuildx(BuildXConfiguration config, ValueProvi
342343
.attestations(extractAttestations(config.getAttestations(), valueProvider))
343344
.cacheFrom(valueProvider.getString(BUILDX_CACHE_FROM, config.getCacheFrom()))
344345
.cacheTo(valueProvider.getString(BUILDX_CACHE_TO, config.getCacheTo()))
346+
.secret(extractSecret(config.getSecret(), valueProvider))
345347
.build();
346348
}
347349

@@ -356,6 +358,17 @@ private AttestationConfiguration extractAttestations(AttestationConfiguration co
356358
.build();
357359
}
358360

361+
private SecretConfiguration extractSecret(SecretConfiguration config, ValueProvider valueProvider) {
362+
if (config == null) {
363+
config = new SecretConfiguration();
364+
}
365+
366+
return new SecretConfiguration.Builder()
367+
.envs(valueProvider.getMap(BUILDX_SECRET_ENVS, config.getEnvs()))
368+
.files(valueProvider.getMap(BUILDX_SECRET_FILES, config.getFiles()))
369+
.build();
370+
}
371+
359372
// Extract only the values of the port mapping
360373

361374
private List<String> extractPortValues(List<String> config, ValueProvider valueProvider) {

src/main/java/io/fabric8/maven/docker/service/BuildXService.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.fabric8.maven.docker.config.BuildXConfiguration;
1111
import io.fabric8.maven.docker.config.ConfigHelper;
1212
import io.fabric8.maven.docker.config.ImageConfiguration;
13+
import io.fabric8.maven.docker.config.SecretConfiguration;
1314
import io.fabric8.maven.docker.util.EnvUtil;
1415
import io.fabric8.maven.docker.util.ImageName;
1516
import io.fabric8.maven.docker.util.Logger;
@@ -35,6 +36,8 @@
3536
import java.util.Map;
3637
import java.util.Optional;
3738
import java.util.concurrent.CompletableFuture;
39+
import java.util.function.BiConsumer;
40+
import java.util.function.Consumer;
3841

3942
public class BuildXService {
4043
private static final String DOCKER = "docker";
@@ -121,7 +124,7 @@ protected void buildAndLoadSinglePlatform(List<String> buildX, String builderNam
121124
String nativePlatform = dockerAccess.getNativePlatform();
122125
if (platforms.size() == 1) {
123126
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, platforms, buildArchive, "--load");
124-
} else if (platforms.contains(nativePlatform)) {
127+
} else if (platforms.isEmpty() || platforms.contains(nativePlatform)) {
125128
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, Collections.singletonList(nativePlatform), buildArchive, "--load");
126129
} else {
127130
logger.info("More than one platform specified not including native %s, no image built", nativePlatform);
@@ -130,7 +133,11 @@ protected void buildAndLoadSinglePlatform(List<String> buildX, String builderNam
130133

131134
protected void pushMultiPlatform(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException {
132135
// build and push all images. The native platform may be re-built, image should be cached and build should be quick
133-
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, imageConfig.getBuildConfiguration().getBuildX().getPlatforms(), buildArchive, "--push");
136+
List<String> platforms = new ArrayList<>(imageConfig.getBuildConfiguration().getBuildX().getPlatforms());
137+
if (platforms.isEmpty()) {
138+
platforms.add(dockerAccess.getNativePlatform());
139+
}
140+
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, platforms, buildArchive, "--push");
134141
}
135142

136143
protected void buildX(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, List<String> platforms, File buildArchive, String extraParam)
@@ -190,6 +197,15 @@ protected void buildX(List<String> buildX, String builderName, BuildDirs buildDi
190197
if (buildXConfiguration.getCacheTo() != null) {
191198
cmdLine.add("--cache-to=" + buildXConfiguration.getCacheTo());
192199
}
200+
SecretConfiguration secret = buildXConfiguration.getSecret();
201+
if (secret != null) {
202+
if (secret.getEnvs() != null) {
203+
secret.getEnvs().forEach(buildXSecretConsumerFor("env", cmdLine::add));
204+
}
205+
if (secret.getFiles() != null) {
206+
secret.getFiles().forEach(buildXSecretConsumerFor("src", cmdLine::add));
207+
}
208+
}
193209

194210
if (buildConfiguration.squash()) {
195211
cmdLine.add("--squash");
@@ -213,6 +229,17 @@ protected void buildX(List<String> buildX, String builderName, BuildDirs buildDi
213229
}
214230
}
215231

232+
protected BiConsumer<String, String> buildXSecretConsumerFor(String attribute, Consumer<String> cmdLineConsumer) {
233+
return (arg0, arg1) -> {
234+
cmdLineConsumer.accept("--secret");
235+
String secretParameter = "id=" + arg0;
236+
if (arg1 != null) {
237+
secretParameter += "," + attribute + "=" + arg1;
238+
}
239+
cmdLineConsumer.accept(secretParameter);
240+
};
241+
}
242+
216243
protected Path getContextPath(File buildArchive) throws MojoExecutionException {
217244
String archiveName = buildArchive.getName();
218245
String fileName = archiveName.substring(0, archiveName.indexOf('.'));

0 commit comments

Comments
 (0)