terraform-provider-vault icon indicating copy to clipboard operation
terraform-provider-vault copied to clipboard

RFE/pki: provide a way to generate a self-signed root CA

Open LCaparelli opened this issue 3 years ago • 2 comments

Hey folks, thanks for the hard work!

We're creating an internal PKI using the Vault's PKI engine and we're trying to terraform it using this provider. In our initial POCs we used the /root/generate/internal HTTP API endpoint to generate a self-signed certificate that automatically gets configured as the mount's CA.

However, it seems that there is no equivalent operation here. If I'm reading the docs correctly the only way to configure a root CA is via vault_pki_secret_backend_config_ca, but this resource requires a text pem_bundle.

We don't want to keep the private key in our version control, so this option doesn't really help us much. We also have no on-premises infrastructure, so no local air-gapped system/hardware where we can store the root CA and potentially read this value from the filesystem.

Given that this is an existing functionality at the Vault API itself, I believe it's reasonable that this provider also exposes that behavior. Perhaps by allowing users to reference a vault_pki_secret_backend_root_cert in vault_pki_secret_backend_config_ca or something like that.

Sorry if this functionality already exists and I missed it, thanks!

LCaparelli avatar Apr 29 '21 12:04 LCaparelli

If I'm reading the docs correctly the only way to configure a root CA is via vault_pki_secret_backend_config_ca, but this resource requires a text pem_bundle.

Hi @LCaparelli–I was taking a hard look at this provider for my own internal ca, and I was wondering if you could point me to anything that explicitly says that it's not possible. I ended up just reading the code, and if I understand it correctly, it doesn't seem like the resource definitions support this workflow. Specifically, I think it's disallowed with how the Read function is defined for the pki_secret_backend_root_cert resource. Initially, I was confused as to why the cli works in the Build Your Own Certificate Authority (CA) scenario but fails with the equivalent terraform after substep 5 of Step 2: Generate Intermediate CA. Shell and terraform equivalents for this section look something like this:

/*
 * ### 2.5
 * Once the CSR is signed and the root CA returns a certificate, it can be imported back into Vault.
 * ```bash
 * vault write pki_int/intermediate/set-signed [email protected]
 * ```
 */
resource "vault_pki_secret_backend_intermediate_set_signed" "pki_int" {
  backend     = vault_mount.pki_int.path
  certificate = vault_pki_secret_backend_root_sign_intermediate.pki_int.certificate
}

This resource results in the following terraform error:

Error: error creating intermediate set-signed on PKI secret backend "pki_int": Error making API request.

URL: PUT http://127.0.0.1:8200/v1/pki_int/intermediate/set-signed Code: 400. Errors:

  • could not find any existing entry with a private key

I'm assuming that this comes back to storing sensitive values in terraform state, which could make this a bit of a footgun for the general case. I wonder if we couldn't do this safely with some additional controls on the stored tfstate.

n.b. A little frustrating that the provider doesn't (can't?) surface the error on the vault_pki_secret_backend_root_sign_intermediate resource. For this workflow, it wasn't until I queried the audit log to find that the problem was occurring before reaching vault_pki_secret_backend_intermediate_set_signed:

$ jq '.[] | select(.error != null) | { time: .time, error: .error, path: .request.path}' audit.json | jq -s .  
[
  {
    "time": "2021-05-02T17:15:42.303571Z",
    "error": "1 error occurred:\n\t* error fetching CA certificate: stored CA information not able to be parsed\n\n",
    "path": "pki/root/sign-intermediate"
  },
  {
    "time": "2021-05-02T17:15:43.521319Z",
    "error": "1 error occurred:\n\t* error fetching CA certificate: stored CA information not able to be parsed\n\n",
    "path": "pki/root/sign-intermediate"
  }
]

mjburling avatar May 02 '21 17:05 mjburling

Hi @mjburling, I believe one of the problems is that vault_pki_secret_backend_config_ca (seemingly the only way to configure the CA for a root CA mount, someone please correct me if I'm wrong) is only able to receive the CA key-pair as a string field. It can't point to a vault_pki_secret_backend_root_cert as this resource does not expose the private key (rightfully so, IMO).

Even if it did, there would still be the problem of sensitive data on the state. With that in mind, I'd prefer a solution with a resource that represents a root CA with a self-signed cert, where the entire key-pair is stored at the vault (and at the vault alone). In this scenario maybe the state file could contain the public cert itself (or its serial), only regenerating if there is currently no CA in the state or if the cert from state differs from the one in the Vault.

Just spitballing here, of course, I'm not familiar with the codebase and am not sure how viable this is.

LCaparelli avatar May 04 '21 19:05 LCaparelli