├── .gitattributes
├── .github
├── release-drafter.yml
├── build-and-publish.png
├── dependabot.yml
└── workflows
│ ├── cd.yaml
│ └── jenkins-security-scan.yml
├── .mvn
├── maven.config
└── extensions.xml
├── .git-blame-ignore-revs
├── Jenkinsfile
├── LICENSE
├── .gitignore
├── src
├── main
│ ├── resources
│ │ └── index.jelly
│ └── java
│ │ └── com
│ │ └── cloudbees
│ │ └── jenkins
│ │ └── plugins
│ │ └── amazonecr
│ │ ├── AmazonECSRegistryTokenSource.java
│ │ ├── AmazonECSRegistryCredentialsProvider.java
│ │ └── AmazonECSRegistryCredential.java
└── test
│ └── java
│ └── com
│ └── cloudbees
│ └── jenkins
│ └── plugins
│ └── amazonecr
│ └── AmazonECSRegistryCredentialPipelineAccessTest.java
├── CHANGELOG.old.md
├── pom.xml
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | _extends: .github
2 |
--------------------------------------------------------------------------------
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -Pconsume-incrementals
2 | -Pmight-produce-incrementals
3 | -Dchangelist.format=%d.v%s
4 |
--------------------------------------------------------------------------------
/.github/build-and-publish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/amazon-ecr-plugin/main/.github/build-and-publish.png
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Spotless reformat: https://github.com/jenkinsci/amazon-ecr-plugin/pull/108
2 | 3808041a014663a1d830dd982428c19025c10e0a
3 | # Reformat to upstream spotless config
4 | 95904a4e7ced02c2856a1d91b49a7cc0a540a780
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "maven"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | - package-ecosystem: "github-actions"
8 | directory: "/"
9 | schedule:
10 | interval: "weekly"
11 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | /*
2 | See the documentation for more options:
3 | https://github.com/jenkins-infra/pipeline-library/
4 | */
5 | buildPlugin(
6 | useContainerAgent: true, // Set to `false` if you need to use Docker for containerized tests
7 | configurations: [
8 | [platform: 'linux', jdk: 25],
9 | [platform: 'windows', jdk: 21],
10 | ])
11 |
--------------------------------------------------------------------------------
/.mvn/extensions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.jenkins.tools.incrementals
4 | git-changelist-maven-extension
5 | 1.12
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yaml:
--------------------------------------------------------------------------------
1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins
2 |
3 | name: cd
4 | on:
5 | workflow_dispatch:
6 | check_run:
7 | types:
8 | - completed
9 |
10 | jobs:
11 | maven-cd:
12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1
13 | secrets:
14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.github/workflows/jenkins-security-scan.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Jenkins Security Scan
3 | on:
4 | push:
5 | branches:
6 | - "main"
7 | pull_request:
8 | types: [opened, synchronize, reopened]
9 | workflow_dispatch:
10 |
11 | permissions:
12 | security-events: write
13 | contents: read
14 | actions: read
15 |
16 | jobs:
17 | security-scan:
18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
19 | with:
20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015-2017 CloudBees, Inc.
2 | Copyright 2021-2023 TobiX
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | this software and associated documentation files (the "Software"), to deal in
6 | the Software without restriction, including without limitation the rights to
7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 | of the Software, and to permit persons to whom the Software is furnished to do
9 | so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Maven template
2 | target/
3 | pom.xml.tag
4 | pom.xml.releaseBackup
5 | pom.xml.versionsBackup
6 | pom.xml.next
7 | release.properties
8 | dependency-reduced-pom.xml
9 | buildNumber.properties
10 | .mvn/timing.properties
11 | ### JetBrains template
12 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
13 |
14 | *.iml
15 |
16 | ## Directory-based project format:
17 | .idea/
18 | # if you remove the above rule, at least ignore the following:
19 |
20 | # User-specific stuff:
21 | # .idea/workspace.xml
22 | # .idea/tasks.xml
23 | # .idea/dictionaries
24 |
25 | # Sensitive or high-churn files:
26 | # .idea/dataSources.ids
27 | # .idea/dataSources.xml
28 | # .idea/sqlDataSources.xml
29 | # .idea/dynamic.xml
30 | # .idea/uiDesigner.xml
31 |
32 | # Gradle:
33 | # .idea/gradle.xml
34 | # .idea/libraries
35 |
36 | # Mongo Explorer plugin:
37 | # .idea/mongoSettings.xml
38 |
39 | ## File-based project format:
40 | *.ipr
41 | *.iws
42 |
43 | ## Jenkins
44 | work/
45 |
46 | # IntelliJ
47 | /out/
48 |
49 | # mpeltonen/sbt-idea plugin
50 | .idea_modules/
51 |
52 | # JIRA plugin
53 | atlassian-ide-plugin.xml
54 |
55 | # Crashlytics plugin (for Android Studio and IntelliJ)
56 | com_crashlytics_export_strings.xml
57 | crashlytics.properties
58 | crashlytics-build.properties
59 |
60 | # Created by .ignore support plugin (hsz.mobi)
61 |
--------------------------------------------------------------------------------
/src/main/resources/index.jelly:
--------------------------------------------------------------------------------
1 |
2 |
26 |
27 |
30 |
31 | This plugin generates Docker authentication token from Amazon Credentials to access Amazon ECR.
32 |
33 |
--------------------------------------------------------------------------------
/src/test/java/com/cloudbees/jenkins/plugins/amazonecr/AmazonECSRegistryCredentialPipelineAccessTest.java:
--------------------------------------------------------------------------------
1 | package com.cloudbees.jenkins.plugins.amazonecr;
2 |
3 | import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl;
4 | import com.cloudbees.plugins.credentials.CredentialsScope;
5 | import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
6 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
7 | import org.jenkinsci.plugins.workflow.job.WorkflowJob;
8 | import org.junit.jupiter.api.Test;
9 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
10 | import org.jvnet.hudson.test.JenkinsRule;
11 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
12 |
13 | @WithJenkins
14 | class AmazonECSRegistryCredentialPipelineAccessTest {
15 | @Test
16 | @EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".{10,}")
17 | void pipelineCanLoginWithCredential(JenkinsRule r) throws Exception {
18 | SystemCredentialsProvider.getInstance()
19 | .getCredentials()
20 | .add(new AWSCredentialsImpl(
21 | CredentialsScope.GLOBAL,
22 | "test",
23 | System.getenv("AWS_ACCESS_KEY_ID"),
24 | System.getenv("AWS_SECRET_ACCESS_KEY"),
25 | "test"));
26 |
27 | String script =
28 | "docker.withRegistry('https://" + System.getenv("AWS_REGISTRY_HOST") + "', 'ecr:us-east-1:test') {}";
29 |
30 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "testJob");
31 | p.setDefinition(new CpsFlowDefinition(script, true));
32 |
33 | r.assertBuildStatusSuccess(p.scheduleBuild2(0));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/CHANGELOG.old.md:
--------------------------------------------------------------------------------
1 | # Old Changelog
2 |
3 | This is the old changelog imported from the Jenkins wiki, for newer changes see
4 | [GitHub Releases](https://github.com/jenkinsci/amazon-ecr-plugin/releases).
5 |
6 | ## 1.6 (2017-05-16)
7 |
8 | - [JENKINS-34437](https://issues.jenkins-ci.org/browse/JENKINS-34437) Enable
9 | amazon-ecr-plugin behind proxy
10 | - Performance improvements
11 | - Set minor version to 1.642.1
12 | - Upgrade Credentials Plugin
13 | - Upgrade AWS Java SDK Plugin
14 | - Upgrade AWS Credentials Plugin
15 | - Upgrade Docker Commons Plugin
16 | - improve log
17 |
18 | ## 1.5 - Burned
19 |
20 | ## 1.4 (2016-10-29)
21 |
22 | - [JENKINS-38465](https://issues.jenkins-ci.org/browse/JENKINS-38465) ECR
23 | Plugin now it is compatible with credential stored into folders
24 | - [JENKINS-36127](https://issues.jenkins-ci.org/browse/JENKINS-36127) Resolved
25 | a NPE when attempt to configure docker build and publish
26 | - [JENKINS-34958](https://issues.jenkins-ci.org/browse/JENKINS-34958) New
27 | credential format that contains the region. For example, by specifying the
28 | following credentials: ecr:us-west-2:credential-id, the provider will set the
29 | Region of the AWS Client to us-west-2, when requesting for Authorisation
30 | token.
31 |
32 | ## 1.3 (2016-06-06)
33 |
34 | - 1.2 Release failed to upload the artifact - so just release again to
35 | correctly upload the artifact.
36 |
37 | NOTE: This release doesn't contain any update.
38 |
39 | ## 1.2 (2016-06-03)
40 |
41 | - Update parent pom
42 |
43 | ## 1.1 (2016-05-30)
44 |
45 | - [JENKINS-35220](http://localhost:8085/display/JENKINS/Amazon+ECR#)
46 | Correctly display the credentials
47 |
48 | ## 1.0 (2016-01-12)
49 |
50 | - Replace custom ECR API client with aws-java-sdk
51 |
52 | ## 1.0-beta-1 (2015-12-22)
53 |
54 | - Initial release
55 |
--------------------------------------------------------------------------------
/src/main/java/com/cloudbees/jenkins/plugins/amazonecr/AmazonECSRegistryTokenSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015, CloudBees, Inc.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | *
24 | */
25 |
26 | package com.cloudbees.jenkins.plugins.amazonecr;
27 |
28 | import edu.umd.cs.findbugs.annotations.NonNull;
29 | import hudson.Extension;
30 | import hudson.util.Secret;
31 | import java.util.logging.Level;
32 | import java.util.logging.Logger;
33 | import jenkins.authentication.tokens.api.AuthenticationTokenException;
34 | import jenkins.authentication.tokens.api.AuthenticationTokenSource;
35 | import org.jenkinsci.plugins.docker.commons.credentials.DockerRegistryToken;
36 |
37 | @Extension
38 | public class AmazonECSRegistryTokenSource
39 | extends AuthenticationTokenSource {
40 |
41 | private static final Logger LOG = Logger.getLogger(AmazonECSRegistryTokenSource.class.getName());
42 |
43 | public AmazonECSRegistryTokenSource() {
44 | super(DockerRegistryToken.class, AmazonECSRegistryCredential.class);
45 | }
46 |
47 | @NonNull
48 | @Override
49 | public DockerRegistryToken convert(@NonNull AmazonECSRegistryCredential credential)
50 | throws AuthenticationTokenException {
51 | LOG.log(Level.FINE, "Converting credential to Docker registry token : {0}", credential.getCredentialsId());
52 | return new DockerRegistryToken(credential.getEmail(), Secret.toString(credential.getPassword()));
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/cloudbees/jenkins/plugins/amazonecr/AmazonECSRegistryCredentialsProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015, CloudBees, Inc.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | *
24 | */
25 |
26 | package com.cloudbees.jenkins.plugins.amazonecr;
27 |
28 | import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials;
29 | import com.cloudbees.plugins.credentials.Credentials;
30 | import com.cloudbees.plugins.credentials.CredentialsProvider;
31 | import com.cloudbees.plugins.credentials.domains.DomainRequirement;
32 | import edu.umd.cs.findbugs.annotations.NonNull;
33 | import edu.umd.cs.findbugs.annotations.Nullable;
34 | import hudson.Extension;
35 | import hudson.model.ItemGroup;
36 | import java.util.Collections;
37 | import java.util.LinkedList;
38 | import java.util.List;
39 | import java.util.logging.Level;
40 | import java.util.logging.Logger;
41 | import org.springframework.security.core.Authentication;
42 | import software.amazon.awssdk.regions.Region;
43 |
44 | /**
45 | * This class automatically wraps existing {@link AmazonWebServicesCredentials} instances into a
46 | * username password credential type that is compatible with Docker remote API client plugin.
47 | */
48 | @Extension
49 | public class AmazonECSRegistryCredentialsProvider extends CredentialsProvider {
50 |
51 | private static final Logger LOG = Logger.getLogger(AmazonECSRegistryCredentialsProvider.class.getName());
52 |
53 | @NonNull
54 | @Override
55 | public List getCredentialsInItemGroup(
56 | @NonNull Class type,
57 | @Nullable ItemGroup itemGroup,
58 | @Nullable Authentication authentication,
59 | @NonNull List domainRequirements) {
60 |
61 | if (!type.isAssignableFrom(AmazonECSRegistryCredential.class)) {
62 | return Collections.emptyList();
63 | }
64 |
65 | List derived = new LinkedList<>();
66 |
67 | final List list = lookupCredentialsInItemGroup(
68 | AmazonWebServicesCredentials.class, itemGroup, authentication, domainRequirements);
69 |
70 | for (AmazonWebServicesCredentials credentials : list) {
71 | LOG.log(
72 | Level.FINE,
73 | "Resolving Amazon Web Services credentials of scope {0} with id {1} , itemgroup {2}",
74 | new Object[] {credentials.getScope(), credentials.getId(), itemGroup});
75 | derived.add((C) new AmazonECSRegistryCredential(
76 | credentials.getScope(), credentials.getId(), credentials.getDescription(), itemGroup));
77 |
78 | for (Region region : Region.regions()) {
79 | LOG.log(
80 | Level.FINE,
81 | "Resolving Amazon Web Services credentials of scope {0} with id {1} and region {2}",
82 | new Object[] {credentials.getScope(), credentials.getId(), region});
83 | derived.add((C) new AmazonECSRegistryCredential(
84 | credentials.getScope(), credentials.getId(), region, credentials.getDescription(), itemGroup));
85 | }
86 | }
87 |
88 | return derived;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 |
7 | org.jenkins-ci.plugins
8 | plugin
9 | 5.22
10 |
11 |
12 | com.cloudbees.jenkins.plugins
13 | amazon-ecr
14 | ${revision}.${changelist}
15 | hpi
16 |
17 | Amazon ECR plugin
18 | Integrate Jenkins with Amazon EC2 Container Registry (ECR)
19 | https://github.com/jenkinsci/amazon-ecr-plugin
20 |
21 |
22 | MIT License
23 | http://opensource.org/licenses/MIT
24 |
25 |
26 |
27 |
28 |
29 | TobiX
30 | Tobias Gruetzmacher
31 | tobias-git@23.gs
32 |
33 | Maintainer
34 |
35 |
36 |
37 |
38 |
39 |
40 | Nicolas De Loof
41 |
42 | Maintainer (retired)
43 |
44 |
45 |
46 | Ivan Fernandez Calvo
47 |
48 | Maintainer (retired)
49 |
50 |
51 |
52 |
53 |
54 | scm:git:https://github.com/${gitHubRepo}.git
55 | scm:git:git@github.com:${gitHubRepo}.git
56 | ${scmTag}
57 | https://github.com/${gitHubRepo}
58 |
59 |
60 |
61 | 1
62 | 999999-SNAPSHOT
63 | jenkinsci/amazon-ecr-plugin
64 |
65 | 2.479
66 | ${jenkins.baseline}.3
67 | false
68 | false
69 |
70 |
71 |
72 |
73 |
74 | io.jenkins.tools.bom
75 | bom-${jenkins.baseline}.x
76 | 5054.v620b_5d2b_d5e6
77 | pom
78 | import
79 |
80 |
81 |
82 |
83 |
84 | io.jenkins.plugins.aws-java-sdk2
85 | aws-java-sdk2-ecr
86 |
87 |
88 | org.jenkins-ci.plugins
89 | aws-credentials
90 |
91 |
92 | org.jenkins-ci.plugins
93 | credentials
94 |
95 |
96 | org.jenkins-ci.plugins
97 | docker-commons
98 |
99 |
100 | org.jenkins-ci.plugins
101 | docker-workflow
102 | test
103 |
104 |
105 | org.jenkins-ci.plugins.workflow
106 | workflow-job
107 | test
108 |
109 |
110 |
111 |
112 |
113 | repo.jenkins-ci.org
114 | https://repo.jenkins-ci.org/public/
115 |
116 |
117 |
118 |
119 | repo.jenkins-ci.org
120 | https://repo.jenkins-ci.org/public/
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Amazon ECR Plugin
2 |
3 | [](https://plugins.jenkins.io/amazon-ecr)
4 | [](https://github.com/jenkinsci/amazon-ecr-plugin/releases/latest)
5 | [](https://plugins.jenkins.io/amazon-ecr)
6 | [](https://ci.jenkins.io/job/Plugins/job/amazon-ecr-plugin/job/main/)
7 | [](https://github.com/jenkinsci/amazon-ecr-plugin/blob/main/LICENSE.txt)
8 | 
9 |
10 | This plugin offers integration with [Amazon Container Registry
11 | (ECR)](https://aws.amazon.com/ecr/) as a [DockerRegistryToken] source to convert
12 | Amazon Credentials into a Docker CLI Authentication Token.
13 |
14 | [DockerRegistryToken]: https://github.com/jenkinsci/docker-commons-plugin/blob/master/src/main/java/org/jenkinsci/plugins/docker/commons/credentials/DockerRegistryToken.java
15 |
16 | ## About
17 |
18 | Amazon ECR plugin implements a Docker Token producer to convert Amazon
19 | credentials to Jenkins’ API used by (mostly) all Docker-related plugins.
20 |
21 | Thanks to this producer, you can select your existing registered Amazon
22 | credentials for various Docker operations in Jenkins, for example using the
23 | Docker Build and Publish plugin:
24 |
25 | 
26 |
27 | ## Installation
28 |
29 | Navigate to the "Plugin Manager" screen, install the "Amazon ECR" plugin and
30 | restart Jenkins.
31 |
32 | The plugin will use the proxy configured on Jenkins if it is set.
33 |
34 | Recommended logger for troubleshooting, you have to take care where you publish
35 | these logs could contain sensitive information
36 |
37 | - com.cloudbees.jenkins.plugins.amazonecr
38 | - com.amazonaws
39 | - org.apache.http.wire
40 | - org.jenkinsci.plugins.docker.workflow
41 |
42 | ## Docker Pipeline Usage
43 |
44 | When using the [Docker Pipeline
45 | Plugin](https://plugins.jenkins.io/docker-workflow/), in order to obtain an ECR
46 | login credential, you must use the ecr provider prefix.
47 |
48 | ```groovy
49 | docker.withRegistry("https://your.ecr.domain.amazonws.com", "ecr:us-east-1:credential-id") {
50 | docker.image("your-image-name").push()
51 | }
52 | ```
53 |
54 | If you experience authentication issues, you would try to remove user
55 | docker configuration files on the agents before to run the docker
56 | commands, something like this pipeline script.
57 |
58 | ```groovy
59 | node {
60 | // cleanup current user docker credentials
61 | sh 'rm -f ~/.dockercfg ~/.docker/config.json || true'
62 |
63 | // configure registry
64 | docker.withRegistry('https://ID.ecr.eu-west-1.amazonaws.com', 'ecr:eu-west-1:86c8f5ec-1ce1-4e94-80c2-18e23bbd724a') {
65 |
66 | // build image
67 | def customImage = docker.build("my-image:${env.BUILD_ID}")
68 |
69 | // push image
70 | customImage.push()
71 | }
72 | }
73 | ```
74 |
75 | ## Development
76 |
77 | ### Testing
78 |
79 | Unfortunately, testing against AWS isn't very straightforward, since you always
80 | need an AWS account with correct setup, which might incur some costs. Current
81 | tests try to make this as easy as possible. You need a user with read
82 | permission to ECR (AWS IAM policy `AmazonEC2ContainerRegistryReadOnly` should
83 | suffice) and an (empty) container registry. The test expect these details in
84 | the following environment variables:
85 |
86 | ```shell
87 | export AWS_ACCESS_KEY_ID=
88 | export AWS_SECRET_ACCESS_KEY=
89 | export AWS_REGISTRY_HOST=.dkr.ecr.us-east-1.amazonaws.com
90 | ```
91 |
92 | When those are set correctly, `mvn test` should run those tests successfully.
93 |
94 | ### Code Style
95 |
96 | This plugin uses [Google Java Code Style], which is enforced by the [spotless]
97 | plugin. If the build fails because you were using the "wrong" style, you can
98 | fix it by running:
99 |
100 | $ mvn spotless:apply
101 |
102 | to reformat code in the proper style.
103 |
104 | [Google Java Code Style]: https://google.github.io/styleguide/javaguide.html
105 | [spotless]: https://github.com/diffplug/spotless
106 |
--------------------------------------------------------------------------------
/src/main/java/com/cloudbees/jenkins/plugins/amazonecr/AmazonECSRegistryCredential.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015, CloudBees, Inc.
5 | * Copyright (c) 2021, TobiX
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | package com.cloudbees.jenkins.plugins.amazonecr;
28 |
29 | import com.amazonaws.regions.Regions;
30 | import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials;
31 | import com.cloudbees.plugins.credentials.CredentialsProvider;
32 | import com.cloudbees.plugins.credentials.CredentialsScope;
33 | import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
34 | import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
35 | import edu.umd.cs.findbugs.annotations.CheckForNull;
36 | import edu.umd.cs.findbugs.annotations.NonNull;
37 | import hudson.ProxyConfiguration;
38 | import hudson.model.ItemGroup;
39 | import hudson.security.ACL;
40 | import hudson.util.Secret;
41 | import java.net.URI;
42 | import java.util.List;
43 | import java.util.logging.Level;
44 | import java.util.logging.Logger;
45 | import java.util.regex.Pattern;
46 | import java.util.stream.Collectors;
47 | import jenkins.model.Jenkins;
48 | import org.apache.commons.lang.StringUtils;
49 | import software.amazon.awssdk.http.apache.ApacheHttpClient;
50 | import software.amazon.awssdk.regions.Region;
51 | import software.amazon.awssdk.services.ecr.EcrClient;
52 | import software.amazon.awssdk.services.ecr.model.AuthorizationData;
53 | import software.amazon.awssdk.services.ecr.model.GetAuthorizationTokenRequest;
54 | import software.amazon.awssdk.services.ecr.model.GetAuthorizationTokenResponse;
55 |
56 | /**
57 | * This new kind of credential provides an embedded {@link software.amazon.awssdk.auth.credentials.AwsCredentials} when a
58 | * credential for Amazon ECS Registry end point is needed.
59 | */
60 | public class AmazonECSRegistryCredential extends BaseStandardCredentials
61 | implements StandardUsernamePasswordCredentials {
62 | private static final Logger LOG = Logger.getLogger(AmazonECSRegistryCredential.class.getName());
63 |
64 | private final String credentialsId;
65 |
66 | private final String region;
67 |
68 | private final ItemGroup itemGroup;
69 |
70 | public AmazonECSRegistryCredential(
71 | CredentialsScope scope, @NonNull String credentialsId, String description, ItemGroup itemGroup) {
72 | this(scope, credentialsId, Region.US_EAST_1, description, itemGroup);
73 | }
74 |
75 | @Deprecated
76 | public AmazonECSRegistryCredential(
77 | @CheckForNull CredentialsScope scope,
78 | @NonNull String credentialsId,
79 | Regions region,
80 | String description,
81 | ItemGroup itemGroup) {
82 | this(scope, credentialsId, Region.of(region.getName()), description, itemGroup);
83 | }
84 |
85 | public AmazonECSRegistryCredential(
86 | @CheckForNull CredentialsScope scope,
87 | @NonNull String credentialsId,
88 | Region region,
89 | String description,
90 | ItemGroup itemGroup) {
91 | super(
92 | scope,
93 | "ecr:" + region.id() + ":" + credentialsId,
94 | "Amazon ECR Registry:"
95 | + (StringUtils.isNotBlank(description) ? description : credentialsId)
96 | + "-"
97 | + region);
98 | this.credentialsId = credentialsId;
99 | this.region = region.id();
100 | this.itemGroup = itemGroup;
101 | }
102 |
103 | @NonNull
104 | public String getCredentialsId() {
105 | return credentialsId;
106 | }
107 |
108 | public @CheckForNull AmazonWebServicesCredentials getCredentials() {
109 | LOG.log(Level.FINE, "Looking for Amazon web credentials ID: {0} Region: {1}", new Object[] {
110 | this.credentialsId, this.region
111 | });
112 | List credentials = CredentialsProvider.lookupCredentialsInItemGroup(
113 | AmazonWebServicesCredentials.class, itemGroup, ACL.SYSTEM2);
114 |
115 | if (LOG.isLoggable(Level.FINEST)) {
116 | String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(new Throwable());
117 | LOG.log(Level.FINEST, "Trace: {0}", fullStackTrace);
118 | }
119 |
120 | if (credentials.isEmpty()) {
121 | LOG.fine("ID not found");
122 | return null;
123 | }
124 |
125 | for (AmazonWebServicesCredentials awsCredentials : credentials) {
126 | if (awsCredentials.getId().equals(this.credentialsId)) {
127 | LOG.log(Level.FINE, "ID found {0}", this.credentialsId);
128 | return awsCredentials;
129 | }
130 | }
131 | LOG.fine("ID not found");
132 | return null;
133 | }
134 |
135 | @NonNull
136 | @Override
137 | public String getDescription() {
138 | String description = super.getDescription();
139 | LOG.finest(description);
140 | return description;
141 | }
142 |
143 | @NonNull
144 | @Override
145 | public Secret getPassword() {
146 | final AmazonWebServicesCredentials credentials = getCredentials();
147 | if (credentials == null) throw new IllegalStateException("Invalid credentials");
148 | LOG.log(Level.FINE, "Get password for {0} region : {1}", new Object[] {credentials.getDisplayName(), region});
149 | if (LOG.isLoggable(Level.ALL)) {
150 | String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(new Throwable());
151 | LOG.log(Level.ALL, "Trace: {0}", fullStackTrace);
152 | }
153 | ApacheHttpClient.Builder builder = ApacheHttpClient.builder();
154 | Jenkins instance = Jenkins.getInstanceOrNull();
155 | ProxyConfiguration proxy = instance != null ? instance.proxy : null;
156 | if (proxy != null) {
157 | software.amazon.awssdk.http.apache.ProxyConfiguration.Builder proxyConfiguration =
158 | software.amazon.awssdk.http.apache.ProxyConfiguration.builder()
159 | .endpoint(URI.create(String.format("http://%s:%s", proxy.name, proxy.port)));
160 | if (proxy.getUserName() != null) {
161 | proxyConfiguration.username(proxy.getUserName());
162 | proxyConfiguration.password(Secret.toString(proxy.getSecretPassword()));
163 | }
164 | List patterns = proxy.getNoProxyHostPatterns();
165 | if (patterns != null && !patterns.isEmpty()) {
166 | proxyConfiguration.nonProxyHosts(
167 | patterns.stream().map(Pattern::pattern).collect(Collectors.toSet()));
168 | }
169 | builder.proxyConfiguration(proxyConfiguration.build());
170 | }
171 |
172 | try (EcrClient client = EcrClient.builder()
173 | .httpClientBuilder(builder)
174 | .region(Region.of(region))
175 | .credentialsProvider(credentials)
176 | .build()) {
177 |
178 | GetAuthorizationTokenRequest request =
179 | GetAuthorizationTokenRequest.builder().build();
180 | final GetAuthorizationTokenResponse authorizationToken = client.getAuthorizationToken(request);
181 | final List authorizationData = authorizationToken.authorizationData();
182 | if (authorizationData == null || authorizationData.isEmpty()) {
183 | throw new IllegalStateException("Failed to retrieve authorization token for Amazon ECR");
184 | }
185 | LOG.fine("Success");
186 | if (LOG.isLoggable(Level.ALL)) {
187 | LOG.finest("Auth token: " + authorizationToken);
188 | LOG.finest("Request: " + request);
189 | }
190 | return Secret.fromString(authorizationData.get(0).authorizationToken());
191 | }
192 | }
193 |
194 | @NonNull
195 | @Override
196 | public String getUsername() {
197 | return "AWS";
198 | }
199 |
200 | @NonNull
201 | public String getEmail() {
202 | return "nobody@example.com";
203 | }
204 | }
205 |
--------------------------------------------------------------------------------