LetsEncrypt is probably one of the best things that has happened to the Internet. However, in a homelab, it can be complex to manage ssl certificates to encrypt all your data internally too. This post details how I set up an internal ACME server using Step-CA. I won’t cover using clients with it yet, maybe in another post.
The setup code
Straight to the meat, I can show you the chef recipe I’m using to set up step-ca. It will install step-ca according to the specified version, and enable a systemd service file.
version = '0.13.3'
ruby_block "check-installed-step-ca-version" do
block do
require 'mixlib/shellout'
# find the executable
file = "/usr/bin/step-ca"
if File.exists?(file)
step_ca_command = Mixlib::ShellOut.new('/usr/bin/step-ca -v')
step_ca_command.run_command
found_version = step_ca_command.stdout.split("\n").first.match(/Smallstep CA\/(.*)-dev.*/)[1]
node.default['step_ca']['version'] = found_version
else
node.default['step_ca']['version'] = "0"
end
end
end
group 'step-ca' do
gid 5002
end
user 'step-ca' do
comment 'Step CA server'
uid 5002
gid 5002
home '/srv/step-ca'
shell '/bin/bash'
end
directory '/srv/step-ca' do
owner 'step-ca'
group 'step-ca'
mode '0750'
end
directory "/etc/step-ca" do
owner 'step-ca'
group 'step-ca'
mode '0750'
end
package_file = "/opt/step-certificates_#{version}_amd64.deb"
# https://github.com/smallstep/certificates/releases/download/v0.13.3/step-certificates_0.13.3_amd64.deb
remote_file package_file do
source "https://github.com/smallstep/certificates/releases/download/v#{version}/step-certificates_#{version}_amd64.deb"
owner 'root'
group 'root'
mode '0640'
not_if { node['step_ca']['version'] == version }
action :create
notifies :install, 'package[step-ca]', :immediately
end
package 'step-ca' do
source package_file
action :nothing
end
file "delete_step-certificates_deb" do
path package_file
action :delete
end
cookbook_file '/etc/systemd/system/step-ca.service' do
source 'step-ca.service'
owner 'root'
group 'root'
mode '0440'
notifies :run, 'execute[systemd-reload]', :immediately
end
execute 'systemd-reload' do
command 'systemctl daemon-reload'
action :nothing
end
service 'step-ca' do
action :enable
end
It is actually remarkably easy to set up, and get running. There’s only one manual step, configuring the password to start the service itself. I chose to put it into a config file so that the software can automatically start up. It’s only readable by the app service, so it’s as safe as I can make it. The systemd service follows.
[Unit]
Description=Step Certificate Authority Server
Wants=network-online.target
After=network-online.target
[Service]
User=step-ca
Group=step-ca
Type=simple
ExecStart=/usr/bin/step-ca /srv/step-ca/.step/config/ca.json \
--password-file /etc/step-ca/password
[Install]
WantedBy=multi-user.target
Why should you use this?
This is probably the 4th thing I have tried to use to manage SSL certificates in my homelab. I have used easyrsa by the OpenVPN project, which has gone through about 3 major revisions since I used it. None of them were automated, but it was reasonably easy to set up. Using an internal ACME server using step-ca will make things so much easier. There are many ACME clients at this point that I can use to get certificates, including the step client itself.
No longer will I have to encrypt private certs inside of chef-vault. I can rely on the ACME Protocol to automatically get certificates for each host on my network. It can even be used by applications to secure themselves that way. Especially when I get into an app deployment system, like kubernetes, or something like that. Being able to issue internal SSL certificates automatically to keep all my stuff TLS encrypted is going to be awesome.