fabric8io / docker-maven-plugin

Maven plugin for running and creating Docker images
https://dmp.fabric8.io
Apache License 2.0
1.88k stars 644 forks source link

Prefer Docker authentication to 'EC2 instance roles' when pushing to ECR (or way to disable it) #1656

Open axel3rd opened 1 year ago

axel3rd commented 1 year ago

Description

io.fabric8:docker-maven-plugin could be used on CI pipeline which execute jobs/builds on some AWS EC2, which doesn't belong to your project.

Often, CI integration offers a way (plugin, ...) to provide a "Docker support", to handle the Docker authentication (~ config.json file with auths key).

This AWS EC2 can have IAM profile (a common one could be at min the SSM profile to be able to "connect" to EC2 via AWS Console for admin), which has no permission(s) for your AWS project account (and ECR push).

In this case (since https://github.com/fabric8io/docker-maven-plugin/issues/1177), the EC2 instance roles is used for ECR authentication, which isn't authorized for your ECR push.

The Docker authentication isn't used, and there isn't a proper way to disable it (skipExtendedAuth doesn't work).

The workaround could be to "enforce" an AWS authentication (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY) but you lost "Docker support" facilities provided by CI Docker integration.

Request

It would perhaps be preferable that "project Docker Authentication" is used (if exist) before any AWS authentication (EC2 Role, ...) which belong to hostname which execute build.

Otherwise, offer a way to disable it properly (part of -Ddocker.skip.extendedAuth=true ?).

Info

Reproduction (pure command line)

Consider some end-user context and AWS authentication for following 'aws ecr get-login-password' command:

export AWS_ACCESS_KEY_ID="ABCDEFGHIJKLMNOPQRST"
export AWS_SECRET_ACCESS_KEY="yourOne"
export AWS_SESSION_TOKEN="yourOne"
export AWS_REGION=eu-west-3
export ECR_URI=123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image

Create a generic & variabilized pom.xml for following command line tests:

cat >> pom.xml << 'END'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.test</groupId>
    <artifactId>test</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Test</name>
    <build>
        <plugins>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${docker.plugin.version}</version>
                <configuration>
                    <images>
                        <image>
                            <name>${docker.plugin.image}</name>
                            <build />
                        </image>
                    </images>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
END

Prepare Docker image tag:

docker pull hello-world
docker tag hello-world $ECR_URI

Define Docker authentication (in tmp dir for fresh context usage) and unset any AWS credentials used for 'aws ecr get-login-password' (this part in done by CI Docker integration, here in command line for reproduction):

export DOCKER_CONFIG=tmp-docker
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_URI

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

Validate plugin behavior before AWS role usage (<= 0.28.0):

mvn docker:push -Ddocker.plugin.version=0.28.0 -Ddocker.plugin.image=$ECR_URI -X

...
[DEBUG] Configuring mojo 'io.fabric8:docker-maven-plugin:0.28.0:push' with basic configurator -->
[DEBUG]   (f) execution = io.fabric8:docker-maven-plugin:0.28.0:push {execution: default-cli}
[DEBUG]   (s) name = 123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image
[DEBUG]   (f) build = io.fabric8.maven.docker.config.BuildImageConfiguration@71a3a190
[DEBUG]   (f) images = [ImageConfiguration {name='123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image', alias='null'}]
[DEBUG]   (f) keepContainer = false
[DEBUG]   (f) logStdout = false
[DEBUG]   (f) maxConnections = 100
[DEBUG]   (f) project = MavenProject: org.test:test:1.0.0-SNAPSHOT @ /home/ubuntu/tmp/pom.xml
[DEBUG]   (f) removeVolumes = false
[DEBUG]   (f) retries = 0
[DEBUG]   (f) session = org.apache.maven.execution.MavenSession@588ffeb
[DEBUG]   (f) settings = org.apache.maven.execution.SettingsAdapter@baf1bb3
[DEBUG]   (f) skip = false
[DEBUG]   (f) skipExtendedAuth = false
[DEBUG]   (f) skipMachine = false
[DEBUG]   (f) skipPush = false
[DEBUG]   (f) skipTag = false
[DEBUG]   (f) useColor = true
[DEBUG]   (f) verbose = false
[DEBUG] -- end configuration --
[DEBUG] DOCKER> AuthConfig: credentials from ~/.docker/config.json
[INFO] DOCKER> The push refers to repository [123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image]
[INFO] DOCKER> latest: digest: sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 size: 525
[INFO] DOCKER> Pushed 123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image in 477 milliseconds
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Proof that AWS role used before Docker authentication (>= 0.29.0):

mvn docker:push -Ddocker.plugin.version=0.42.0 -Ddocker.plugin.image=$ECR_URI -X

...
[DEBUG] Configuring mojo 'io.fabric8:docker-maven-plugin:0.42.0:push' with basic configurator -->
[DEBUG]   (f) execution = io.fabric8:docker-maven-plugin:0.42.0:push {execution: default-cli}
[DEBUG]   (s) name = 123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image
[DEBUG]   (f) build = io.fabric8.maven.docker.config.BuildImageConfiguration@1d782abe
[DEBUG]   (f) images = [ImageConfiguration {name='123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image', alias='null'}]
[DEBUG]   (f) jib = false
[DEBUG]   (f) jibImageFormat = docker
[DEBUG]   (f) keepContainer = false
[DEBUG]   (f) logStdout = false
[DEBUG]   (f) maxConnections = 100
[DEBUG]   (f) outputDirectory = target/docker
[DEBUG]   (f) packaging = jar
[DEBUG]   (f) project = MavenProject: org.test:test:1.0.0-SNAPSHOT @ /home/ubuntu/tmp/pom.xml
[DEBUG]   (f) removeVolumes = false
[DEBUG]   (f) retries = 0
[DEBUG]   (f) session = org.apache.maven.execution.MavenSession@1ddd3478
[DEBUG]   (f) settings = org.apache.maven.execution.SettingsAdapter@4d33940d
[DEBUG]   (f) skip = false
[DEBUG]   (f) skipExtendedAuth = false
[DEBUG]   (f) skipMachine = false
[DEBUG]   (f) skipPom = false
[DEBUG]   (f) skipPush = false
[DEBUG]   (f) skipTag = false
[DEBUG]   (f) sourceDirectory = src/main/docker
[DEBUG]   (f) useColor = true
[DEBUG] -- end configuration --
[INFO] DOCKER> It appears that you're using AWS ECR. Consider integrating the AWS SDK in order to make use of common AWS authentication mechanisms, see https://dmp.fabric8.io/#extended-authentication
[DEBUG] DOCKER> System environment not set for variable AWS_ACCESS_KEY_ID, no AWS credentials found
[DEBUG] DOCKER> No user and password set for ECR, checking EC2 instance role
[DEBUG] DOCKER> Found instance role role-something-ssm, getting temporary security credentials
[DEBUG] DOCKER> Received temporary access key ABCDEFGH...
[DEBUG] DOCKER> AuthConfig: credentials from EC2 instance role
[DEBUG] DOCKER> registry = 123456789000.dkr.ecr.eu-west-3.amazonaws.com, isValid= true
[DEBUG] DOCKER> Get ECR AuthorizationToken from api.ecr.eu-west-3.amazonaws.com
[DEBUG] DOCKER> Response status 400
[ERROR] DOCKER> AWS authentication failure
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Proof that currently cannot be skipped:

mvn docker:push -Ddocker.plugin.version=0.42.0 -Ddocker.plugin.image=$ECR_URI -Ddocker.skip.extendedAuth=true -X

...
[DEBUG] Configuring mojo 'io.fabric8:docker-maven-plugin:0.42.0:push' with basic configurator -->
[DEBUG]   (f) execution = io.fabric8:docker-maven-plugin:0.42.0:push {execution: default-cli}
[DEBUG]   (s) name = 123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image
[DEBUG]   (f) build = io.fabric8.maven.docker.config.BuildImageConfiguration@1d782abe
[DEBUG]   (f) images = [ImageConfiguration {name='123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image', alias='null'}]
[DEBUG]   (f) jib = false
[DEBUG]   (f) jibImageFormat = docker
[DEBUG]   (f) keepContainer = false
[DEBUG]   (f) logStdout = false
[DEBUG]   (f) maxConnections = 100
[DEBUG]   (f) outputDirectory = target/docker
[DEBUG]   (f) packaging = jar
[DEBUG]   (f) project = MavenProject: org.test:test:1.0.0-SNAPSHOT @ /home/ubuntu/tmp/pom.xml
[DEBUG]   (f) removeVolumes = false
[DEBUG]   (f) retries = 0
[DEBUG]   (f) session = org.apache.maven.execution.MavenSession@1ddd3478
[DEBUG]   (f) settings = org.apache.maven.execution.SettingsAdapter@4d33940d
[DEBUG]   (f) skip = false
[DEBUG]   (f) skipExtendedAuth = true
[DEBUG]   (f) skipMachine = false
[DEBUG]   (f) skipPom = false
[DEBUG]   (f) skipPush = false
[DEBUG]   (f) skipTag = false
[DEBUG]   (f) sourceDirectory = src/main/docker
[DEBUG]   (f) useColor = true
[DEBUG] -- end configuration --
[INFO] DOCKER> It appears that you're using AWS ECR. Consider integrating the AWS SDK in order to make use of common AWS authentication mechanisms, see https://dmp.fabric8.io/#extended-authentication
[DEBUG] DOCKER> System environment not set for variable AWS_ACCESS_KEY_ID, no AWS credentials found
[DEBUG] DOCKER> No user and password set for ECR, checking EC2 instance role
[DEBUG] DOCKER> Found instance role role-something-ssm, getting temporary security credentials
[DEBUG] DOCKER> Received temporary access key ABCDEFGH...
[DEBUG] DOCKER> AuthConfig: credentials from EC2 instance role
[INFO] DOCKER> The push refers to repository [123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image]
[INFO] DOCKER> Temporary image tag skipped. Target image '123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image:latest' already has registry set or no registry is available
[ERROR] DOCKER> Unable to push '123456789000.dkr.ecr.eu-west-3.amazonaws.com/tmp-test-image' to registry '123456789000.dkr.ecr.eu-west-3.amazonaws.com' : unauthorized: authentication required  [unauthorized: authentication required ]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
axel3rd commented 1 year ago

Workaround: Using Extended Authentication (com.amazonaws:aws-java-sdk-core as dependency) and overrides AWS_CREDENTIAL_PROFILES_FILE environment variable is working fine (DefaultAWSCredentialsProviderChain includes ProfileCredentialsProvider where override is possible due to CredentialsEnvVarOverrideLocationProvider).

=> If CI integration provides AWS_SHARED_CREDENTIALS_FILE configuration, this snippet is working fine:

AWS_CREDENTIAL_PROFILES_FILE=$AWS_SHARED_CREDENTIALS_FILE mvn docker:push -Ddocker.plugin.version=0.43.0 -Ddocker.plugin.image=$ECR_URI -X