使用 terraform 创建 IAM 角色并将其附加到 EC2

Posted

技术标签:

【中文标题】使用 terraform 创建 IAM 角色并将其附加到 EC2【英文标题】:Create and attach IAM role to EC2 using terraform 【发布时间】:2020-11-07 05:05:44 【问题描述】:

我有一个 terraform 脚本来创建实例并为其附加角色。

一切都按预期创建。

我面临的问题是正在创建 IAM 角色并且正在将策略附加到该角色,但 角色没有附加到实例。请帮忙。

我有以下 terraform 脚本:

provider "aws" 
  region = "ap-southeast-1"


terraform 
  backend "s3" 
    bucket = "example.com"
    key    = "terraform/aws/ec2/xxxNNN/terraform.tfstate"
    region = "ap-southeast-1"
  


resource "aws_iam_policy" "xxx_nodes_role_policy" 
  name        = "xxx_nodes_role_policy"
  description = "IAM Policy for XXX nodes"
  policy      = "$file("xxx_nodes_role_policy.json")"


resource "aws_iam_role" "ec2_role_for_xxx_nodes" 
  name               = "ec2_role_for_xxx_nodes"
  assume_role_policy = "$file("ec2_assumerolepolicy.json")"


resource "aws_iam_role_policy_attachment" "xxx_nodes_role_policy_attachment" 
  role       = "$aws_iam_role.ec2_role_for_xxx_nodes.name"
  policy_arn = "$aws_iam_policy.xxx_nodes_role_policy.arn"


resource "aws_iam_instance_profile" "xxx_instance_profile" 
  name  = "xxx_instance_profile"
  role = "$aws_iam_role.ec2_role_for_xxx_nodes.name"


variable "sgids" 
  type = list(string)
  default = [ "sg-XXX", "sg-XXX" ]


resource "aws_instance" "xxxNNN" 
  ami           = "ami-063e3af9d2cc7fe94"
  instance_type = "r5.large"
  iam_instance_profile = "$aws_iam_instance_profile.xxx_instance_profile.name"

  availability_zone = "ap-southeast-1a"
  key_name = "KKK"
  vpc_security_group_ids = var.sgids
  subnet_id = "subnet-XXX"
  associate_public_ip_address = false
  user_data = "$file("set-up.sh")"

  root_block_device 
    volume_type = "gp2"
    volume_size = "200"
    delete_on_termination = true
  

  tags = 
    Name = "XXXXXXXXXXX/XXXNNN"
  

  lifecycle 
    prevent_destroy = true
  


resource "aws_eip" "XXXNNN" 
  vpc = true
  instance = "$aws_instance.xxxNNN.id"

  tags = 
    Name = "XXXNNN"
  

  lifecycle 
    prevent_destroy = true
  

xxx_nodes_role_policy.json的内容如下:


    "Version": "2012-10-17",
    "Statement": [
        
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:ap-southeast-1:0000:log-group:*",
                "arn:aws:logs:ap-southeast-1:0000:log-group:production:*"
            ]
        
    ]

ec2_assumerolepolicy.json的内容如下:


 "Version": "2012-10-17",
 "Statement": [
   
     "Action": "sts:AssumeRole",
     "Principal": 
       "Service": "ec2.amazonaws.com"
     ,
     "Effect": "Allow",
     "Sid": ""
   
 ]

一切都按预期创建。

我面临的问题是正在创建 IAM 角色,并且正在将策略附加到角色,但角色没有附加到实例。请帮忙。

编辑:在下面添加terraform apply 输出:

