Create Private CA and Certificates using Terraform

Amod Kadam
5 min readFeb 18, 2023

--

Private CA and Server Certificate using Terraform

In this post we will look at how to create Private CA and Certificates using Terraform.

If you want to create this using OpenSSL refer the following post.

The terraform code will create following. This can be logically divided into two parts.

Part I — Setting up Private CA

  • Create CA Private Key
  • Create CA Certificate

Part II — Create Server Certificates

  • Create Server Private key
  • Create Certificate Signing Request (CSR)
  • Create Certificate signed by Private CA

We will do this in a single terraform code base which is good for development purpose.

Just to keep it simple we will have a following set of files in the Terraform code.

/main.tf 
/providers.tf

Part I — Create Private CA

  1. Create Private Key for CA
# main.tf

resource "tls_private_key" "cm_ca_private_key" {
algorithm = "RSA"
}
#
resource "local_file" "cloudmanthan_ca_key" {
content = tls_private_key.cm_ca_private_key.private_key_pem
filename = "${path.module}/certs/cloudmanthanCA.key"
}
# Run the terraform workflow
terraform init

terraform plan

terraform apply

This should create private key and save it on the local machine as well.

The Private Key is (cm_private_key) is marked as sensitive and it’s value is not shown in the output. However you can inspect the private key by opening the state file — terraform.tfstate from your local machine.

For Production environment ensure that you keep your CA’s private key secured. The terraform state file keeps everything in an unencrypted manner and is security issue. You can also see the security notice on the official Terraform documentation as well !

https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key

2. Create Private CA certificate

This is going to be self signed certificate as we are our own Certificate Authority !

resource "tls_self_signed_cert" "cm_ca_cert" {
private_key_pem = tls_private_key.cm_ca_private_key.private_key_pem

is_ca_certificate = true

subject {
country = "IN"
province = "Mahrashatra"
locality = "Mumbai"
common_name = "Cloud Manthan Root CA"
organization = "Cloud Manthan Software Solutions Pvt Ltd."
organizational_unit = "Cloud Manthan Root Certification Auhtority"
}

validity_period_hours = 43800 // 1825 days or 5 years

allowed_uses = [
"digital_signature",
"cert_signing",
"crl_signing",
]
}

resource "local_file" "cloudmanthan_ca_cert" {
content = tls_self_signed_cert.cm_ca_cert.cert_pem
filename = "${path.module}/certs/cloudmanthanCA.cert"
}
terraform apply
Key and Certificate created for Private CA

Thus we have CA Private Key (cloudmanthanCA.key) and CA Certificate (cloudmanthanCA.cert).

Part II — Create Server Certificate signed by Private CA

  1. Create Private Key for server certificate and store it locally
# Create private key for server certificate 
resource "tls_private_key" "cm_internal" {
algorithm = "RSA"
}

resource "local_file" "cm_internal_key" {
content = tls_private_key.cm_internal.private_key_pem
filename = "${path.module}/certs/dev.cloudmanthan.key"
}

2. Create Certificate Signing Request (CSR)

Note : Earlier we created self signed certificate for our own CA. In this case we are creating certificate signing request.

# Create CSR for for server certificate 
resource "tls_cert_request" "cm_internal_csr" {

private_key_pem = tls_private_key.cm_internal.private_key_pem

dns_names = ["dev.cloudmanthan.internal"]

subject {
country = "IN"
province = "Mahrashatra"
locality = "Mumbai"
common_name = "Cloud Manthan Internal Development "
organization = "Cloud Manthan"
organizational_unit = "Development"
}
}

3. Sign Server certificate by Private CA and store certificate in local file

# Sign Seerver Certificate by Private CA 
resource "tls_locally_signed_cert" "cm_internal" {
// CSR by the development servers
cert_request_pem = tls_cert_request.cm_internal_csr.cert_request_pem
// CA Private key
ca_private_key_pem = tls_private_key.cm_ca_private_key.private_key_pem
// CA certificate
ca_cert_pem = tls_self_signed_cert.cm_ca_cert.cert_pem

validity_period_hours = 43800

allowed_uses = [
"digital_signature",
"key_encipherment",
"server_auth",
"client_auth",
]
}

resource "local_file" "cm_internal_cert" {
content = tls_locally_signed_cert.cm_internal.cert_pem
filename = "${path.module}/certs/dev.cloudmanthan.cert"
}

Run the Terraform workflow.

terraform apply 
Certificates created by Terraform
Certificates created by Terraform

Let us verify the generated server certificate using OpenSSL.

openssl x509 -text -noout -in dev.cloudmanahtn.cert
Server Certificate Detail

This shows the server certificate details. Note the following values

  • CA : FALSE
  • Subject Alternative Name : dev.cloudmanthan.internal
  • Key Id : 05:9C:…:BA:4A

Similarly let us check the CA Certificate.

openssl x509 -noout -text -in cloudmanthanCA.cert
CA Certiciate Details

You should note following attributes for this certificate

  • CA: TRUE
  • Subject Key Identifier : 05:9C:…BA:4A

Subject Key Identifier matches with the Authority Key Identifier for the Server certificate seen earlier.

This confirms that the server certificate is signed by our Private CA !

Thus we have seen how to create Private CA and use the Private CA to sign the server certificate !

Note : The source code is available here for easy reference.

Summary

Terraform makes it very easy to create Private CA and using it to sign server certificates. This is really useful when you want to have a self contained development environment with various certificates created and installed on the various servers internally.

However make a note of security concern around Private Key in terraform state file, as it is kept in the plain text. It is better to create it outside the Terraform or store it securely !

https://buymeacoffee.com/amodkadam

--

--

Amod Kadam

AWS Community Builder | upGrad Course Author | 7 x AWS | Terraform Associate | Cloud Consulting | AWS | Azure | Docker | Kubernetes | Software Architecture