如何在Terraform中创建SSH密钥?



我需要为不同的用户启动一堆EC2盒子。每个用户都应与所有其他用户进行沙盒化,因此每个 EC2 机箱都需要自己的 SSH 密钥。

在Terraform中实现这一目标的最佳方法是什么?

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

(坏)示例:

  • https://github.com/hashicorp/terraform/issues/1243,
  • http://2ninjas1blog.com/terraform-assigning-an-aws-key-pair-to-your-ec2-instance-resource/
  • Terraform 无法通过 Amazon EC2 导入密钥对)

由于我需要以编程方式为许多用户生成唯一密钥,因此这是不切实际的。

这似乎不是一个困难的用例,但我在任何地方都找不到关于它的文档。

在紧要关头,我可以生成 Terraform 脚本并使用 Bash 即时注入 SSH 密钥。但这似乎正是Terraform首先应该做的事情。

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 20.04 实例,其中ubuntu用户可以使用生成的私有密钥进行访问。

然后,您必须从状态文件中提取私钥并将其提供给用户。您可以使用output在应用 Terraform 时将其直接吐出到 stdout。

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

terraform output -raw private_key

安全注意事项

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

通常,我只会使用上述方式为您控制的非常临时的开发环境生成SSH密钥,因此您无需将私钥传递给任何人。如果您确实需要将私钥传递给人们,则需要确保在安全通道中执行此操作,并确保 Terraform 状态(包含纯文本形式的私钥)也得到适当的保护。

> 2022 年 2 月更新:

下面的代码创建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

否则,将出现以下错误。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         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
}

但是,像这样保存文件的一个缺点是路径最终将处于地形状态。如果只是 CI/CD 和/或一个人运行 terraform 应用,这没什么大不了的,但如果有更多的"应用者",每当有人与上次应用运行不同的人适用时,tfstate 就会更新。这将产生一些"更新"噪音。没什么大不了的,但需要注意。

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

2023 年 3 月更新:

local_sensitive_file自 2022 年 3 月起上市。请改用它:

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

感谢@kangkyud指出如何改进这篇文章!

补充 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
}
}

您必须将其与@ydaetskcoR答案一起添加

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

相关内容

  • 没有找到相关文章

最新更新