↓Pular para o conteúdo principal
  1. blog/
ARTIGO TÉCNICO

Docker host usa uma conta AWS, mas a imagem está em outro ECR: diagnosticando pull cross-account

Como separar identidade AWS, permissão IAM, autenticação do registry e credential helper quando um Docker host precisa puxar imagens de outro ECR.

·6 minutos

Um docker pull em ECR pode falhar por vários motivos que parecem a mesma coisa quando a gente olha rápido.

O host tem AWS CLI configurado. sts get-caller-identity funciona. O repositório existe. A imagem existe.

Mesmo assim, o pull não fecha.

Em um caso real, havia ainda um detalhe que complicava a leitura: a identidade AWS padrão do host não era da mesma conta que armazenava algumas das imagens usadas naquele servidor.

Isso obrigou a separar quatro perguntas que normalmente ficam misturadas:

1
2
3
4
Quem o AWS CLI diz que eu sou?
Tenho permissão IAM no repositório?
Em qual registry o Docker está autenticado?
O Docker conseguiu salvar a credencial localmente?

Resolver ECR sem separar essas camadas vira tentativa e erro bem rápido.

Primeiro: descobrir quem o host realmente é na AWS #

Antes de renovar login ou mexer em policy:

1
aws sts get-caller-identity

Se existem profiles:

1
aws sts get-caller-identity --profile <perfil>

Essa resposta é a referência para a identidade usada pelo AWS CLI naquele comando.

Ela não prova que o Docker está autenticado no registry certo.

E também não prova que a identidade tem autorização no repositório da imagem.

Só responde a primeira pergunta.

O registry já entrega uma pista importante #

Uma imagem ECR tem um endereço parecido com:

1
<ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/<repository>:<tag>

O ACCOUNT_ID faz parte do hostname.

Então, se o host está operando normalmente com a conta A, mas o Compose aponta para:

1
conta-B.dkr.ecr.../api:latest

já existe um boundary cross-account que precisa ser entendido.

Isso não significa que a arquitetura está errada.

Um host pode perfeitamente consumir imagens de outra conta.

O que não pode é depender de um login implícito e ninguém lembrar dessa diferença meses depois.

Confirmar que repositório e tag realmente existem #

Do lado da conta que possui a imagem:

1
2
3
aws ecr describe-repositories \
  --region <regiao> \
  --repository-names <repositorio>

Depois:

1
2
3
aws ecr describe-images \
  --region <regiao> \
  --repository-name <repositorio>

No diagnóstico que originou esta pauta, essa verificação confirmou duas coisas:

  • o repositório existia;
  • havia uma imagem com a tag esperada.

Isso eliminou a hipótese de “o Compose aponta para uma imagem que nunca foi publicada”.

Depois veio a camada IAM #

A identidade usada no host não tinha todas as ações necessárias naquele repositório específico.

Entre as permissões que faltavam estavam operações de leitura como:

1
2
ecr:DescribeRepositories
ecr:BatchGetImage

Para pull, o conjunto normalmente envolve também ações como:

1
2
3
ecr:GetAuthorizationToken
ecr:BatchCheckLayerAvailability
ecr:GetDownloadUrlForLayer

O ponto não é decorar a lista.

É entender que aws ecr get-login-password funcionar não significa que o usuário tem direito de baixar qualquer imagem de qualquer repositório.

O token de autenticação e a autorização sobre o recurso são partes diferentes.

Política pequena é melhor que abrir o ECR inteiro #

Quando o problema é um repositório específico, a correção não precisa virar uma policy genérica para todos os registries.

Um desenho mais controlado é:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:DescribeRepositories",
        "ecr:DescribeImages",
        "ecr:ListImages",
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ],
      "Resource": "arn:aws:ecr:<region>:<account>:repository/<repo>"
    }
  ]
}

Se o host também precisa fazer push, as ações de upload entram deliberadamente.

Se só precisa puxar, não há motivo para dar escrita por conveniência.

Aí apareceu outro erro — e ele não era IAM #

Depois da parte AWS, o docker login ainda podia falhar com algo como:

