Lessons learned from buying, connecting, and operating domains
Free Trial
Engineering

How to Automate SSL Certificate Installation using Chef and the DNSimple Cookbook

Stephen Nelson's profile picture Stephen Nelson

We're big fans of infrastructure automation here at DNSimple. We started automating our infrastructure provisioning with Chef in the earliest days of the company, and have continued ever since. When a new machine is brought online, we use the DNSimple Chef Cookbook to configure DNS records through the DNSimple API. If the machine requires a public-facing certificate for TLS, we download and install the certificate automatically as well. This helps us ensure that our systems are secure and run smoothly – without the risk of human error.

In this post, we'll talk about how to automate your certificate installation using Chef in the same way. We'll provision an Nginx web server and install an SSL certificate to securely display a web page. The following code will be converged onto an Ubuntu 18.04 system. You may need to change the install paths and file permissions to match your system's recommended configuration.

Prerequisites

You need to have a domain linked to your DNSimple account and a certificate purchased for the domain that you'll be installing an SSL certificate for. At DNSimple, we offer both single name and wildcard certificates from Comodo and Let's Encrypt. You also need to generate an access token that you'll use to communicate with the DNSimple API, allowing you to download the certificate from your account.

To securely store the access token, you need to add it into chef-vault. In this example, you'll create an item called dnsimple inside the secrets vault. With chef-vault, you'll bootstrap any nodes with an empty run-list, then run knife vault update to add the new node to the access list. For more information about chef-vault, check out the documentation on Chef's website.

knife vault create secrets dnsimple -S '*:*'
knife vault edit secrets dnsimple
{
  "user": "my@email.com",
  "token": "MyExampleToken"
}

Once you have all the prerequisites in place, it's time to automate the setup of your web server, and test provisioning our SSL certificate using the DNSimple Chef cookbook.

Retrieving credentials from Chef Vault in our recipe

The following code will install the chef-vault ruby gem at compile time, require 'chef-vault' in the recipe, and retrieve the credentials you created in the previous step for access to the DNSimple API:

chef_gem 'chef-vault' do
  compile_time true if respond_to?(:compile_time)
end

require 'chef-vault'

chef_vault_item = ChefVault::Item.load('secrets', 'dnsimple')

Installing the web server

To begin, you'll install a basic Nginx web server, define the service, then enable and start the service. The following example uses Chef's package and service resources to accomplish this:

package 'nginx' do
  action :install
end

service 'nginx' do
  supports status: true, restart: true, reload: true
  action [ :enable, :start ]
end

Creating a simple website

Next, create a simple website that shows Hello World! using Chef's directory and file resources to store the website code.

directory '/var/www/dnsimple.xyz' do
  owner 'www-data'
  group 'www-data'
  mode '0755'
  action :create
end

file '/var/www/dnsimple.xyz/index.html' do
  content '<html>Hello World!</html>'
  mode '0664'
  owner 'www-data'
  group 'www-data'
end

Installing the certificate

Use the DNSimple Chef cookbook to download and provision our certificate files that will be used to secure your site.

Reference the DNSimple cookbook in your wrapper cookbook's metadata.rb and Policyfile / Berksfile to satisfy the dependency.

Add the blocks that create a directory to store our SSL certificates, then use the dnsimple_certificate resource to connect to the DNSimple API, and download and store the certificate in the directory you created.

directory '/etc/nginx/ssl' do
  owner 'root'
  group 'root'
  mode '0600'
  action :create
end

dnsimple_certificate '/etc/nginx/ssl' do
  install_path '/etc/nginx/ssl'
  common_name 'www.dnsimple.xyz'
  domain 'dnsimple.xyz'
  expires_on '2020-07-01'
  mode '0600'
  owner 'root'
  group 'root'
  access_token chef_vault_item['token']
end

Configure Nginx

Use Chef's template resource to create our Nginx config file referencing the SSL certificate files you provisioned using the dnsimple_certificate method.

Let's create a file inside of the templates directory in our wrapper cookbook called dnsimple.xyz.nginx.conf.erb with the following content:

server {
  listen 443;
  listen [::]:443;

  ssl on;
  ssl_certificate /etc/nginx/ssl/dnsimple.xyz.crt;
  ssl_certificate_key /etc/nginx/ssl/dnsimple.xyz.key;

  server_name dnsimple.xyz;

  root /var/www/dnsimple.xyz;
  index index.html index.htm;

  location / {
    try_files $uri $uri/ =404;
  }
}

Finally, you'll render the new template file using Chef's template resource referencing the template you just created in our recipe file. You'll also use the notify directive to automatically reload the Nginx service with any changes to the configuration file:

template '/etc/nginx/sites-enabled/dnsimple.xyz.nginx.conf' do
  source 'dnsimple.xyz.nginx.conf.erb'
  owner 'root'
  group 'root'
  mode '0640'
  notifies :reload, 'service[nginx]', :immediate
end

Force HTTPS connections with Nginx

In this section, I'll show you how to add another configuration block. This will redirect non-secure traffic to the HTTPS version of the site, and ensure all visitors are using the secure version of your site.

You'll need to add another server block above the existing one in your Nginx configuration template. The following code will show the complete Nginx configuration template with the added redirection server block:

server {
  listen 80;
  listen [::]:80;

  server_name dnsimple.xyz;
  return 301 https://dnsimple.xyz$request_uri;
}

server {
  listen 443;
  listen [::]:443;

  ssl on;
  ssl_certificate /etc/nginx/ssl/dnsimple.xyz.crt;
  ssl_certificate_key /etc/nginx/ssl/dnsimple.xyz.key;

  server_name dnsimple.xyz;

  root /var/www/dnsimple.xyz;
  index index.html index.htm;

  location / {
    try_files $uri $uri/ =404;
  }
}

Conclusion

Hopefully this example has been helpful in automating your SSL certificate installation!

If you want notifications about events related to your SSL certificates, check out our documentation for how to receive webhooks for certificate issue and reissue events. Want to read more about DNSimple's commitment to domain management automation? We've got a blog post just for you.

When you're ready to upgrade to expert DNS management and infrastructure automation, give us a try free for 30 days. Have more questions? Send us a message - we're always happy to help.

Share on Twitter and Facebook

Stephen Nelson's profile picture

Stephen Nelson

Driven by concepts, ideas, logic and reason. Enjoys creating music, learning, technology and traveling.