Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkiCert now gets the Cert, Private key and CA #1591

Merged
merged 2 commits into from
Jun 24, 2022
Merged

pkiCert now gets the Cert, Private key and CA #1591

merged 2 commits into from
Jun 24, 2022

Conversation

eikenb
Copy link
Contributor

@eikenb eikenb commented Jun 22, 2022

Reworked PKICert to return an object with the Cert, the CA and the Private Key. They are stored as stings on a returned struct with appropriate names (Cert, Key, CA).

Fixes #1567

Note chains were left out as they are difficult/impossible to differentiate from the CA cert and in the file. Plus they are available after the fact from the API.

@eikenb eikenb added enhancement vault Related to the Vault integration labels Jun 22, 2022
@eikenb eikenb added this to the v0.30.0 milestone Jun 22, 2022
@eikenb eikenb requested a review from a team June 22, 2022 23:01
@eikenb eikenb added the hashicat-update-required Changes that need to be ported to hashicat label Jun 22, 2022
@eikenb eikenb force-pushed the pki-private-key branch 3 times, most recently from 3eae49a to aa19ffe Compare June 23, 2022 19:21
Copy link

@swenson swenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to run this locally with Vault, but got an error indicating that somehow cert was nil:

2022-06-23T12:49:23.717-0700 [INFO] (runner) creating watcher
2022-06-23T12:49:23.717-0700 [INFO] (runner) starting
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) running initial templates
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) initiating run
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) checking template 035fc374ef90b59e0ecad00e3bf14553
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) missing data for 1 dependencies
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) missing dependency: vault.pki(pki/issue/example-dot-com)
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) add used dependency vault.pki(pki/issue/example-dot-com) to missing since isLeader but do not have a watcher
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) was not watching 1 dependencies
2022-06-23T12:49:23.717-0700 [DEBUG] (watcher) adding vault.pki(pki/issue/example-dot-com)
2022-06-23T12:49:23.717-0700 [TRACE] (watcher) vault.pki(pki/issue/example-dot-com) starting
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) diffing and updating dependencies
2022-06-23T12:49:23.717-0700 [DEBUG] (runner) watching 1 dependencies
2022-06-23T12:49:23.717-0700 [TRACE] (view) vault.pki(pki/issue/example-dot-com) starting fetch
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x2b8 pc=0x10759c76c]

goroutine 30 [running]:
github.com/hashicorp/consul-template/dependency.goodFor(0x14000f51300?)
	/Users/swenson/projects/consul-template/dependency/vault_pki.go:114 +0x1c
github.com/hashicorp/consul-template/dependency.(*VaultPKIQuery).Fetch.func1(0x0)
	/Users/swenson/projects/consul-template/dependency/vault_pki.go:89 +0xc0
github.com/hashicorp/consul-template/dependency.(*VaultPKIQuery).Fetch(0x14000191280, 0x14000be1b90, 0x1400033c788?)
	/Users/swenson/projects/consul-template/dependency/vault_pki.go:96 +0xd0
github.com/hashicorp/consul-template/watch.(*View).fetch(0x14000208d00, 0x105048704?, 0x14000f46000?, 0x0?)
	/Users/swenson/projects/consul-template/watch/view.go:203 +0xf4
created by github.com/hashicorp/consul-template/watch.(*View).poll
	/Users/swenson/projects/consul-template/watch/view.go:117 +0x100

dependency/vault_pki.go Outdated Show resolved Hide resolved
@eikenb eikenb force-pushed the pki-private-key branch from aa19ffe to 65b8049 Compare June 23, 2022 20:56
@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

That traceback basically says that the response to vault call to get the PKI cert didn't contain the cert data. I'm not sure why this would happen but I think I could add a check so it would return an error in this case and trigger a retry.

If you could get a dump of the data fetched when consul-template calls vault here to see what's in the response to the PKI call, it could help shed some light on what's going on. I can't seem to reproduce this with just consul-template (yet).

Reworked `PKICert` to return an object with the Cert, the CA and the
Private Key. They are stored as stings on a returned struct with
appropriate names (Cert, Key, CA).

Made it so that the `Data` intermediary variable works like secret so
the differing behavior between `secret` and `pkiCert` wouldn't be
a snag.

Includes updated tests and documentation.
@eikenb eikenb force-pushed the pki-private-key branch from 65b8049 to 0de91f2 Compare June 23, 2022 21:16
@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

Just pushed up a tweak to the documentation to call out that you must have the Certificate itself in the rendered template file for it to work as it contains the TTL data.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

