diff --git a/lib/modules/manager/helmfile/artifacts.ts b/lib/modules/manager/helmfile/artifacts.ts
index 87c0b6c229b103efe026ebcc1d71491d8d18dbc3..447fa645fe527ceae90e812dec905b6b785d1f7c 100644
--- a/lib/modules/manager/helmfile/artifacts.ts
+++ b/lib/modules/manager/helmfile/artifacts.ts
@@ -75,7 +75,7 @@ export async function updateArtifacts({
     const doc = parseDoc(newPackageFileContent);
 
     for (const value of coerceArray(doc.repositories).filter(isOCIRegistry)) {
-      const loginCmd = generateRegistryLoginCmd(
+      const loginCmd = await generateRegistryLoginCmd(
         value.name,
         `https://${value.url}`,
         // this extracts the hostname from url like format ghcr.ip/helm-charts
diff --git a/lib/modules/manager/helmfile/utils.ts b/lib/modules/manager/helmfile/utils.ts
index b8acb7cc114a90c7d6e9d871185e66abee5b7a71..76234764b876f85831f6ef467bb1060b9967265f 100644
--- a/lib/modules/manager/helmfile/utils.ts
+++ b/lib/modules/manager/helmfile/utils.ts
@@ -45,11 +45,11 @@ export function isOCIRegistry(repository: Repository): boolean {
   return repository.oci === true;
 }
 
-export function generateRegistryLoginCmd(
+export async function generateRegistryLoginCmd(
   repositoryName: string,
   repositoryBaseURL: string,
   repositoryHost: string
-): string | null {
+): Promise<string | null> {
   const repositoryRule: RepositoryRule = {
     name: repositoryName,
     repository: repositoryHost,
@@ -59,5 +59,5 @@ export function generateRegistryLoginCmd(
     }),
   };
 
-  return generateLoginCmd(repositoryRule, 'helm registry login');
+  return await generateLoginCmd(repositoryRule, 'helm registry login');
 }
diff --git a/lib/modules/manager/helmv3/__fixtures__/ChartECR.yaml b/lib/modules/manager/helmv3/__fixtures__/ChartECR.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..af9e279589476a6526b1fa140a9dde9cadff353c
--- /dev/null
+++ b/lib/modules/manager/helmv3/__fixtures__/ChartECR.yaml
@@ -0,0 +1,7 @@
+apiVersion: v2
+name: app
+version: 0.1.0
+dependencies:
+  - name: some-ecr-chart
+    version: 1.2.3
+    repository: oci://123456789.dkr.ecr.us-east-1.amazonaws.com
diff --git a/lib/modules/manager/helmv3/__fixtures__/oci_1_ecr.lock b/lib/modules/manager/helmv3/__fixtures__/oci_1_ecr.lock
new file mode 100644
index 0000000000000000000000000000000000000000..16f834c7eee325cc397f2dd4022e7a6e1d08daf4
--- /dev/null
+++ b/lib/modules/manager/helmv3/__fixtures__/oci_1_ecr.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: some-ecr-chart
+  repository: oci://123456789.dkr.ecr.us-east-1.amazonaws.com
+  version: 1.2.3
+digest: sha256:886f204516ea48785fe615d22071d742f7fb0d6519ed3cd274f4ec0978d8b82b
+generated: "2022-01-20T17:48:47.610371241+01:00"
diff --git a/lib/modules/manager/helmv3/__fixtures__/oci_2_ecr.lock b/lib/modules/manager/helmv3/__fixtures__/oci_2_ecr.lock
new file mode 100644
index 0000000000000000000000000000000000000000..623c5f993ec016874cd8396d8fb0a7ab6beb00d6
--- /dev/null
+++ b/lib/modules/manager/helmv3/__fixtures__/oci_2_ecr.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: some-ecr-chart
+  repository: oci://123456789.dkr.ecr.us-east-1.amazonaws.com
+  version: 1.3.4
+digest: sha256:886f204516ea48785fe615d22071d742f7fb0d6519ed3cd274f4ec0978d8b82b
+generated: "2022-01-20T17:48:47.610371241+01:00"
diff --git a/lib/modules/manager/helmv3/artifacts.spec.ts b/lib/modules/manager/helmv3/artifacts.spec.ts
index a0166b1a2ba6127b3066e2347325570ce8996a52..3029b358f35c65411944f8f13f9348f2f1142904 100644
--- a/lib/modules/manager/helmv3/artifacts.spec.ts
+++ b/lib/modules/manager/helmv3/artifacts.spec.ts
@@ -1,3 +1,9 @@
+import {
+  ECRClient,
+  GetAuthorizationTokenCommand,
+  GetAuthorizationTokenCommandOutput,
+} from '@aws-sdk/client-ecr';
+import { mockClient } from 'aws-sdk-client-mock';
 import { mockDeep } from 'jest-mock-extended';
 import { join } from 'upath';
 import { envMock, mockExecAll } from '../../../../test/exec-util';
@@ -8,6 +14,7 @@ import type { RepoGlobalConfig } from '../../../config/types';
 import * as docker from '../../../util/exec/docker';
 import type { StatusResult } from '../../../util/git/types';
 import * as hostRules from '../../../util/host-rules';
+import { toBase64 } from '../../../util/string';
 import * as _datasource from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import * as helmv3 from '.';
@@ -17,7 +24,6 @@ jest.mock('../../../util/exec/env');
 jest.mock('../../../util/http');
 jest.mock('../../../util/fs');
 jest.mock('../../../util/git');
-
 const datasource = mocked(_datasource);
 
 const adminConfig: RepoGlobalConfig = {
@@ -35,12 +41,29 @@ const ociLockFile1Alias = Fixtures.get('oci_1_alias.lock');
 const ociLockFile2Alias = Fixtures.get('oci_2_alias.lock');
 const chartFileAlias = Fixtures.get('ChartAlias.yaml');
 
+const ociLockFile1ECR = Fixtures.get('oci_1_ecr.lock');
+const ociLockFile2ECR = Fixtures.get('oci_2_ecr.lock');
+const chartFileECR = Fixtures.get('ChartECR.yaml');
+
+const ecrMock = mockClient(ECRClient);
+
+function mockEcrAuthResolve(
+  res: Partial<GetAuthorizationTokenCommandOutput> = {}
+) {
+  ecrMock.on(GetAuthorizationTokenCommand).resolvesOnce(res);
+}
+
+function mockEcrAuthReject(msg: string) {
+  ecrMock.on(GetAuthorizationTokenCommand).rejectsOnce(new Error(msg));
+}
+
 describe('modules/manager/helmv3/artifacts', () => {
   beforeEach(() => {
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
     GlobalConfig.set(adminConfig);
     docker.resetPrefetchedImages();
     hostRules.clear();
+    ecrMock.reset();
   });
 
   afterEach(() => {
@@ -723,6 +746,240 @@ describe('modules/manager/helmv3/artifacts', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
 
+  it('supports ECR authentication', async () => {
+    mockEcrAuthResolve({
+      authorizationData: [
+        { authorizationToken: toBase64('token-username:token-password') },
+      ],
+    });
+
+    hostRules.add({
+      username: 'some-username',
+      password: 'some-password',
+      token: 'some-session-token',
+      hostType: 'docker',
+      matchHost: '123456789.dkr.ecr.us-east-1.amazonaws.com',
+    });
+
+    fs.getSiblingFileName.mockReturnValueOnce('Chart.lock');
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile1ECR as never);
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile2ECR as never);
+    fs.privateCacheDir.mockReturnValue(
+      '/tmp/renovate/cache/__renovate-private-cache'
+    );
+    fs.getParentDir.mockReturnValue('');
+
+    expect(
+      await helmv3.updateArtifacts({
+        packageFileName: 'Chart.yaml',
+        updatedDeps: [],
+        newPackageFileContent: chartFileECR,
+        config: {
+          ...config,
+          updateType: 'lockFileMaintenance',
+          registryAliases: {},
+        },
+      })
+    ).toMatchObject([
+      {
+        file: {
+          type: 'addition',
+          path: 'Chart.lock',
+          contents: ociLockFile2ECR,
+        },
+      },
+    ]);
+
+    const ecr = ecrMock.call(0).thisValue as ECRClient;
+    expect(await ecr.config.region()).toBe('us-east-1');
+    expect(await ecr.config.credentials()).toEqual({
+      accessKeyId: 'some-username',
+      secretAccessKey: 'some-password',
+      sessionToken: 'some-session-token',
+    });
+
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'helm registry login --username token-username --password token-password 123456789.dkr.ecr.us-east-1.amazonaws.com',
+      },
+      {
+        cmd: "helm dependency update ''",
+      },
+    ]);
+  });
+
+  it("does not use ECR authentication when the host rule's username is AWS", async () => {
+    mockEcrAuthResolve({
+      authorizationData: [
+        { authorizationToken: toBase64('token-username:token-password') },
+      ],
+    });
+
+    hostRules.add({
+      username: 'AWS',
+      password: 'some-password',
+      token: 'some-session-token',
+      hostType: 'docker',
+      matchHost: '123456789.dkr.ecr.us-east-1.amazonaws.com',
+    });
+
+    fs.getSiblingFileName.mockReturnValueOnce('Chart.lock');
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile1ECR as never);
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile2ECR as never);
+    fs.privateCacheDir.mockReturnValue(
+      '/tmp/renovate/cache/__renovate-private-cache'
+    );
+    fs.getParentDir.mockReturnValue('');
+
+    expect(
+      await helmv3.updateArtifacts({
+        packageFileName: 'Chart.yaml',
+        updatedDeps: [],
+        newPackageFileContent: chartFileECR,
+        config: {
+          ...config,
+          updateType: 'lockFileMaintenance',
+          registryAliases: {},
+        },
+      })
+    ).toMatchObject([
+      {
+        file: {
+          type: 'addition',
+          path: 'Chart.lock',
+          contents: ociLockFile2ECR,
+        },
+      },
+    ]);
+
+    expect(ecrMock.calls).toHaveLength(0);
+
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'helm registry login --username AWS --password some-password 123456789.dkr.ecr.us-east-1.amazonaws.com',
+      },
+      {
+        cmd: "helm dependency update ''",
+      },
+    ]);
+  });
+
+  it('continues without auth if the ECR token is invalid', async () => {
+    mockEcrAuthResolve({
+      authorizationData: [{ authorizationToken: ':' }],
+    });
+
+    hostRules.add({
+      username: 'some-username',
+      password: 'some-password',
+      token: 'some-session-token',
+      hostType: 'docker',
+      matchHost: '123456789.dkr.ecr.us-east-1.amazonaws.com',
+    });
+
+    fs.getSiblingFileName.mockReturnValueOnce('Chart.lock');
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile1ECR as never);
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile2ECR as never);
+    fs.privateCacheDir.mockReturnValue(
+      '/tmp/renovate/cache/__renovate-private-cache'
+    );
+    fs.getParentDir.mockReturnValue('');
+
+    expect(
+      await helmv3.updateArtifacts({
+        packageFileName: 'Chart.yaml',
+        updatedDeps: [],
+        newPackageFileContent: chartFileECR,
+        config: {
+          ...config,
+          updateType: 'lockFileMaintenance',
+          registryAliases: {},
+        },
+      })
+    ).toMatchObject([
+      {
+        file: {
+          type: 'addition',
+          path: 'Chart.lock',
+          contents: ociLockFile2ECR,
+        },
+      },
+    ]);
+
+    const ecr = ecrMock.call(0).thisValue as ECRClient;
+    expect(await ecr.config.region()).toBe('us-east-1');
+    expect(await ecr.config.credentials()).toEqual({
+      accessKeyId: 'some-username',
+      secretAccessKey: 'some-password',
+      sessionToken: 'some-session-token',
+    });
+
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: "helm dependency update ''",
+      },
+    ]);
+  });
+
+  it('continues without auth if ECR authentication fails', async () => {
+    mockEcrAuthReject('some error');
+
+    hostRules.add({
+      username: 'some-username',
+      password: 'some-password',
+      token: 'some-session-token',
+      hostType: 'docker',
+      matchHost: '123456789.dkr.ecr.us-east-1.amazonaws.com',
+    });
+
+    fs.getSiblingFileName.mockReturnValueOnce('Chart.lock');
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile1ECR as never);
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce(ociLockFile2ECR as never);
+    fs.privateCacheDir.mockReturnValue(
+      '/tmp/renovate/cache/__renovate-private-cache'
+    );
+    fs.getParentDir.mockReturnValue('');
+
+    expect(
+      await helmv3.updateArtifacts({
+        packageFileName: 'Chart.yaml',
+        updatedDeps: [],
+        newPackageFileContent: chartFileECR,
+        config: {
+          ...config,
+          updateType: 'lockFileMaintenance',
+          registryAliases: {},
+        },
+      })
+    ).toMatchObject([
+      {
+        file: {
+          type: 'addition',
+          path: 'Chart.lock',
+          contents: ociLockFile2ECR,
+        },
+      },
+    ]);
+
+    const ecr = ecrMock.call(0).thisValue as ECRClient;
+    expect(await ecr.config.region()).toBe('us-east-1');
+    expect(await ecr.config.credentials()).toEqual({
+      accessKeyId: 'some-username',
+      secretAccessKey: 'some-password',
+      sessionToken: 'some-session-token',
+    });
+
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: "helm dependency update ''",
+      },
+    ]);
+  });
+
   it('alias name is picked, when repository is as alias and dependency defined', async () => {
     hostRules.add({
       username: 'basicUser',
diff --git a/lib/modules/manager/helmv3/artifacts.ts b/lib/modules/manager/helmv3/artifacts.ts
index a5d1538a832b489719b711e8f239c5383d34261d..16677538e5a5a552472b26aaca5cf1adf31fcb1d 100644
--- a/lib/modules/manager/helmv3/artifacts.ts
+++ b/lib/modules/manager/helmv3/artifacts.ts
@@ -1,5 +1,6 @@
 import is from '@sindresorhus/is';
 import yaml from 'js-yaml';
+import pMap from 'p-map';
 import { quote } from 'shlex';
 import { TEMPORARY_ERROR } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
@@ -46,8 +47,8 @@ async function helmCommands(
     });
 
   // if credentials for the registry have been found, log into it
-  registries.forEach((value) => {
-    const loginCmd = generateLoginCmd(value, 'helm registry login');
+  await pMap(registries, async (value) => {
+    const loginCmd = await generateLoginCmd(value, 'helm registry login');
     if (loginCmd) {
       cmd.push(loginCmd);
     }
diff --git a/lib/modules/manager/helmv3/common.ts b/lib/modules/manager/helmv3/common.ts
index d2c81669b4cb469ce13ca2ea7f50c6f586b0e0ce..50c61003216c0f81f1249a5fcc406bcddf2bdc59 100644
--- a/lib/modules/manager/helmv3/common.ts
+++ b/lib/modules/manager/helmv3/common.ts
@@ -1,19 +1,43 @@
 import { quote } from 'shlex';
 import upath from 'upath';
 
+import { logger } from '../../../logger';
+import { coerceArray } from '../../../util/array';
 import type { ExtraEnv } from '../../../util/exec/types';
 import { privateCacheDir } from '../../../util/fs';
+import { addSecretForSanitizing } from '../../../util/sanitize';
+import { fromBase64 } from '../../../util/string';
+import { ecrRegex, getECRAuthToken } from '../../datasource/docker/ecr';
 import type { RepositoryRule } from './types';
 
-export function generateLoginCmd(
+export async function generateLoginCmd(
   repositoryRule: RepositoryRule,
   loginCMD: string
-): string | null {
-  const { username, password } = repositoryRule.hostRule;
+): Promise<string | null> {
+  const { hostRule, repository } = repositoryRule;
+  const { username, password } = hostRule;
+  if (username !== 'AWS' && ecrRegex.test(repository)) {
+    logger.trace({ repository }, `Using ecr auth for Helm registry`);
+    const [, region] = coerceArray(ecrRegex.exec(repository));
+    const auth = await getECRAuthToken(region, hostRule);
+    if (!auth) {
+      return null;
+    }
+    const [username, password] = fromBase64(auth).split(':');
+    if (!username || !password) {
+      return null;
+    }
+    addSecretForSanitizing(username);
+    addSecretForSanitizing(password);
+    return `${loginCMD} --username ${quote(username)} --password ${quote(
+      password
+    )} ${repository}`;
+  }
   if (username && password) {
+    logger.trace({ repository }, `Using basic auth for Helm registry`);
     return `${loginCMD} --username ${quote(username)} --password ${quote(
       password
-    )} ${repositoryRule.repository}`;
+    )} ${repository}`;
   }
   return null;
 }