Skip to content

Commit e8f555e

Browse files
maxjiang153scottfrederick
authored andcommitted
Support authentication to private docker registry
This commit adds the ability to configure Docker image registry authentication credentials in the Maven and Gradle plugins. The authentication credentials are passed to the Docker daemon with all daemon API calls, and the daemon forwards the credentials to the image registry when necessary. This makes it possible to use builder and run images stored in a private Docker registry. See gh-22972
1 parent f0dfff8 commit e8f555e

File tree

22 files changed

+922
-12
lines changed

22 files changed

+922
-12
lines changed

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
2525
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
2626
import org.springframework.boot.buildpack.platform.docker.UpdateListener;
27+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
2728
import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;
2829
import org.springframework.boot.buildpack.platform.docker.type.Image;
2930
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
@@ -48,8 +49,16 @@ public Builder() {
4849
this(BuildLog.toSystemOut());
4950
}
5051

52+
public Builder(DockerConfiguration dockerConfiguration) {
53+
this(BuildLog.toSystemOut(), dockerConfiguration);
54+
}
55+
5156
public Builder(BuildLog log) {
52-
this(log, new DockerApi());
57+
this(log, new DockerApi(new DockerConfiguration()));
58+
}
59+
60+
public Builder(BuildLog log, DockerConfiguration dockerConfiguration) {
61+
this(log, new DockerApi(dockerConfiguration));
5362
}
5463