If you wanted to try my idea of returning an error to trigger the retry, it would go in vault_pki.go, around line 88. Just a check if cert == nil and a return PemEncoded{}, fmt.Errorf("missing cert") or like.

@swenson
Copy link

swenson commented Jun 23, 2022

I added the retry, but I still get the same error.

Here is the response I see from Vault:

{-----BEGIN CERTIFICATE-----
MIIDxzCCAq+gAwIBAgIUG/ytMR3vmzZ9BgF4qmae/ZbQoK0wDQYJKoZIhvcNAQEL
BQAwGTEXMBUGA1UEAxMObXktd2Vic2l0ZS5jb20wHhcNMjIwNjIzMTk0MjExWhcN
MjIwNjIzMTk0MzQxWjAdMRswGQYDVQQDExJ3d3cubXktd2Vic2l0ZS5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5bEZpSWTLKRPMfiewvFKO+kp2
IDWAHks3d6vOPTHoj+avh81dNW1DpdV8d8D6hnhfMfBDyqEnfTX9fRgxQ8BaImH8
Sg8wYf0OMk0Gvwuq+iPBxX/wbmgVr9Njtiln2EQ/JNNA2/AIZdkUBGo5FmEOmld5
Xf/JcXdIi0s47+HGdLnLmQ+YaPxRG/G1HYJwHoKRs51P450yCk5vihQgl1dVspAm
58Pabl8I9h3yuF09PbHeKZbEArdGmkWrYE1xlfYglJx+I4eg6Q5S7enjxhtZXa+s
PbLLXnTifUtrfShH0m+6c4NI8Dk5YL2DaI1c56p5I5uQ8PuxReOWQBdZm69hAgMB
AAGjggEBMIH+MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwHQYDVR0OBBYEFG4lZNOFK8GUgVnP+pScFG4DGjQ6MB8GA1UdIwQY
MBaAFCDycTqJdiJfS9Z/l6/BVh7/eviZMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF
BQcwAoYfaHR0cDovLzEyNy4wLjAuMTo4MjAwL3YxL3BraS9jYTAdBgNVHREEFjAU
ghJ3d3cubXktd2Vic2l0ZS5jb20wMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovLzEy
Ny4wLjAuMTo4MjAwL3YxL3BraS9jcmwwDQYJKoZIhvcNAQELBQADggEBAJxS0z+t
tfBLHmjhRGHgWwvEQBegwWEL0ILKmFz4aU05x8WHgukfU+f1WEIi7LauQacVJu8E
Ujp73xg9oIxcCYDmUrpReglN7W0VXGAz4dZ+e5nBuzfqhlCZ7v8pRYLtR/YilJUz
tAN9zx4tEKI4aCd9zoBoS6EYYyvxw57+dNzixd8qM8T+JJCldGi5GDkCyKZ9blMi
uCZUJxMN/pR2pHSqlqhfpt3pp0xaoN1CTJD16yKmR/WC+wql2bLnbH5INTC9Tt1i
kpgKz47KTAxkgIwqLdjvR23mlxY38LVLMMWnHADMZOi37VMgk/c3ae6XbGy7u0BM
Glr7UnQAyOWZSFU=
-----END CERTIFICATE-----
 -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuWxGaUlkyykTzH4nsLxSjvpKdiA1gB5LN3erzj0x6I/mr4fN
XTVtQ6XVfHfA+oZ4XzHwQ8qhJ301/X0YMUPAWiJh/EoPMGH9DjJNBr8LqvojwcV/
8G5oFa/TY7YpZ9hEPyTTQNvwCGXZFARqORZhDppXeV3/yXF3SItLOO/hxnS5y5kP
mGj8URvxtR2CcB6CkbOdT+OdMgpOb4oUIJdXVbKQJufD2m5fCPYd8rhdPT2x3imW
xAK3RppFq2BNcZX2IJScfiOHoOkOUu3p48YbWV2vrD2yy1504n1La30oR9JvunOD
SPA5OWC9g2iNXOeqeSObkPD7sUXjlkAXWZuvYQIDAQABAoIBABHINXRxam4lUVXC
H3JOjShTDoMHkbnordPy8RIFQl0IN9pLjsFKl2DubWvTXDlqXe7bLiyCKTRNSLk3
nvNSiQbb10PHom9EZm1PG53zAl5yQK2bkCpxnB/ATeh5Fr1zuw/HK09ECF/1zHyj
87/nyoUI/iyQfDBIZmUZnqwmLSPH8iIYeYb9jtim4il0yXL83RMYDyLmwB1LhyMC
+iuHPDjSytyCDN7L7Zn6be1vPEFzRV26L0yy3cex6GpmTgXClBx/kJ41r0lUXyG9
YsPGKs6eLTfm8ZjtBIYmW2+MAmd7wuh97EE57xzGhE+9ufO9J6ikQHhHmOTC5Kkr
7LZAR8ECgYEA1jxfTh8Bpqb7D/wZvv2G+CtlspYNHkSAMP0Hycec4WPEoECwTjrQ
949Fqi/Ii/LnSXe7SIJLlfnL+dtQq4CGsIKsa2Xe003QGU4H7M55mM/f1zMiidRg
0g0PQOGdV6DzxJgzo5mXhFST9ykFIxQPyyuW9Dturo2Wikw4DqHcYGkCgYEA3ZH4
elZe6Obe51RzINrkxAl4jcb/t0IdDuJQOTg2ocUqHGgyG7GV+Ysz5dto94J8QVaa
vjvDARlVW87PTLpVDQl+Pk0V163nH4noXwly2w5mg0ypNmlhsi7M7DJ8eNBUAEs7
kQaLuto5hoQDyga7I9zt6rlCORWujsR9BVRxeDkCgYEApGXRsM4kYzFSCbMoQqKk
lv4eXUu+J1LjmDQjbNkL7v2zXlIluPJzdvVvvShL2fD9QShrBDpQLHdy6no8zk6j
jQHJs+SJeFcG8NQrSrIrJ3OlTquDvobGAYpaASzgo+T0CxHM1qc/WSHaJdlJguCb
OgpqHWMaDULDmb7haYEV7rkCgYAni7MOmrXL2dD09tSpi4gDGTGkFF11pt4q1ue8
nrTZgKg4c7xlxvdel6LGpreAXZCx1LQ/ucjfPFdI0IudRTCC6CvZEMcSPJ6guWt4
8uXGBTb0vk0BQiPGuqWmjog6w+wKNWNHSiTMT8CuqodGmpbyGq94EmKob589KgKq
Xdz2uQKBgFgEq9qBYgVHyYI5BMe7igulZaMnxnchEehWfOmbruaNUaHY06e0AIvG
i5npkwnXQc6Qh9u8hODKM1Ve1hsS5aoKQJ6gsC5h0MIqKvqc420eLwWjGEeqmEtQ
aQjvhZPefLxOmcV5pMEpwrUlzONB7kgjO2dHb2SBehz6zaZH+R1x
-----END RSA PRIVATE KEY-----
 -----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIUZ/EXxdZi3cY6QAT3b3ooeDEUS68wDQYJKoZIhvcNAQEL
BQAwGTEXMBUGA1UEAxMObXktd2Vic2l0ZS5jb20wHhcNMjIwNjIzMTk0MTQxWhcN
MjIwNzI1MTk0MjExWjAZMRcwFQYDVQQDEw5teS13ZWJzaXRlLmNvbTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALnuK1nrYxJWQGcIo52h2Vtkno9BKjmw
kt00CiHoN4Elqjq89jP1ljzNlxh/y1BDjJfLsFhMI/ND4xD3E/vQbwpJBnXy0C5r
AkpcN3o7SLTeYZqvGFWR7SVEApxXVWpuLe8sJE+MNg5SIldZM8NLPRixM36ZqlNU
JtY4ZvmzVzpL89u3g25YmHTSY4A4KJubLgsdJb8F+12O8ADQc+x21tGsfDB03ZDX
ZO+T2SRIhIOnTF6ipTlhY1XCkZbxd1GLSXTUxabLFtvyRzDGYoembR2uiU2RVhkO
Ra+yehSFktdaZ/eO7xiH/nI/j0pcMRTgGLVC/2jL4DzZ2G2NKxk4Hh0CAwEAAaN+
MHwwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCDy
cTqJdiJfS9Z/l6/BVh7/eviZMB8GA1UdIwQYMBaAFCDycTqJdiJfS9Z/l6/BVh7/
eviZMBkGA1UdEQQSMBCCDm15LXdlYnNpdGUuY29tMA0GCSqGSIb3DQEBCwUAA4IB
AQAgVnwLMj5ymykP4eXDQrz0uJMWMRyHzZHywr8Jnlbged4uw3/Gcn9uw9x7FMR9
Ldi+NRtIjAQALDuwtk1g4NyWztiO20kokp9m6Ru8FhL3JM98ZvilIajmPvnTmJ/z
0p0hk3XISlylziO0q95JRYvNJzIHCCyzZ38XqDaYplDe9X3H+R81uMHdgQ8NAfGs
sS9A7YM4UOooUtPsTVBrp4PMAzwe7CRopCSr/UeU0FyzycDXyc6ZkFiWfIX/lRji
69f6FGZq0I+P/wKrGgP+bPBKfzQ4zxrBKK60eoEEMdEnnFqw5yzrkuEhvcntzfKn
fjtUwx+oGtmUfCYsPmj9B9IQ
-----END CERTIFICATE-----
}

