繁体   English   中英

无法从 Fargate 容器内访问 S3 存储桶(错误请求且无法找到凭据)

[英]Can't access S3 bucket from within Fargate container (Bad Request and unable to locate credentials)

我使用一个简单的任务创建了一个私有 s3 存储桶和一个 fargate 集群,该任务尝试使用python 3boto3从该存储桶中读取数据。 我已经在 2 个不同的 docker 图像上尝试过这个,在一个图像上我从 boto 得到一个ClientErrorHeadObject 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"
}

桶定义非常简单:

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 session 没有设置AWS_CONTAINER_CREDENTIALS_RELATIVE_URI环境变量。

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

我在这个问题上苦苦挣扎,并不断将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当我在任务执行角色之外添加了一个任务角色时,例如负责从某个bucket中读取;

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

总之; 确保两者都有一个角色,用于1) executionRoleArn用于访问以运行任务和2) taskRoleArn用于访问以向任务定义中设置的授权 AWS 服务发出 API 请求。

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

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

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

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

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

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

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

您应该需要一个 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 任务未应用角色

经过无数小时的挖掘这个参数终于为我解决了这个问题:

ecs服务上的 a.network_configuration 块内的auto_assign_public_ip = true

事实证明,这些服务运行的我的任务没有分配 IP,因此与外界没有联系。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM