【问题标题】:Can't access S3 bucket from within Fargate container (Bad Request and unable to locate credentials)无法从 Fargate 容器中访问 S3 存储桶(错误请求并且无法找到凭据)
【发布时间】:2018-12-29 06:25:17
【问题描述】:

我创建了一个私有 s3 存储桶和一个 Fargate 集群,其中包含一个尝试使用 python 3boto3 从该存储桶读取的简单任务。我已经在 2 个不同的 docker 图像上尝试过这个,其中一个我从 boto 得到一个 ClientError,说 HeadObject Bad request (400),另一个我得到 NoCredentialsError: Unable to locate credentials

图像中唯一真正不同的是,一个说错误请求正在正常运行,另一个是我通过 ssh 手动运行到任务容器。所以我不确定为什么一张图片说“错误请求”而另一张图片说“无法找到凭据”。

我尝试了几种不同的 IAM 政策,包括 (terraform) 以下政策:

data "aws_iam_policy_document" "access_s3" {
  statement {
    effect    = "Allow"
    actions   = ["s3:ListBucket"]
    resources = ["arn:aws:s3:::bucket_name"]
  }

  statement {
    effect = "Allow"

    actions = [
      "s3:GetObject",
      "s3:GetObjectVersion",
      "s3:GetObjectTagging",
      "s3:GetObjectVersionTagging",
    ]

    resources = ["arn:aws:s3:::bucket_name/*"]
  }
}

第二次尝试:

data "aws_iam_policy_document" "access_s3" {
  statement {
    effect    = "Allow"
    actions   = ["s3:*"]
    resources = ["arn:aws:s3:::*"]
  }
}

我尝试的最后一个是内置策略:

resource "aws_iam_role_policy_attachment" "access_s3" {
  role       = "${aws_iam_role.ecstasks.name}"
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}

bucket的定义很简单:

resource "aws_s3_bucket" "bucket" {
  bucket = "${var.bucket_name}"
  acl    = "private"
  region = "${var.region}"
}

用于访问 s3 存储桶的代码:

try:
    s3 = boto3.client('s3')
    tags = s3.head_object(Bucket='bucket_name', Key='filename')
    print(tags['ResponseMetadata']['HTTPHeaders']['etag'])
except ClientError:
    traceback.print_exc()

无论我做什么,我都无法使用 boto3Fargate 容器任务中访问 AWS 资源。我可以在EC2 实例上使用boto3 访问相同的s3 存储桶,而无需提供任何类型的凭据,并且仅使用IAM 角色/策略。我究竟做错了什么?不能以同样的方式从 Fargate 容器访问 AWS 资源吗?

忘了提到我正在将 IAM 角色分配给任务定义执行策略和任务策略。

更新:事实证明,我遇到的 unable to find credentials 错误是一个红鲱鱼。我无法获得凭据的原因是因为我的直接 ssh 会话没有设置 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 环境变量。

AWS Fargate 将代表您注入一个名为 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 的环境变量,其中包含 boto 应用于获取 API 访问凭证的 URL。所以Bad request 错误是我实际得到的并且需要帮助解决的错误。我检查了容器内的环境变量,AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 值正在由 Fargate 设置。

【问题讨论】:

标签: python-3.x amazon-s3 boto3 amazon-iam aws-fargate


【解决方案1】:

我在这个问题上遇到了很多困难,并且经常将 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 错误地设置为 None,直到我添加了一个自定义任务角色除了到我当前的任务执行角色。

1) 任务执行角色负责访问 ECR 中的容器并授予运行任务本身的访问权限,而 2) 任务角色负责用于向其他授权 AWS 服务发出 API 请求的 docker 容器。

1) 对于我的任务执行角色,我使用 AmazonECSTaskExecutionRolePolicy 和以下 JSON;

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

2)我终于摆脱了NoCredentialsError: Unable to locate credentials,除了任务执行角色之外,还添加了一个任务角色,比如负责从某个bucket中读取;

