I have created a service account key for a GCP service account using the Terraform google
provider. I've set the private key type to "TYPE_PKCS12_FILE"
, which we require for compatibility with an existing application.
When I was testing this as a PoC, I created the P12 key though the console, and it worked with no issues. Now, I want to handle key generation in our Terraform script, and I cannot get a working P12 key. The actual key resource is created, and it contains a public_key
field, which can be base64 decoded to a valid RSA certificate, and a private_key
, which is supposedly a P12 file which has been base64 encoded, if I am reading the documentation properly.
I have tried saving the private_key
value from Terraform into a file, and base64 decoding it manually. It superficially resembles a known valid P12 bundle, but it is reported as an invalid certificate when I try to import it anywhere.
The object in the state looks like:
"private_key": "MIIJ[...]GoA==",
"private_key_type": "TYPE_PKCS12_FILE",
"public_key": "LS0t[...]LQo=",
"public_key_data": null,
"public_key_type": "TYPE_X509_PEM_FILE",
So, how do I turn the private_key
from the Terraform resource into a usable P12 file that can be uploaded to our application?
Answering this question for myself because the specific error received from Terraform needs some explanation. If you try to use TF's built-in base64decode()
function on the private key, it gives the error "the result of decoding the provided string is not valid UTF-8"
.
I originally assumed that this was an error with the cert, because I had thought that I was expecting the private key to be a PEM certificate, but the private_key
value actually contains the full P12 bundle.
The basic operation of decoding that string as base64 is correct, but as it turns out, Terraform only supports a limited range of encodings. Decoding to a P12 bundle is not supported in Terraform, because TF parses the output of the base64decode()
call to confirm it is valid and it cannot validate the encoding of a P12, since that encoding is not supported.
The solution is to save the output string of the private_key
property into a txt file, then use a certificate management tool like openssl
or certutil
to handle the decoding.
Example:
certutil -decode please-decode-me.txt my-mydecoded-cert.p12
EDIT: Also, note that at minimum, the encode/decode extensions for VS Code do NOT handle that operation correctly for P12 files. I tried that approach thinking that those operations would leave the underlying data of the file unchanged and simply parse it again with a different encoding. This is incorrect, it will change the file data to match the "symbol not found" glyph wherever that glyph is used.
I assume this is well known and/or obvious for security specialists, but I thought I'd explicitly mention it in case it's of use to any other SREs or application devs who don't interact with certificate automation on a regular basis.