3
respostas

Task não está conseguindo obter a imagem do ECR

Tentei pelo NAT gateway conforme o curso, porém sem sucesso. Verifiquei que atualmente a AWS está utilizando o VPC endpoint com ECR. Modifiquei os códigos e ainda não está conseguindo obter a imagem.

Task stopped at: 2024-02-24T10:15:59.264Z CannotPullContainerError: ref pull has been retried 5 time(s): failed to copy: httpReadSeeker: failed open: failed to do request: Get xxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/production:V1: dial tcp 52.92.163.10:443: i/o timeout

VPC.tf:

module "vpc" {
....... 
}

# Create a VPC endpoint for ECR in the private subnet
resource "aws_vpc_endpoint" "ecr_dkr_endpoint" {
  depends_on  = [aws_ecr_repository.ecr_repository]
  service_name = "com.amazonaws.${var.aws_region}.ecr.dkr"
  vpc_id = module.vpc.vpc_id
  vpc_endpoint_type = "Interface"
  private_dns_enabled = true

  subnet_ids = module.vpc.private_subnets
  security_group_ids = [aws_security_group.vpc_endpoint_service.id, aws_security_group.privatenet.id]
}

resource "aws_vpc_endpoint" "ecr_api_endpoint" {
  depends_on  = [aws_ecr_repository.ecr_repository]
  service_name = "com.amazonaws.${var.aws_region}.ecr.api"
  vpc_id = module.vpc.vpc_id
  vpc_endpoint_type = "Interface"
  private_dns_enabled = true

  subnet_ids = module.vpc.private_subnets
  security_group_ids = [aws_security_group.vpc_endpoint_service.id, aws_security_group.privatenet.id]
}

resource "aws_vpc_endpoint" "s3" {
  depends_on  = [aws_ecr_repository.ecr_repository]
  vpc_id       = module.vpc.vpc_id
  service_name = "com.amazonaws.${var.aws_region}.s3"
}

Estou com a impressão de que é alguma falha nos grupos de segurança.

# Public Subnet security group (ALB)
resource "aws_security_group" "alb" {
  name        = "alb_ECS"
  description = "Application Load Balancer - Public"
  vpc_id      = module.vpc.vpc_id
}

resource "aws_security_group_rule" "ingress_alb" {
  type              = "ingress"
  from_port         = 8000 # Ports allowed to access the ALB
  to_port           = 8000
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"] # 0.0.0.0  - 255.255.255.255
  # ipv6_cidr_blocks  = [aws_vpc.example.ipv6_cidr_block]
  security_group_id = aws_security_group.alb.id # The ID of the security group to authorize access to.
}
resource "aws_security_group_rule" "egress_alb" {
  type              = "egress"
  from_port         = 0 # Ports allowed to respond
  to_port           = 0
  protocol          = "-1" # All protocols
  cidr_blocks       = ["0.0.0.0/0"] # 0.0.0.0  - 255.255.255.255
  # ipv6_cidr_blocks  = [aws_vpc.example.ipv6_cidr_block]
  security_group_id = aws_security_group.alb.id # The ID of the security group to authorize access to.
}

# Private Subnet security group
resource "aws_security_group" "privatenet" {
  name        = "private_ECS"
  description = "To access the Private subnet"
  vpc_id      = module.vpc.vpc_id

  # tags = {
  #   Name = "alb"
  # }
}
resource "aws_security_group_rule" "ingress_ECS" {
  type              = "ingress"
  from_port         = 0 # Ports allowed to access the Private subnet
  to_port           = 0
  protocol          = "-1"
  source_security_group_id = aws_security_group.alb.id # Ingress only from the ALB Security Group
  security_group_id = aws_security_group.privatenet.id # The ID of the security group to authorize access to.
}
resource "aws_security_group_rule" "egress_ECS" {
  type              = "egress"
  from_port         = 0 # Ports allowed to respond
  to_port           = 0
  protocol          = "-1" # All protocols
  source_security_group_id = aws_security_group.alb.id # Egress only to the ALB Security Group
  # ipv6_cidr_blocks  = [aws_vpc.example.ipv6_cidr_block]
  security_group_id = aws_security_group.privatenet.id # The ID of the security group to authorize access to.
}


