Skip to content

Document why OpenVox Server overwrites hostcrl, and the workaround when the agent trusts a different CA #488

Description

@miharp

Summary

A recent Slack thread asked why OpenVox Server rewrites /etc/puppetlabs/puppet/ssl/crl.pem every time it starts, and whether that is a bug. It is deliberate, and the docs mention it in one sentence, but they don't say why it happens, that it also happens while the server is running, or what to do when it gets in the way.

Source of truth (openvox-server):

  • services/master/master_service.clj: on every start the master service calls retrieve-ca-cert! and then retrieve-ca-crl!.
  • puppetserver/certificate_authority.clj: retrieve-ca-cert! copies cacert to localcacert only when localcacert does not exist. retrieve-ca-crl! has no such check: whenever cacrl exists and cacrl and hostcrl are different paths, it validates the cacrl content and writes it over hostcrl.
  • services/ca/certificate_authority_service.clj: the CA service also registers a file watcher on the cacrl directory and runs the same copy whenever cacrl changes (for example after a revocation), so the overwrite is not limited to start time.
  • services/config/puppet_server_config_core.clj (init-webserver!): when webserver.conf sets none of the ssl-* settings, Jetty's ssl-crl-path is taken from hostcrl. That is the reason for the copy: it is how revocations reach the TLS layer that authenticates clients.

Gaps

1. The cacrl and hostcrl sections understate the copy

docs/_openvox-server_8x/puppet_conf_setting_diffs.markdown and the 9.x copy say, under both cacrl and hostcrl:

At start time, OpenVox Server copies the file for the cacrl setting, if one exists, over to the location in the hostcrl setting.

Missing:

  • the copy also runs whenever the cacrl file changes while the server is running;
  • it always overwrites an existing hostcrl, unlike the CA certificate, which is only copied when localcacert is missing;
  • the reason: the web server reads hostcrl, so this copy is what makes a revocation take effect for client authentication.

2. Nothing covers a server whose agent trusts a different CA

hostcrl is shared by the agent and the server on the same host. That is fine when both belong to the same CA. It breaks when they don't, for example while building a new CA server that is still managed as an agent of an existing one:

  • the agent's certificate and localcacert come from the old CA, and are left alone because localcacert already exists;
  • each start of the new server (and each change to its cacrl) replaces the agent's CRL with the new CA's CRL;
  • the next agent run fails revocation checking, because the CRL on disk was not issued by the CA in the agent's chain;
  • deleting crl.pem fixes it until the next restart, because the agent downloads the CRL again when the file is missing. Otherwise the agent only refreshes it after crl_refresh_interval (default one day), so it does not repair itself on the next run.

The workaround is to give the server its own CRL path in puppet.conf so the two roles stop sharing a file:

[server]
hostcrl = /etc/puppetlabs/puppetserver/ca/host_crl.pem

The agent keeps $ssldir/crl.pem. Jetty follows the [server] value unless webserver.conf sets ssl-* settings explicitly, in which case ssl-crl-path applies instead. This should be tested in a lab before it goes into the docs.

Proposed fix

One PR touching the 8.x and 9.x copies of puppet_conf_setting_diffs.markdown:

  • expand the shared cacrl / hostcrl text to cover the overwrite, the file watcher, and the reason for the copy;
  • add a short note on the mismatched-CA case with the [server] hostcrl workaround, once verified;
  • cross-link from the hostcrl mentions in docs/_openvox_9x/dirs_ssldir.markdown and config_ssl_external_ca.markdown (and the 8.x copies) if the note fits there.

Assisted by Claude.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions