使用自己的能力编写tfstate,并将不支持Terraforming的现有资源纳入Terraform管理

首先

我使用Terraform来管理AWS云资源的代码。

虽然Terraform可用于创建新资源,但使用Terraform时,人们往往也想管理现有资源。当前,Terraform本身没有这个功能,但有一个补充工具Terraforming。

关于Terraforming的使用方法,我之前写过如下的文章。

将现有的IAM用户纳入Terraform的管理范围中

然而,尽管Terraforming并非完美,也并非适用于Terraform所支持的所有资源类型。

我正在使用最新版本的 Terraforming v0.8.0 编写,我想要使用 aws_iam_policy_attachment,但它不支持(´・ω・`)

最近我开始习惯于修改tfstate,所以我决定自己写tfstate并尝试操作,结果成功了,现在分享一些心得。

(2016/06/12更新) aws_iam_policy_attachment已在Terraforming v0.9.0中得到支持。感谢dtan4先生。

在这篇文章中要做的事

将现有的aws_iam_policy_attachment资源通过Terraform的管理方式加入

把要操作的资源用tf文件来描述的话,会像这样。

resource "aws_iam_policy_attachment" "aws_codedeploy_role_attachment" {
    name = "AWSCodedeployRoleAttachment"
    roles = [
      "appProductionCodeDeployRole",
      "appStagingCodeDeployRole"
    ]
    policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole"
}

流动

    • Terraformのドキュメントを眺めつつダミーのtfファイルを作る

 

    • ダミーのリソースを terraform apply してtfstateの雛形作成

 

    • AWSコンソールを眺めつつターゲットとなるリソースのtfファイルを作る

 

    • tfstateの雛形をコピーしてターゲットとなるリソースのtfstateの枠を作る

terraform refresh して terraformでtfstateを既存リソースの状態に合わせる
ダミーリソースを削除して terraform plan で差分がなくなれば完成

请注意,对于手动编辑tfstate文件,每个人都要自行承担责任。另外,在我写下这句话时,terraform的最新版本是v0.6.16。

制作一个虚拟的TF文件。

首先,创建目标资源类型的tf文件。

Terraform的官方文档在这里
https://www.terraform.io/docs/providers/aws/r/iam_policy_attachment.html

暫時先製作一個類似的虛擬資源。這次我們順便為測試創建了IAM角色。
(註:最終目標是將所需的AWS托管策略附加到目標資源上,但由於aws_iam_policy_attachments的特性,如果在管理策略上進行測試,將會對現有設定進行更改,因此也創建了測試角色)


resource "aws_iam_role" "test_role" {
    name = "test_role"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_policy" "test_policy" {
    name = "test_policy"
    path = "/"
    description = "My test policy"
    policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

resource "aws_iam_policy_attachment" "test_attachment" {
    name = "test_attachment"
    roles = ["${aws_iam_role.test_role.name}"]
    policy_arn = "${aws_iam_policy.test_policy.arn}"
}

创建tfstate的模板

执行 terraform plan,然后执行 apply,创建 tfstate 的模板。


$ terraform plan

+ aws_iam_policy.test_policy
    arn:         "" => "<computed>"
    description: "" => "My test policy"
    name:        "" => "test_policy"
    path:        "" => "/"
    policy:      "" => "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Action\": [\n        \"ec2:Describe*\"\n      ],\n      \"Effect\": \"Allow\",\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"

+ aws_iam_policy_attachment.test_attachment
    name:             "" => "test_attachment"
    policy_arn:       "" => "${aws_iam_policy.test_policy.arn}"
    roles.#:          "" => "1"
    roles.1376821413: "" => "test_role"

+ aws_iam_role.test_role
    arn:                "" => "<computed>"
    assume_role_policy: "" => "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Action\": \"sts:AssumeRole\",\n      \"Principal\": {\n        \"Service\": \"ec2.amazonaws.com\"\n      },\n      \"Effect\": \"Allow\",\n      \"Sid\": \"\"\n    }\n  ]\n}\n"
    name:               "" => "test_role"
    path:               "" => "/"
    unique_id:          "" => "<computed>"


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

$ terraform apply

省略部分はありますが、以下のような形でtfstateを作成しました。
ダミーリソースで生成されたtfstateを詳しく観察します。

{
    "version": 1,
    "serial": 54,
    "remote": {
        (略)
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                (略)
                "aws_iam_policy_attachment.test_attachment": {
                    "type": "aws_iam_policy_attachment",
                    "depends_on": [
                        "aws_iam_policy.test_policy",
                        "aws_iam_role.test_role"
                    ],
                    "primary": {
                        "id": "test_attachment",
                        "attributes": {
                            "groups.#": "0",
                            "id": "test_attachment",
                            "name": "test_attachment",
                            "policy_arn": "arn:aws:iam::XXXXXXXXXXX:policy/test_policy",
                            "roles.#": "1",
                            "roles.1376821413": "test_role",
                            "users.#": "0"
                        }
                    }
                },
                (略)
            }
        }
    ]
}

创建目标资源的tf文件

在浏览AWS控制台的同时,我会创建目标资源的tf文件。


resource "aws_iam_policy_attachment" "aws_codedeploy_role_attachment" {
    name = "AWSCodedeployRoleAttachment"
    roles = [
      "appProductionCodeDeployRole",
      "appStagingCodeDeployRole"
    ]
    policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole"
}

创建目标资源的tfstate框架

刚刚创建虚拟资源时生成的 tfstate,请将其复制并创建一个类似的 tfstate。

这时候要重点考虑以下两个要点

    • tfstateを手動で編集する場合はserialの値をインクリメントする

 

    配列を受け取る場所、この例だとattributes.roles.# のところにattachするロールの数だけを入れ、roles.1376821413 のようにIDが採番されてる子リソースの行を削除する。

当ID部分似乎已经被编号时,稍后可以使用terraform refresh命令来生成terraform。

{
    "version": 1,
    "serial": 55,
    "remote": {
        (略)
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                (略)
                "aws_iam_policy_attachment.aws_codedeploy_role_attachment": {
                    "type": "aws_iam_policy_attachment",
                    "primary": {
                        "id": "aws_codedeploy_role_attachment",
                        "attributes": {
                            "groups.#": "0",
                            "id": "aws_codedeploy_role_attachment",
                            "name": "AWSCodedeployRoleAttachment",
                            "policy_arn": "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole",
                            "roles.#": "2",
                            "users.#": "0"
                        }
                    }
                },
                "aws_iam_policy_attachment.test_attachment": {
                    "type": "aws_iam_policy_attachment",
                    "depends_on": [
                        "aws_iam_policy.test_policy",
                        "aws_iam_role.test_role"
                    ],
                    "primary": {
                        "id": "test_attachment",
                        "attributes": {
                            "groups.#": "0",
                            "id": "test_attachment",
                            "name": "test_attachment",
                            "policy_arn": "arn:aws:iam::XXXXXXXXXXX:policy/test_policy",
                            "roles.#": "1",
                            "roles.1376821413": "test_role",
                            "users.#": "0"
                        }
                    }
                },
                (略)
            }
        }
    ]
}

使用terraform refresh将现有资源与其状态相匹配。

执行terraform refresh命令将更新tfstate的状态,将资源的实体视为正确。通过这样做,将正确地获取之前未分配ID的部分的状态。

$ terraform refresh
{
    "version": 1,
    "serial": 56,
    "remote": {
        (略)
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                (略)
                "aws_iam_policy_attachment.aws_codedeploy_role_attachment": {
                    "type": "aws_iam_policy_attachment",
                    "primary": {
                        "id": "aws_codedeploy_role_attachment",
                        "attributes": {
                            "groups.#": "0",
                            "id": "aws_codedeploy_role_attachment",
                            "name": "AWSCodedeployRoleAttachment",
                            "policy_arn": "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole",
                            "roles.#": "2",
                            "roles.2660578725": "appStagingCodeDeployRole",
                            "roles.3320175550": "appProductionCodeDeployRole",
                            "users.#": "0"
                        }
                    }
                },
                "aws_iam_policy_attachment.test_attachment": {
                    "type": "aws_iam_policy_attachment",
                    "depends_on": [
                        "aws_iam_policy.test_policy",
                        "aws_iam_role.test_role"
                    ],
                    "primary": {
                        "id": "test_attachment",
                        "attributes": {
                            "groups.#": "0",
                            "id": "test_attachment",
                            "name": "test_attachment",
                            "policy_arn": "arn:aws:iam::XXXXXXXXXXX:policy/test_policy",
                            "roles.#": "1",
                            "roles.1376821413": "test_role",
                            "users.#": "0"
                        }
                    }
                },
                (略)
            }
        }
    ]
}

在这个阶段,进行一次terraform plan,并确认差异已经消失。

$ terraform plan

有时候以为是默认值的东西,实际上需要明确定义,所以如果有差异的情况下,可以参考官方文档中资源的定义以及AWS控制台上的实际资源,适当进行调整。

删除不再需要的虚拟资源。

从tf文件中删除不再需要的虚拟资源并计划以及应用。

$ terraform plan

- aws_iam_policy.test_policy

- aws_iam_policy_attachment.test_attachment

- aws_iam_role.test_role


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


$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 3 destroyed.

在这个阶段,没有虚拟资源,只剩下目标资源,所以应该通过执行terraform plan,得到没有差异的状态,这样就完成了。

$ terraform paln

总结

    • tfstateなんてただのJSON

 

    既存リソースもTerraformで管理するんだ、という熱いハートと気合が大事

这样一来,即使现有资源没有进行 Terraforming 处理,也可以任意管理 Terraform 了呢~

广告
将在 10 秒后关闭
bannerAds