Setting Up SSL for Running Foreman on HTTPS

I’ve now tried it out. There are some considerations to take into account. I’ll list those at the bottom.

Using localhost gem without client certificates

This is the most minimal developer setup, but it doesn’t allow you to use client certificates from Smart Proxies.

First make sure the localhost gem is loaded:

cat > bundler.d/localhost.local.rb <<EOF
group :development do
  # For HTTPS certificates with bundler
  gem 'localhost'
end
EOF

Now start the process

BIND=ssl://localhost:5000 bundle exec foreman start

Verify it works:

curl --cacert ~/.localhost/localhost.crt https://localhost:5000

As you can see in the curl example, the certificates were placed in ~/.localhost. You can use these same certificates in the Smart Proxy.

Limitations

Serving both HTTP & HTTPS

Right now there is no way to bind to both HTTP and HTTPS in this setup. Puma can do this, but we don’t have config options exposed right now.

You can drop something like this in config/puma/development.rb and force it though:

port ENV.fetch('FOREMAN_PORT', '3000'), ENV['FOREMAN_BIND']

ssl_bind ENV.fetch('FOREMAN_HOST', 'localhost'), ENV.fetch('FOREMAN_SSL_PORT', '5000'), {
  cert: ENV.fetch('FOREMAN_SSL_CERT', nil),
  key: ENV.fetch('FOREMAN_SSL_KEY', nil),
  verify_mode: 'peer',
}

No client certificates

Puma will present the client certificate in the environment as puma.peercert so you can set ssl_client_cert_env to that, but Puma doesn’t send a simple status in the environment.

I think this simple patch should work:

diff --git a/app/services/foreman/client_certificate.rb b/app/services/foreman/client_certificate.rb
index d463d1cef..ac650421d 100644
--- a/app/services/foreman/client_certificate.rb
+++ b/app/services/foreman/client_certificate.rb
@@ -29,6 +29,10 @@ module Foreman
     end
 
     def verify
+      # Puma doesn't provide the verify status, but assume it passed if the
+      # cert is there
+      return 'SUCCESS' if certificate_env_key == 'puma.peercert' && raw_cert_available?
+
       request.env[verify_key]
     end
 

I then also set the following in config/settings.yaml:

:ssl_client_cert_env: puma.peercert
:ssl_certificate: /home/ekohl/.localhost/localhost.crt
:ssl_ca_file: /home/ekohl/.localhost/localhost.crt
:ssl_priv_key: /home/ekohl/.localhost/localhost.key

With this I could at least register a Smart Proxy on localhost using the same certificates, but I haven’t verified if the auth actually works.

No NodeJS

I didn’t configure NodeJS yet to serve HTTPS.