| Updating the local CA file when the file doesn't exist yet (new agent) is a weak link in puppet's security model, because it's the only time that puppet agents don't authenticate the server (VERIFY_NONE). To avoid MTIM attacks, puppet has a ca_fingerprint command line argument which can be used to verify the contents of the CA file over an untrusted channel. The argument accepts the SHA256 digest of the CA file, which can be computed on the CA server as:
# openssl dgst -sha256 -r /etc/puppetlabs/puppet/ssl/certs/ca.pem | cut -f1 -d' ' |
6e09bc3e6778d6b497d233a49f9906b95adc212468d9d3e260398f093badaf03
|
Then on the agent, pass the CA fingerprint when bootstrapping the agent (or running puppet agent -t. Puppet will reject the file if the digests don't match:
# puppet ssl bootstrap --ca_fingerprint FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
Error: CA bundle with digest (SHA256) 6E:09:BC:3E:67:78:D6:B4:97:D2:33:A4:9F:99:06:B9:5A:DC:21:24:68:D9:D3:E2:60:39:8F:09:3B:AD:AF:03 did not match expected digest FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF
|
So if we allow agents to refresh an expired CA certificate, then we have two problems: 1. If ca_fingerprint is not set (the default), then it expands the window of opportunity when an agent could be vulnerable to MITM. 2. If ca_fingerprint is set, then won't match the new CA file. The first issue could be handled by ignoring the expiration date of the CA certificate for the TLS connection that downloads the new CA certificate. All other errors (like bad signature would continue to fail the connection). This could be done by passing a custom Puppet::SSL::Verifier. The second issue could be handled by only applying the ca_fingerprint to the very first CA file download. Once we have a trust anchor, then we can use that CA to download the next once (ignoring the expiration date issue above), preserving the chain of trust. |