@swenson
Copy link

swenson commented Jun 23, 2022

Looks like the { and } wrapping it are throwing off the pem.Decode(encoded) call, which always returns nil in that case.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

Great find. Thanks. Was working through your test PEMs but hadn't got to that point. Is it messing with pem.Decode()?

@swenson
Copy link

swenson commented Jun 23, 2022

Yep! Easy fix though. Something like

	encoded = []byte(strings.TrimSpace(string(encoded)))
	if len(encoded) > 0 && encoded[0] == '{' {
		encoded = []byte(strings.TrimSpace(string(encoded[1:])))
	}

at the top of pemsCert() will do the trick.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

The pem.Decode() is supposed to handle things like that. Skipping over data until if finds the prefix. To me it looks more like it is that space at the start of the line more than the bracket. It goes line by line and does a HasPrefix for the "-----BEGIN". If I add spaces before the test PEMs (cert, key or ca) I can get it to fail parsing.

I'm not sure why it goes line-by-line on a byte stream. I don't remember anything in the spec about it having to be at the start of the line. But it looks like we need to deal with that.

I think I'll see if I can add code to scan for the "-----BEGIN" and make that the start of what I feed to pem.Decode(). Going to try this locally and if it seems to help I'll push it so you can test it.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 23, 2022

It also requires nothing on the ending line. It uses HasSuffix to look for it. So there can be nothing at the end either.