5564
Builder(BuildLog log, DockerApi docker) {

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424
import java.util.Collections;
2525
import java.util.List;
2626

27+
import org.apache.http.Header;
2728
import org.apache.http.client.utils.URIBuilder;
29+
import org.apache.http.message.BasicHeader;
2830

31+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
32+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration;
2933
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;
3034
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;
3135
import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
@@ -68,7 +72,15 @@ public class DockerApi {
6872
* Create a new {@link DockerApi} instance.
6973
*/
7074
public DockerApi() {
71-
this(HttpTransport.create());
75+
this(new DockerConfiguration());
76+
}
77+
78+
/**
79+
* Create a new {@link DockerApi} instance.
80+
* @param dockerConfiguration the Docker configuration options.
81+
*/
82+
public DockerApi(DockerConfiguration dockerConfiguration) {
83+
this(HttpTransport.create(createDockerEngineAuthenticationHeaders(dockerConfiguration)));
7284
}
7385

7486
/**
@@ -84,6 +96,22 @@ public DockerApi() {
8496
this.volume = new VolumeApi();
8597
}
8698

99+
static Collection<Header> createDockerEngineAuthenticationHeaders(DockerConfiguration dockerConfiguration) {
100+
Assert.notNull(dockerConfiguration, "Docker configuration must not be null");
101+
102+
DockerRegistryConfiguration dockerRegistryConfiguration = dockerConfiguration.getDockerRegistryConfiguration();
103+
if (dockerRegistryConfiguration == null) {
104+
return Collections.emptyList();
105+
}
106+
107+
String dockerRegistryAuthToken = dockerRegistryConfiguration.createDockerRegistryAuthToken();
108+
if (StringUtils.isEmpty(dockerRegistryAuthToken)) {
109+
return Collections.emptyList();
110+
}
111+
112+
return Arrays.asList(new BasicHeader("X-Registry-Auth", dockerRegistryAuthToken));
113+
}
114+
87115
private HttpTransport http() {
88116
return this.http;
89117
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.buildpack.platform.docker.configuration;
18+
19+
/**
20+
* Docker configuration options.
21+
*
22+
* @author Wei Jiang
23+
* @since 2.4.0
24+
*/
25+
public class DockerConfiguration {
26+
27+
/**
28+
* The docker registry configuration.
29+
*/
30+
private DockerRegistryConfiguration dockerRegistryConfiguration;
31+
32+
public DockerConfiguration() {
33+
super();
34+
}
35+
36+
public DockerConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) {
37+
super();
38+
this.dockerRegistryConfiguration = dockerRegistryConfiguration;
39+
}
40+
41+
public DockerRegistryConfiguration getDockerRegistryConfiguration() {
42+
return this.dockerRegistryConfiguration;
43+
}
44+
45+
public void setDockerRegistryConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) {
46+
this.dockerRegistryConfiguration = dockerRegistryConfiguration;
47+
}
48+
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.buildpack.platform.docker.configuration;
18+
19+
import java.io.IOException;
20+
21+
import com.fasterxml.jackson.annotation.JsonIgnore;
22+
import com.fasterxml.jackson.annotation.JsonProperty;
23+
24+
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
25+
import org.springframework.util.Base64Utils;
26+
import org.springframework.util.StringUtils;
27+
28+
/**
29+
* Docker registry configuration options.
30+
*
31+
* @author Wei Jiang
32+
* @since 2.4.0
33+
*/
34+
public class DockerRegistryConfiguration {
35+
36+
/**
37+
* Docker registry server address.
38+
*/
39+
@JsonProperty("serveraddress")
40+
private String url;
41+
42+
/**
43+
* Docker registry authentication username.
44+
*/
45+
private String username;
46+
47+
/**
48+
* Docker registry authentication password.
49+
*/
50+
private String password;
51+
52+
/**
53+
* Docker registry authentication email.
54+
*/
55+
private String email;
56+
57+
/**
58+
* Docker registry authentication identity token.
59+
*/
60+
@JsonIgnore
61+
private String token;
62+
63+
public DockerRegistryConfiguration() {
64+
super();
65+
}
66+
67+
public DockerRegistryConfiguration(String url, String username, String password, String email, String token) {
68+
super();
69+
this.url = url;
70+
this.username = username;
71+
this.password = password;
72+
this.email = email;
73+
this.token = token;
74+
}
75+
76+
public String createDockerRegistryAuthToken() {
77+
if (!StringUtils.isEmpty(this.getToken())) {
78+
return this.getToken();
79+
}
80+
81+
try {
82+
return Base64Utils.encodeToString(SharedObjectMapper.get().writeValueAsBytes(this));
83+
}
84+
catch (IOException ex) {
85+
throw new IllegalStateException("create docker registry authentication token failed.", ex);
86+
}
87+
}
88+
89+
public String getUrl() {
90+
return this.url;
91+
}
92+
93+
public void setUrl(String url) {
94+
this.url = url;
95+
}
96+
97+
public String getUsername() {
98+
return this.username;
99+
}
100+
101+
public void setUsername(String username) {
102+
this.username = username;
103+
}
104+
105+
public String getPassword() {
106+
return this.password;
107+
}
108+
109+
public void setPassword(String password) {
110+
this.password = password;
111+
}
112+
113+
public String getEmail() {
114+
return this.email;
115+
}
116+
117+
public void setEmail(String email) {
118+
this.email = email;
119+
}
120+
121+
public String getToken() {
122+
return this.token;
123+
}
124+
125+
public void setToken(String token) {
126+
this.token = token;
127+
}
128+
129+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Docker configuration options.
19+
*/
20+
package org.springframework.boot.buildpack.platform.docker.configuration;

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import java.io.InputStream;
2222
import java.io.OutputStream;
2323
import java.net.URI;
24+
import java.util.Collection;
25+
import java.util.Collections;
26+
27+
import org.apache.http.Header;
2428

2529
import org.springframework.boot.buildpack.platform.io.IOConsumer;
2630
import org.springframework.boot.buildpack.platform.system.Environment;
@@ -84,7 +88,17 @@ public interface HttpTransport {
8488
* @return a {@link HttpTransport} instance
8589
*/
8690
static HttpTransport create() {
87-
return create(Environment.SYSTEM);
91+
return create(Collections.emptyList());
92+
}
93+
94+
/**
95+
* Create the most suitable {@link HttpTransport} based on the
96+
* {@link Environment#SYSTEM system environment}.
97+
* @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine.
98+
* @return a {@link HttpTransport} instance
99+
*/
100+
static HttpTransport create(Collection<Header> dockerEngineAuthenticationHeaders) {
101+
return create(Environment.SYSTEM, dockerEngineAuthenticationHeaders);
88102
}
89103

90104
/**
@@ -94,8 +108,21 @@ static HttpTransport create() {
94108
* @return a {@link HttpTransport} instance
95109
*/
96110
static HttpTransport create(Environment environment) {
97-
HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment);
98-
return (remote != null) ? remote : LocalHttpClientTransport.create(environment);
111+
return create(environment, Collections.emptyList());
112+
}
113+
114+
/**
115+
* Create the most suitable {@link HttpTransport} based on the given
116+
* {@link Environment}.
117+
* @param environment the source environment
118+
* @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine.
119+
* @return a {@link HttpTransport} instance
120+
*/
121+
static HttpTransport create(Environment environment, Collection<Header> dockerEngineAuthenticationHeaders) {
122+
HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment,
123+
dockerEngineAuthenticationHeaders);
124+
return (remote != null) ? remote
125+
: LocalHttpClientTransport.create(environment, dockerEngineAuthenticationHeaders);
99126
}
100127

101128
/**

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
import java.net.InetSocketAddress;
2222
import java.net.Socket;
2323
import java.net.UnknownHostException;
24+
import java.util.Collection;
2425

2526
import com.sun.jna.Platform;
27+
import org.apache.http.Header;
2628
import org.apache.http.HttpHost;
2729
import org.apache.http.config.Registry;
2830
import org.apache.http.config.RegistryBuilder;
@@ -41,6 +43,7 @@
4143
import org.springframework.boot.buildpack.platform.socket.DomainSocket;
4244
import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket;
4345
import org.springframework.boot.buildpack.platform.system.Environment;
46+
import org.springframework.util.CollectionUtils;
4447

4548
/**
4649
* {@link HttpClientTransport} that talks to local Docker.
@@ -60,10 +63,14 @@ private LocalHttpClientTransport(CloseableHttpClient client) {
6063
super(client, LOCAL_DOCKER_HOST);
6164
}
6265

63-
static LocalHttpClientTransport create(Environment environment) {
66+
static LocalHttpClientTransport create(Environment environment,
67+
Collection<Header> dockerEngineAuthenticationHeaders) {
6468
HttpClientBuilder builder = HttpClients.custom();
6569
builder.setConnectionManager(new LocalConnectionManager(socketFilePath(environment)));
6670
builder.setSchemePortResolver(new LocalSchemePortResolver());
71+
if (!CollectionUtils.isEmpty(dockerEngineAuthenticationHeaders)) {
72+
builder.setDefaultHeaders(dockerEngineAuthenticationHeaders);
73+
}
6774
return new LocalHttpClientTransport(builder.build());
6875
}
6976

0 commit comments

Comments
 (0)