diff --git a/README.md b/README.md index 6c6e4d8b..0b3ce8fc 100644 --- a/README.md +++ b/README.md @@ -183,3 +183,20 @@ service-b: Now, `docker-compose up` and `docker-compose build` will work as expected. + +## Authentication and private Docker registry support + +Since version 1.3.0, the plugin will automatically use any configuration in +your `~/.dockercfg` or `~/.docker/config.json` file when pulling, pushing, or +building images to private registries. + +Additionally the plugin will enable support for Google Container Registry if it +is able to successfully load [Google's "Application Default Credentials"][ADC]. +The plugin will also load Google credentials from the file pointed to by the +environment variable `DOCKER_GOOGLE_CREDENTIALS` if it is defined. Since GCR +authentication requires retrieving short-lived access codes for the given +credentials, support for this registry is baked into the underlying +docker-client rather than having to first populate the docker config file +before running the plugin. + +[ADC]: https://developers.google.com/identity/protocols/application-default-credentials diff --git a/extension/pom.xml b/extension/pom.xml index e31b1569..1de69d72 100644 --- a/extension/pom.xml +++ b/extension/pom.xml @@ -5,7 +5,7 @@ dockerfile-maven com.spotify - 1.2.3-SNAPSHOT + 1.3.0-SNAPSHOT dockerfile-maven-extension diff --git a/plugin/pom.xml b/plugin/pom.xml index 04f2f942..e27b6389 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -5,7 +5,7 @@ com.spotify dockerfile-maven - 1.2.3-SNAPSHOT + 1.3.0-SNAPSHOT dockerfile-maven-plugin @@ -29,7 +29,7 @@ com.spotify docker-client shaded - 8.6.2 + 8.7.1 com.google.auth @@ -44,7 +44,7 @@ com.spotify dockerfile-maven-extension - 1.2.3-SNAPSHOT + 1.3.0-SNAPSHOT diff --git a/plugin/src/main/java/com/spotify/plugin/dockerfile/AbstractDockerMojo.java b/plugin/src/main/java/com/spotify/plugin/dockerfile/AbstractDockerMojo.java index ba4c4d85..d535c737 100644 --- a/plugin/src/main/java/com/spotify/plugin/dockerfile/AbstractDockerMojo.java +++ b/plugin/src/main/java/com/spotify/plugin/dockerfile/AbstractDockerMojo.java @@ -20,24 +20,26 @@ package com.spotify.plugin.dockerfile; +import com.google.auth.oauth2.GoogleCredentials; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.io.Files; import com.spotify.docker.client.DefaultDockerClient; import com.spotify.docker.client.DockerClient; +import com.spotify.docker.client.auth.ConfigFileRegistryAuthSupplier; +import com.spotify.docker.client.auth.MultiRegistryAuthSupplier; +import com.spotify.docker.client.auth.RegistryAuthSupplier; +import com.spotify.docker.client.auth.gcr.ContainerRegistryAuthSupplier; import com.spotify.docker.client.exceptions.DockerCertificateException; - -import com.spotify.docker.client.gcr.ContainerRegistryAuthSupplier; -import com.spotify.docker.client.messages.RegistryAuthSupplier; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; - -import java.util.concurrent.ExecutorService; import javax.annotation.Nonnull; import javax.annotation.Nullable; - import org.apache.maven.archiver.MavenArchiveConfiguration; import org.apache.maven.archiver.MavenArchiver; import org.apache.maven.execution.MavenSession; @@ -380,16 +382,8 @@ protected static String formatImageName(@Nonnull String repository, @Nonnull Str } @Nonnull - protected DockerClient openDockerClient() throws MojoExecutionException { - ContainerRegistryAuthSupplier authSupplier = null; - try { - authSupplier = ContainerRegistryAuthSupplier.forApplicationDefaultCredentials() - .build(); - getLog().info("Using Google application credentials"); - } catch (IOException ex) { - // No GCP default credentials available - getLog().debug("Failed to create Google default credentials", ex); - } + private DockerClient openDockerClient() throws MojoExecutionException { + final RegistryAuthSupplier authSupplier = createRegistryAuthSupplier(); try { return DefaultDockerClient.fromEnv() @@ -401,4 +395,69 @@ protected DockerClient openDockerClient() throws MojoExecutionException { throw new MojoExecutionException("Could not load Docker certificates", e); } } + + @Nonnull + private RegistryAuthSupplier createRegistryAuthSupplier() { + final List suppliers = new ArrayList<>(); + suppliers.add(new ConfigFileRegistryAuthSupplier()); + + try { + final RegistryAuthSupplier googleSupplier = googleContainerRegistryAuthSupplier(); + if (googleSupplier != null) { + suppliers.add(0, googleSupplier); + } + } catch (IOException ex) { + getLog().info("ignoring exception while loading Google credentials", ex); + } + + return new MultiRegistryAuthSupplier(suppliers); + } + + /** + * Attempt to load a GCR compatible RegistryAuthSupplier based on a few conditions: + *
    + *
  1. First check to see if the environemnt variable DOCKER_GOOGLE_CREDENTIALS is set and points + * to a readable file
  2. + *
  3. Otherwise check if the Google Application Default Credentials can be loaded
  4. + *
+ * Note that we use a special environment variable of our own in addition to any environment + * variable that the ADC loading uses (GOOGLE_APPLICATION_CREDENTIALS) in case there is a need for + * the user to use the latter env var for some other purpose in their build. + * + * @return a GCR RegistryAuthSupplier, or null + * @throws IOException if an IOException occurs while loading the credentials + */ + @Nullable + private RegistryAuthSupplier googleContainerRegistryAuthSupplier() throws IOException { + GoogleCredentials credentials = null; + + final String googleCredentialsPath = System.getenv("DOCKER_GOOGLE_CREDENTIALS"); + if (googleCredentialsPath != null) { + final File file = new File(googleCredentialsPath); + if (file.exists()) { + try (FileInputStream inputStream = new FileInputStream(file)) { + credentials = GoogleCredentials.fromStream(inputStream); + getLog().info("Using Google credentials from file: " + file.getAbsolutePath()); + } + } + } + + // use the ADC last + if (credentials == null) { + try { + credentials = GoogleCredentials.getApplicationDefault(); + getLog().info("Using Google application default credentials"); + } catch (IOException ex) { + // No GCP default credentials available + getLog().debug("Failed to load Google application default credentials", ex); + } + } + + if (credentials == null) { + return null; + } + + return ContainerRegistryAuthSupplier.forCredentials(credentials).build(); + } + } diff --git a/pom.xml b/pom.xml index 4f0e59f6..fc1d41ab 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ dockerfile-maven - 1.2.3-SNAPSHOT + 1.3.0-SNAPSHOT pom Dockerfile Maven Support