无法从Fargate容器内访问S3存储桶(出现"Bad Request"和无法定位凭证的错误)

26

我创建了一个私有的s3存储桶和一个fargate集群,其中包含一个简单的任务,试图使用 python 3boto3 从该存储桶中读取数据。我在两个不同的docker镜像上尝试了这个任务,在其中一个镜像上,boto返回ClientError,提示HeadObject Bad request (400),而在另一个镜像上,则返回NoCredentialsError: Unable to locate credentials

这两个镜像唯一真正的区别是,一个报告错误的镜像是正常运行的,而另一个是通过ssh手动运行到任务容器中。因此,我不确定为什么一个镜像会显示“bad request”,而另一个则是“unable to locate credentials”。

我已经尝试了几个不同的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"
}
桶的定义非常简单:
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()
无论我做什么,我都无法在Fargate容器任务中使用boto3来访问AWS资源。我能够在EC2实例上使用boto3访问同一个S3存储桶,而不需要提供任何凭证,只使用IAM角色/策略即可。我做错了什么?从Fargate容器以相同的方式访问AWS资源是否不可能?
忘记提到我正在将IAM角色分配给任务定义执行策略和任务策略。
更新:事实证明,我所遇到的“找不到凭证”错误是一个误导。我无法获得凭证的原因是我的直接ssh会话没有设置AWS_CONTAINER_CREDENTIALS_RELATIVE_URI环境变量。
AWS Fargate将代表您注入名为AWS_CONTAINER_CREDENTIALS_RELATIVE_URI的环境变量,其中包含boto用于获取API访问凭证的URL。因此,我实际上遇到并需要帮助解决的是“Bad request”错误。我检查了容器内的环境变量,并且Fargate已经设置了AWS_CONTAINER_CREDENTIALS_RELATIVE_URI值。

我遇到了一个类似的问题:https://dev59.com/Xbroa4cB1Zd3GeqPjmeP 。我该如何在容器内设置环境变量? - wawawa
5个回答

26

在此问题上我遇到了不少困难,经常发现AWS_CONTAINER_CREDENTIALS_RELATIVE_URI被错误地设置为None,直到我除了当前的任务执行角色之外,另外添加了一个自定义任务角色。

1) 任务执行角色负责访问ECR中的容器并授权运行任务,而2) 任务角色负责您的Docker容器向其他授权的AWS服务发出API请求。

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

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

简而言之,请确保在任务定义中同时为1)executionRoleArn(用于访问运行任务)和2)taskRoleArn(用于访问在任务定义中设置的授权AWS服务以进行API请求)分配角色。


我在S3存储桶的资源ARN中漏掉了/* :| - Jordan Stewart
在我的情况下,添加“s3:*”操作会导致完全相同的错误 :/ - Tomás Denis Reyes Sánchez
对我来说它没有起作用。请问您是在Fargate模式还是EC2模式下运行任务?我正在考虑是否将同一策略附加到容器运行的EC2实例上? - SKSKSKSK
我正在以Fargate模式运行任务@SKSKSKSK。 - NorahKSakal
看起来AWS现在已经撰写了一份指南:https://aws.amazon.com/premiumsupport/knowledge-center/ecs-fargate-access-aws-services/ - Mike Averto

1

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

打开IAM控制台,网址为https://console.aws.amazon.com/iam/

在导航面板中,选择“角色”。

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

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

在“附加策略”页面上,对于筛选器,请键入S3以缩小策略结果。

选择AmazonS3ReadOnlyAccess策略左侧的框,并选择“附加策略”。


1
经过数小时的搜寻,我终于找到了解决此问题的参数:auto_assign_public_ip = true。需要在 ecs service 的 network_configuration 块中设置。
原来这些服务运行的任务没有被分配 IP,因此无法连接到外部世界。

1
那就是我的问题,谢谢! - Toseef Zafar

1
您需要一个 IAM 角色才能从 ECS 任务访问您的 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任务未应用角色


-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容器中。

8
这不正确。当使用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自动完成。 - vane
不是很准确,如果您想按任务隔离权限,应该使用AWS_CONTAINER_CREDENTIALS_RELATIVE_URI。然而,为了方便调试和更新,按应用程序隔离权限更有意义。对我来说,一个好的方法是将给定IAM的密钥对存储在KMS中,并在应用程序内获取它们。 - Paul
但是 KMS 也使用凭据来解密那些密钥。 - Rajesh Kumar Dash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接