{
    "Version": "2012-10-17",
    "Statement": [
           {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::bucket_name/*"
        }
    ]
}

总结;确保两者都有一个角色:1) executionRoleArn 可以运行任务,2) taskRoleArn 可以向任务定义中设置的授权 AWS 服务发出 API 请求.

【讨论】:

  • 我在 s3 存储桶的资源 arn 中缺少 /* :|
  • 就我而言,添加操作s3:* 会导致完全相同的错误:/
  • 这对我不起作用。请问您是在fargate模式还是ec2模式下运行任务?我正在考虑是否应该将相同的策略附加到运行容器的 ec2 实例上?
  • 我正在远程模式下运行任务@SKSKSKSK
【解决方案2】:

允许对您的容器实例角色进行 Amazon S3 只读访问

打开 IAM 控制台https://console.aws.amazon.com/iam/

在导航窗格中,选择角色。

选择要用于您的容器实例的 IAM 角色(该角色可能名为 ecsInstanceRole)。有关更多信息,请参阅 Amazon ECS 容器实例 IAM 角色。

在托管策略下,选择附加策略。

在附加策略页面上,对于过滤器,键入 S3 以缩小策略结果范围。

选中 AmazonS3ReadOnlyAccess 策略左侧的框,然后选择附加策略。

【讨论】:

    【解决方案3】:

    您应该需要一个 IAM 角色才能从您的 ecs-task 访问您的 S3 存储桶。

    resource "aws_iam_role" "AmazonS3ServiceForECSTask" {
      assume_role_policy = <<EOF
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": "sts:AssumeRole",
          "Principal": {
            "Service": [
              "ecs-tasks.amazonaws.com"
            ]
          },
          "Effect": "Allow",
          "Sid": ""
        }
      ]
    }
    EOF
    }
    
    data "aws_iam_policy_document" "bucket_policy" {
      statement {
        principals {
          type        = "AWS"
          identifiers = [aws_iam_role.AmazonS3ServiceForECSTask.arn]
        }
    
        actions = [
          "s3:ListBucket",
        ]
    
        resources = [
          "arn:aws:s3:::${var.your_bucket_name}",
        ]
      }
      statement {
        principals {
          type        = "AWS"
          identifiers = [aws_iam_role.AmazonS3ServiceForECSTask.arn]
        }
    
        actions = [
          "s3:GetObject",
        ]
    
        resources = [
          "arn:aws:s3:::${var.your_bucket_name}/*",
        ]
      }
    }
    

    您应该需要在任务定义的 task_role_arn 中添加您的 IAM 角色。

    resource "aws_ecs_task_definition" "_ecs_task_definition" {
      task_role_arn               = aws_iam_role.AmazonS3ServiceForECSTask.arn
      execution_role_arn          = aws_iam_role.ECS-TaskExecution.arn
      family                      = "${var.family}"
      network_mode                = var.network_mode[var.launch_type]
      requires_compatibilities    = var.requires_compatibilities
      cpu                         = var.task_cpu[terraform.workspace]
      memory                      = var.task_memory[terraform.workspace]
      container_definitions       = module.ecs-container-definition.json
    }
    

    ECS Fargate task not applying role

    【讨论】:

      【解决方案4】:

      Boto3 有一个凭证查找路径:https://boto3.readthedocs.io/en/latest/guide/configuration.html。当您使用 AWS 提供的映像创建 EC2 实例时,该实例会预安装 aws 命令和其他 AWS 凭证环境变量。然而,Fargate 只是一个容器。您需要手动将 AWS 凭证注入容器。一种快速的解决方案是将 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY 添加到 Fargate 容器。

      【讨论】:

      • 这是不正确的。使用 IAM 角色时,容器内部甚至容器外部都不需要 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY。我实际上已经找到了更多关于此的信息,需要更新我的问题。 Fargate 实例代表您在后台注入一个名为 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 的环境变量,然后 boto 使用该变量进行 AWS API 调用以确定 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY。因此,这些不是事先需要的,而是由 AWS SDK 和 Fargate 自动完成的
      • 并非如此,如果您想按任务隔离权限,则应使用 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI。但是,为了方便调试和更新,隔离应用程序的权限更有意义。对我来说,一种好方法是将给定 IAM 的密钥对存储在 KMS 中并在应用程序中获取它们。
      • 但是 Kms 也使用凭证来解密这些密钥
      猜你喜欢
      • 1970-01-01
      • 2020-05-05
      • 2012-06-22
      • 1970-01-01
      • 2018-05-05
      • 2018-09-27
      • 2020-05-20
      • 2017-08-17
      • 2023-02-19
      相关资源
      最近更新 更多