Issue, Deploy and Renew your Private Certificates with Vault and Consul-Template
Automate your Certificates Lifecycle with Vault — Part 2
This article is a part of a series about how to
Automate your Certificates Lifecycle with Vault.
- Build an Internal PKI with Vault
- Issue, Deploy and Renew your Private Certificates with Vault and Consul-Template (this article)
- Rotate your CA seamlessly using a Vault PKI
- Securely store Public Certificates in Vault, generated by acme.sh
- Codify Vault Internal PKI using Terraform
Introduction
This article contains a walkthrough to issue, deploy and renew your private certificates using the Vault PKI built in the previous article of this series.
Pre-Requisites
- Install consul-template 0.29.0 or higher
- Create a three-tier PKI CA from the Build an Internal PKI with Vault article with one of the following solutions:
— Follow the walkthrough step by step
— Follow the Summary of commands section (at the end of the article)
Consul-Template
Consul-Template is a template rendering daemon that queries a Consul, Vault, or Nomad cluster and updates any number of specified templates on the filesystem.
Consul-Template uses the Go Template format with additional functions. The dedicated functions for Vault are secret
, secrets
and pkiCert
.
Before using
pkiCert
, read the Special Note carefully to understand its usage. The rendered file is used as a cache and must contain the certificate.
For instance, here are the following templates that issue the private key, the certificate, and the CA chain for the issued leaf certificate test.example.com
. The last one queries the CA chain stored in pki_iss
without issuing any leaf certificate.
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{ .Data.private_key }}
{{- end -}}{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{ .Data.certificate }}
{{- end -}}{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{ .Data.ca_chain }}
{{- end -}}{{- with secret "pki_iss/cert/ca_chain" -}}
{{ .Data.ca_chain }}
{{- end -}}
Issue and Deploy Certificate
First of all, the consul-template daemon should be configured with a dedicated configuration file:
- to connect to the Vault server
- to generate files from specified templates
Read the configuration documentation for further information
Here is a configuration file that uses the exemple
role (built in the previous article) to generate cert.key
, cert.crt
and cert.ca
files related to an issued certificate for test.example.com
.
Disclaimer: On production
- Don’t use the root token
- Create auth methods, entities, groups and policies to grant or forbid access to PKI features
$ cat <<EOF > consul-template.hcl
vault {
address = "http://127.0.0.1:8200"
token = "root"
renew_token = false
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{ .Data.private_key }}
{{- end }}
EOH
destination = "cert.key"
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{ .Data.certificate }}
{{- end }}
EOH
destination = "cert.crt"
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" -}}
{{- range .Data.ca_chain -}}
{{ . }}
{{ end -}}
{{- end -}}
EOH
destination = "cert.ca"
}EOF
Start consul-template, but only once, not in a daemon mode to check the generated files. Next, check the rendered files.
$ consul-template -config=consul-template.hcl -log-level info -once
[INFO] consul-template v0.29.2 (06389a3d)
[INFO] (runner) creating new runner (dry: false, once: true)
[INFO] (runner) creating watcher
[INFO] (runner) starting
[INFO] (runner) rendered "(dynamic)" => "cert.key"
[INFO] (runner) rendered "(dynamic)" => "cert.crt"
[INFO] (runner) rendered "(dynamic)" => "cert.ca"
[INFO] (runner) once mode and all templates rendered
[INFO] (runner) stopping
$ cat cert.key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJm+Ep54nx2009V3EXIl5l4TmnEvsr4RiFxp7ryQFcS8oAoGCCqGSM49
AwEHoUQDQgAEVfh8VvQ/eKeKqvIYHvu59cpAr+G/aXU5xKhd//gn2wdBmaUCyZdj
aqtUo1muPKjAhROaNukXFu8DeJYJJoEJ2Q==
-----END EC PRIVATE KEY-----
$ cat cert.crt
-----BEGIN CERTIFICATE-----
MIICfjCCAiSgAwIBAgIUT0UMUxONeUwDTrK8wrpZCoeDJ9AwCgYIKoZIzj0EAwIw
QDEVMBMGA1UEChMMRXhhbXBsZSBMYWJzMScwJQYDVQQDEx5FeGFtcGxlIExhYnMg
SXNzdWluZyBDQSB2MS4xLjEwHhcNMjIwOTE5MTQ0MjU0WhcNMjIxMDIxMTQ0MzI0
WjAyMRUwEwYDVQQKEwxFeGFtcGxlIExhYnMxGTAXBgNVBAMTEHRlc3QuZXhhbXBs
ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARV+HxW9D94p4qq8hge+7n1
ykCv4b9pdTnEqF3/+CfbB0GZpQLJl2Nqq1SjWa48qMCFE5o26RcW7wN4lgkmgQnZ
o4IBCDCCAQQwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAdBgNVHQ4EFgQUWV8iJwDXTuATSIYPrd1QYjr3fi0wHwYDVR0jBBgw
FoAU3j+4uC3xM3gfb2709xpS0G9Jp8UwPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUF
BzAChiNodHRwOi8vMTI3LjAuMC4xOjgyMDAvdjEvcGtpX2lzcy9jYTAbBgNVHREE
FDASghB0ZXN0LmV4YW1wbGUuY29tMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly8x
MjcuMC4wLjE6ODIwMC92MS9wa2lfaXNzL2NybDAKBggqhkjOPQQDAgNIADBFAiB0
asvZHDOB/XQGkEkd9OCGtXL8lbEDsacvxckhzWUmYQIhAIlVoA10TSZk8pbOc3p2
6o0MxJV7FRfSLSZHwngiWaAr
-----END CERTIFICATE-----
$ cat cert.ca
-----BEGIN CERTIFICATE-----
MIICYDCCAgagAwIBAgIUfzDvhr6caTp7VORPG2TMW1YxW/kwCgYIKoZIzj0EAwIw
PjEQMA4GA1UEChMHRXhhbXBsZTEqMCgGA1UEAxMhRXhhbXBsZSBMYWJzIEludGVy
bWVkaWF0ZSBDQSB2MS4xMB4XDTIyMDkxOTE0MTkxMloXDTIzMDkxOTE0MTk0Mlow
QDEVMBMGA1UEChMMRXhhbXBsZSBMYWJzMScwJQYDVQQDEx5FeGFtcGxlIExhYnMg
SXNzdWluZyBDQSB2MS4xLjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASlLm4w
h3+pun+oJ1LMvJ22rZRgxSPOkJJPBCUKONeM6n5Q0HF4ntcfzW0WHJfYDZWy1J0C
D0sFTMTMye5DSAQSo4HfMIHcMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG
AQH/AgEAMB0GA1UdDgQWBBTeP7i4LfEzeB9vbvT3GlLQb0mnxTAfBgNVHSMEGDAW
gBTWcE1m0LHFXpHrZqaGizi1A1PjtzA/BggrBgEFBQcBAQQzMDEwLwYIKwYBBQUH
MAKGI2h0dHA6Ly8xMjcuMC4wLjE6ODIwMC92MS9wa2lfaW50L2NhMDUGA1UdHwQu
MCwwKqAooCaGJGh0dHA6Ly8xMjcuMC4wLjE6ODIwMC92MS9wa2lfaW50L2NybDAK
BggqhkjOPQQDAgNIADBFAiAOkTLPtqcMIhm7MxRJ+TEUlqo6uyeBSgMSdlTslL3q
xwIhALzEQPavjZDWvMqrqv++RPaEO2Jn9LqIrIDMjRwHwzFX
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB1zCCAX2gAwIBAgIRAOOa8Aj6bj5pqA/EADwcgRQwCgYIKoZIzj0EAwIwNDEQ
MA4GA1UEChMHRXhhbXBsZTEgMB4GA1UEAxMXRXhhbXBsZSBMYWJzIFJvb3QgQ0Eg
djEwHhcNMjIwOTE5MTQwOTQyWhcNMjcwOTE5MTQxOTQyWjA+MRAwDgYDVQQKEwdF
eGFtcGxlMSowKAYDVQQDEyFFeGFtcGxlIExhYnMgSW50ZXJtZWRpYXRlIENBIHYx
LjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASBVFRRBZk5UAk5Cc6ikbrexDaQ
+HqhGEoANTQni7aGAPIBL7jnTjk9XP4qovrdtWCfc5xc4Q3DsZmmCuJieqbko2Yw
ZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU
1nBNZtCxxV6R62amhos4tQNT47cwHwYDVR0jBBgwFoAUU8mUMKg2/sC1c1b+QhK3
MQkdqXAwCgYIKoZIzj0EAwIDSAAwRQIga3l340j1PM+2DCno8mXqJg0fpc8a01Cf
KyxEpOG9t14CIQDO0AIX9uIcg7bvraAIGMjQ7iEXMo36Op0gt/gI3XUymQ==
-----END CERTIFICATE-----
$ openssl x509 -in cert.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
4f:45:0c:53:13:8d:79:4c:03:4e:b2:bc:c2:ba:59:0a:87:83:27:d0
Signature Algorithm: ecdsa-with-SHA256
Issuer: O = Example, CN = Example Labs Issuing CA v1.1.1
Validity
Not Before: Sep 19 14:42:54 2022 GMT
Not After : Oct 21 14:43:24 2022 GMT
Subject: O = Example, CN = test.example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:55:f8:7c:56:f4:3f:78:a7:8a:aa:f2:18:1e:fb:
b9:f5:ca:40:af:e1:bf:69:75:39:c4:a8:5d:ff:f8:
27:db:07:41:99:a5:02:c9:97:63:6a:ab:54:a3:59:
ae:3c:a8:c0:85:13:9a:36:e9:17:16:ef:03:78:96:
09:26:81:09:d9
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Key Agreement
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Auth
X509v3 Subject Key Identifier:
59:5F:22:27:00:D7:4E:E0:13:48:86:0F:AD:DD:50:62:...
X509v3 Authority Key Identifier:
keyid:DE:3F:B8:B8:2D:F1:33:78:1F:6F:6E:F4:F7:1A:... Authority Information Access:
CA Issuers - URI:http://127.0.0.1:8200/v1/pki_iss/ca X509v3 Subject Alternative Name:
DNS:test.example.com
X509v3 CRL Distribution Points: Full Name:
URI:http://127.0.0.1:8200/v1/pki_iss/crlSignature Algorithm: ecdsa-with-SHA256
30:45:02:20:74:6a:cb:d9:1c:33:81:fd:74:06:90:49:1d:f4:
e0:86:b5:72:fc:95:b1:03:b1:a7:2f:c5:c9:21:cd:65:26:61:
02:21:00:89:55:a0:0d:74:4d:26:64:f2:96:ce:73:7a:76:ea:
8d:0c:c4:95:7b:15:17:d2:2d:26:47:c2:78:22:59:a0:2b
Renew Certificate
By default, the certificate (as a non-renewable secret) is automatically renewed by Consul-Template at 90% of its TTL. The default TTL has been set to one month in theexample
role. To test more often, let’s reduce the TTL to 30 seconds to see a renewal of the certificate (ttl=30s
).
Consul-Template can optionally run arbitrary commands when the template is rendered and the output has changed. The exec
block in the configuration should be added to execute a command.
exec {
command = [ "systemctl", "reload”, "nginx" ]
timeout = “30s”
}
So, you can reload or restart a service or an application that uses the certificate. For the sake of the demo, the command outputs the rendered template (cat cert.key
) or the parsed certificate (openssl x509 -in cert.crt -issuer -subject -startdate -enddate -noout
).
Here is the updated consul-template configuration file.
$ cat <<EOF > consul-template.hcl
vault {
address = "http://127.0.0.1:8200"
token = "root"
renew_token = false
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" "ttl=30s" -}}
{{ .Data.private_key }}
{{- end }}
EOH
destination = "cert.key"
exec {
command = [ "cat", "cert.key" ]
}
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" "ttl=30s" -}}
{{ .Data.certificate }}
{{- end }}
EOH
destination = "cert.crt"
exec {
command = [
"openssl", "x509", "-in", "cert.crt",
"-issuer", "-subject", "-startdate", "-enddate",
"-noout"
]
}
}template {
contents = <<EOH
{{- with secret "pki_iss/issue/example" "common_name=test.example.com" "ttl=30s" -}}
{{- range .Data.ca_chain -}}
{{ . }}
{{ end -}}
{{- end -}}
EOH
destination = "cert.ca"
exec {
command = [ "cat", "cert.ca" ]
}
}EOF
So, let’s start the consul-template daemon.
$ consul-template -config=consul-template.hcl
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDe+3rXfvouGK/bymTvuCG++mVtJU+V5/VF2/ouBrp1moAoGCCqGSM49
AwEHoUQDQgAERpPVrgsyT3OvTfKqxEkFqSklcKYShrWuWHlZpWwNTa0WMHS6eTvm
1Ly7WLeMkMPHgsoalMEjFx6HIVgWZjEvAw==
-----END EC PRIVATE KEY-----
issuer=O = Example, CN = Example Labs Issuing CA v1.1.1
subject=O = Example, CN = test.example.com
notBefore=Sep 19 16:30:24 2022 GMT
notAfter=Sep 19 16:31:24 2022 GMT
-----BEGIN CERTIFICATE-----
MIICWzCCAgGgAwIBAgIUTknVQDg1TmMqIYU/H4Z0j9q6q2IwCgYIKoZIzj0EAwIw
PjEQMA4GA1UEChMHRXhhbXBsZTEqMCgGA1UEAxMhRXhhbXBsZSBMYWJzIEludGVy
bWVkaWF0ZSBDQSB2MS4xMB4XDTIyMDkxOTE1MDQzOFoXDTIzMDkxOTE1MDUwOFow
OzEQMA4GA1UEChMHRXhhbXBsZTEnMCUGA1UEAxMeRXhhbXBsZSBMYWJzIElzc3Vp
bmcgQ0EgdjEuMS4xMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWlU5PUeiItWC
YyltWZaS4W8fNANZkSjmd2oShXp2nSVDwN4+Dvf2ixFdzUWbklo5cBRLZxweL59c
hbYsbVgL9qOB3zCB3DAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
ADAdBgNVHQ4EFgQUqUDW46qmyyNELSER3ILqIXbmgOIwHwYDVR0jBBgwFoAU1v5V
z/G4Ai+KsgSqLatba/3vJMIwPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzAChiNo
dHRwOi8vMTI3LjAuMC4xOjgyMDAvdjEvcGtpX2ludC9jYTA1BgNVHR8ELjAsMCqg
KKAmhiRodHRwOi8vMTI3LjAuMC4xOjgyMDAvdjEvcGtpX2ludC9jcmwwCgYIKoZI
zj0EAwIDSAAwRQIhALbt1mZx0pLyGMO8hyUDHfQpRAah0c3dZn5vusIW+vcCAiAz
/WTjjxMm5QeaEh9KBLQrcXXN2jXV7PI886sLBE/xCQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB2DCCAX2gAwIBAgIRAMlAuLmxYK0hqR4uaheiDMowCgYIKoZIzj0EAwIwNDEQ
MA4GA1UEChMHRXhhbXBsZTEgMB4GA1UEAxMXRXhhbXBsZSBMYWJzIFJvb3QgQ0Eg
djEwHhcNMjIwOTE5MTQ1NTA4WhcNMjcwOTE5MTUwNTA4WjA+MRAwDgYDVQQKEwdF
eGFtcGxlMSowKAYDVQQDEyFFeGFtcGxlIExhYnMgSW50ZXJtZWRpYXRlIENBIHYx
LjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATBv71in6dt4FYoFIUWPEl8/PTk
N7vIryxD2sff7PY421erP9ZlWjG3dG5+1kFvHUrp26PGBYid304oVPIYWPHIo2Yw
ZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU
1v5Vz/G4Ai+KsgSqLatba/3vJMIwHwYDVR0jBBgwFoAUwkn7K1yzMRL7FLDIlZxg
7z5RvXYwCgYIKoZIzj0EAwIDSQAwRgIhAIgYXf1QhKLiAZxp08viP0jU57qRkNMP
xYSDwURq/rvoAiEAuq3Wytby/RsaMUvPhjOT0CR7fim9Pwaw1W5HdZ1WWg0=
-----END CERTIFICATE-----
After 27 seconds (=30*0.90), the following output is shown. Only the new cert.key
and cert.crt
are displayed because the CA chain is unchanged.
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBn/Km4pnfB8OTOfmiSjHeqUtfdUtQVJ/kSX1pdRwM05oAoGCCqGSM49
AwEHoUQDQgAEALSYUgTvSjZw8Eb5gEL7RLtcpDSpi1neCM2dHXY+XbeKeDKWxYP3
DUHYu0A5mJZFzt/Yy/CZFkg50JABNPRyjg==
-----END EC PRIVATE KEY-----
issuer=O = Example, CN = Example Labs Issuing CA v1.1.1
subject=O = Example, CN = test.example.com
notBefore=Sep 19 16:30:50 2022 GMT
notAfter=Sep 19 16:31:50 2022 GMT
Conclusion
This article shows how to issue, deploy and renew your private certificates using Vault PKI and Consul-Template.
Consul-Template features are also available in:
- Vault Agent on VM
- Vault Agent on Kubernetes (using vault-k8s)
- Nomad
Vault Agent can use Auto-Auth to simplify the generation of the required token to query Vault.
Nomad replaces the exec
block with thechange_mode
parameter that specifies the behavior Nomad should take if the rendered template changes.
"noop"
- take no action (continue running the task)"restart"
- restart the task"signal"
- send a configurable signal to the task"script"
- run a script
On top of this, if you have to manage multiple nodes and applications, Nomad is easier than Consul-Template daemons or Vault Agent to configure and manage.
Next Steps
The next article (Part 3) explains how to rotate your CA seamlessly.