terraformでkey pairを作成してEC2にアクセス

EC2へアクセスするキーペアをterraformを使ってコードで作成及び管理してみる。
ローカルでキーペアを作成する **ssh-keygen** をterraformを利用して作成する流れで行きます。

terraformで鍵を作成→AWSにアップロード→アップロードした鍵を使ってEC2にアクセス
と、こんな感じでまずは試してみます。

今回のversion

```
$ terraform --version

Terraform v1.0.3
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v3.42.0

Your version of Terraform is out of date! The latest version
is 1.0.6. You can update by downloading from https://www.terraform.io/downloads.html
```

tfファイルはこんな感じ。

```:key-pair.tf
variable “key_name” {
  type        = string
  description = “keypair name”
#キーペア名はここで指定
  default     = “hoge-key”
}

#作成したキーペアを格納するファイルを指定。
存在しないディレクトリを指定した場合は新規にディレクトリを作成してくれる
locals {
  public_key_file  = “./.key_pair/${var.key_name}.id_rsa.pub”
  private_key_file = “./.key_pair/${var.key_name}.id_rsa”
}

#privateキーのアルゴリズム設定
resource “tls_private_key” “keygen” {
  algorithm = “RSA”
  rsa_bits  = 4096
}

#local_fileのリソースを指定するとterraformを実行するディレクトリ内でファイル作成やコマンド実行が出来る。
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}”
  }
}

resource “local_file” “public_key_openssh” {
  filename = local.public_key_file
  content  = tls_private_key.keygen.public_key_openssh
  provisioner “local-exec” {
    command = “chmod 600 ${local.public_key_file}”
  }
}
```

上記で作成したキーペアの内、public_keyをaws側に紐付ける。

```
resource “aws_key_pair” “key_pair” {
  key_name   = var.key_name
  public_key = tls_private_key.keygen.public_key_openssh
}
```

AWSのコンソールを見に行って問題なく鍵が表示されていれば確認はOK。

---

動作確認

terraformで適当なec2を作成し、public_keyに上記で作成したものを指定する。

```:ec2.tf
resource “aws_instance” “example” {
  ami                    = “ami-09c5e030f74651050”
  vpc_security_group_ids = [aws_security_group.allow_internal.id]
  subnet_id              = aws_subnet.public_1a.id
  key_name               = aws_key_pair.key_pair.id
  instance_type          = “t2.micro”
  tags = {
    Name = “huga”
  }
}

output “public_ip” {
  value       = aws_instance.example.public_ip
}
```

接続確認

```
$ ssh -i hoge.pem ec2-user@54.203.1.131
The authenticity of host ‘54.203.1.131 (54.203.1.131)’ can’t be established.
ECDSA key fingerprint is SHA256:nL9QqcZbcCQp9r0BRq0Awa/4XdKXwS5ePU3T7zzYPEY.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘54.203.1.131’ (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-100-13-195 ~]$ ifconfig | grep inet
        inet 10.100.13.195  netmask 255.255.224.0  broadcast 10.100.31.255
        inet6 fe80::4f2:16ff:fef5:803f  prefixlen 64  scopeid 0x20<link>
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
[ec2-user@ip-10-100-13-195 ~]$ logout
Connection to 54.203.1.131 closed.
```

いい感じに接続できました。

---

#moduleを使用したキーペア作成

ココまでだと少しコードを書く量が多く手間なので、今度はキーペア作成をmodule化してみる。
moduleを作成してinitすると、ソースが.terraform配下に作成される。

公式サイトを見ながらこんな感じでmodukeを作成。

```:key_module.tf
resource “tls_private_key” “key” {
  algorithm = “RSA”
  rsa_bits  = 4096
}

module “key_pair” {
  source     = “terraform-aws-modules/key-pair/aws”
  key_name   = “hoge-key”
  public_key = tls_private_key.key.public_key_openssh
}

output “private_key_pem” {
  value = tls_private_key.key.private_key_pem
}

output “public_key_pem” {
  value = tls_private_key.key.public_key_openssh
}
```

moduleの環境用意はについてはこれを参考に

https://www.terraform.io/docs/language/modules/index.html

実行するとキーペアが作成される

```:
Outputs:

private_key_pem = -----BEGIN RSA PRIVATE KEY-----
MIIJKwIBAAKCAgEAuECq3DTeDqtQuw7S7ihSXSG4wsz/AhABE6aZQaTJAdQ28Xbj
RRLaxvwV/QzFbedl8CyXW+k418mABH........
-----END RSA PRIVATE KEY-----

public_key_pem = ssh-rsa AAAAB.......
...
...
==
```

