我需要为不同的用户启动一堆EC2盒子。每个用户都应该使用其他所有用户进行沙盒处理,因此每个EC2框都需要自己的SSH密钥。
在terraform中实现这一目标的最佳方法是什么?
我发现的几乎所有说明都要我手动创建SSH密钥并将其粘贴到terraform脚本中。
(差)示例:
由于我需要以编程方式为许多用户生成唯一键,因此这是不切实际的。
这似乎不是一个困难的用例,但我无法在任何地方找到文档。
在紧要关头,我可以使用bash生成terraform脚本并动态注入SSH密钥。但这似乎就像terraform应该首先做的那样。
答案 0 :(得分:31)
Terraform可以使用tls_private_key
resource生成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-trusty-14.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"
}
}
这将创建一个生活在Terraform状态的SSH密钥对(它不会写入不使用远程状态时Terraform状态本身可能执行的文件中的磁盘),创建一个基于的AWS密钥对公钥然后创建一个Ubuntu 14.04实例,其中ubuntu
用户可以使用生成的私钥访问。
然后,您必须从状态文件中提取私钥并将其提供给用户。当应用Terraform时,您可以使用output
直接将其吐出到stdout。
我应该在这里指出,传递私钥通常是一个坏主意,让开发人员创建自己的密钥对并为您提供您(或他们)可以用来生成的公钥,您会好得多。 AWS密钥对(可能使用上例中使用的aws_key_pair
resource),然后可以在创建实例时指定。
一般情况下,我只会使用上述为您控制的非常临时的开发环境生成SSH密钥的方法,这样您就不需要将私钥传递给任何人。如果您确实需要将私钥传递给人员,则需要确保在安全通道中执行此操作,并确保Terraform状态(包含纯文本的私钥)也得到适当保护。
答案 1 :(得分:4)
下面的代码创建了 myKey
到 AWS
和 myKey.pem
到 your computer
并且创建的 myKey
和 myKey.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).
答案 2 :(得分:0)
对先前答案的扩展,不适合评论:
将生成的密钥写入具有正确权限的私有文件:
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 和/或一个人运行 terraform apply 没什么大不了的,但如果更多,每当有人与上次应用运行不同时,tfstate 就会更新。这会产生一些“更新”噪音。不是拥抱交易,而是需要注意的事情。
避免这种情况的替代方法是将 pem 文件保存在 AWS Secrets Manager 中,或在 S3 中加密,并提供一个命令来获取它并创建本地文件。
答案 3 :(得分:0)
您必须将此与@ydaetskcoR 答案一起添加
output "ssh_key" {
description = "ssh key generated by terraform"
value = tls_private_key.asg_lc_key.private_key_pem
}
答案 4 :(得分:0)
添加到Kai's answer:
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 = "echo '${tls_private_key.dev_key.private_key_pem}' > ./'${var.generated_key_name}'.pem"
}
provisioner "local-exec" {
command = "chmod 400 ./'${var.generated_key_name}'.pem"
}
}
答案 5 :(得分:-1)
以上应该适用于 15x 版本,但不适用于更高版本,因为它将其标记为敏感值。如果有解决方法,我会很高兴知道。