Terraform Putty Private Key (PPK)
Hei people, for this story I developed a terraform module contained in this GitHub repo. The article is a guide that can be useful for beginners of the popular IAC language Terraform; but even more it can be interesting for who has encountered my same issue: how to create putty private key (the keys with .ppk extension) by Terraform???
But first …what is a private key? A private key is a variable in cryptography that is used with an algorithm to encrypt and decrypt data.
Why do you need it?
Usually, it can be used as an authentification method with Linux System. So, in case you are deploying a Linux virtual machine, probably you need to create the private key. If you are using terraform for your deploys, it would be better and faster to create by terraform even this key.
I’ve been searching on the web and the Terraform has got a provider which is just our case.
TLS Provider
There it is the TLS Provider, and its resource tls_private_key.
resource "tls_private_key" "admin" {
algorithm = "RSA"
rsa_bits = 4096
}
As you can see from the documentation, the creation of the key is really simple. However, the created resource thought different outputs. The one more important for this case, are the private and the public openssh keys.
The public is the key that you will send to the machine in order to set the authentification method. The private key instead, is the one that you want to save on your laptop, you will use it in order to authenticate to the machine.
Now, it is really easy doing that ok. But for any requirements it can happens you need to have a particular type of private key…
I’m speaking of the Putty private key!
Now, Putty is a tool that allow connecting remote machines… it is probably the most known app in the sector. To connect to a machine you need a Putty Private Key, and a password. An extension of Putty, called Puttygen, allows creating these private keys specifying a password.

The private key obtained by terraform is a pem private key. It allows you to ahve direct acces to a remote machine using different protocols. The main difference when you use Putty, is that that the ppk key needs a further authentication, it needs the password.
When generating a ppk you have to enter a password (or passphrase).

Then when you open Putty to connect to a remote machine, you need to browse the file from the SSH “Auth” sheet, and select the previously created key. Putty will prompt you to enter the password for the ppk.
Now let’s come back to terraform. Summarizing… you are creating some sort of virtual machine and for any reason you need to use a private putty key instead of a pem key. It can be for security reasons or for any company policy… or whatever. However, you found the tls provider, you can create your key pem but after that you need to convert your pem to ppk. Puttygen already offers the possibility, it is not difficult .

You need to import the key under the table conversions and specify a passphrase.
But… we are using Terraform to automate processes!!!
If we just use the tls package and then we convert the key manually where is out great advantage?
Terraform unfortunately is not prepared for every kind of necessity. Its providers allow you to do a lot of cool stuff, such the passphrase creation for example (we wiil see it next); but there are a quantity of things providers does not provide really.
But there is always a way to do things, no?
This one I’m just introducing you it’s always suggested as the last option… practically there is a way you can link your “terraform apply” with any command you can run from your cmd or powershell.
Let’s talk about Terraform Provisioners!
Terraform provisioners allow you to do three basic things:
- run a command on the local machine
- run a command on the remote machine
- move a file from the local machine to the remote one or viceversa.
(yes… theoretically it was sufficient to have the possibility running cmd local commands in order to accomplish both other two actions)
If you are not practical with these elements, I suggest you to look at the docs. You will see the provisioner should always be attached to a resource (like a virtual machine for example). In most of cases it it preferable to have a resource dedicated. For this reason it exists a provider called (null )[hashicorp/null | Terraform Registry]. You can create an empty resource, just to add a provisiner and run a cmd command. That’s what we are going to do!!
resource "null_resource" "pem2ppk" {
provisioner "local-exec" {
command = "..."
}
depends_on = [
local_file.private_openssh_key_admin,
random_password.password
]
}
In the code above you can see how to use the local-exec provisioner, the one responsible to run local commands. As you noticed, the null_resource can be really helpful even because you can specify dependencies there.
The provisioner however is not too complex; you only have to open the block and write the command between double quotes (or with the EOT in case of a multiline code).
How to fill that command?
So, we discovered our terraform tools. What we need to do right now is to understand how to convert a key pem to ppk via cmd. What I discovered on internet is that Putty provides a command line interface only on Linux.
puttygen ${var.path}/${var.username}.pem
-o=${var.path}/${var.username}.ppk
-P ${random_password.password.result}
The command is really simple as you can see above. It takes as main argument the input pem; then it requires an output path fot the ppk, to be specified under the option -o, and a passphrase, to be specified after the -P.
However, it does not work on Windows, so I had to search an alternative method. One of the most known tool it was for sure winscp. Download it: it serves for great quantity of communication protocols; but we are intersted in a side functionality of the tool.
First thing, you need to install the program. Then I recommend to add the program to the environmental variable path.

Otherwise, you are not going to be able to use the CLI. So, ensure from your prompt that the tool is correctly installed by running the command winscp. It will open a sort of cli. If the command is not recognised the tool has not been installed correctly.
Ok!! Let’s see the functionality now!!!
winscp.com /keygen ${var.path}/${var.username}.pem /output=${var.path}/${var.username}.ppk /changepassphrase=${random_password.password.result}
This command works exactly how the puttygen one seen above, therefore I do not think it needs further explanations. But maybe you have still some questions.
In fact, you want probably to see…
…how to create a password in terraform!
resource "random_password" "password" {
length = var.psw_lenght
override_special = var.override_special
}
The provider is called random. I suggest to specify the override_special attribute in order to avoid some special characters generating problems.
One last thing before to let you go. For sure you noticed that the commands take as input some file (the path is specified). It is important to be able to generate that file.
Yet another terraform provider is reaching us to help…
…the local_file provider gives you the possibility of writing a file on the local machine.
resource "local_file" "private_openssh_key_admin" {
content = tls_private_key.admin.private_key_openssh
filename = "${var.path}/${var.username}.pem"
}
It’s time to go guys. This tutorial has come to an end. Just never forget what an output in terraform is and it can be useful in this module in particular.
Summarize what you lern today:
- private key
- putty private key
- tls provider
- provisioner local-exec
- winscp.com keygen
- provider random
- provider local_file
Those seems a lot of things. And all of this stuff just for a ppk. F**K
What is important for me is that you learn something and moreover I’m happy if I solved your problem :D
If worth it, start following me and stay tuned !!
BYE