前提
- Terraform 0.11系。
説明
- 以下のように「
ssh-keygen
」などで作成したものを利用しているのを、Terraformの方に作成までやらせてみる。
ssh-keygen -t rsa -b 4096 -C '' -N '' -f example.id_rsa
tfファイル
キーペア作成
- 「TLS」プロバイダの「tls_private_key」リソースを利用して作成する。
keygen.tf
/**
* require
**/
terraform {
required_version = ">= 0.11.0"
}
/**
* variable
**/
variable "key_name" {
type = "string"
description = "keypair name"
#default = "example" # キー名を固定したかったらdefault指定。指定なしならインタラクティブにキー入力して決定。
}
# キーファイル
## 生成場所のPATH指定をしたければ、ここを変更するとよい。
locals {
public_key_file = "./${var.key_name}.id_rsa.pub"
private_key_file = "./${var.key_name}.id_rsa"
}
/**
* resource
**/
# キーペアを作る
resource "tls_private_key" "keygen" {
algorithm = "RSA"
rsa_bits = 4096
}
/**
* file
**/
# 秘密鍵ファイルを作る
resource "local_file" "private_key_pem" {
filename = "${local.private_key_file}"
content = "${tls_private_key.keygen.private_key_pem}"
# local_fileでファイルを作ると実行権限が付与されてしまうので、local-execでchmodしておく。
provisioner "local-exec" {
command = "chmod 600 ${local.private_key_file}"
}
}
resource "local_file" "public_key_openssh" {
filename = "${local.public_key_file}"
content = "${tls_private_key.keygen.public_key_openssh}"
# local_fileでファイルを作ると実行権限が付与されてしまうので、local-execでchmodしておく。
provisioner "local-exec" {
command = "chmod 600 ${local.public_key_file}"
}
}
/**
* output
**/
# キー名
output "key_name" {
value = "${var.key_name}"
}
# 秘密鍵ファイルPATH(このファイルを利用してサーバへアクセスする。)
output "private_key_file" {
value = "${local.private_key_file}"
}
# 秘密鍵内容
output "private_key_pem" {
value = "${tls_private_key.keygen.private_key_pem}"
}
# 公開鍵ファイルPATH
output "public_key_file" {
value = "${local.public_key_file}"
}
# 公開鍵内容(サーバの~/.ssh/authorized_keysに登録して利用する。)
output "public_key_openssh" {
value = "${tls_private_key.keygen.public_key_openssh}"
}
AWSアカウント情報
aws.tf
provider "aws" {
profile = "example"
region = "ap-northeast-1"
}
- 「
profile
」にはAWS CLIのプロファイル名を指定。
EC2のキーペアとして登録
aws_key_pair.tf
resource "aws_key_pair" "key_pair" {
key_name = "${var.key_name}"
public_key = "${tls_private_key.keygen.public_key_openssh}"
}
使い方
- キーペア作成するだけなら、AWSプロバイダ関連の記述は不要(上記tfファイル群のうち「
keygen.tf
」だけで良い)。
plan
terraform plan
var.key_name
keypair name
Enter a value:
- キーペア名を聞かれるので、「
example
」と入力すると、以下のように表示される。
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:
+ local_file.private_key_pem
id: <computed>
content: "${tls_private_key.keygen.private_key_pem}"
filename: "./example.id_rsa"
+ local_file.public_key_openssh
id: <computed>
content: "${tls_private_key.keygen.public_key_openssh}"
filename: "./example.id_rsa.pub"
+ tls_private_key.keygen
id: <computed>
algorithm: "RSA"
ecdsa_curve: "P224"
private_key_pem: <computed>
public_key_fingerprint_md5: <computed>
public_key_openssh: <computed>
public_key_pem: <computed>
rsa_bits: "4096"
Plan: 3 to add, 0 to change, 0 to destroy.
apply
terraform plan
var.key_name
keypair name
Enter a value:
- ここでもキーペア名を聞かれるので、「
example
」と入力すると、以下のように表示される。
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:
+ local_file.private_key_pem
id: <computed>
content: "${tls_private_key.keygen.private_key_pem}"
filename: "./example.id_rsa"
+ local_file.public_key_openssh
id: <computed>
content: "${tls_private_key.keygen.public_key_openssh}"
filename: "./example.id_rsa.pub"
+ tls_private_key.keygen
id: <computed>
algorithm: "RSA"
ecdsa_curve: "P224"
private_key_pem: <computed>
public_key_fingerprint_md5: <computed>
public_key_openssh: <computed>
public_key_pem: <computed>
rsa_bits: "4096"
Plan: 3 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へのEC2キーペア登録もするなら、同時に登録される。
以下のように変数を指定してやっても良い。
terraform apply -var 'key_name=example'
注意点
- ssh-keygenと同じような感覚で、このまま「キーペア生成ツール」としては利用できない。
- 「
key_name
」変数を変更すると、既に作成したキーペアファイルが削除(destroy)されてしまう。 - lifecycleブロックで適切にignore_changes
指定してやればいける?(未検証)- 以下で検証した通り、単にignore_changes指定しただけでは「キーペア生成ツール」として利用することはできない、ということが分かった。
- 「
[追記] ignore_changes
についての検証結果
- 例えば以下のように、上記例「
keygen.tf
」のうち、秘密鍵(private_key_pem
)、公開鍵(public_key_openssh
)それぞれについて、lifecycleブロックで「filename」をignore_changes指定してやったところ、削除(destroy)はされなくなったものの、単にそれだけで、再生成自体が行われなくなった。
resource "local_file" "private_key_pem" {
filename = "${local.private_key_file}"
content = "${tls_private_key.keygen.private_key_pem}"
provisioner "local-exec" {
command = "chmod 600 ${local.private_key_file}"
}
lifecycle {
ignore_changes = [
"filename",
]
}
}
- 考えてみれば当たり前のことで、「
ignore_changes
」は変更を無視するということなんだから、ここに「filename
」を指定すれば、「変数の値を変更してファイル名が変わったとしても、何もしない。」となるだけの、至って正常な挙動だった。 - 「
lifecycle
」ブロックには、「ignore_changes
」も含め、以下のような項目がある。(※ 詳細はマニュアル参照)-
ignore_changes
- 指定した属性の変更を無視して何もしない。
- 属性名をlist指定
-
prevent_destroy
- このリソースをdestroyしない。変更などの影響でdestroyが実行されるとエラーになる。
- true/falseのbool指定
-
create_before_destroy
- 同名リソースを再生成(create)する時に、先に削除(destroy)する。
- false指定すると、createしてからdestroyするようになるという、処理順制御の項目。(削除はされる)
- true/falseのbool指定
- 暗黙のデフォルト値は「
true
」になっている。
- 暗黙のデフォルト値は「
- 同名リソースを再生成(create)する時に、先に削除(destroy)する。
-
よって、「ssh-keygenコマンドのように、ただ鍵ペアを生成するだけ、というツール利用はできない。」というのが結論になる。
逆に、鍵名を変数化せずにしておけば、削除や生成がtfファイルの記述内容と連動するので、「鍵管理ツール」として利用することはできるかも知れない。
参考情報など
モジュールについて
- 外部モジュールとして指定してやれば、変数指定だけで利用できたりする。
- 「Terraform Module Registry」で探すと良い。
参考モジュール
-
- https://github.com/cloudposse/terraform-aws-key-pair
- Terraform Module Registry URL
- 様々なTerraformモジュールを作っている「Cloud Posse」謹製モジュール。色々指定できる。ガッツリ系。
-
- https://github.com/cloudposse/terraform-tls-ssh-key-pair
- Terraform Module Registry URL
- 上記モジュールからAWS部分を除外して、キーペア作成だけにしたもの。
-
- https://github.com/mitchellh/terraform-aws-dynamic-keys
- Terraform Module Registry URL
- Terraformを作っているHashiCorp代表、ミッチェル・ハシモト氏(mitchellh)謹製モジュール。アッサリ系。分かりやすい。
- 今回の記事は、ほぼこのモジュール内容のパクリ。