DEV Community

Ernesto Lopez
Ernesto Lopez

Posted on • Updated on

Quickops: creating ssh key and inserting inside OCI instance using terraform

During an instance creation on Oracle cloud infrastructure, there is one step to provide a SSH Public key, paste the content of a public key o let Oracle generate private and public key for you.

Instance-creation-ssh-option

When yo are creating an instance from Terraform, and consult the documentation
oci_core_instance

You will notice that this option correspond to the field metadata which says:

(Optional) (Updatable) Custom metadata key/value pairs that you provide, such as the SSH public key required to connect to the instance.

So based on this you can have the option to send you local public key to the instance during creation by using this inside the main.tf file

resource "oci_core_instance" "instance01" {
    #the rest of the output not shown 
    #METADATA for the instance
    metadata = {
        ssh_authorized_keys = file("<path to your ssh public key>")
    } 
    preserve_boot_volume = false
Enter fullscreen mode Exit fullscreen mode

Also you can have this inside the main.tf file:

resource "oci_core_instance" "instance01" {
    #the rest of the output not shown 
    #METADATA for the instance
    metadata = {
        ssh_authorized_keys = file(var.path_local_public_key)
    } 
    preserve_boot_volume = false
Enter fullscreen mode Exit fullscreen mode

And then another file called variables.tf and inside declare the variable:

variable "path_local_public_key" {
  default = "~/.ssh/id_rsa.pub"
  sensitive = true
}
Enter fullscreen mode Exit fullscreen mode

and the current path inside another file with this naming best practice convention env.tfvars:

path_local_public_key = "/Users/user01/.ssh/id_rsa.pub"
Enter fullscreen mode Exit fullscreen mode

note this .tfvars should not be send to the code repo as it can contain sensitive information as IDs.


But, is there another way?

Indeed, there is a way where you can control de key creation and send it to the main.tf template

There is a TLS Provider that comes with terraform:

The TLS provider provides utilities for working with Transport Layer Security keys and certificates. It provides resources that allow private keys, certificates and certficate requests to be created as part of a Terraform deployment.

Under this scenario you can have another file called keys.tf with the following content:

resource "tls_private_key" "key01" {
  algorithm   = "RSA"
  rsa_bits = "2048"
}
Enter fullscreen mode Exit fullscreen mode

This are the config required to create a key for OCI instances but you can also use rsa_bits = "4096" or algorithm = "ECDSA" ecdsa_curve = "P384" it depends on the requirement.

The point is that this file will generate a private key and the public key, but how can we pass it to the main.tf file? well you need to generate the outputs first.

Create a file called outputs.tf and write the following inside:

output "key-private-pem" {
  value = tls_private_key.key01.private_key_pem
  sensitive = true
}

output "key-public-openssh" {
  value = tls_private_key.key01.public_key_openssh
}
Enter fullscreen mode Exit fullscreen mode

If we move to the documentation of the tls resource it mentions that the resource creation generate the following outputs:

  • algorithm
  • private_key_pem
  • public_key_pem
  • public_key_openssh
  • public_key_fingerprint_md5

Basically we need the private key to store inside the bastion server and the public key to send it to the instance creation. But, and here is the interesting part, OCI for example only support the openssh format

The public key data in OpenSSH authorized_keys format. ll RSA keys are supported, and ECDSA keys with curves "P256", "P384" and "P521" are supported.
These format start with ssh-rsa ...

That is the reason why we only put the private_key_pem and public_key_openssh inside the outputs file.

Notice also that the output file has a sensitive = true under the private_key_pem output definition, this is a requirement by terraform as the private key is sensitive information otherwise you will receive an error about sharing sensitive information.

Don't worry this only avoid the key to show on logs or in the console but it will display on the tfstate file.

Ok back to our configuration, inside the main file you can put this:

resource "oci_core_instance" "instance01" {
    #the rest of the output not shown 
    #METADATA for the instance
    metadata = {
        ssh_authorized_keys = tls_private_key.key01public_key_openssh
    } 
    preserve_boot_volume = false
Enter fullscreen mode Exit fullscreen mode

So basically you are calling the output from one resource and using as an input ion other resource.

after the creation you can copy the private and public keys from the tfstate and create your own private and .pub files (example id_rsa and id_rsa.pub)

Don't forget to assign the required permissions to the private key file:

$ sudo chmod 600 id_rsa
Enter fullscreen mode Exit fullscreen mode

And also remember to store the tfstate file in a secure way.

Note: Terraform is intelligent enough to know that it will need to create first the key and then imported inside the instance creation, there is no need for a depends on

Discussion (0)