CertWatch
A Rails engine to manage and automatically obtain, install and renew SSL certificates.
Ingredients
CertWatch consists of the following components:
- Resque jobs to renew and install certificates.
- A mixin for models with a
cname
attribute to request certificats on attribute change. - Rake tasks to reinstall certificates on a fresh server
Optionally:
- An Active Admin resource to manage certificates.
- An Arbre view component to display certificate status for a given domain.
Requirements
- Rails 4
- Resque
- Resque Scheduler
- Resque Logger
- Certbot
Limitations
- Requires
sudo
on the server. Thecertbot
script used to obtain certificates needs root priviledges. This could probably be avoided by using theacme-client
gem instead. - Works only with webservers that can read certificates from a directory (Tested with HAProxy).
Installation
Add the following lines to your Gemfile
and run bundle install
:
gem 'cert_watch'
# Required since state_machine gem is unmaintained
gem 'state_machine', git: 'https://github.com/codevise/state_machine.git'
Add an initializer:
# config/initializers/cert_watch.rb
CertWatch.setup do |config|
# Uncomment any of the below options to change the default
# Maximum age of certificates before renewal.
# config.renewal_interval = 1.month
# Number of expiring certificates to renew in one run of the
# `RenewExpiringCertificatesJob`.
# config.renewal_batch_size = 10
# File name of the certbot executable.
# config.certbot_executable = '/usr/local/share/letsencrypt/bin/certbot'
# Port for the standalone certbot HTTP server
# config.certbot_port = 9999
# Directory certbot outputs certificates to
# config.certbot_output_directory = '/etc/letsencrypt/live'
# Directory the web server reads pem files from
# config.pem_directory = '/etc/haproxy/ssl/'
# Place pem files in provider specific subdirectories of pem directory.
# By default, all pem files are placed in pem directory itself.
# config.provider_install_directory_mapping = {
# certbot: 'letsencrypt',
# custom: 'custom'
# }
# Command to make server reload pem files
# config.server_reload_command = '/etc/init.d/haproxy reload'
end
Ensure private keys do not show up in log files:
# config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [:private_key]
Include the DomainOwner
mixin into a model with a domain
attribute. This makes CertWatch obtain or renew certificates whenever
the attribute changes. Validation has to be provided by the host
application.
# app/models/account.rb
# assuming Account has a cname attribute
class Account
include CertWatch.domain_owner(attribute: :cname)
end
If you want to use the Active Admin resource, add the following line to the top of your Active Admin initializer:
# config/initializers/active_admin.rb
ActiveAdmin.application.load_paths.unshift(CertWatch.active_admin_load_path)
If you use the CanCan authorization adapter, you also need to add the following rule for users that should be allowed to manage certificats:
# app/models/ability.rb
can :manage, CertWatch::Certificate
Now install migrations and migrate your database:
$ bin/rake cert_watch:install:migrations
$ bin/rake db:migrate
Setup your resque_schedule.yml
to check for expiring certificates:
# config/resque_schedule.yml
fetch_billed_traffic_usages:
every:
- "5h"
- :first_in: "1m"
class: "CertWatch::RenewExpiringCertificatesJob"
queue: cert_watch
description: "Check for expiring SSL certificates"
Finally ensure Resque workers have been assigned to the cert_watch
queue.
Rake Tasks
Add the following line to your application's Rakefile
:
# Rakefile
require 'cert_watch/tasks'
To reinstall all certificates (i.e. on a new server), run:
$ bin/rake cert_watch:reinstall:all
Active Admin View Components
You can render a status tag displaying the current certificate state for a given domain:
# app/admin/dashboard.rb
require 'cert_watch/views/certificate_state'
div(class: 'account_cname') do
text_node(account.cname)
cert_watch_certificate_state(account.cname)
end
Troubleshooting
If you run into problems or want to discuss a feature request, please file an issue.