Skip to content

Certificate Management

Watchdog uses a shared PKI to secure its own HTTPS API, the Kafka external listener, and Elasticsearch with a single CA and server certificate. The PKI is generated by init-pki.sh during install and lives at /opt/watchdog/pki/ on the host.

This page covers the two changes operators most commonly need to make after install:

  1. Replace the TLS certificate (with your own, or a freshly rotated one).
  2. Rotate the Kafka SASL password.

PKI Layout

File Purpose
ca.crt, ca.key Self-signed root CA (10-year validity)
server.crt, server.key Server certificate signed by the CA — used by Watchdog, Kafka, and Elasticsearch
kafka.keystore.p12 PKCS12 bundle (server cert + key) consumed by Kafka
kafka.truststore.p12 PKCS12 bundle (CA cert) consumed by Kafka
kafka_store_pass.env PKCS12 store password — read by watchdog-installer.sh and written to .env as KAFKA_STORE_PASS so Compose can substitute it into the Kafka container config

The same /opt/watchdog/pki directory is mounted read-only into all three containers.


What the Bundled Certificate Covers

The certificate generated during installation includes the following Subject Alternative Names (SANs):

Type Values
DNS localhost, watchdog, kafka, kafka-connect, elasticsearch, mongo
IP 127.0.0.1

These cover internal connections between containers and connections from the same VM. They do not include the customer-reachable hostname or IP that BrowserMon controllers connect to over the network.

By default BrowserMon controllers connect to Watchdog with strict TLS verification disabled (verify=false), so the bundled certificate works out of the box without further configuration. If you turn verify=true on the controller side, the controller will check that the hostname or IP it dialed against appears in the certificate's SAN list — and the bundled certificate will fail that check unless your reachable address is present.

You have two options:

1. Add your address to the certificate (recommended). Edit the SAN entries in ssl_config.ini:

[SSLConfig]
subject.CN = localhost

san.dns = watchdog.example.com, watchdog-2.internal
san.ip  = 10.0.0.42, 192.168.1.10

Both keys accept comma-separated lists. The bundled internal hostnames stay in place — your entries are appended to them.

The right file to edit depends on when you make the change:

  • Before installing (recommended): open ssl_config.ini from the TUI's Edit config dropdown during the first-boot setup. The TUI edits /opt/watchdog-release/deps/watchdog/ssl_config.ini, which is the same file the installer reads when it generates the certificate. Save and click Install — the SANs are baked in automatically.

  • After installing: the certificate has already been generated, so editing alone has no effect. You must regenerate it. Edit /opt/watchdog-release/deps/watchdog/ssl_config.ini directly (not the runtime copy at /opt/watchdog/watchdog/ssl_config.ini — that one is only used as a container mount target and is ignored by the certificate generator), then run:

    cd /opt/watchdog-release
    sudo docker compose -f docker-compose.base.yml down
    sudo ./scripts/init-pki.sh --out-dir /opt/watchdog/pki --config ./deps/watchdog/ssl_config.ini --force
    sudo docker compose -f docker-compose.base.yml up -d
    

    Add the other compose files (-f docker-compose.kafka.yml -f docker-compose.elastic.yml -f docker-compose.eti.yml -f docker-compose.ucs.yml) to both commands if those services are running. The PKCS12 store password is reused, so .env does not need updating.

2. Replace the certificate with one issued by your internal or public CA whose SANs include your reachable hostname/IP. See Replacing the TLS Certificate below.


Replacing the TLS Certificate

Use this when you want to install a certificate signed by your own internal or public CA, or when rotating the existing one.

