google-cloud-platformterraformterraform-provider-gcpp12

Get usable P12 bundle/private key from Terraform google_service_account_key resource


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?


Solution

  • 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.