今天要使用 terraform 設定 AWS account structure
賽後文章會整理放到個人的部落格上 http://chechia.net/
--
Provision AWS Account
今天要把 aws account 設定完成,並且開始使用 live-repository 來搭建 aws 元件
今天的進度與 code base
對,我們且戰且走常常會這樣,發現昨天寫的東西寫錯臨時改,請大家見諒
X) 因為我們沒有付錢,不能用 gruntwork 的 priviate repository (大誤
O) 因為我們想要使用開源版本的 terraform module (XD)
我們快速看一下 module 裡面的內容
https://github.com/chechiachang/terragrunt-infrastructure-modules/tree/v0.0.1/aws/modules/account-baseline-root
resource "aws_organizations_organization" "org" {
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
"config.amazonaws.com",
]
feature_set = "ALL"
}
resource "aws_organizations_account" "account" {
for_each = var.child_accounts
name = each.key
email = each.value["email"]
depends_on = [
aws_organizations_organization.org
]
}
我們的需求
for_each
function 來迭代 variabel 傳入的 organization accounts (型別是 map) child_accounts = {
logs = {},
security = {},
shared = {},
dev = {},
stage = {},
prod = {}
}
NOTE: 這些 email 請使用你收得到的 email
這個 terraform module 的寫法完全忽略其他 each.value 內的值
在跑 terragrunt 之前,我們先要切換成 root account 的 iam User,昨天新建的 IAM User,存放在密碼企理,還記得嗎?
記住:我們不能用 root account 做這些工作
由於我們現在要使用 IAM User 做 terraform 來創建新的 child accounts,未來會使用新的 child accounts 來做各個環境中的 terraform 元件操作,我們需要一個工具來協助切換這些 account
我們使用的工具是 aws-vault
$ aws-vault --help
usage: aws-vault [<flags>] <command> [<args> ...]
A vault for securely storing and accessing AWS credentials in development environments.
...
使用 Root Account IAM User 身份執行 terragrunt
在本機紀錄 access key (請好好保護本機的安全)
aws-vault add terraform-30day-root-iam-user
Enter Access Key Id: XXXXXXXXXXXX
Enter Secret Key: YYYYYYYYYYYY
透過 aws-cli 取得 caller identity,也就是現在的身份是誰,確定是 Administrator
aws-vault exec terraform-30day-root-iam-user -- aws sts get-caller-identity
{
"UserId": "AIDAxxxxxxxxxxxKGW",
"Account": "706136188012",
"Arn": "arn:aws:iam::706136188012:user/Administrator"
}
然後透過 aws-vault 來執行 terragunt,這樣 terragrunt 就會使用 IAM User 的 credential 來操作 provider 去呼叫 aws api
aws-vault exec terraform-30day-root-iam-user -- terragrunt init
aws-vault exec terraform-30day-root-iam-user -- terragrunt plan
Terraform will perform the following actions:
# aws_organizations_account.account["dev"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "dev"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["logs"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "logs"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["prod"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "prod"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["security"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "security"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["shared"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "shared"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["stage"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "terraform30days@outlook.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "stage"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_account.account["prod"] will be created
+ resource "aws_organizations_account" "account" {
+ arn = (known after apply)
+ close_on_deletion = false
+ create_govcloud = false
+ email = "chechiachang999+terraform-test@gmail.com"
+ govcloud_id = (known after apply)
+ id = (known after apply)
+ joined_method = (known after apply)
+ joined_timestamp = (known after apply)
+ name = "prod"
+ parent_id = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
# aws_organizations_organization.org will be created
+ resource "aws_organizations_organization" "org" {
+ accounts = (known after apply)
+ arn = (known after apply)
+ aws_service_access_principals = [
+ "cloudtrail.amazonaws.com",
+ "config.amazonaws.com",
]
+ feature_set = "ALL"
+ id = (known after apply)
+ master_account_arn = (known after apply)
+ master_account_email = (known after apply)
+ master_account_id = (known after apply)
+ non_master_accounts = (known after apply)
+ roots = (known after apply)
}
Plan: 8 to add, 0 to change, 0 to destroy.
Terragrunt plan 後產生 terraform plan,我們要仔細 review
review 沒問題後,我們進行 apply
aws-vault exec terraform-30day-root-iam-user -- terragrunt apply
aws_organizations_account.account["logs"]: Creating...
aws_organizations_account.account["stage"]: Creating...
aws_organizations_account.account["prod"]: Creating...
aws_organizations_account.account["security"]: Creating...
aws_organizations_account.account["dev"]: Creating...
aws_organizations_account.account["shared"]: Creating...
aws_organizations_account.account["prod"]: Creating...
aws_organizations_account.account["logs"]: Creating...
aws_organizations_account.account["logs"]: Still creating... [10s elapsed]
aws_organizations_account.account["prod"]: Still creating... [10s elapsed]
aws_organizations_account.account["logs"]: Creation complete after 14s [id=557659608246]
aws_organizations_account.account["prod"]: Creation complete after 14s [id=420896464212]
創建完成 organization 與 organization accounts 後,我們可以進行檢查
到 aws console -> organization 頁面,可以看到新建的 organization 與 accounts
也可以使用 aws-cli 列出 organization 的 accounts
aws-vault exec terraform-30day-root-iam-user --no-session -- aws organizations list-accounts
使用開源的 terraform module 也是有很多好處
順便提一下,如果之後要自己動手寫其他元件,應該如何找到適合的 external terraform module?
一個好的 terraform module 通常有幾個特徵
有時候某些外部 module 會有雷,導致我們去引用時出現錯誤
為了避免我們原本好好的 terraform code 受到影響,如果有使用外部 module,我們可以先 fork 一份外部 module 到 internal repository (clone 一份再 push 到自家的 cvs 上面),然後把 source url 改成 fork internal repository
使用 external module 也要注意資訊安全
如果發現自己使用的元件比較冷門,符合自己需求的 external module 也年久失修,也可以考慮 hard fork 一版,由團隊自己維護