Hi,
I wanted to change how I use/classify my puppet agents, and use trusted
facts but had to figure out, it doesn't work for me as it should ;)
It took me quite some time to dig through it, but I eventually got it to
work with unicorn behind nginx and apache, and the plain webrick
puppetmaster.
First I tried to run the puppet built-in webrick puppetmaster, to get the
certificate extensions available in my manifests, I had to tweak the
lib/puppet/ssl/certificate.rb.
Don't know what's wrong here, why it not worked as it was before, maybe
some Ruby guru can shed some light on that one.
After I got that to work, I switched back to my unicorn behind nginx
setup, and found that also not working. Some debugging, I found the
lib/puppet/network/http/rack/rest.rb, esp. the +ExportCertData
comment in it. This is only available in Apache, so switched to use
apache in front of unicorn, but still no luck.
I figured that running unicorn behind apache reverse proxying, the
environment variable is not available. Therefore I added an additional
header that gets passed to unicorn: X-SSL-Client-Cert.
However, that header is sent as single line from Apache to unicorn,
and not as valid PEM encoded certificate. Therefore the gsub!
manipulations to restore a valid PEM certificate again.
To make trusted facts work for Apache/unicorn, add a line like:
RequestHeader set X-SSL-Client-Cert %{SSL_CLIENT_CERT}e
To pass that on.
Then switched back to nginx. Nginx has $ssl_client_cert variable as
well, but nginx passes that variable on as multi-line header. Doh!
Unicorn doesn't like that at all.
For nginx, install the lua flavor, and add this to the location statement:
location / {
set_by_lua $client_cert "return ngx.var.ssl_client_raw_cert:gsub('\\n','
')";
proxy_set_header X-SSL-Client-Cert $client_cert;
}
That's transforming the certificate into a single line before it is passed
on to the unicorn.
Is someone using puppetmaster on OpenBSD, and makes use of trusted facts?
If so, how are you using it?
I planned to also report this upstream.
Generally, feedback welcome, or even OK?
cheers,
Sebastian
Index: Makefile
===================================================================
RCS file: /cvs/ports/sysutils/ruby-puppet/3/Makefile,v
retrieving revision 1.132
diff -u -r1.132 Makefile
--- Makefile 29 Apr 2016 07:59:53 -0000 1.132
+++ Makefile 27 May 2016 08:15:42 -0000
@@ -3,7 +3,7 @@
PORTROACH= limit:^3
VERSION= 3.8.7
-REVISION= 2
+REVISION= 3
RUN_DEPENDS+= databases/ruby-hiera,${MODRUBY_FLAVOR} \
sysutils/ruby-facter>=2.0.1p0
Index: patches/patch-lib_puppet_network_http_rack_rest_rb
===================================================================
RCS file: patches/patch-lib_puppet_network_http_rack_rest_rb
diff -N patches/patch-lib_puppet_network_http_rack_rest_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_puppet_network_http_rack_rest_rb 27 May 2016 08:15:42
-0000
@@ -0,0 +1,31 @@
+$OpenBSD$
+
+Make puppet trusted facts available when running with unicorn behind
+nginx or apache
+
+--- lib/puppet/network/http/rack/rest.rb.orig Fri May 27 10:11:44 2016
++++ lib/puppet/network/http/rack/rest.rb Fri May 27 10:11:50 2016
+@@ -92,7 +92,22 @@ class Puppet::Network::HTTP::RackREST
+ # NOTE: The SSL_CLIENT_CERT environment variable will be the empty string
+ # when Puppet agent nodes have not yet obtained a signed certificate.
+ if cert.nil? || cert.empty?
+- nil
++ # When running with unicorn, the SSL_CLIENT_CERT variable is not
available
++ # in the environment, therefore we have to pass a header:
'X-SSL-Client-Cert'
++ cert = request.env['HTTP_X_SSL_CLIENT_CERT']
++ if cert.nil? || cert.empty?
++ nil
++ else
++ # in contrast to the environment variable, the client cert is passed
in
++ # as single string, therefore restore the certificate to a valid pem
++ # encoded certificate
++ cert.gsub!(/ /, "\n")
++ cert.gsub!(/BEGIN\nCERT/, "BEGIN CERT")
++ cert.gsub!(/END\nCERT/, "END CERT")
++ cert =
Puppet::SSL::Certificate.from_instance(OpenSSL::X509::Certificate.new(cert))
++ warn_if_near_expiration(cert)
++ cert
++ end
+ else
+ cert =
Puppet::SSL::Certificate.from_instance(OpenSSL::X509::Certificate.new(cert))
+ warn_if_near_expiration(cert)
Index: patches/patch-lib_puppet_ssl_certificate_rb
===================================================================
RCS file: patches/patch-lib_puppet_ssl_certificate_rb
diff -N patches/patch-lib_puppet_ssl_certificate_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_puppet_ssl_certificate_rb 27 May 2016 08:15:42 -0000
@@ -0,0 +1,16 @@
+$OpenBSD$
+
+Make certificate extension available in puppet manifests
+
+--- lib/puppet/ssl/certificate.rb.orig Wed May 25 08:13:50 2016
++++ lib/puppet/ssl/certificate.rb Wed May 25 08:14:35 2016
+@@ -60,6 +60,8 @@ DOC
+ Puppet::SSL::Oids.subtree_of?('ppPrivCertExt', ext.oid)
+ end
+
+- custom_exts.map { |ext| {'oid' => ext.oid, 'value' => ext.value} }
++ extensions = []
++ custom_exts.map { |ext| extensions << {'oid' => ext.oid, 'value' =>
ext.value} }
++ return extensions
+ end
+ end
Index: Makefile
===================================================================
RCS file: /cvs/ports/sysutils/ruby-puppet/3/Makefile,v
retrieving revision 1.132
diff -u -r1.132 Makefile
--- Makefile 29 Apr 2016 07:59:53 -0000 1.132
+++ Makefile 27 May 2016 08:15:42 -0000
@@ -3,7 +3,7 @@
PORTROACH= limit:^3
VERSION= 3.8.7
-REVISION= 2
+REVISION= 3
RUN_DEPENDS+= databases/ruby-hiera,${MODRUBY_FLAVOR} \
sysutils/ruby-facter>=2.0.1p0
Index: patches/patch-lib_puppet_network_http_rack_rest_rb
===================================================================
RCS file: patches/patch-lib_puppet_network_http_rack_rest_rb
diff -N patches/patch-lib_puppet_network_http_rack_rest_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_puppet_network_http_rack_rest_rb 27 May 2016 08:15:42 -0000
@@ -0,0 +1,31 @@
+$OpenBSD$
+
+Make puppet trusted facts available when running with unicorn behind
+nginx or apache
+
+--- lib/puppet/network/http/rack/rest.rb.orig Fri May 27 10:11:44 2016
++++ lib/puppet/network/http/rack/rest.rb Fri May 27 10:11:50 2016
+@@ -92,7 +92,22 @@ class Puppet::Network::HTTP::RackREST
+ # NOTE: The SSL_CLIENT_CERT environment variable will be the empty string
+ # when Puppet agent nodes have not yet obtained a signed certificate.
+ if cert.nil? || cert.empty?
+- nil
++ # When running with unicorn, the SSL_CLIENT_CERT variable is not available
++ # in the environment, therefore we have to pass a header: 'X-SSL-Client-Cert'
++ cert = request.env['HTTP_X_SSL_CLIENT_CERT']
++ if cert.nil? || cert.empty?
++ nil
++ else
++ # in contrast to the environment variable, the client cert is passed in
++ # as single string, therefore restore the certificate to a valid pem
++ # encoded certificate
++ cert.gsub!(/ /, "\n")
++ cert.gsub!(/BEGIN\nCERT/, "BEGIN CERT")
++ cert.gsub!(/END\nCERT/, "END CERT")
++ cert = Puppet::SSL::Certificate.from_instance(OpenSSL::X509::Certificate.new(cert))
++ warn_if_near_expiration(cert)
++ cert
++ end
+ else
+ cert = Puppet::SSL::Certificate.from_instance(OpenSSL::X509::Certificate.new(cert))
+ warn_if_near_expiration(cert)
Index: patches/patch-lib_puppet_ssl_certificate_rb
===================================================================
RCS file: patches/patch-lib_puppet_ssl_certificate_rb
diff -N patches/patch-lib_puppet_ssl_certificate_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_puppet_ssl_certificate_rb 27 May 2016 08:15:42 -0000
@@ -0,0 +1,16 @@
+$OpenBSD$
+
+Make certificate extension available in puppet manifests
+
+--- lib/puppet/ssl/certificate.rb.orig Wed May 25 08:13:50 2016
++++ lib/puppet/ssl/certificate.rb Wed May 25 08:14:35 2016
+@@ -60,6 +60,8 @@ DOC
+ Puppet::SSL::Oids.subtree_of?('ppPrivCertExt', ext.oid)
+ end
+
+- custom_exts.map { |ext| {'oid' => ext.oid, 'value' => ext.value} }
++ extensions = []
++ custom_exts.map { |ext| extensions << {'oid' => ext.oid, 'value' => ext.value} }
++ return extensions
+ end
+ end