Terraform ELB S3权限问题

27

我在使用 Terraform(v0.9.2)向 ELB 添加服务时遇到了问题(我正在使用:https://github.com/segmentio/stack/blob/master/s3-logs/main.tf)。

当我运行 terraform apply 时,出现以下错误:

* module.solr.module.elb.aws_elb.main: 1 error(s) occurred:

* aws_elb.main: Failure configuring ELB attributes: 
    InvalidConfigurationRequest: Access Denied for bucket: my-service-
    logs. Please check S3bucket permission
    status code: 409, request id: xxxxxxxxxx-xxxx-xxxx-xxxxxxxxx

我的服务看起来像这样:

module "solr" {
  source = "github.com/segmentio/stack/service"
  name = "${var.prefix}-${terraform.env}-solr"
  environment = "${terraform.env}"
  image = "123456789876.dkr.ecr.eu-west-2.amazonaws.com/my-docker-image"
  subnet_ids = "${element(split(",", module.vpc_subnets.private_subnets_id), 3)}"
  security_groups = "${module.security.apache_solr_group}"
  port = "8983"
  cluster = "${module.ecs-cluster.name}"
  log_bucket = "${module.s3_logs.id}"

  iam_role = "${aws_iam_instance_profile.ecs.id}"
  dns_name = ""
  zone_id = "${var.route53_zone_id}"
}

我的s3-logs存储桶看起来像这样:

module "s3_logs" {
  source = "github.com/segmentio/stack/s3-logs"
  name = "${var.prefix}"
  environment = "${terraform.env}"
  account_id = "123456789876"
}

我在S3中检查了一下,存储桶策略看起来是这样的:

{
  "Version": "2012-10-17",
  "Id": "log-bucket-policy",
  "Statement": [
  {
  "Sid": "log-bucket-policy",
  "Effect": "Allow",
  "Principal": {
  "AWS": "arn:aws:iam::123456789876:root"
  },
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::my-service-logs/*"
  }
  ]
}
就我所知,ELB需要访问S3存储桶以存储日志(它正在同一个AWS账户中运行)。
存储桶和ELB都在eu-west-2区域。
如有任何问题,请不吝赐教。
6个回答

44

ELB访问日志的文档指出,您希望允许特定的Amazon账户能够写入S3,而不是您自己的账户。

因此,您需要这样做:

{
  "Id": "Policy1429136655940",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1429136633762",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::my-loadbalancer-logs/my-app/AWSLogs/123456789012/*",
      "Principal": {
        "AWS": [
          "652711504416"
        ]
      }
    }
  ]
}
在Terraform中,您可以使用aws_elb_service_account数据源自动获取用于编写日志的帐户ID,正如文档中的示例所示。
data "aws_elb_service_account" "main" {}

resource "aws_s3_bucket" "elb_logs" {
  bucket = "my-elb-tf-test-bucket"
  acl    = "private"

  policy = <<POLICY
{
  "Id": "Policy",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::my-elb-tf-test-bucket/AWSLogs/*",
      "Principal": {
        "AWS": [
          "${data.aws_elb_service_account.main.arn}"
        ]
      }
    }
  ]
}
POLICY
}

resource "aws_elb" "bar" {
  name               = "my-foobar-terraform-elb"
  availability_zones = ["us-west-2a"]

  access_logs {
    bucket   = "${aws_s3_bucket.elb_logs.bucket}"
    interval = 5
  }

  listener {
    instance_port     = 8000
    instance_protocol = "http"
    lb_port           = 80
    lb_protocol       = "http"
  }
}

1
将策略中的“Resource”正确设置是解决我的问题的关键。文档要求类似于"arn:aws:s3:::my-loadbalancer-logs/my-app/AWSLogs/123456789012/*"这样的内容。在末尾省略帐户ID可以解决问题(例如"arn:aws:s3:::my-loadbalancer-logs/my-app/AWSLogs/*")。 - Thismatters
帮了我很大的忙!谢谢分享 :) - learner
很遗憾,这个答案已经过时了,因为它不能与AWS应用程序或网络负载均衡器一起使用,data.aws_elb_service_account.main.arn仅是经典负载均衡器的一部分,并且已经被弃用。 - SebastianG

7

即使按照文档的指示操作,我仍然不断收到“访问存储桶被拒绝”的错误提示。将存储桶的加密功能移除后,问题得以解决。


谢谢,这解决了我的问题。你找到修改策略的方法了吗,这样就不必要了吗? - IanB
不,我停止尝试了,因为这对我的情况并不关键。如果有人找到了使其工作的方法,我很想听听。 - hernvnc
也为我解决了这个问题。文档中没有提到这可能是一个问题。关闭加密会与CIS AWS基准产生冲突。 - Pablo

6
在存储桶策略中,账户号码不应该是你的,而应该是AWS的。对于每个区域,你应该在你的存储桶策略中使用列在下面的账户号码:https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-access-logs.html#attach-bucket-policy 例如,对于us-east-1 区域,账户号码是127311923021
虽然这个问题是关于Terraform的,但我发布了一个CloudFormation片段,为ELB的访问日志创建了一个存储桶策略:
    MyAccessLogsBucket:
        Type: AWS::S3::Bucket
        DeletionPolicy: Retain


    MyAllowELBAccessBucketPolicy:
        Type: AWS::S3::BucketPolicy
        Properties: 
            Bucket: !Ref MyAccessLogsBucket
            PolicyDocument: 
                Version: "2012-10-17"
                Statement: 
                    - Effect: "Allow"
                      Principal: 
                          AWS: "arn:aws:iam::127311923021:root"
                      Action: 
                          - "s3:PutObject"
                      Resource: !Sub "arn:aws:s3:::${MyAccessLogsBucket}/AWSLogs/*"

在原则上,127311923021 被用作 AWS 帐户号。这也是适用于 us-east-1 的帐户号。


4

存储桶权限

当启用访问日志记录时,必须指定一个S3存储桶用于存储访问日志。该存储桶必须符合以下要求。

要求:

  • 存储桶必须位于与负载均衡器相同的区域。
  • 需使用Amazon S3托管的加密密钥(SSE-S3),不支持其他加密选项。
  • 存储桶必须有一项“存储桶策略”,授予Elastic Load Balancing将访问日志写入您的存储桶的权限。存储桶策略是一组JSON语句,编写在访问策略语言中,以定义存储桶的访问权限。每个语句包含关于单个权限的信息,并包含一系列元素。

请使用以下其中一个选项准备S3存储桶以进行访问日志记录。

必须使用Amazon S3托管的加密密钥(SSE-S3),不支持其他加密选项。

因此,AWS文档指出不支持KMS...


2

这是一个完整的工作示例。

data "aws_caller_identity" "current" {}
data "aws_elb_service_account" "elb_account_id" {}

resource "aws_s3_bucket" "lb_logs" {
  bucket = "${local.name}-loadbalancer-logs"
}

resource "aws_s3_bucket_policy" "lb_logs" {
  bucket = aws_s3_bucket.lb_logs.id
  policy = data.aws_iam_policy_document.allow_lb.json
}

data "aws_iam_policy_document" "allow_lb" {
  statement {
    effect = "Allow"
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.lb_logs.bucket}/AWSLogs/${data.aws_caller_identity.current.account_id}/*",
    ]
    actions = ["s3:PutObject"]
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_elb_service_account.elb_account_id.id}:root"]
    }
  }

  statement {
    effect = "Allow"
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.lb_logs.bucket}/AWSLogs/${data.aws_caller_identity.current.account_id}/*",
    ]
    actions = ["s3:PutObject"]
    principals {
      type        = "Service"
      identifiers = ["delivery.logs.amazonaws.com"]
    }
    condition {
      test     = "StringEquals"
      variable = "s3:x-amz-acl"
      values   = ["bucket-owner-full-control"]
    }
  }

  statement {
    effect = "Allow"
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.lb_logs.bucket}",
    ]
    actions = ["s3:GetBucketAcl"]
    principals {
      type        = "Service"
      identifiers = ["delivery.logs.amazonaws.com"]
    }
  }
}

resource "aws_alb" "lb" {
  name               = "${local.name}-lb"
  load_balancer_type = "application"
  subnets            = var.subnet_ids
  security_groups    = [
    aws_security_group.lb.id
  ]

  access_logs {
    bucket  = aws_s3_bucket.lb_logs.id
    enabled = true
  }

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Name = "${local.name}-lb"
  }
}

0
在我的情况下,问题出在设置了request_payer选项为Requester。需要将其设置为BucketOwner才能正常工作。

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