So it looks like the pem library only deals with simply formatted, cert only files. If we stuck to that we could deal with the spaces with a simple bytes.TrimSpace() and that would fix things. But I'm guessing some people will embed these PEMs in other sorts of config files and we'll need to handle stripping any prefixes or suffixes to get that behavior.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 24, 2022

I've pushed up the changes to get it working with the PEM embedded in other text. I kept it a separate commit for now so you can see the changes better but I plan to squash it before merging.

Let me know how it goes with this. Seems like this should do it.

Thanks 💯 for the review and testing BTW! So many weird edge cases.

@eikenb
Copy link
Contributor Author

eikenb commented Jun 24, 2022

I filed a bug against the pem.Decode() docs.

golang/go#53524

Copy link

@swenson swenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; I pulled it down and tested that it works with Vault as expected, e.g., with a template:

{{ with pkiCert "pki/issue/example-dot-com" "common_name=www.my-website.com" "ttl=1m" }}
cert:
{{ .Data.Cert }}

key:
{{ .Data.Key}}


CA:

{{ .Data.CA}}
{{ end }}

@eikenb eikenb merged commit ba98581 into main Jun 24, 2022
@eikenb eikenb deleted the pki-private-key branch June 24, 2022 19:06
swenson pushed a commit to hashicorp/vault that referenced this pull request Jun 24, 2022
swenson added a commit to hashicorp/vault that referenced this pull request Jun 27, 2022
Update consul-template to latest for pkiCert fix

So that we get the fixes in hashicorp/consul-template#1590
and hashicorp/consul-template#1591.

I tested manually that this no longer causes `pkiCert` to get into an
infinite failure loop when the cert expires, and that the key and CA certificate are also accessible.

Co-authored-by: Theron Voran <[email protected]>
swenson added a commit to hashicorp/vault that referenced this pull request Jun 27, 2022
cherry-picked c165363

Update consul-template to latest for pkiCert fix

So that we get the fixes in hashicorp/consul-template#1590
and hashicorp/consul-template#1591.

I tested manually that this no longer causes `pkiCert` to get into an
infinite failure loop when the cert expires, and that the key and CA certificate are also accessible.

Co-authored-by: Theron Voran <[email protected]>
swenson added a commit to hashicorp/vault that referenced this pull request Jun 27, 2022
cherry-picked c165363

Update consul-template to latest for pkiCert fix

So that we get the fixes in hashicorp/consul-template#1590
and hashicorp/consul-template#1591.

I tested manually that this no longer causes `pkiCert` to get into an
infinite failure loop when the cert expires, and that the key and CA certificate are also accessible.

Co-authored-by: Theron Voran <[email protected]>

Co-authored-by: Christopher Swenson <[email protected]>
Co-authored-by: Theron Voran <[email protected]>
@tsiamer
Copy link

tsiamer commented Jul 7, 2022

