当尝试使用s3作为terraform后端时,如何解决“Error loading state: AccessDenied: Access Denied status code: 403”错误?

26

我的简单Terraform文件如下:

provider "aws" {
  region = "region"
  access_key = "key" 
  secret_key = "secret_key"
}

terraform {
  backend "s3" {
    # Replace this with your bucket name!
    bucket         = "great-name-terraform-state-2"
    key            = "global/s3/terraform.tfstate"
    region         = "eu-central-1"
    # Replace this with your DynamoDB table name!
    dynamodb_table = "great-name-locks-2"
    encrypt        = true
  }
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "great-name-terraform-state-2"
  # Enable versioning so we can see the full revision history of our
  # state files
  versioning {
    enabled = true
  }
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "great-name-locks-2"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"
  attribute {
    name = "LockID"
    type = "S"
    }
}

我所做的就是将后端从本地替换到S3存储。 我正在执行以下操作:

  1. terraform init(当 terraform {} 语句块被注释掉时)

  2. terrafrom apply - 我可以在我的 AWS 中看到 Bucket 已经创建并且 Dynamo 表也已经创建。

  3. 现在我正在取消注释 terraform 代码块,然后再运行 terraform init ,但是我收到了以下错误提示:

Error loading state:
    AccessDenied: Access Denied
        status code: 403, request id: xxx, host id: xxxx

我的身份和访问管理系统(IAM)拥有管理员访问权限 我正在使用Terraform v0.12.24 可以看到,我直接在文件中编写我的AWS密钥和秘钥

我做错了什么吗?

非常感谢任何帮助!

14个回答

25

我之前遇到过这个问题。 以下是可以帮助你克服这个错误的步骤-

  1. 删除 .terraform 目录
  2. 将 access_key 和 secret_key 放在 backend 块下面,如下所示的代码
  3. 运行 terraform init
  backend "s3" {
    bucket = "great-name-terraform-state-2"
    key    = "global/s3/terraform.tfstate"
    region = "eu-central-1"
    access_key = "<access-key>"
    secret_key = "<secret-key>"
  }
}

错误应该已经消失了。


6
您也可以设置AWS配置文件名称,而不是使用访问密钥和秘密密钥。 - Juancho
18
最佳实践不建议您将敏感材料如访问密钥和秘密密钥存储在Terraform文件中,特别是如果您还使用像Github这样的代码存储库。正如@Juancho指出的那样,您只需要在后端包含一行,例如:profile = your_profile_name_from_the_aws_credentials_file 。此外,删除.terraform目录完全是不必要的。 - eatsfood
此外,如果需要,您可以使用 shared_credentials_file 来指向不同位置上的凭证文件,而非 ~/.aws/credentials。 - Juancho
我确认唯一需要的是添加 profile 属性。不要删除 .terraform 目录,最好不要将 access_keysecret_key 放在其中,而是使用配置文件。 - Edeph

10

我知道通过在与其他项目共享Terraform后端的相同S3存储桶上运行terraform init可以验证我的凭证是可用的。

对我有用的方法:

rm -rf .terraform/

编辑

在删除本地的.terraform目录后,请务必运行terraform init以确保您已安装所需的软件包。


1
运行完此命令后,您还需要再次执行 terraform init - Amin Bashiri

5

我也遇到了同样的问题。然后我手动从本地系统中删除了状态文件。你可以在 .terraform/ 目录下找到 terraform.tfstate 文件,然后再次运行 init 命令。如果你在 AWS CLI 中配置了多个配置文件,请不要在 aws provider 配置中提及配置文件,这将使 Terraform 使用默认配置文件。


4
为了提高安全性,您可以按以下方式使用 shared_credentials_fileprofile
provider "aws" {
  region = "region"
  shared_credentials_file = "$HOME/.aws/credentials # default
  profile = "default" # you may change to desired profile
}

terraform {
  backend "s3" {
    profile = "default" # change to desired profile
    # Replace this with your bucket name!
    bucket         = "great-name-terraform-state-2"
    key            = "global/s3/terraform.tfstate"
    region         = "eu-central-1"
    # Replace this with your DynamoDB table name!
    dynamodb_table = "great-name-locks-2"
    encrypt        = true
  }
}