無事に作成された。
しかし、作成されたキーペアはローカルにはファイルとして生成されないため、キーを確認するためには都度applyしないと行けなさそう。。。

とりあえず作成はできたので接続確認してみる。


```
$ ssh -i .ssh/hoge.pem ec2-user@54.244.18.123
Warning: Permanently added ‘54.244.18.123’ (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-100-3-160 ~]$ ifconfig | grep inet
        inet 10.100.3.160  netmask 255.255.224.0  broadcast 10.100.31.255
        inet6 fe80::4e2:1dff:fe42:d21  prefixlen 64  scopeid 0x20<link>
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
```

接続確認できた。

moduleを使って作成するキーペアをworkspaceでリージョン切り替え。
VPCをマルチリージョンで展開するときにこれも入れ込んでしまえば楽に管理が出来そうですね。


```:key-pair.tf
resource “tls_private_key” “key” {
  algorithm = “RSA”
  rsa_bits  = 4096
}

module “key_pair” {
  source     = “terraform-aws-modules/key-pair/aws”
  key_name   = lookup(var.vpc_name, “${terraform.workspace}_staging.vpc_name”)
  public_key = tls_private_key.key.public_key_openssh
}

output “private_key_pem” {
  value = tls_private_key.key.private_key_pem
}

output “public_key_pem” {
  value = tls_private_key.key.public_key_openssh
}
```


# aws上にある既存のkeyのimport方法

下記のようにimportするkey nameを指定

```public_key.tf
$ cat public_key.tf
resource “aws_key_pair” “test” {
  name = hoge-key
}
```

上記で指定したリソース名とidを引数にコマンド実行

```
$ terraform import aws_key_pair.test hoge-key
aws_key_pair.test: Importing from ID “hoge-key”...
aws_key_pair.test: Import prepared!
  Prepared aws_key_pair for import
aws_key_pair.test: Refreshing state... [id=hoge-key]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
```

importしたkeyはあくまでterraform管理下におけるようになるようになるだけで、公開鍵の内容を閲覧したり編集することは出来ない模様

下記のようにリソースを定義して

```
public_key.tf
resource “aws_key_pair” “test” {
  key_name   = “hoge-key”
}
```

下記コマンドでimportできるが

```
$ terraform import aws_key_pair.test hoge-key
aws_key_pair.test: Importing from ID “hoge-key”...
aws_key_pair.test: Import prepared!
  Prepared aws_key_pair for import
aws_key_pair.test: Refreshing state... [id=hoge-key]
resource “aws_key_pair” “test” {

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
```

リソースに公開鍵が追記されるような挙動はない模様

# キーペアのalgorithmとbit数の変更

moduleを使用してキーペアのargorithmとbit数を変更してみる。

AWS公式

```
Amazon EC2 が使用するキーは、2048-bit SSH-2 RSA キーです。リージョンごとに最大 5,000 のキーペアを設定できます。
```

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-key-pairs.html

terraformで作成できるキーのalgorithmは **RSA** 又は **ECDSA** を使用可能。
bit数はデフォルトで2048bit
ssh-1はそもそも作成できない模様。

```
Error: invalid key_algorithm “RSA1”
```

https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key

検証としてRSAでキーを2つ作成してみます。bit数は2048と4096。

```:key_module.tf
resource “tls_private_key” “key2048” {
  algorithm = “RSA”
  rsa_bits  = 2048
}

resource “tls_private_key” “key4096" {
  algorithm = “RSA”
  rsa_bits  = 4096
}

module “key_pair” {
  source     = “terraform-aws-modules/key-pair/aws”
  key_name   = “hoge2048"
  public_key = tls_private_key.key2048.public_key_openssh
}

module “key_pair1” {
  source     = “terraform-aws-modules/key-pair/aws”
  key_name   = “hoge4096”
  public_key = tls_private_key.key4096.public_key_openssh
}


output “private_key_pem2048" {
  value = tls_private_key.key2048.private_key_pem
}

output “public_key_pem2048” {
  value = tls_private_key.key2048.public_key_openssh
}

output “private_key_pem4096" {
  value = tls_private_key.key4096.private_key_pem
}

output “public_key_pem4096” {
  value = tls_private_key.key4096.public_key_openssh
}
```

apply

