如何在 Terraform 中创建 SSH 密钥?

我需要为不同的用户旋转一些 EC2框。每个用户都应该与其他所有用户隔离开来,因此每个 EC2框都需要自己的 SSH 密钥。

在 Terraform 中,最好的方法是什么?

我找到的几乎所有指令都要求我手动创建一个 SSH 密钥并将其粘贴到 terraform 脚本中。

(不好的)例子:

因为我需要通过编程为许多用户生成唯一的密钥,所以这是不切实际的。

This doesn't seem like a difficult use case, but I can't find docs on it anywhere.

必要时,我可以使用 Bash 生成 Terraform 脚本并动态注入 SSH 密钥。但这似乎正是 Terraform 一开始就应该做的事情。

102838 次浏览

Terraform 可以使用 tls_private_key资源生成 SSL/SSH 私钥。

因此,如果您想动态地生成 SSH 密钥,您可以这样做:

variable "key_name" {}


resource "tls_private_key" "example" {
algorithm = "RSA"
rsa_bits  = 4096
}


resource "aws_key_pair" "generated_key" {
key_name   = var.key_name
public_key = tls_private_key.example.public_key_openssh
}


data "aws_ami" "ubuntu" {
most_recent = true


filter {
name   = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}


filter {
name   = "virtualization-type"
values = ["hvm"]
}


owners = ["099720109477"] # Canonical
}


resource "aws_instance" "web" {
ami           = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
key_name      = aws_key_pair.generated_key.key_name


tags {
Name = "HelloWorld"
}
}


output "private_key" {
value     = tls_private_key.example.private_key_pem
sensitive = true
}


这将创建一个生活在 Terraform 状态的 SSH 密钥对(除了不使用远程状态时可能对 Terraform 状态本身执行的操作之外,它不会写到磁盘上) ,基于公钥创建一个 AWS 密钥对,然后创建一个 Ubuntu 14.04实例,在该实例中,ubuntu用户可以使用生成的私钥访问。

You would then have to extract the private key from the state file and provide that to the users. You could use an output to spit this straight out to stdout when Terraform is applied.

通过以下命令从私钥获取输出:

terraform output -raw private_key

安全警告

我应该在这里指出,传递私钥通常是一个坏主意,最好让开发人员创建他们自己的密钥对,并为您提供可用于生成 AWS 密钥对(可能使用上面示例中使用的 aws_key_pair资源)的公钥,然后可以在创建实例时指定这个公钥对。

一般来说,我只会使用类似上面的方法为您正在控制的非常临时的开发环境生成 SSH 密钥,因此您不需要将私钥传递给任何人。如果您确实需要将私钥传递给用户,那么您需要确保您在一个安全通道中完成此操作,并确保 Terraform 状态(其中包含纯文本的私钥)也得到适当的安全保护。

Feb, 2022 Update:

下面的代码创建 myKeyAWSmyKey.pemyour computer,并且创建的 myKeymyKey.pem具有相同的私钥。(我用的是 Terraform v0.15.4)

resource "tls_private_key" "pk" {
algorithm = "RSA"
rsa_bits  = 4096
}


resource "aws_key_pair" "kp" {
key_name   = "myKey"       # Create "myKey" to AWS!!
public_key = tls_private_key.pk.public_key_openssh


provisioner "local-exec" { # Create "myKey.pem" to your computer!!
command = "echo '${tls_private_key.pk.private_key_pem}' > ./myKey.pem"
}
}

不要忘记,只有在 ssh 到 ec2实例之前运行下面的代码,才能使 myKey.pem可读。

chmod 400 myKey.pem

Otherwise the error below occurs.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0664 for 'myKey.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "myKey.pem": bad permissions
ubuntu@35.72.30.251: Permission denied (publickey).

对前一个答案的扩展,不适用于评论:

将生成的密钥写入具有正确权限的私有文件:

resource "local_file" "pem_file" {
filename = pathexpand("~/.ssh/${local.ssh_key_name}.pem")
file_permission = "600"
directory_permission = "700"
sensitive_content = tls_private_key.ssh.private_key_pem
}

然而,像这样保存文件的一个缺点是,路径最终将处于 terraform 状态。如果只有 CI/CD 和/或一个人运行应用程序,这没什么大不了的,但是如果有更多的“应用程序”,tfstate 将在与上次应用程序不同的人应用程序时得到更新。这将产生一些“更新”噪音。没什么大不了的,但是有些事情需要注意。

另一种避免这种情况的方法是将 pem 文件保存在 AWS 保密管理器中,或者在 S3中加密,并提供一个命令来获取它并创建本地文件。

你必须在@ydaetskcoR 的回答旁边加上这个

output "ssh_key" {
description = "ssh key generated by terraform"
value       = tls_private_key.asg_lc_key.private_key_pem
}

Adding to Kai 的回答:

variable "generated_key_name" {
type        = string
default     = "terraform-key-pair"
description = "Key-pair generated by Terraform"
}


resource "tls_private_key" "dev_key" {
algorithm = "RSA"
rsa_bits  = 4096
}


resource "aws_key_pair" "generated_key" {
key_name   = var.generated_key_name
public_key = tls_private_key.dev_key.public_key_openssh


provisioner "local-exec" {    # Generate "terraform-key-pair.pem" in current directory
command = <<-EOT
echo '${tls_private_key.dev_key.private_key_pem}' > ./'${var.generated_key_name}'.pem
chmod 400 ./'${var.generated_key_name}'.pem
EOT
}


}