Following this Special Note: This function uses the template file destination as a cache for the certificate to prevent Consul-Template from re-fetching it on reload or restart. This special behavior is to better work with Vault’s PKI behavior of always returning a new certificate even if the current one is still good. Using the destination file as a local “cache” allows Consul-Template to check for the certificate in that local file and, if found, parse it and checks it’s valid date range only fetching a new certificate if the local one has expired. It can only get re-populate the fields (Cert, CA, Key) if that data is in the file. Eg. If you don’t include the CA in the file the CA field will be blank when loading from cache. And note that you must include the Certificate itself in this file as it contains the TTL/expiration data,

{{ with pkiCert “pki/issue/my-domain-dot-com” “common_name=foo.example.com” }}
Certificate: {{ .Cert }}
Private Key: {{ .Key }}
Cert Authority: {{ .CA }}
{{ end }}

and have the template saved as .txt it seem that the file is not honored and the cert keep getting generated, anyone experiencing this?

@eikenb
Copy link
Contributor Author

eikenb commented Jul 7, 2022

Hey @Siamert, sorry for your issues. I am unable to reproduce it. Once consul-template is started and the PKI certs file is written I can restart/reload consul-template without it changing the certs.

I simplified the test case as much as I could, down to this shell script which works for me (ie. doesn't re-create the certs). I run that script then Ctrl-C and restart, or use pkill -HUP to trigger it to reload and rerun the templates. Neither results in the certs being re-pulled from Vault.

#!/bin/sh

export VAULT_TOKEN=a_token # <- Put your vault root token here
export VAULT_ADDR='http://127.0.0.1:8200'

cat > template.tmpl << EOF
{{- with pkiCert "pki/issue/example-dot-com" "common_name=foo.example.com" -}}
Certificate: {{ .Cert }}
Private Key: {{ .Key }}
Authority: {{ .CA }}
{{ end }}
EOF

if ! vault secrets list | grep -q 'pki'
then
    vault secrets enable pki
    vault secrets tune -max-lease-ttl=8760h pki/
    vault write -field=certificate pki/root/generate/internal \
            common_name="example.com" \
            ttl=8760h
    vault write pki/roles/example-dot-com \
        allowed_domains=example.com \
        allow_subdomains=true \
        max_ttl=72h
fi

consul-template \
    -log-level=warn \
    -vault-renew-token=false \
    -template template.tmpl:certs

If you still have problems please file an issue or ask on the discuss forum. Comments on already closed issues/PRs hides the discussion that might help someone else.

Thanks and I hope this helps!

@tsiamer
Copy link

tsiamer commented Jul 7, 2022

Thank you eikenb

These are for nginx cert.tpl & nginx.tpl

##cert.tpl -- cert

{{ with secret "pki_int/issue/nginx" "ttl=30m" "common_name=foo.example.com" }}
{{ .Data.certificate }}
{{ .Data.issuing_ca }}{{ end }}

##nginx.tpl -- Key

{{ with secret "pki_int/issue/nginx" "ttl=30m" "common_name=foo.example.com" }}
{{ .Data.private_key }}{{ end }}

##nginx.hcl

template {
source = "/etc/consul-template.d/cert.tpl"
destination = "/etc/nginx/certs/nginx.crt"
perms = 0755
command = "systemctl reload nginx"
}

template {
source = "/etc/consul-template.d/nginx.tpl"
destination = "/etc/nginx/certs/nginx_key"
perms = 0755
command = "systemctl reload nginx"
}

template {
source = "/etc/consul-template.d/rendered_cert.tpl"
destination = "/etc/nginx/certs/rendered_cert.txt"
}

rendered_cert.tpl contains this:

{{ with pkiCert "pki_int/issue/nginx" "ttl=30m" "common_name=foo.example.com" }}
{{ .Data.Key }}
{{ .Data.Cert }}
{{ .Data.CA }}
{{ end }}

The document state that, it use the destination file rendered_cert.txt as local cache but seems it is not read as
cert.tpl and nginx.tpl keep generating cert and key after a restart, agree this rendered_cert.tpl does not get generated
am i doing something wrong? I thought it reads the output of destination file rendered_cert.tpl then do not renew the certs cert.tpl and the key.

@eikenb
Copy link
Contributor Author

eikenb commented Jul 7, 2022

Hey @Siamert, if you want more help with this please consider filing a new issue or asking on the discuss forum. Either place will be better than in the comments of a closed PR. Thanks.

@tsiamer
Copy link

tsiamer commented Jul 7, 2022

Thanks i did already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement hashicat-update-required Changes that need to be ported to hashicat vault Related to the Vault integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pkiCert like support for other PKI values; CA + Chains and the Private-Key
3 participants