1
Error saving credentials: error storing credentials - err: exit status 1, out: `not implemented`

Esse erro é de outra camada.

O token pode ter sido obtido corretamente e a policy pode estar certa, mas o Docker não consegue persistir a credencial usando o helper configurado naquele host.

Misturar esse erro com IAM leva a ficar alterando policy quando o problema já mudou de lugar.

DOCKER_CONFIG isolado resolveu sem mexer no login global #

Para testar o registry específico sem alterar a configuração Docker usada pelas outras aplicações do host, a abordagem foi criar um config temporário:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
export REGION="<region>"
export REGISTRY="<account>.dkr.ecr.<region>.amazonaws.com"
export IMAGE="${REGISTRY}/<repo>:latest"

mkdir -p /tmp/docker-ecr-test
printf '{}\n' > /tmp/docker-ecr-test/config.json

aws ecr get-login-password --region "$REGION" \
  | DOCKER_CONFIG=/tmp/docker-ecr-test docker login \
      --username AWS \
      --password-stdin "$REGISTRY"

DOCKER_CONFIG=/tmp/docker-ecr-test docker pull "$IMAGE"

Isso tem duas vantagens importantes.

Primeiro, evita sobrescrever ou depender do ~/.docker/config.json global do usuário.

Segundo, transforma o teste em algo reproduzível: sabemos exatamente qual registry foi autenticado e qual configuração Docker foi usada naquele pull.

AWS CLI e Docker não compartilham estado do jeito que parece #

Esse caso reforçou uma distinção que vale guardar:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
AWS profile/credencial
        ↓
aws ecr get-login-password
        ↓
token para um registry
        ↓
docker login
        ↓
configuração de credenciais do Docker
        ↓
docker pull

Uma etapa pode funcionar e a próxima falhar.

Por isso comandos como estes respondem perguntas diferentes:

1
2
3
4
5
aws sts get-caller-identity
aws ecr describe-images ...
aws ecr get-login-password ...
docker login ...
docker pull ...

Não vale tratar tudo como “autenticação AWS”.

Cross-account precisa virar parte do inventário do host #

Na migração em que esse cenário apareceu, alguns Docker hosts tinham uma conta AWS padrão, mas executavam imagens guardadas em outro ECR.

Isso funciona, mas precisa ser explícito na documentação operacional.

Eu registraria no mínimo:

1
2
3
4
5
6
7
host
AWS default
registries externos usados
como o login é renovado
qual identidade tem acesso
quais repositórios estão autorizados
se existe cron/script de ECR login

Senão, na próxima troca de usuário ou rotação de credencial, o container atual continua rodando e ninguém percebe que o pull da próxima versão já está quebrado.

Checklist rápido para ECR que não faz pull #

Quando o Docker host não consegue baixar uma imagem ECR:

  1. rode aws sts get-caller-identity;
  2. leia o account ID do próprio hostname do registry;
  3. confirme região;
  4. confirme que repositório existe;
  5. confirme que a tag/digest existe;
  6. valide a policy da identidade usada;
  7. gere login explicitamente para o registry correto;
  8. teste com DOCKER_CONFIG isolado se houver dúvida sobre credential helper;
  9. faça o docker pull fora do Compose primeiro;
  10. só depois investigue o serviço/container.

O principal aprendizado #

O erro de ECR raramente é só “Docker não autenticou”.

Nesse caso havia, no mínimo, três fronteiras relevantes:

  • identidade AWS;
  • autorização IAM sobre o repositório;
  • armazenamento local da credencial Docker.

E o ambiente ainda tinha a complexidade adicional de usar imagens de uma conta diferente da conta AWS padrão do host.

Quando cada camada foi testada separadamente, o problema deixou de parecer aleatório.

Antes de renovar login pela décima vez, descubra quem está autenticando, em qual registry e com qual permissão.

TEM UM CENÁRIO PARECIDO?

Me chama.

Manda o contexto, os sintomas e o que já foi testado. Bora organizar as evidências antes de sair mexendo.

Falar com Castro →
Sem enrolação. Com evidência.