Как создать SSH-ключ в Terraform? (AWS)

Мне нужно раскрутить кучу боксов EC2 для разных пользователей. Каждый пользователь должен быть изолирован от всех остальных, поэтому каждому блоку EC2 нужен собственный SSH-ключ.

Как лучше всего добиться этого в Terraform?

Почти все найденные мной инструкции требуют, чтобы я вручную создал ключ SSH и вставил его в скрипт терраформирования.

(Плохо) Примеры:

Поскольку мне нужно программно генерировать уникальные ключи для многих пользователей, это непрактично.

Это не кажется сложным вариантом использования, но я нигде не могу найти документацию по нему.

В крайнем случае, я мог бы генерировать сценарии Terraform и на лету вводить ключи SSH с помощью Bash. Но это похоже на то, что Terraform должна делать в первую очередь.


person Abe    schedule 09.04.2018    source источник
comment
Эти пользователи обычно предоставляют вам свои открытые ключи, поэтому вам не нужно ничего создавать. Зачем вашим пользователям головная боль от управления большим количеством закрытых ключей?   -  person jarmod    schedule 10.04.2018
comment
Долгая история, но это определенно требование. Часть этой сборки terraform предназначена для контракта, в котором мы также занимаемся управлением пользователями.   -  person Abe    schedule 10.04.2018


Ответы (5)


Terraform может генерировать закрытые ключи SSL / SSH с помощью tls_private_key ресурса.

Итак, если вы хотите сгенерировать ключи 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"
  }
}

Это создаст пару ключей SSH, которая живет в состоянии Terraform (она не записывается на диск в файлах, кроме того, что может быть сделано для самого состояния Terraform, когда не используется удаленное состояние), создает пару ключей AWS на основе открытого ключа а затем создает экземпляр Ubuntu 14.04, в котором пользователь ubuntu доступен по сгенерированному закрытому ключу.

Затем вам нужно будет извлечь закрытый ключ из файла состояния и предоставить его пользователям. Вы можете использовать output, чтобы выплюнуть это прямо на стандартный вывод, когда Terraform применяемый.

Предостережения по безопасности

Я должен указать здесь, что передача закрытых ключей, как правило, является плохой идеей, и вам было бы намного лучше, если бы разработчики создали свои собственные пары ключей и предоставили вам открытый ключ, который вы (или они) можете использовать для генерации пары ключей AWS. (возможно, с использованием aws_key_pair ресурса, использованного в приведенном выше примере) которые затем можно указать при создании экземпляров.

В общем, я бы использовал только что-то вроде вышеуказанного способа генерации ключей SSH для очень временных сред разработки, которые вы контролируете, поэтому вам не нужно никому передавать закрытые ключи. Если вам действительно нужно передать закрытые ключи людям, вам необходимо убедиться, что вы делаете это в безопасном канале и что состояние Terraform (которое содержит закрытый ключ в виде обычного текста) также защищено надлежащим образом.

person ydaetskcoR    schedule 12.04.2018
comment
проблема в том, что закрытый ключ нельзя использовать с remote_exec - person Archimedes Trajano; 30.06.2018
comment
@ArchimedesTrajano Почему нельзя использовать закрытый ключ с remote_exec? - person Caleb Macdonald Black; 02.07.2018
comment
@ArchimedesTrajano Я только что протестировал, и закрытый ключ у меня работает в remote_exec с экземпляром aws - person Caleb Macdonald Black; 02.07.2018
comment
У вас есть образец, подтверждающий это? Я попытался вставить свой, но на самом деле он не работает должным образом с tls, сгенерированным terraform github .com / trajano / terraform-docker-swarm-aws. - person Archimedes Trajano; 02.07.2018
comment
Исходный вопрос не требует, чтобы он затем использовался как часть exec, поэтому вам, вероятно, лучше всего задать отдельный вопрос, связать в нем ссылку и объяснить, почему ответ здесь не соответствует вашему конкретному варианту использования. , показывая ваш код и ошибку, которую вы получаете при его запуске. - person ydaetskcoR; 02.07.2018
comment
Как вывести все закрытые ключи? Для этого требуется цикл, и я не уверен, как это сделать с помощью terraform. - person C Johnson; 18.11.2019
comment
Этот ответ генерирует только один закрытый ключ. Если вы делаете что-то другое, вероятно, стоит создать новый вопрос, показывающий, что вы сделали, и дать ссылку на этот в качестве справки. - person ydaetskcoR; 18.11.2019
comment
Если вы генерируете ключ ssh в файле состояния, рассмотрите возможность использования удаленного состояния с шифрованием. И, пожалуйста, используйте чувствительный флаг, чтобы ключ не отображался в выводе cli. Подробнее: terraform.io/docs/extend/best-practices /sensitive-state.html - person Bojan Radulovic; 30.03.2021

Приведенный ниже код создает 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"
  }
}

Не забудьте сделать 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
[email protected]: Permission denied (publickey).
person Kai    schedule 04.05.2021

Расширение предыдущих ответов не помещается в комментарии:

Чтобы записать сгенерированный ключ в закрытый файл с правильными разрешениями:

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 apply, но если больше, tfstate будет обновляться всякий раз, когда применяется кто-то, отличный от последнего выполнения. Это создаст некоторый шум обновления. Не объятия, а то, о чем нужно знать.

Альтернатива, позволяющая избежать этого, - сохранить файл pem в AWS Secrets Manager или зашифровать его в S3 и предоставить команду для его получения и создания локального файла.

person Oliver    schedule 02.06.2021

вы должны добавить это вместе с ответом @ydaetskcoR

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

Добавление к ответу Кая:

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

person Saurabh    schedule 26.06.2021