Enforce builder and run images in the same registry

Previously, when an authenticated Docker builder registry was
configured in the Maven or Gradle plugin and the builder and run
images specified different registries, the authentication credentials
would be sent to both registries. This could cause confusion if both
registries don't recognize the same credentials. This commit enforces
that both images are in the same registry when authentication
is configured.

Fixes gh-24552
This commit is contained in:
Scott Frederick
2021-01-12 17:50:28 -06:00
parent a6a7c06e55
commit a9e711e503
3 changed files with 179 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -116,6 +116,7 @@ public class Builder {
ImageReference runImage = getRunImageReferenceForStack(builderStack);
request = request.withRunImage(runImage);
}
assertImageRegistriesMatch(request);
Image runImage = getImage(request, ImageType.RUNNER);
assertStackIdsMatch(runImage, builderImage);
return request;
@@ -172,6 +173,14 @@ public class Builder {
? this.dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader() : null;
}
private void assertImageRegistriesMatch(BuildRequest request) {
if (getBuilderAuthHeader() != null) {
Assert.state(request.getRunImage().getDomain().equals(request.getBuilder().getDomain()),
"Builder image '" + request.getBuilder() + "' and run image '" + request.getRunImage()
+ "' must be pulled from the same authenticated registry");
}
}
private void assertStackIdsMatch(Image runImage, Image builderImage) {
StackId runImageStackId = StackId.fromImage(runImage);
StackId builderImageStackId = StackId.fromImage(builderImage);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -308,6 +308,42 @@ class BuilderTests {
.withMessage("Builder lifecycle 'creator' failed with status code 9");
}
@Test
void buildWhenDetectedRunImageInDifferentAuthenticatedRegistryThrowsException() throws Exception {
TestPrintStream out = new TestPrintStream();
DockerApi docker = mockDockerApi();
Image builderImage = loadImage("image-with-run-image-different-registry.json");
DockerConfiguration dockerConfiguration = new DockerConfiguration()
.withBuilderRegistryTokenAuthentication("builder token");
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(),
eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader())))
.willAnswer(withPulledImage(builderImage));
Builder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration);
BuildRequest request = getTestRequest();
assertThatIllegalStateException().isThrownBy(() -> builder.build(request))
.withMessageContaining(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)
.withMessageContaining("example.com/custom/run:latest")
.withMessageContaining("must be pulled from the same authenticated registry");
}
@Test
void buildWhenRequestedRunImageInDifferentAuthenticatedRegistryThrowsException() throws Exception {
TestPrintStream out = new TestPrintStream();
DockerApi docker = mockDockerApi();
Image builderImage = loadImage("image.json");
DockerConfiguration dockerConfiguration = new DockerConfiguration()
.withBuilderRegistryTokenAuthentication("builder token");
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(),
eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader())))
.willAnswer(withPulledImage(builderImage));
Builder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration);
BuildRequest request = getTestRequest().withRunImage(ImageReference.of("example.com/custom/run:latest"));
assertThatIllegalStateException().isThrownBy(() -> builder.build(request))
.withMessageContaining(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)
.withMessageContaining("example.com/custom/run:latest")
.withMessageContaining("must be pulled from the same authenticated registry");
}
private DockerApi mockDockerApi() throws IOException {
ContainerApi containerApi = mock(ContainerApi.class);
ContainerReference reference = ContainerReference.of("container-ref");