aws_iam_policy.xxx_nodes_role_policy: Refreshing state... [id=arn:aws:iam::XXX:policy/xxx_nodes_role_policy]
aws_iam_role.ec2_role_for_xxx_nodes: Refreshing state... [id=ec2_role_for_xxx_nodes]
data.aws_iam_policy_document.instance-assume-role-policy: Refreshing state...
aws_iam_role_policy_attachment.xxx_nodes_role_policy_attachment: Refreshing state... [id=ec2_role_for_xxx_nodes-20200717102807715700000001]
aws_iam_instance_profile.xxx_instance_profile: Refreshing state... [id=xxx_instance_profile]
aws_instance.xxxNNN: Refreshing state... [id=i-XXX]
aws_eip.XXXNNN: Refreshing state... [id=eipalloc-XXX]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_eip.XXXNNN will be created
  + resource "aws_eip" "XXXNNN" 
      + allocation_id     = (known after apply)
      + association_id    = (known after apply)
      + customer_owned_ip = (known after apply)
      + domain            = (known after apply)
      + id                = (known after apply)
      + instance          = (known after apply)
      + network_interface = (known after apply)
      + private_dns       = (known after apply)
      + private_ip        = (known after apply)
      + public_dns        = (known after apply)
      + public_ip         = (known after apply)
      + public_ipv4_pool  = (known after apply)
      + tags              = 
          + "Name" = "XXXNNN"
        
      + vpc               = true
    

  # aws_iam_policy.xxx_nodes_role_policy will be created
  + resource "aws_iam_policy" "xxx_nodes_role_policy" 
      + arn         = (known after apply)
      + description = "IAM Policy for XXX nodes"
      + id          = (known after apply)
      + name        = "xxx_nodes_role_policy"
      + path        = "/"
      + policy      = jsonencode(
            
              + Statement = [
                  + 
                      + Action   = [
                          + "logs:CreateLogStream",
                          + "logs:DescribeLogGroups",
                          + "logs:DescribeLogStreams",
                          + "logs:PutLogEvents",
                        ]
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:logs:ap-southeast-1:XXX:log-group:*",
                          + "arn:aws:logs:ap-southeast-1:XXX:log-group:production:*",
                        ]
                      + Sid      = "VisualEditor0"
                    ,
                ]
              + Version   = "2012-10-17"
            
        )
    

  # aws_iam_role.ec2_role_for_xxx_nodes will be created
  + resource "aws_iam_role" "ec2_role_for_xxx_nodes" 
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            
              + Statement = [
                  + 
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = 
                          + Service = "ec2.amazonaws.com"
                        
                      + Sid       = ""
                    ,
                ]
              + Version   = "2012-10-17"
            
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + max_session_duration  = 3600
      + name                  = "ec2_role_for_xxx_nodes"
      + path                  = "/"
      + unique_id             = (known after apply)
    

  # aws_iam_role_policy_attachment.xxx_nodes_role_policy_attachment will be created
  + resource "aws_iam_role_policy_attachment" "xxx_nodes_role_policy_attachment" 
      + id         = (known after apply)
      + policy_arn = (known after apply)
      + role       = "ec2_role_for_xxx_nodes"
    

  # aws_instance.xxxNNN will be created
  + resource "aws_instance" "xxxNNN" 
      + ami                          = "ami-063e3af9d2cc7fe94"
      + arn                          = (known after apply)
      + associate_public_ip_address  = false
      + availability_zone            = "aws-region"
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + iam_instance_profile         = "xxx_instance_profile"
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "r5.large"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = "key.name"
      + network_interface_id         = (known after apply)
      + outpost_arn                  = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + security_groups              = (known after apply)
      + source_dest_check            = true
      + subnet_id                    = "subnet-XXX"
      + tags                         = 
          + "Name" = "XXXNNN"
        
      + tenancy                      = (known after apply)
      + user_data                    = "060b3d9c8929ff0f18bdd9fa151f5d982c256a78"
      + volume_tags                  = (known after apply)
      + vpc_security_group_ids       = [
          + "sg-XXX",
          + "sg-XXX",
        ]

      + ebs_block_device 
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        

      + ephemeral_block_device 
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        

      + metadata_options 
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        

      + network_interface 
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        

      + root_block_device 
          + delete_on_termination = true
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = 200
          + volume_type           = "gp2"
        
    

Plan: 5 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_iam_policy.xxx_nodes_role_policy: Creating...
aws_iam_role.ec2_role_for_xxx_nodes: Creating...
aws_instance.xxxNNN: Creating...
aws_iam_role.ec2_role_for_xxx_nodes: Creation complete after 3s [id=ec2_role_for_xxx_nodes]
aws_iam_policy.xxx_nodes_role_policy: Creation complete after 4s [id=arn:aws:iam::XXX:policy/xxx_nodes_role_policy]
aws_iam_role_policy_attachment.xxx_nodes_role_policy_attachment: Creating...
aws_iam_role_policy_attachment.xxx_nodes_role_policy_attachment: Creation complete after 2s [id=ec2_role_for_xxx_nodes-20200717110045184300000001]
aws_instance.xxxNNN: Still creating... [10s elapsed]
aws_instance.xxxNNN: Still creating... [20s elapsed]
aws_instance.xxxNNN: Creation complete after 22s [id=i-XXX]
aws_eip.XXXNNN: Creating...
aws_eip.XXXNNN: Creation complete after 3s [id=eipalloc-XXX]

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

【问题讨论】:

apply的相关输出是什么? @MattSchuchard 添加到问题本身 【参考方案1】:

通过与其他人的讨论,我自己解决了这个问题。

RCA(根本原因分析)

因此,问题在于第一次运行 terraform apply 时,创建了一个实例配置文件,但可能不是因为 IAM 权限不足,IAM 角色无法附加到 IAM 实例配置文件。在terraform apply 的所有后续执行中,terraform 正在使用已经存在的实例配置文件(可能是因为我没有授予 terraform 用户销毁权限)。

我是如何发现的

这是一件被忽视的简单事情。如果您在问题中计算我的 terraform 脚本中的资源数量,您会看到定义的资源数量为 6,而在输出中,terraform 始终响应:

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

这就是我认为可能永远不会删除实例配置文件的原因。

通过 AWS CLI 从 IAM 中删除实例配置文件,然后重新执行 terraform apply 修复了此问题。

IAM权限可以参考:https://iam.cloudonaut.io/reference/iam.html

在此 URL 上在页面上查找 并搜索 InstanceProfile 并将所需的权限添加到您的 terraform 用户。我都添加了。

【讨论】:

@HelderSepulveda 我发布答案只是因为我自己问了这个问题,并且觉得可能会有人处于类似情况。如果版主觉得这篇文章不值得发,我会敦促他们删除这篇文章。 您的评论很清楚 6 个资源输出显示添加了 5 个...是的,您显然忽略了一个简单的事情 堆栈溢出特别是encourages answering your own question。

以上是关于使用 terraform 创建 IAM 角色并将其附加到 EC2的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Terraform 创建没有代入角色策略的 AWS IAM 角色?

Terraform aws_iam_role_policy 中的 JSON 语法错误

GCP 为每个项目和 Terraform 预定义 IAM 角色

terraform 中的任务执行 IAM 角色

仅在不存在时如何创建 terraform 资源

Terraform:附加非托管 IAM 角色