Skip to content

Instantly share code, notes, and snippets.

@jbontech
Forked from fm-jason/_readme.md
Created August 2, 2020 19:12
Show Gist options
  • Save jbontech/f05ff1fb9ef26de6d832f7368d8c52e8 to your computer and use it in GitHub Desktop.
Save jbontech/f05ff1fb9ef26de6d832f7368d8c52e8 to your computer and use it in GitHub Desktop.
Salt SSL Certificate Deployment

Overview

This gist provides a quick overview of deploying SSL certificates to servers using Salt. I use a wildcard certificate for our domain, which makes management easier.

Quick Start

  1. Start with pillar_ssl-certificate.sls, which should be populated with your certificates and placed in Salt's pillar_roots directory (typically /srv/pillar).
  2. Place state_ssl-certificate.sls in Salt's file_roots directory (typically /srv/salt).
  3. Include the contents of top.sls in both the pillar and state top.sls file. (Modify for your minion IDs of course.)

Details

Use pillars to distribute sensitive data, such as SSL certificates. Accoring to the Salt Pillar Walkthrough:

Information transferred via pillar is guaranteed to only be presented to the minions that are targeted, making Pillar suitable for managing security information, such as cryptographic keys and passwords.

Also read through Salt Best Practices: Storing Secure Data.

Make sure to match minion IDs in the pillar file, not grains! (See is targeting using grain data secure?)

I have embedded the file contents directly in the pillar SLS and used contents_pillar in the state SLS. Since I'm also defining the owning user and group, filenames, and permissions, this keeps everything together. PEM encoding works best, by the way.

You'll notice that I am maintaining symlinks (current.{crt,key}) to the certificate files. This allows me to point service configuration files to the symlinks, which in turn allows me to keep older certificate versions on the server for troubleshooting and easy roll-back without touching service config files. This also means that service.running has to watch the symlinks and the certificate files to trigger a restart under all necessary circumstances.

For service auto-restart, define ssl.services for each minion. These don't have to be assigned as pillars (they could be grains or state variables), but I find it's easiest to use pillars. I have included an example ~pillar_top.sls segment, which references ~pillar_web-server.sls. (Place under pillar_roots.) The nice thing is, ssl.services is addtive, so you can assign services to the same minion in multiple SLS files, and they will simply append to the existing list.

Notes

  • If your certificate chain includes intermediate certificates, remember to include the entire chain (sans root) in cert.contents. (See RFC 5246.)
  • The leading pillar_, state_, etc. in the gist filenames should be stripped. (These are used to organize this gist.)
  • The exercise of deploying separate certificates to individual minions is left to the reader.
ssl:
user: root
group: root
cert:
filename: 'public.20160505.crt'
mode: 444
contents: |
-----BEGIN CERTIFICATE-----
BASE64
-----END CERTIFICATE-----
key:
filename: 'public.20160505.key'
mode: 400
contents: |
-----BEGIN PRIVATE KEY-----
BASE64
-----END PRIVATE KEY-----
Server Public Cert:
file.managed:
- name: /etc/ssl/private/{{ pillar['ssl']['cert']['filename'] }}
- user: {{ pillar['ssl']['user'] }}
- group: {{ pillar['ssl']['group'] }}
- mode: {{ pillar['ssl']['cert']['mode'] }}
- contents_pillar: ssl:cert:contents
Server Private Key:
file.managed:
- name: /etc/ssl/private/{{ pillar['ssl']['key']['filename'] }}
- user: {{ pillar['ssl']['user'] }}
- group: {{ pillar['ssl']['group'] }}
- mode: {{ pillar['ssl']['key']['mode'] }}
- contents_pillar: ssl:key:contents
/etc/ssl/private/current.crt:
file.symlink:
- target: {{ pillar['ssl']['cert']['filename'] }}
- watch:
- file: Server Public Cert
/etc/ssl/private/current.key:
file.symlink:
- target: {{ pillar['ssl']['key']['filename'] }}
- watch:
- file: Server Private Key
{% for svc in pillar['ssl']['services'] %}
Restart SSL service {{svc}}:
service.running:
- name: {{svc}}
- enable: True
- full_restart: true
- watch:
- file: /etc/ssl/private/current.key
- file: /etc/ssl/private/current.crt
- file: Server Public Cert
- file: Server Private Key
{% endfor %}
base:
# Include the following in both the Pillar and State 'top.sls'
'ssl server ID list goes here':
- ssl-certificate
base:
'web server ID list':
- web-server
ssl:
services:
- nginx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment