hashicorp / packer

Packer is a tool for creating identical machine images for multiple platforms from a single source configuration.
http://www.packer.io
Other
15.13k stars 3.33k forks source link

Allowing ssh private keys as base64 encoded #11413

Open frippe75 opened 3 years ago

frippe75 commented 3 years ago

Hi there, this should be possible using the vault function to pull the key from vault and assign it to a variable. You can not pull it directly to the "ssh_private_key" as the vault function is only available in the variables block.

{
  "variables": {
    "ssh_private_key": "{{ vault `/kv/data/myimage` `ssh_key`}}"
  } 
 "builders": [
   {
    "ssh_private_key": "{{user `ssh_private_key`}}"
   }
]
}

I'm going to close this issue as GItHub is used for tracking bugs and feature requests. If you end up needing more help with this kind of initial configuration, the mailing list or community forum are generally more useful. Issues opened here on the Packer issue tracker are only viewed by a small handful of developers who work on the tool, and we don't always have the most depth or experience when it comes to custom issues with particular build configurations.

Originally posted by @nywilken in https://github.com/hashicorp/packer/issues/11276#issuecomment-928895488

frippe75 commented 3 years ago

Not sure why the original enhancement request was changed to a question and then closed.

The request was about (in the variable section) pulling a Vault secret (base64 encoded ssh private key) as a string and then using it later in the ssh communicator part. I don't see how this can be done today.

There is no option in the ssh communicator to pass the ssh private key as a STRING.

azr commented 3 years ago

Hey @frippe75 ! So, the ssh communicator has a ssh_private_key field:

https://github.com/hashicorp/packer-plugin-sdk/blob/27bd01ebe2e4980121d6fd140548a007dac8931c/communicator/config.go#L190

It is also available in HCL2, and in HCL2 there is a base64decode function.

I am not sure if setting that field will work with every builder, but it will be worth checking; also if it does not work, feel free to open a PR on your builder in order to make it work :).

FYI: in the past we have recommended to not using that field as it could be quite unsafe. That is also why it is undocumented.

Now, if that private key comes from Vault, it would make a lot of sense to allow using it and trusting you over your own security, I believe. I'll bring that one up to our meeting to try to see if we can gather more thoughts... In order to re-document it better.

frippe75 commented 2 years ago

@azr thats good news! Will try it out!

azr commented 2 years ago

Cool, let us know how that works !

nickpetrovic commented 2 years ago

Hi @azr I've run into this today and can't seem to get it working.

I'm fetching the private key using the aws_secretsmanager function. The ssh key is b64 encoded in the AWS Secrets Manager. Here is the error I'm getting.

Error: Incorrect attribute value type

  on sources.pkr.hcl line 9:
  (source code not available)

with local.ssh_private_key as "LS{b64 encoded key content here}==".

Inappropriate value for attribute "ssh_private_key": list of number required.

I've also tried b64 decoding the private key and it still doesn't work. It does print out the actual key in the error, so I know its encoded properly. Any ideas?

azr commented 2 years ago

Ah, bummer, that is because the ssh_private_key expects a byte field, and not a string, so that def. won't work. Thanks for trying !

frippe75 commented 2 years ago

So back again for the same thing. Moved from JSON -> HCL for a few builds. Getting the same error as @nickpetrovic.

Doing Packer builds via Docker and not sure how to grab that private SSH key from Hashicorp Vault and use it in the SSH communicator to authenticate.

Is there a way I'm not seeing... Maybe create a tempfile with the key and use ssh_private_key_file?

frippe75 commented 2 years ago

Tried using templatefile but I guess that will not actually generate a file that can get picked up by the ssh_private_key_file

frippe75 commented 1 year ago

Hi again @azr and @nywilken .

This is really a blocker for me. Am I going about this the wrong way?

