An example runbook that handles SSL cert rotation
#!/usr/bin/env ruby | |
require "runbook" | |
host = ENV["HOST"] # e.x. ldap01.stg | |
raise "Error no host specified using HOST env var" unless host | |
service = ENV["SERVICE"] # e.x. slapd | |
raise "Error no service specified using SERVICE env var" unless service | |
local_user = ENV["USER"] | |
company_name = "patricks_pickles" | |
intermediate_ca_path = "/root/ca/intermediate" | |
local_git_dir = "/home/#{local_user}/dev/#{company_name}/pp-infrastructure" | |
local_cert_path = "modules/ldap/files" | |
local_cert_file = "#{host}_#{service}.cert.pem" | |
staging_suffix = "#{company_name}-staging.com" | |
prod_suffix = "#{company_name}.com" | |
runbook = Runbook.book "Renew SSL Certs" do | |
description <<-DESC | |
This Runbook rotates SSL Certs. | |
DESC | |
layout [[:runbook, :commands]] | |
section "Setup" do | |
step { ruby_command { @env = host.split(".").last.to_sym } } | |
end | |
section "Create New Cert" do | |
user "root" | |
step "Backup and update index.txt" do | |
capture %Q{ls #{intermediate_ca_path}/index.txt.old* | tail -n 1 | sed -E "s/.*([0-9]{2})/\\1/"}, into: :backup_num | |
ruby_command do | |
@backup_num = (backup_num.to_i + 1).to_s.rjust(2, "0") | |
command "cp #{intermediate_ca_path}/index.txt #{intermediate_ca_path}/index.txt.old#{@backup_num}" | |
command "cp #{intermediate_ca_path}/index.txt.attr #{intermediate_ca_path}/index.txt.attr.old#{@backup_num}" | |
command %Q{sed -i "/#{host} #{service.upcase}/d" #{intermediate_ca_path}/index.txt} | |
end | |
end | |
step "Generate new cert" do | |
ruby_command do | |
case env | |
when :stg | |
@expiration_days = 1035 | |
when :prod | |
@expiration_days = 1095 | |
else | |
raise "Unknown env: #{env}" | |
end | |
tmux_command "sudo openssl ca -config #{intermediate_ca_path}/openssl.cnf -extensions server_cert -days #{@expiration_days} -notext -md sha256 -in #{intermediate_ca_path}/csr/#{host}_#{service}.csr.pem -out #{intermediate_ca_path}/certs/#{local_cert_file}", :commands | |
confirm "Have you generated the cert?" | |
end | |
command "sudo chmod 444 #{intermediate_ca_path}/certs/#{local_cert_file}" | |
tmux_command "sudo openssl x509 -noout -text -in #{intermediate_ca_path}/certs/#{local_cert_file}", :commands | |
confirm "Does the cert look correct?" | |
tmux_command "sudo openssl verify -CAfile #{intermediate_ca_path}/certs/ca-chain.cert.pem #{intermediate_ca_path}/certs/#{local_cert_file}", :commands | |
confirm "Is the cert valid?" | |
end | |
end | |
section "Upload Cert" do | |
step "Copy the cert to pp-infrastructure" do | |
user "root" | |
command "cp #{intermediate_ca_path}/certs/#{local_cert_file} #{local_git_dir}/#{local_cert_path}" | |
command "chown #{local_user}:#{local_user} #{local_git_dir}/#{local_cert_path}/#{local_cert_file}" | |
end | |
step "Upload the cert" do | |
server host | |
upload "#{local_git_dir}/#{local_cert_path}/#{local_cert_file}", to: "/home/#{local_user}" | |
end | |
step "Install the cert" do | |
server host | |
user "root" | |
command "mv ~#{local_user}/#{local_cert_file} /etc/ssl" | |
command "chown root:ssl-cert /etc/ssl/#{local_cert_file}" | |
command "chmod 444 /etc/ssl/#{local_cert_file}" | |
command "cp /etc/ssl/#{local_cert_file} /etc/ssl/certs" | |
end | |
step "Restart the service" do | |
server host | |
user "root" | |
command "service #{service} restart" | |
end | |
step "Validate the service cert is valid" do | |
ruby_command do | |
case env | |
when :stg | |
@suffix = staging_suffix | |
when :prod | |
@suffix = prod_suffix | |
else | |
raise "Unknown env: #{env}" | |
end | |
tmux_command "ssh #{host}", :commands | |
tmux_command "openssl s_client -connect #{host}.#{@suffix}:12345 -CApath /etc/ssl/certs", :commands | |
confirm "Is the cert valid?" | |
end | |
end | |
step "Commit cert changes" do | |
path "#{local_git_dir}" | |
command "git add #{local_cert_path}/#{local_cert_file}" | |
command %Q{git commit -m "Update #{local_cert_file} certificate"} | |
command "git push" | |
end | |
end | |
end | |
if __FILE__ == $0 | |
Runbook::Runner.new(runbook).run | |
else | |
runbook | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment