Add Docker configuration authentication to Maven and Gradle plugins
Update the Maven and Gradle plugins to make use of the new Docker configuration authentication support. See gh-45269 Signed-off-by: Dmytro Nosan <dimanosan@gmail.com> Co-authored-by: Phillip Webb <phil.webb@broadcom.com>
This commit is contained in:
parent
e6fbccef7e
commit
da61d63db8
|
@ -100,6 +100,18 @@ The following table summarizes the available properties for `docker.builderRegis
|
|||
|
||||
For more details, see also xref:packaging-oci-image.adoc#build-image.examples.docker[examples].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If credentials are not provided, the plugin reads the user's existing Docker configuration file (typically located at `$HOME/.docker/config.json`) to determine authentication methods.
|
||||
Using these methods, the plugin attempts to provide authentication credentials for the requested image.
|
||||
|
||||
The plugin supports the following authentication methods:
|
||||
|
||||
- *Credential Helpers*: External tools configured in the Docker configuration file to provide credentials for specific registries. For example, tools like `osxkeychain` or `ecr-login` handle authentication for certain registries.
|
||||
- *Credential Store*: A default fallback mechanism that securely stores and retrieves credentials (e.g., `desktop` for Docker Desktop).
|
||||
- *Static Credentials*: Credentials that are stored directly in the Docker configuration file under the `auths` section.
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[build-image.customization]]
|
||||
|
|
|
@ -145,13 +145,14 @@ public abstract class DockerSpec {
|
|||
}
|
||||
|
||||
private BuilderDockerConfiguration customizeBuilderAuthentication(BuilderDockerConfiguration dockerConfiguration) {
|
||||
return dockerConfiguration
|
||||
.withBuilderRegistryAuthentication(getRegistryAuthentication("builder", this.builderRegistry, null));
|
||||
return dockerConfiguration.withBuilderRegistryAuthentication(getRegistryAuthentication("builder",
|
||||
this.builderRegistry, DockerRegistryAuthentication.configuration(null)));
|
||||
}
|
||||
|
||||
private BuilderDockerConfiguration customizePublishAuthentication(BuilderDockerConfiguration dockerConfiguration) {
|
||||
return dockerConfiguration.withPublishRegistryAuthentication(
|
||||
getRegistryAuthentication("publish", this.publishRegistry, DockerRegistryAuthentication.EMPTY_USER));
|
||||
return dockerConfiguration
|
||||
.withPublishRegistryAuthentication(getRegistryAuthentication("publish", this.publishRegistry,
|
||||
DockerRegistryAuthentication.configuration(DockerRegistryAuthentication.EMPTY_USER)));
|
||||
}
|
||||
|
||||
private DockerRegistryAuthentication getRegistryAuthentication(String type, DockerRegistrySpec registry,
|
||||
|
|
|
@ -54,7 +54,7 @@ class DockerSpecTests {
|
|||
void asDockerConfigurationWithDefaults() {
|
||||
BuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
|
||||
assertThat(dockerConfiguration.connection()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -73,7 +73,7 @@ class DockerSpecTests {
|
|||
assertThat(host.secure()).isTrue();
|
||||
assertThat(host.certificatePath()).isEqualTo("/tmp/ca-cert");
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isFalse();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -90,7 +90,7 @@ class DockerSpecTests {
|
|||
assertThat(host.secure()).isFalse();
|
||||
assertThat(host.certificatePath()).isNull();
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isFalse();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -106,7 +106,7 @@ class DockerSpecTests {
|
|||
.connection();
|
||||
assertThat(host.context()).isEqualTo("test-context");
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isFalse();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -132,7 +132,7 @@ class DockerSpecTests {
|
|||
assertThat(host.secure()).isFalse();
|
||||
assertThat(host.certificatePath()).isNull();
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isTrue();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -213,7 +213,7 @@ class DockerSpecTests {
|
|||
}
|
||||
|
||||
String decoded(String value) {
|
||||
return new String(Base64.getDecoder().decode(value));
|
||||
return (value != null) ? new String(Base64.getDecoder().decode(value)) : value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -115,6 +115,18 @@ The following table summarizes the available parameters for `docker.builderRegis
|
|||
|
||||
For more details, see also xref:build-image.adoc#build-image.examples.docker[examples].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If credentials are not provided, the plugin reads the user's existing Docker configuration file (typically located at `$HOME/.docker/config.json`) to determine authentication methods.
|
||||
Using these methods, the plugin attempts to provide authentication credentials for the requested image.
|
||||
|
||||
The plugin supports the following authentication methods:
|
||||
|
||||
- *Credential Helpers*: External tools configured in the Docker configuration file to provide credentials for specific registries. For example, tools like `osxkeychain` or `ecr-login` handle authentication for certain registries.
|
||||
- *Credential Store*: A default fallback mechanism that securely stores and retrieves credentials (e.g., `desktop` for Docker Desktop).
|
||||
- *Static Credentials*: Credentials that are stored directly in the Docker configuration file under the `auths` section.
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[build-image.customization]]
|
||||
|
|
|
@ -262,9 +262,9 @@ public abstract class BuildImageMojo extends AbstractPackagerMojo {
|
|||
Libraries libraries = getLibraries(Collections.emptySet());
|
||||
try {
|
||||
BuildRequest request = getBuildRequest(libraries);
|
||||
BuilderDockerConfiguration dockerConfiguration = (this.docker != null)
|
||||
? this.docker.asDockerConfiguration(request.isPublish())
|
||||
: new Docker().asDockerConfiguration(request.isPublish());
|
||||
Docker docker = (this.docker != null) ? this.docker : new Docker();
|
||||
BuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(getLog(),
|
||||
request.isPublish());
|
||||
Builder builder = new Builder(new MojoBuildLog(this::getLog), dockerConfiguration);
|
||||
builder.build(request);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.maven;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;
|
||||
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;
|
||||
|
||||
|
@ -141,15 +143,16 @@ public class Docker {
|
|||
* Returns this configuration as a {@link BuilderDockerConfiguration} instance. This
|
||||
* method should only be called when the configuration is complete and will no longer
|
||||
* be changed.
|
||||
* @param log the output log
|
||||
* @param publish whether the image should be published
|
||||
* @return the Docker configuration
|
||||
*/
|
||||
BuilderDockerConfiguration asDockerConfiguration(boolean publish) {
|
||||
BuilderDockerConfiguration asDockerConfiguration(Log log, boolean publish) {
|
||||
BuilderDockerConfiguration dockerConfiguration = new BuilderDockerConfiguration();
|
||||
dockerConfiguration = customizeHost(dockerConfiguration);
|
||||
dockerConfiguration = dockerConfiguration.withBindHostToBuilder(this.bindHostToBuilder);
|
||||
dockerConfiguration = customizeBuilderAuthentication(dockerConfiguration);
|
||||
dockerConfiguration = customizePublishAuthentication(dockerConfiguration, publish);
|
||||
dockerConfiguration = customizeBuilderAuthentication(log, dockerConfiguration);
|
||||
dockerConfiguration = customizePublishAuthentication(log, dockerConfiguration, publish);
|
||||
return dockerConfiguration;
|
||||
}
|
||||
|
||||
|
@ -167,18 +170,23 @@ public class Docker {
|
|||
return dockerConfiguration;
|
||||
}
|
||||
|
||||
private BuilderDockerConfiguration customizeBuilderAuthentication(BuilderDockerConfiguration dockerConfiguration) {
|
||||
return dockerConfiguration
|
||||
.withBuilderRegistryAuthentication(getRegistryAuthentication("builder", this.builderRegistry, null));
|
||||
private BuilderDockerConfiguration customizeBuilderAuthentication(Log log,
|
||||
BuilderDockerConfiguration dockerConfiguration) {
|
||||
DockerRegistryAuthentication authentication = DockerRegistryAuthentication.configuration(null,
|
||||
(message, ex) -> log.warn(message));
|
||||
return dockerConfiguration.withBuilderRegistryAuthentication(
|
||||
getRegistryAuthentication("builder", this.builderRegistry, authentication));
|
||||
}
|
||||
|
||||
private BuilderDockerConfiguration customizePublishAuthentication(BuilderDockerConfiguration dockerConfiguration,
|
||||
boolean publish) {
|
||||
private BuilderDockerConfiguration customizePublishAuthentication(Log log,
|
||||
BuilderDockerConfiguration dockerConfiguration, boolean publish) {
|
||||
if (!publish) {
|
||||
return dockerConfiguration;
|
||||
}
|
||||
DockerRegistryAuthentication authentication = DockerRegistryAuthentication
|
||||
.configuration(DockerRegistryAuthentication.EMPTY_USER, (message, ex) -> log.warn(message));
|
||||
return dockerConfiguration.withPublishRegistryAuthentication(
|
||||
getRegistryAuthentication("publish", this.publishRegistry, DockerRegistryAuthentication.EMPTY_USER));
|
||||
getRegistryAuthentication("publish", this.publishRegistry, authentication));
|
||||
}
|
||||
|
||||
private DockerRegistryAuthentication getRegistryAuthentication(String type, DockerRegistry registry,
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.boot.maven;
|
|||
|
||||
import java.util.Base64;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.apache.maven.plugin.logging.SystemStreamLog;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;
|
||||
|
@ -34,12 +36,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
|||
*/
|
||||
class DockerTests {
|
||||
|
||||
private final Log log = new SystemStreamLog();
|
||||
|
||||
@Test
|
||||
void asDockerConfigurationWithDefaults() {
|
||||
Docker docker = new Docker();
|
||||
BuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);
|
||||
assertThat(dockerConfiguration.connection()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication()).isNull();
|
||||
assertThat(dockerConfiguration.builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -59,7 +63,7 @@ class DockerTests {
|
|||
assertThat(host.secure()).isTrue();
|
||||
assertThat(host.certificatePath()).isEqualTo("/tmp/ca-cert");
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isFalse();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication()).isNull();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -76,7 +80,7 @@ class DockerTests {
|
|||
.connection();
|
||||
assertThat(context.context()).isEqualTo("test-context");
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isFalse();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication()).isNull();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -106,7 +110,7 @@ class DockerTests {
|
|||
assertThat(host.secure()).isTrue();
|
||||
assertThat(host.certificatePath()).isEqualTo("/tmp/ca-cert");
|
||||
assertThat(dockerConfiguration.bindHostToBuilder()).isTrue();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication()).isNull();
|
||||
assertThat(createDockerConfiguration(docker).builderRegistryAuthentication().getAuthHeader()).isNull();
|
||||
assertThat(decoded(dockerConfiguration.publishRegistryAuthentication().getAuthHeader()))
|
||||
.contains("\"username\" : \"\"")
|
||||
.contains("\"password\" : \"\"")
|
||||
|
@ -157,7 +161,7 @@ class DockerTests {
|
|||
Docker docker = new Docker();
|
||||
docker.setPublishRegistry(
|
||||
new Docker.DockerRegistry("user", null, "https://docker.example.com", "docker@example.com"));
|
||||
BuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(false);
|
||||
BuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(this.log, false);
|
||||
assertThat(dockerConfiguration.publishRegistryAuthentication()).isNull();
|
||||
}
|
||||
|
||||
|
@ -193,12 +197,12 @@ class DockerTests {
|
|||
dockerRegistry.setToken("token");
|
||||
Docker docker = new Docker();
|
||||
docker.setPublishRegistry(dockerRegistry);
|
||||
BuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(false);
|
||||
BuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(this.log, false);
|
||||
assertThat(dockerConfiguration.publishRegistryAuthentication()).isNull();
|
||||
}
|
||||
|
||||
private BuilderDockerConfiguration createDockerConfiguration(Docker docker) {
|
||||
return docker.asDockerConfiguration(true);
|
||||
return docker.asDockerConfiguration(this.log, true);
|
||||
}
|
||||
|
||||
String decoded(String value) {
|
||||
|
|
Loading…
Reference in New Issue