```
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

private_key_pem2048 = -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA1oXWPOYjSTb6j+KNhTRUWVAURbxAnReko28IY/CxC2urD5z7
********
h6dqY5gOJx7/pFJkaWgZhQBbb1EAozoHUBfR+NCXx9Cgay0kpJ7i0IE=
-----END RSA PRIVATE KEY-----

private_key_pem4096 = -----BEGIN RSA PRIVATE KEY-----
MIIJKgIBAAKCAgEAwnqAZsFADX5A4Jp5PxOseYIUWcfs+T8JJMqlRyV6GJB8QDQd
********
o+3MS1x74DPeDCt+N3ZROlwSpWj9hY2DIctfrXmLYuONA7VLZV5MT4bOW4v5DQ==
-----END RSA PRIVATE KEY-----

public_key_pem2048 = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWhdY85iNJNvqP4o2FNFRZUBRFvECdF6Sjbwhj8LELa6
********
MmsXrCK4xtEHnY3Z6P7fj38OP6eObHbcJqAwOckW8GaVBLgk86Ku9gNurfg5tXvQ2BapwFT

public_key_pem4096 = ssh-rsa MIIJKgIBAAKCAgEAwnqAZsFADX5A4Jp5PxOseYIUWcfs+T8JJMqlRyV6GJB8QDQd
********
o+3MS1x74DPeDCt+N3ZROlwSpWj9hY2DIctfrXmLYuONA7VLZV5MT4bOW4v5DQ==
```

2048bitも4098bitも作成できた。

ec2を作成して接続確認

```:ec2.tf
resource “aws_instance” “hoge2048” {
  ami                    = “ami-09c5e030f74651050"
  vpc_security_group_ids = [aws_security_group.allow_internal.id]
  subnet_id              = aws_subnet.public_1a.id
  key_name               = “hoge2048”
  instance_type          = “t2.micro”
  tags = {
    Name = “hoge2048”
  }
}

resource “aws_instance” “hoge4096” {
  ami                    = “ami-09c5e030f74651050"
  vpc_security_group_ids = [aws_security_group.allow_internal.id]
  subnet_id              = aws_subnet.public_1a.id
  key_name               = “hoge4096”
  instance_type          = “t2.micro”
  tags = {
    Name = “hoge4096”
  }
}

output “public_ip2048" {
  value = aws_instance.hoge2048.public_ip
}

output “public_ip4096” {
  value = aws_instance.hoge4096.public_ip
}
```

apply

```
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

private_key_pem2048 = -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA1oXWPOYjSTb6j+KNhTRUWVAURbxAnReko28IY/CxC2urD5z7
********
h6dqY5gOJx7/pFJkaWgZhQBbb1EAozoHUBfR+NCXx9Cgay0kpJ7i0IE=
-----END RSA PRIVATE KEY-----

private_key_pem4096 = -----BEGIN RSA PRIVATE KEY-----
MIIJKgIBAAKCAgEAwnqAZsFADX5A4Jp5PxOseYIUWcfs+T8JJMqlRyV6GJB8QDQd
********
o+3MS1x74DPeDCt+N3ZROlwSpWj9hY2DIctfrXmLYuONA7VLZV5MT4bOW4v5DQ==
-----END RSA PRIVATE KEY-----

public_ip2048 = 34.208.205.55
public_ip4096 = 52.32.241.168
public_key_pem2048 = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWhdY85iNJNvqP4o2FNFRZUBRFvECdF6Sjbwhj8LELa6
********
MmsXrCK4xtEHnY3Z6P7fj38OP6eObHbcJqAwOckW8GaVBLgk86Ku9gNurfg5tXvQ2BapwFT

public_key_pem4096 = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDCeoBmwUANfkDgmnk/E6x5ghRZx+z5PwkkyqVHJXoYk
********
uG/QIpf8vJ6y+NC0irr24w==
```

接続確認

```
$ ssh -i .ssh/2048.pem ec2-user@34.208.205.55
The authenticity of host ‘34.208.205.55 (34.208.205.55)’ can’t be established.
ECDSA key fingerprint is SHA256:Q3gIMbkKR0CkL+nQY/EykMqO9WIimDC2Dre2rhQzmqs.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘34.208.205.55’ (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
No packages needed for security; 2 packages available
Run “sudo yum update” to apply all updates.
[ec2-user@ip-10-100-6-6 ~]$ logout
Connection to 34.208.205.55 closed.
$ ssh -i .ssh/4096.pem ec2-user@52.32.241.168
The authenticity of host ‘52.32.241.168 (52.32.241.168)’ can’t be established.
ECDSA key fingerprint is SHA256:AeA5vxqt/6uZRS3WhpiQVheZYiB/5LqAEAhv34LPRLg.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘52.32.241.168’ (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
No packages needed for security; 2 packages available
Run “sudo yum update” to apply all updates.
[ec2-user@ip-10-100-6-97 ~]$ logout
Connection to 52.32.241.168 closed.
```

共に接続できた。

terraformで作成するkey pairは、リソース作成時に明示的に仕様を指定しない場合はawsが作成するkey pairと同じ仕様で作成される模様。