Hardening the OCI Terraform provider authentication security

J.K. Kashe
Jun 9 · 4 min read

If you want to run Terraform scripts from your machine, you need to make sure that you do it securely. Terraform is extremely powerful, and if a rogue actor manages to impersonate you, they might get full access to your OCI environment, depending on what you are authorised to do.

If you are just starting out with OCI, you might have created an unencrypted API key, and used it in your OCI CLI and/or Terraform scripts. If you have, please delete it, now!

How do you know that you are using an unencrypted key?
If your terraform looks something like this

provider "oci" {
tenancy_ocid = "ocid1.tenancy.oc1......"
user_ocid = "ocid1.user.oc1......"
fingerprint = "aa:bb:cc:dd:ee:ff:..."
private_key_path = "~/.oci/mykey.pem"
}

and it works, then yes, you are using unencrypted key. How can you know? Because if the key was encrypted, OCI provider would fail complaining of a missing passphrase.

I probably don’t have to stress how bad this is, right? It’s only using “something you have”. And that something can be stolen. I’m sure your local storage as well as backup drive(s) are encrypted, but still, you should not use unencrypted keys in any kind of production environment.

Using a passphrase encrypted key

Assuming you have a passphrase encrypted key (follow these steps if you don’t), the story is not over. The question is, how to manage the passphrase itself?

provider "oci" {
tenancy_ocid = "ocid1.tenancy.oc1......"
user_ocid = "ocid1.user.oc1......"
fingerprint = "aa:bb:cc:dd:ee:ff:..."
private_key_path = "~/.oci/mykey.pem"
private_key_password = "hunter2"
}

That is obviously not a solution. It’s not any better than using an unencrypted key, in my book this is even worse.

Obviously we need to pass the passphrase as a variable, but how do we do it securely?

One would hope that declaring variable as sensitive would make tf to redact echo:

provider "oci" {
...
private_key_password = var.private_key_password
}
variable private_key_password {
sensitive=true
}

But currently, tf only redacts variable output when printing plan/apply, while happily echoes it in clear text. Maybe that’s not terrible, but I’m not supper happy with it. There is a tf issue to change that, in case you want to give your +1.

So now what? Setting TF_VAR or passing passphrase as a parameter would be even worse, as your passphrase would end up in your shell history files. Yikes!

One alternative is to create a simple shell script which prompts for the password, assigns a variable and calls terraform, like this:

read -r -s -p "private_key_password: " TFPWD
TF_VAR_private_key_password=$TFPWD terraform "$@"

This script will prompt for passphrase and it won’t echo it back. Then in will assign a value to the TF_VAR_ variable, and call terraform, passing any arguments to it.

After the prompt terraform executes using the encrypted key:

The good thing is that the passphrase is held in memory only as long as terraform is running. Once it completes and control returns to bash, the variables are gone.

Admittedly, this does not eliminate the risk, as a hacker who controls you machine could potentially also install a keylogger, but at least we added another problem for the attacker to solve.

Skipping the keys and authenticate using security tokens

There is another option, which is to not using the keys at all! Instead, you can configure the provider to use security token authentication.

Assuming you have the OCI CLI installed, start by invoking

oci session authenticate

you will need to select the OCI region, and once you do, it’s going to open a web browser and authenticate you agains the OCI tenancy. Once you are authenticated, it will ask for the profile name you would like to create:

Completed browser authentication process!Enter the name of the profile you would like to create:

I called mine “tf” (no quotes). Now I can configure the provider to use the token:

provider "oci" {
auth = "SecurityToken"
config_file_profile = "tf"
}

Remember, the token is only valid for an hour. You can refresh it with

oci session refresh --profile <profile_name>

but once it expires, just start with

oci session authenticate

save it under the same profile name (“tf” in my example) and you are good to go!

This is not an official Oracle blog. Information in here might be outdated or incorrect. Views are my own.

Oracle Developers

Aggregation of articles from Oracle engineers, Groundbreaker Ambassadors, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.

J.K. Kashe

Written by

Oracle Developers

Aggregation of articles from Oracle engineers, Groundbreaker Ambassadors, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store