The ssh_private_key is really just a string to hold the path of the key and not the key itself. So I'm not finding a way to create that ssh_private_key file during the build. I would have to create a pre-stage script in my GitLab pipeline grabbing the ssh key from Vault myself but not really well integrated thinking both Packer and Vault are from Hashicorp. So couldn't ssh_private_key be either a path or an actual key.

This would make sense but off course break today's behavior: ssh_private_key_path (path) ssh_private_key (key)

So maybe: ssh_private_key (path) ssh_private_key_content (key)

JulesdeCube commented 1 year ago

As describe above there is an undocumented ssh_private_key^1 attribute that can be used for that. The only issue is that it as a byte[] type. In reality the file contain the content of the ssh_private_key_file read un bare bytes^2.

In the hcl language bytes can be a list of number (between 0 and 255). So by using a ascii table you can generate the byte buffer.

Example:

variable "ssh_private_key" {
  type        = string
  description = "SSH private key in PEM file format."
}

locals {
  ssh_private_key_bytes = [
    for b in regexall(".|\n", var.ssh_private_key):
    index(local.ascii_table, b)
  ]
  ascii_table =  ["\u0000", "\u0001", "\u0002", "\u0003", "\u0004", "\u0005", "\u0006", "\u0007", "\u0008", "\t", "\n", "\u000b", "\u000c", "\r", "\u000e", "\u000f", "\u0010", "\u0011", "\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018", "\u0019", "\u001a", "\u001b", "\u001c", "\u001d", "\u001e", "\u001f", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\u007f", "\u0080", "\u0081", "\u0082", "\u0083", "\u0084", "\u0085", "\u0086", "\u0087", "\u0088", "\u0089", "\u008a", "\u008b", "\u008c", "\u008d", "\u008e", "\u008f", "\u0090", "\u0091", "\u0092", "\u0093", "\u0094", "\u0095", "\u0096", "\u0097", "\u0098", "\u0099", "\u009a", "\u009b", "\u009c", "\u009d", "\u009e", "\u009f", "\u00a0", "\u00a1", "\u00a2", "\u00a3", "\u00a4", "\u00a5", "\u00a6", "\u00a7", "\u00a8", "\u00a9", "\u00aa", "\u00ab", "\u00ac", "\u00ad", "\u00ae", "\u00af", "\u00b0", "\u00b1", "\u00b2", "\u00b3", "\u00b4", "\u00b5", "\u00b6", "\u00b7", "\u00b8", "\u00b9", "\u00ba", "\u00bb", "\u00bc", "\u00bd", "\u00be", "\u00bf", "\u00c0", "\u00c1", "\u00c2", "\u00c3", "\u00c4", "\u00c5", "\u00c6", "\u00c7", "\u00c8", "\u00c9", "\u00ca", "\u00cb", "\u00cc", "\u00cd", "\u00ce", "\u00cf", "\u00d0", "\u00d1", "\u00d2", "\u00d3", "\u00d4", "\u00d5", "\u00d6", "\u00d7", "\u00d8", "\u00d9", "\u00da", "\u00db", "\u00dc", "\u00dd", "\u00de", "\u00df", "\u00e0", "\u00e1", "\u00e2", "\u00e3", "\u00e4", "\u00e5", "\u00e6", "\u00e7", "\u00e8", "\u00e9", "\u00ea", "\u00eb", "\u00ec", "\u00ed", "\u00ee", "\u00ef", "\u00f0", "\u00f1", "\u00f2", "\u00f3", "\u00f4", "\u00f5", "\u00f6", "\u00f7", "\u00f8", "\u00f9", "\u00fa", "\u00fb", "\u00fc", "\u00fd", "\u00fe", "\u00ff"]
}

source "libvirt" "my_image" {
  communicator {
    communicator    = "ssh"
    ssh_private_key = local.ssh_private_key_bytes
  }
}
frippe75 commented 1 year ago

@JulesdeCube unfortunately nothing that helps me. But maybe someone else.