From 06349b9ac760082dd9ee86f0bb019b75411a7615 Mon Sep 17 00:00:00 2001
From: super-mcgin <103895120+super-mcgin@users.noreply.github.com>
Date: Sun, 7 Jul 2024 10:20:44 +0100
Subject: [PATCH] feat(datasource/docker): Enable additional authentication
 mechansim for private ECR repositories (#30053)

---
 docs/usage/docker.md                        | 23 ++++++++++++++++++
 lib/modules/datasource/docker/ecr.ts        | 10 +++++++-
 lib/modules/datasource/docker/index.spec.ts | 27 +++++++++++++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/docs/usage/docker.md b/docs/usage/docker.md
index 4044921c9c..43b0113102 100644
--- a/docs/usage/docker.md
+++ b/docs/usage/docker.md
@@ -237,6 +237,8 @@ module.exports = {
 
 #### AWS ECR (Amazon Web Services Elastic Container Registry)
 
+#### Using access key id & secret
+
 Renovate can authenticate with AWS ECR using AWS access key id & secret as the username & password, for example:
 
 ```json
@@ -254,6 +256,27 @@ Renovate can authenticate with AWS ECR using AWS access key id & secret as the u
 }
 ```
 
+##### Using `get-login-password`
+
+Renovate can also authenticate with AWS ECR using the output from the `aws ecr get-login-password` command as outlined in
+the [AWS documentation](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html#registry-auth-token).
+To make use of this authentication mechanism, specify the username as `AWS`:
+
+```json
+{
+  "hostRules": [
+    {
+      "hostType": "docker",
+      "matchHost": "12345612312.dkr.ecr.us-east-1.amazonaws.com",
+      "username": "AWS",
+      "encrypted": {
+        "password": "w...A"
+      }
+    }
+  ]
+}
+```
+
 #### Google Container Registry / Google Artifact Registry
 
 ##### Using Application Default Credentials / Workload Identity (Self-Hosted only)
diff --git a/lib/modules/datasource/docker/ecr.ts b/lib/modules/datasource/docker/ecr.ts
index f90a660849..4a2d1be216 100644
--- a/lib/modules/datasource/docker/ecr.ts
+++ b/lib/modules/datasource/docker/ecr.ts
@@ -16,7 +16,15 @@ export async function getECRAuthToken(
   opts: HostRule,
 ): Promise<string | null> {
   const config: ECRClientConfig = { region };
-  if (opts.username && opts.password) {
+  if (opts.username === `AWS` && opts.password) {
+    logger.trace(
+      `AWS user specified, encoding basic auth credentials for ECR registry`,
+    );
+    return Buffer.from(`AWS:${opts.password}`).toString('base64');
+  } else if (opts.username && opts.password) {
+    logger.trace(
+      `Using AWS accessKey to get Authorization token for ECR registry`,
+    );
     config.credentials = {
       accessKeyId: opts.username,
       secretAccessKey: opts.password,
diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts
index 52a8fef258..96e576aa07 100644
--- a/lib/modules/datasource/docker/index.spec.ts
+++ b/lib/modules/datasource/docker/index.spec.ts
@@ -358,6 +358,33 @@ describe('modules/datasource/docker/index', () => {
       expect(res).toBeNull();
     });
 
+    it('supports ECR authentication for private repositories', async () => {
+      httpMock
+        .scope(amazonUrl)
+        .get('/')
+        .reply(401, '', {
+          'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
+        })
+        .head('/node/manifests/some-tag')
+        .matchHeader('authorization', 'Basic QVdTOnNvbWUtcGFzc3dvcmQ=')
+        .reply(200, '', { 'docker-content-digest': 'some-digest' });
+
+      hostRules.find.mockReturnValue({
+        username: 'AWS',
+        password: 'some-password',
+      });
+
+      const res = await getDigest(
+        {
+          datasource: 'docker',
+          packageName: '123456789.dkr.ecr.us-east-1.amazonaws.com/node',
+        },
+        'some-tag',
+      );
+
+      expect(res).toBe('some-digest');
+    });
+
     it('supports Google ADC authentication for gcr', async () => {
       httpMock
         .scope(gcrUrl)
-- 
GitLab