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

Reply via email to