[SERVER-217] Cannot decode Apache-formatted X-Client-Cert header Created: 2014/12/02 Updated: 2016/12/09 Resolved: 2016/12/09
|Affects Version/s:||SERVER 0.4.0|
|Remaining Estimate:||Not Specified|
|Time Spent:||Not Specified|
|Original Estimate:||Not Specified|
Docs impact: This issue is referenced in the documentation/external_ssl_termination.markdown file. Once resolved, it'll need an update.
Puppet Server is intended to support the ability for the client certificate to be passed into a request to the master via an X- header – X-Client-Cert – when allow-header-cert-info is set to true. Puppet Server expects the content in the X-Client-Cert to be a URI-encoded form of the original Base-64 PEM certificate, i.e., with the newline characters from the original certificate replaced with %0A characters.
A VirtualHost configuration in an Apache server, where mod_proxy is used to proxy client requests on to a Puppet master, might inject this header with the following:
This results in the full content of the client certificate being included in the X-Client-Cert header in the request. Apache, however, does not URI-encode the original content of the certificate. Instead, the spaces inside of the...
... PEM tags are preserved and newline characters are replaced with spaces as well.
Puppet Server uses functionality from the puppetlabs/certificate-authority library to load the certificate into an X509Certificate object in memory. This library uses BouncyCastle classes to do the loading work. The BouncyCastle classes apparently do not understand spaces in the body of the PEM as being equivalent to newline characters. Any requests routed through Apache which have the X-Client-Cert header appended in the above way will result in the request failing, with the following error being written to the log and returned from the agent request:
In order to overcome this problem and not require further changes to be made in the upstream Apache configuration, Puppet Server could be enhanced to handle decoding the Apache spaces format back to a proper PEM format. This would need to be done in such a way that the URI-encoding method would still be supported, e.g., for non-Apache proxies. This would arguably be a "new feature" for Puppet Server, though, in that if the X-Client-Cert were sent from Apache mod_proxy to a Ruby Puppet master running under Apache/Passenger where no special decoding of the header were provided at the Apache/Passenger layer, the Ruby Puppet master would similarly be unable to handle decoding the certificate and would, therefore, fail the request.
|Comment by banuchka [ 2015/08/14 ]|
As a workaround it is possible with nginx. At first we need to compile it with "HttpSetMiscModule" (http://wiki.nginx.org/HttpSetMiscModule) and use its "set_escape_uri" based on $ssl_client_raw_cert. For example it may looks like that:
|Comment by Luis Fernandez Alvarez [ 2016/06/09 ]|
In case it helps someone, a workaround on HAProxy could be something like:
To be added in the frontend section.
|Comment by Lennard Klein [ 2016/06/23 ]|
If you really want to use apache, this workaround works for me. It's not pretty, so I don't recommend it if you have the option of using i.e. nginx or haproxy as commented earlier.
Edit 2016/08/18 to incorporate a different fix for the problem Alan Schwarzenberger identified below (to be able to keep it in puppetlabs-apache apache::vhosts request_headers param)
|Comment by Alan Schwarzenberger [ 2016/08/17 ]|
It appears in my use case (apache 2.4.16 with Puppet Server 2.2.0) that the workaround from Lennard Klein is not quite complete. It works once an agent has a certificate, but on an initial connection from a puppet agent sending a CSR, there is of course no certificate yet. It appears that environment variable SSL_CLIENT_CERT is then set to an empty string rather than not being set at all, which results in the X-Client-Cert header being set but empty, rather than not being set at all. This then results in Puppet server giving the error "No certs found in PEM read from x-client-cert"