3

我在谷歌上搜索过但没有找到解决方案。希望这能解决你的问题。我的情况是:我正在将状态从本地迁移到AWS S3存储桶。

  1. 注释掉terraform范围
provider "aws" {
  region = "region"
  access_key = "key" 
  secret_key = "secret_key"
}

#terraform {
#  backend "s3" {
#    # Replace this with your bucket name!
#    bucket         = "great-name-terraform-state-2"
#    key            = "global/s3/terraform.tfstate"
#    region         = "eu-central-1"
#    # Replace this with your DynamoDB table name!
#    dynamodb_table = "great-name-locks-2"
#    encrypt        = true
#  }
#}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "great-name-terraform-state-2"
  # Enable versioning so we can see the full revision history of our
  # state files
  versioning {
    enabled = true
  }
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "great-name-locks-2"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"
  attribute {
    name = "LockID"
    type = "S"
    }
}
  1. 运行
terraform init
terraform plan -out test.tfplan
terraform apply "test.tfplan"

创建资源 (S3存储桶和DynamoDb)

  1. 接着取消注释terraform作用域,运行
AWS_PROFILE=REPLACE_IT_WITH_YOUR  TF_LOG=DEBUG   terraform init

如果出现错误,只需搜索 X-Amz-Bucket-Region:
-----------------------------------------------------
2020/08/14 15:54:38 [DEBUG] [aws-sdk-go] DEBUG: Response s3/ListObjects Details:
---[ RESPONSE ]--------------------------------------
HTTP/1.1 403 Forbidden
Connection: close
Transfer-Encoding: chunked
Content-Type: application/xml
Date: Fri, 14 Aug 2020 08:54:37 GMT
Server: AmazonS3
X-Amz-Bucket-Region: eu-central-1
X-Amz-Id-2: REMOVED
X-Amz-Request-Id: REMOVED

复制 X-Amz-Bucket-Region 的值,我的情况是 eu-central-1

  1. 将 terraform 后端配置中的 region 更改为相应的值。
terraform {
  backend "s3" {
    # Replace this with your bucket name!
    bucket         = "great-name-terraform-state-2"
    key            = "global/s3/terraform.tfstate"
    region         = "eu-central-1"
    # Replace this with your DynamoDB table name!
    dynamodb_table = "great-name-locks-2"
    encrypt        = true
  }
}

明确设置环境变量AWS_PROFILE就解决了问题! - Benjamin

2

正如Mintu所说,我们需要在后端配置中包含凭据。另一种不包括凭据的方法是:

  backend "s3" {
    bucket = "great-name-terraform-state-2"
    key    = "global/s3/terraform.tfstate"
    region = "eu-central-1"
    profile = "AWS_PROFILE"
  }
}

需要在机器上配置AWS个人资料才行:

aws configure

或者

nano .aws/credentials

这里需要注意一点,当你需要在 EC2 实例内部应用 terraform 时,你可能已经给该实例分配了 IAM 角色,这可能会导致权限冲突。


1
我遇到了同样的问题,我的 IAM 角色没有正确的权限来在存储桶上执行 List 操作。请检查使用情况:
aws s3 ls

检查您是否有访问权限。如果没有,请添加适当的 IAM 角色。


0

对我有效的是@Exequiel Barriero(Case 2)关于主题“错误刷新状态:S3中的状态数据没有预期的内容”的答案。

链接:{{link1:@Exequiel Barriero的答案}}

但是,如果您尝试创建带有层的lambda函数并传递错误的ARN,则会出现与后端无关的不同原因导致此错误。在我的情况下,ARN中多了一个额外的字符,这给我带来了麻烦,请仔细检查您的ARN。


0

这件事发生在我身上,问题是我试图创建一个已经存在的存储桶名称!


0

我在运行terraform apply后遇到了同样的问题;terraform init可以正常工作。这里的任何建议都没有起作用,但将我的shell从zsh切换到bash解决了这个问题。


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