Certificate Management

saltext-nebula provides comprehensive certificate lifecycle management, from initial generation through automatic renewal.

Certificate Generation

Certificates are generated on the Salt master using the nebula runner and distributed to minions via the Salt fileserver.

Manual Generation

Generate a certificate for a specific minion:

# Generate using pillar configuration
salt-run nebula.get_certificate minion_id=web01

# The certificate is automatically placed in the Salt fileserver
# at salt://nebula/certs/web01.crt and salt://nebula/certs/web01.key

The runner reads the minion’s configuration from pillar and generates a certificate with:

  • The IP address specified in pillar

  • Group memberships for firewall rules

  • The configured validity duration

  • Optional subnet assignments

Certificate Parameters

Certificate properties are defined in pillar:

nebula:
  hosts:
    web01:
      ip: "10.10.10.50/24"         # Required: Nebula IP address
      groups:                       # Optional: Security groups
        - "web"
        - "production"
      subnets:                      # Optional: Routable subnets
        - "192.168.1.0/24"
      duration: "8760h"             # Optional: Validity (default: 720h / 30 days)

Batch Generation

Generate certificates for multiple minions:

# Using shell loop
for minion in web01 web02 db01 db02; do
    salt-run nebula.get_certificate minion_id=$minion
done

# Or via orchestration
salt-run state.orchestrate orch.generate_certs

Certificate Distribution

Certificates are distributed to minions via the certificates_present state.

Basic Distribution

nebula_certificates:
  nebula.certificates_present:
    - name: nebula_certs

This state:

  1. Checks if certificates exist locally

  2. Validates existing certificates against the CA

  3. Downloads new certificates from salt://nebula/certs/ if needed

  4. Sets appropriate file permissions

  5. Validates the deployed certificate chain

Distribution Options

nebula_certificates:
  nebula.certificates_present:
    - name: nebula_certs_{{ grains['id'] }}
    - minion_id: {{ grains['id'] }}          # Default: current minion
    - cert_dir: /etc/nebula                   # Default: auto-detected
    - force_regenerate: false                 # Force fresh download
    - auto_renew: true                        # Check expiration
    - renewal_threshold_days: 30              # Days before expiry to renew
    - backup_old_certs: true                  # Backup before replacing
    - validate_after_deploy: true             # Verify chain after deployment

Certificate Validation

Check Certificate Status

# Comprehensive status check
salt web01 nebula.check_certificate_status

# Output includes:
# - Certificate existence
# - Key existence
# - CA existence
# - Expiration date
# - Days until expiry
# - Validity status

Validate Certificate Chain

# Verify certificate was signed by the CA
salt web01 nebula.validate_certificate

# Validate specific files
salt web01 nebula.validate_certificate \
    cert_path=/etc/nebula/web01.crt \
    ca_path=/etc/nebula/ca.crt

Parse Certificate Details

# Get expiration information
salt web01 nebula.parse_cert_expiry cert_path=/etc/nebula/web01.crt

Certificate Renewal

Manual Renewal

# Check if renewal is needed
salt web01 nebula.cert_needs_renewal buffer_days=30

# Regenerate on master
salt-run nebula.get_certificate minion_id=web01

# Redeploy to minion
salt web01 state.apply nebula

Automatic Renewal

The nebula beacon monitors certificate expiration and fires events when renewal is needed.

Configure the Beacon

On minions, add to /etc/salt/minion.d/beacons.conf:

beacons:
  nebula:
    - interval: 86400              # Check every 24 hours
    - renewal_threshold_days: 30   # Alert when < 30 days remaining

Or manage via Salt:

configure_nebula_beacon:
  file.managed:
    - name: /etc/salt/minion.d/beacons.conf
    - contents: |
        beacons:
          nebula:
            - interval: 86400
            - renewal_threshold_days: 30

Beacon Events

When a certificate is within the renewal threshold, the beacon fires:

Tag: salt/beacon/web01/nebula/cert/expiring
Data:
  minion_id: web01
  cert_path: /etc/nebula/web01.crt
  days_until_expiry: 25
  expires_at: 2025-02-15T00:00:00
  renewal_threshold_days: 30
  needs_renewal: true
  reason: "Certificate expires in 25 days (within 30 day buffer)"

Reactor Configuration

Create a reactor to handle renewal events. Add to /etc/salt/master.d/reactor.conf:

reactor:
  - 'salt/beacon/*/nebula/cert/expiring':
    - /srv/reactor/nebula_renew.sls

Create /srv/reactor/nebula_renew.sls:

# Regenerate certificate on master
regenerate_certificate:
  runner.nebula.get_certificate:
    - minion_id: {{ data['minion_id'] }}

# Trigger state apply on minion
deploy_new_certificate:
  local.state.apply:
    - tgt: {{ data['minion_id'] }}
    - arg:
      - nebula
    - require:
      - runner: regenerate_certificate

Listing Certificates

View all certificates managed by the runner:

salt-run nebula.list_certificates

Output:

success: True
total: 5
certificates:
  - minion_id: web01
    cert_path: /etc/nebula/certs/web01.crt
    key_path: /etc/nebula/certs/web01.key
    key_exists: True
    cert_size: 1234
    modified: 2025-01-15T10:30:00
  - minion_id: web02
    ...

Certificate Backup and Rollback

Automatic Backups

The certificates_present state automatically backs up existing certificates:

nebula_certificates:
  nebula.certificates_present:
    - backup_old_certs: true  # Default

Backups are stored in <cert_dir>/backups/ with timestamps.

Manual Backup

# Create a backup of the current configuration
salt web01 nebula.backup_config

Rollback

If a new certificate causes issues:

# Restore the last known good configuration
salt web01 nebula.rollback_config

CA Management

Initialize a New CA

# Using config defaults
salt-run nebula.ca_init

# With custom options
salt-run nebula.ca_init \
    name="Production Network" \
    duration="87600h" \
    encrypt=True \
    passphrase="secure-passphrase"

Force CA Regeneration

Danger

Regenerating the CA invalidates all existing certificates. All nodes will need new certificates.

salt-run nebula.ca_init force=True

CA Security Best Practices

  1. Always encrypt the CA key - Use nebula.ca_encrypt: true

  2. Secure the passphrase - Consider using a secrets manager

  3. Restrict CA directory permissions - chmod 700 /etc/nebula/ca

  4. Back up the CA - Store encrypted backups securely off-system

  5. Monitor CA access - Audit access to the CA key