All commands assume you are in the release directory (the directory containing the compose files and .env). On the OVA this is /opt/watchdog-release. Adjust the list of -f flags to match the compose files you have installed.

  1. Stop the running containers.

    sudo docker compose \
        -f docker-compose.base.yml \
        -f docker-compose.kafka.yml \
        -f docker-compose.elastic.yml \
        -f docker-compose.eti.yml \
        -f docker-compose.ucs.yml \
        down
    
  2. Replace server.crt and server.key with your new pair.

    sudo cp my-cert.crt /opt/watchdog/pki/server.crt
    sudo cp my-cert.key /opt/watchdog/pki/server.key
    sudo chmod 644 /opt/watchdog/pki/server.crt
    sudo chmod 600 /opt/watchdog/pki/server.key
    
  3. Rebuild the Kafka PKCS12 bundle (Kafka cannot read PEM directly).

    source /opt/watchdog/pki/kafka_store_pass.env   # exports KAFKA_STORE_PASS
    
    sudo openssl pkcs12 -export \
        -in       /opt/watchdog/pki/server.crt \
        -inkey    /opt/watchdog/pki/server.key \
        -certfile /opt/watchdog/pki/ca.crt \
        -name     kafka \
        -out      /opt/watchdog/pki/kafka.keystore.p12 \
        -passout  "pass:$KAFKA_STORE_PASS"
    
  4. Start the stack again with the same set of compose files used in step 1.

    sudo docker compose \
        -f docker-compose.base.yml \
        -f docker-compose.kafka.yml \
        -f docker-compose.elastic.yml \
        -f docker-compose.eti.yml \
        -f docker-compose.ucs.yml \
        up -d
    

Note: If your replacement certificate was signed by an external CA, also copy that CA's cert over /opt/watchdog/pki/ca.crt and rebuild kafka.truststore.p12 the same way (use openssl pkcs12 -export -nokeys).

Quick rotation (keep the bundled CA)

If you just want to rotate the server cert and keep using the bundled CA, run init-pki.sh with --force from the release directory (/opt/watchdog-release on the OVA):

cd /opt/watchdog-release
sudo docker compose -f docker-compose.base.yml down
sudo ./scripts/init-pki.sh --out-dir /opt/watchdog/pki --config ./deps/watchdog/ssl_config.ini --force
sudo docker compose -f docker-compose.base.yml up -d

Add the other compose files (-f docker-compose.kafka.yml -f docker-compose.elastic.yml -f docker-compose.eti.yml -f docker-compose.ucs.yml) to both commands if those services are running.

--force regenerates server.crt and server.key and rebuilds the Kafka PKCS12 stores. The existing ca.crt is preserved. Re-running init-pki.sh --force reuses the existing PKCS12 store password from kafka_store_pass.env, so .env does not need updating.

Watchdog logs WD1011 as a WARNING when fewer than 60 days remain on the certificate — this is your cue to rotate.


Rotating the Kafka SASL Password

The Kafka external listener (8092/tcp) uses SASL_SSL with PLAIN authentication. Default credentials:

Field Value
Username browsermon
Password browsermon

The credentials are defined inline in /opt/watchdog-release/docker-compose.kafka.yml:

KAFKA_LISTENER_NAME_EXTERNAL_PLAIN_SASL_JAAS_CONFIG: |
  org.apache.kafka.common.security.plain.PlainLoginModule required
    username="browsermon" password="browsermon" user_browsermon="browsermon";

To rotate the password:

  1. Edit /opt/watchdog-release/docker-compose.kafka.yml and change all three occurrences of the password (username=, password=, and user_browsermon=) to the same new value.

  2. Recreate the kafka container.

    cd /opt/watchdog-release
    sudo docker compose -f docker-compose.kafka.yml up -d --force-recreate kafka
    
  3. Update each BrowserMon controller's Kafka password configuration to match before the controllers reconnect, otherwise they will fail to authenticate. Refer to the BrowserMon controller documentation for the exact setting name.

Note: /opt/watchdog/pki/kafka_store_pass.env and the KAFKA_STORE_PASS line in .env are the PKCS12 store password — not the SASL password. They are managed by init-pki.sh and watchdog-installer.sh and do not need to be touched when rotating SASL.