【问题标题】:How do I create an SSH key in Terraform?如何在 Terraform 中创建 SSH 密钥?
【发布时间】:2018-09-19 11:00:30
【问题描述】:

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

在 Terraform 中完成此任务的最佳方法是什么?

我发现的几乎所有说明都希望我手动创建 SSH 密钥并将其粘贴到 terraform 脚本中。

(坏)例子:

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

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

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

【问题讨论】:

  • 这些用户通常会向您提供他们的公钥,因此您无需生成任何内容。为什么您的用户会为管理大量私钥而头疼?
  • 说来话长,但这绝对是一项要求。此 terraform 构建的一部分是用于我们还处理用户管理的合同。

标签: amazon-web-services amazon-ec2 terraform terraform-provider-aws ssh-keys


【解决方案1】:

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

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

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

安全警告

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

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

【讨论】:

  • 问题是私钥不能和remote_exec一起使用
  • @ArchimedesTrajano 为什么私钥不能与 remote_exec 一起使用?
  • @ArchimedesTrajano 我刚刚测试过,私钥在带有 aws 实例的 remote_exec 中为我工作
  • 原始问题不需要将其用作 exec 的一部分,因此您最好提出一个单独的问题,链接到其中的这个问题,并在此处解释答案的原因不适合您的特定用例,显示您的代码以及运行时遇到的错误。
  • 这个答案只生成一个私钥。如果您正在做一些不同的事情,那么可能值得创建一个新问题来显示您所做的事情并链接回这个问题作为参考。
【解决方案2】:

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

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

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).

【讨论】:

    【解决方案3】:

    对先前答案的扩展,不适合评论:

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

    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 的人申请,这没什么大不了的,但如果有更多的“应用程序”,那么只要与上次应用运行不同的人申请,tfstate 就会更新。这将产生一些“更新”噪音。没什么大不了的,但需要注意。

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

    【讨论】:

      【解决方案4】:

      添加到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 = <<-EOT
            echo '${tls_private_key.dev_key.private_key_pem}' > ./'${var.generated_key_name}'.pem
            chmod 400 ./'${var.generated_key_name}'.pem
          EOT
        }
      
      }
      
      

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 2020-12-04
          • 2021-02-07
          • 1970-01-01
          • 1970-01-01
          • 2022-01-02
          • 1970-01-01
          • 1970-01-01
          • 2018-08-19
          • 1970-01-01
          相关资源
          最近更新 更多