# Private VPC endpoint security group
resource "aws_security_group" "vpc_endpoint_service" {
  name        = "private_VPC_endpoint"
  description = "To access the Private subnet"
  vpc_id      = module.vpc.vpc_id
}

# Allow traffic to and from the ECR endpoint

resource "aws_security_group_rule" "ingress_ECR" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  # self = true
  # cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  cidr_blocks = ["0.0.0.0/0"]
  # prefix_list_ids = [data.aws_prefix_list.ecr_api_endpoint.id, data.aws_prefix_list.ecr_dkr_endpoint.id]
  security_group_id = aws_security_group.vpc_endpoint_service.id
}

resource "aws_security_group_rule" "egress_ECR" {
  type              = "egress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  # self = true # not necessary if cidr_blocks       = ["0.0.0.0/0"]
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.vpc_endpoint_service.id
}
3 respostas

Oii, Daniel, tudo bem?

É bem comum os erros de timeout estarem ligados aos Security Groups, sim, como você pontuou.

O erro "CannotPullContainerError" geralmente indica que o ECS não conseguiu comunicar com o ECR. Algumas regras criadas podem ter sido muito restritivas, e por isso o erro aparece. Você pode reformular o código e deixar apenas algumas permissões? Assim só as necessárias estariam no código.

Por exemplo, o tráfego de entrada:

resource "aws_security_group_rule" "ingress_ECR" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.vpc_endpoint_service.id
  source_security_group_id = aws_security_group.alb.id
}

(Sem liberar o acesso pros IPs como geral)

E o de saída:

resource "aws_security_group_rule" "egress_ECR" {
  type              = "egress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.vpc_endpoint_service.id
  prefix_list_ids   = [data.aws_prefix_list.ecr_dkr.id, data.aws_prefix_list.s3.id]
}

Com apenas o ECS e o S3 estariam com permissão para acessar o ECR.

Caso ainda não funcione, você poderia verificar se a função no IAM associada ao ECS tem permissão para acessar o ECR.

Se a dúvida persistir, estamos aqui.

Abraços!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Muito obrigado pela ajuda. Eu ainda não testei, mas assim que conseguir testar, irei dar o feedback.

Sobre permissões, é preciso dar alguma permissão para usar o S3? Conforme o curso, o código está assim:

resource "aws_iam_role" "environment_role" {
  name = "${var.IAMRole}_role" # Note: also initialize the IAMRole variable at variables.tf file to make it work.

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = ["ec2.amazonaws.com",
                    "ecs-tasks.amazonaws.com"]
        }
      },
    ]
  })

  # tags = {
  #   tag-key = "tag-value"
  # }
}

resource "aws_iam_role_policy" "ecs_ecr" {
  name = "ecs_ecr"
  role = aws_iam_role.environment_role.id

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ecr:GetAuthorizationToken", # For ECR authentication
          "ecr:BatchCheckLayerAvailability", # Check layer availability of docker images
          "ecr:GetDownloadUrlForLayer", # Get url of docker image to download and utilize it
          "ecr:BatchGetImage", # Get image
          "logs:CreateLogStream", # Create logs
          "logs:PutLogEvents", # Create log events
        ]
        Effect   = "Allow"
        Resource = "*"
      #   "Resource": [
      #   "arn:aws:ecr:<region>:<account_id>:repository/<repository_name>", # Specific ECR repository pattern
      #   "arn:aws:logs:<region>:<account_id>:log-group:/ecs/<cluster_name>/*" # Specific log group pattern
      # ]
      },
    ]
  })
}

resource "aws_iam_instance_profile" "profile" {
  name = "${var.IAMRole}_profile"
  role = aws_iam_role.environment_role.name
}

Disponha, Daniel!

O código do S3 parece certinho, ele definiu um acesso pro IAM com as funções para o EC2 e o ECR, além de criar também logs com o ECR.

Pode prosseguir com ele. Se ainda der algum bug, é só retornar.

Abraços!