The Puppet integration has been unchanged for some time. There are various improvements possible. In this document I intend to first describe the current situation and various things we can improve. The overall goal is to decouple components to allow for more flexible installation and support more deployment scenarios.
There are four possible (optional) integration points. For maximum integration, these are currently all deployed by default in the installer.
Two of them are deployed via our foreman::puppetmaster Puppet class. Both live in the same Foreman Puppet module and are configured via /etc/puppetlabs/puppet/foreman.yaml
. They use client certificates to authenticate directly to the Foreman. On the Foreman side it's checked that the hostname on the certificate is a valid Foreman Proxy.
These are mostly contributed by the community.
Puppetserver allows using an External Node Classifier (ENC). The Foreman ENC implementation is pretty straight forward standalone Ruby script that's usually deployed to /etc/puppetlabs/puppet/node.rb
on the Puppetserver. This integration is clean because there's a well defined boundry and interface between Puppet and our script.
In the typical deployment the Puppetserver calls node.rb $AGENT_HOSTNAME
on every Puppet agent catalog compilation to get the ENC. Our script reads the facts from disk (as created by Puppetserver) and sends them to Foreman. This can result in creating a host in Foreman and ensures any Foreman parameters that depend on facts are correct.
An alternative deployment is as a watcher where it uses inotify to receive events about new host facts. This allows integration without being an ENC.
The reporting script is deployed by dropping it in a Ruby library directory. It's the one we've used for many years and generally it's stable but it isn't very clean. If the Ruby version changes, it sometimes needs to be redeployed but in the Puppet AIO installation the path is stable.
It has built up some cruft and still has all the code to handle ancient Puppet reports since that was never removed. That means it'll likely still work with Puppet 0.25.
On the Foreman Proxy side we have two features each with multiple providers.
The Foreman Proxy Puppet feature is responsible for providing an API to Foreman with information about the Puppet environment.
First of all, there's the Run support. This was originally exposing the (now removed) puppet kick functionality. There are multiple providers, such as MCO, Salt, SSH, customrun that still work. On the Foreman side there's a global setting to show the Puppet run button, even if the particular Foreman Proxy doesn't support it.
The other side is listing Puppet environments and its classes. The first provider is the legacy implementation which loads the Puppet gem to parse classes. The current implementation queries the Puppetserver REST API.
A Puppetserver can also be a CA. In Foreman this is exposed as a separate feature since Puppet agents can use a different CA server than the compile server.
The API it exposes to Foreman allows managing certificates. This means listing and revoking certificates as well as dealing with Certificate Signing Requests.
The classic provider, that is still the default, implements autosigning of CSRs. To do this, it modifies /etc/puppetlabs/puppet/autosign.conf
and places the hostname of servers to provision. This introduces a race condition where an attacker can present a certificate before the actual server and receive a certificate. Foreman tried to handle this by making this window as small as possible, but there's a better solution.
The modern provider uses tokens to securely authenticate. While provisioning a server, Foreman creates a JWT which is signed. This is sent to the Foreman Proxy which can independently verify it's a valid token. It is also sent in the provision template so the agent can embed it in the CSR as a challengePassword. The Puppet CA server is configured to call back to the Foreman proxy which verifies or rejects the token. All this communication happens over TLS secured HTTP connections which means a shared filesystem is no longer required. It also replaces the trivial to spoof hostnames authentication.
On the Foreman side a host can be assigned a Foreman Proxy as a Puppet server. For this the Foreman Proxy needs to expose the Puppet feature. The same can be done for a Puppet CA server. To clients the Foreman Proxy hostname is communicated as the Puppet (CA) hostname.
These implementations have certain drawbacks. First of all, they require the Foreman Proxy and Puppetserver to share a hostname and in the case of the classic signing provider a shared filesystem. This makes scaling by clustering harder. It also doesn't allow multi homing where a separate network is used for Foreman to Proxy communication. The user is also required to use our Puppet module (directly or via the installer) or manually extract it.
There are various steps we can take and many of them can be implemented independently.
Support for Puppet 3 was dropped with 1.19 but the legacy Puppet implementation is still part of the Foreman Proxy codebase. It's time to drop this. This will allow us to drop the Puppet gem which greatly simplifies the testing matrix. It also removes a lot of code.
This is mostly unrelated to the other proposals.
Unlike the Foreman scenario, the Katello scenario doesn't depend on the Puppet CA for certificates. That means it's possible to not deploy it, saving a lot of resources. The advice would be to always deploy it on a Proxy.
Due to a technical limitation it's currently not possible to disable the module and have the correct defaults when enabled. It makes sense to remove this limitation, but it should be considered to fully drop Puppetserver support from the scenario.
Using the new proxy registation protocol, we can expose the Puppet URLs. This allows Foreman to decouple from the Proxy's hostname and provision hosts with the correct Puppet URLs.
Decoupling the Puppetserver and Foreman Proxy hostnames removes one limitation of deploying them on separate machines.
TODO: change from registration PR to final URL
While it's been discussed many times, but it never materialized. Alternative deployment scenarios in mind, it's time for a separate package. It could be a standalone git repository which is delivered as a tarball, RPM and DEB. The currently Puppet module will change from installing raw files to ensuring a package. The modern signing provider has a script that now lives in the smart-proxy git repository. This should be part of the same package.
This allows deploying outside of the installer context and move a lot of test code out of the puppet-foreman repository.
For many of the listed benefits, this provider is clearly superior. Adoption will be higher if it's the default.
Foreman already deploys the challengePassword in the CSR by default, even if it won't be used. That means it will involve making sure the users have the correct permissions to read various files and configuring Puppetserver to use the callback script.
Decoupling the Foreman Proxy filesystem from the Puppet filesystem removes one limitation of deploying them on separate machines.
Puppet Enterprise supports load balanced setups. Some people may want to deploy in containers. We should allow this. With the above we've removed the limitations that prevented to do this.
The challenges will be to make sure the Puppetservers have the correct configuration deployed and have the right credentials. Ideally it'd only talk to the Foreman Proxy and never to the Foreman itself.
Possible considerations are reading reports from other sources, such as PuppetDB.