From 30fc4e8f74315a92aaec36dfb9a8d4efa0a21791 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 7 Apr 2023 00:49:19 +0300 Subject: exact style --- ...22-07-30-lets-encrypt-with-openbsd-and-rex.html | 190 ++++++++++++++------- 1 file changed, 130 insertions(+), 60 deletions(-) (limited to 'gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html') diff --git a/gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html b/gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html index a05b193f..7e14c984 100644 --- a/gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html +++ b/gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html @@ -8,8 +8,10 @@ -

Let's Encrypt with OpenBSD and Rex

-

Published at 2022-07-30T12:14:31+01:00

+

Let's Encrypt with OpenBSD and Rex


+
+Published at 2022-07-30T12:14:31+01:00
+
                                                /    _    \
   The Hebern Machine                            \ ." ". /
@@ -36,31 +38,45 @@
              /________________________________________________\
                                  ASCII Art by John Savard
 
-

I was amazed at how easy it is to automatically generate and update Let's Encrypt certificates with OpenBSD.

-

What's Let's Encrypt?

-

Let's Encrypt is a non-profit certificate authority run by Internet Security Research Group that provides X.509 certificates for Transport Layer Security (TLS) encryption at no charge. It is the world's largest certificate authority, used by more than 265 million websites, with the goal of all websites being secure and using HTTPS.

-Source: Wikipedia
-

In short, it gives away TLS certificates for your website - for free! The catch is, that the certificates are only valid for three months. So it is better to automate certificate generation and renewals.

-

Meet acme-client

-

acme-client is the default Automatic Certifcate Management Environment (ACME) client on OpenBSD and part of the OpenBSD base system.

-

When invoked, the client first checks whether certificates actually require to be generated.

+
+I was amazed at how easy it is to automatically generate and update Let's Encrypt certificates with OpenBSD.
+
+

What's Let's Encrypt?


+
+Let's Encrypt is a non-profit certificate authority run by Internet Security Research Group that provides X.509 certificates for Transport Layer Security (TLS) encryption at no charge. It is the world's largest certificate authority, used by more than 265 million websites, with the goal of all websites being secure and using HTTPS.
+
+Source: Wikipedia
+
+In short, it gives away TLS certificates for your website - for free! The catch is, that the certificates are only valid for three months. So it is better to automate certificate generation and renewals.
+
+

Meet acme-client


+
+acme-client is the default Automatic Certifcate Management Environment (ACME) client on OpenBSD and part of the OpenBSD base system.
+
+When invoked, the client first checks whether certificates actually require to be generated.
+
-

Oversimplified, the following steps are undertaken by acme-client for generating a new certificate:

+
  • Otherwise, acme-client won't do anything.
  • +
    +Oversimplified, the following steps are undertaken by acme-client for generating a new certificate:
    +
    -

    Configuration

    -

    There is some (but easy) configuration required to make that all work on OpenBSD.

    -

    acme-client.conf

    -

    This is how my /etc/acme-client.conf looks like (I copied a template from /etc/examples/acme-client.conf to /etc/acme-client.conf and added my domains to the bottom:

    +
  • Let's Encrypt then will contact the hostname for the certificate through a particular URL (e.g. http://foo.zone/.well-known/acme-challenge/...) to verify that the requester is the valid owner of the host.
  • +
  • Let's Encrypt generates a certificate, which then is downloaded to /etc/ssl/....
  • +
    +

    Configuration


    +
    +There is some (but easy) configuration required to make that all work on OpenBSD.
    +
    +

    acme-client.conf


    +
    +This is how my /etc/acme-client.conf looks like (I copied a template from /etc/examples/acme-client.conf to /etc/acme-client.conf and added my domains to the bottom:
    +
     #
     # $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
    @@ -122,8 +138,11 @@ domain snonux.land {
         sign with letsencrypt
     }
     
    -

    httpd.conf

    -

    For ACME to work, you will need to configure the HTTP daemon so that the "special" ACME requests from Let's Encrypt are served correctly. I am using the standard OpenBSD httpd here. These are the snippets I use for the foo.zone host in /etc/httpd.conf (of course, you need a similar setup for all other hosts as well):

    +
    +

    httpd.conf


    +
    +For ACME to work, you will need to configure the HTTP daemon so that the "special" ACME requests from Let's Encrypt are served correctly. I am using the standard OpenBSD httpd here. These are the snippets I use for the foo.zone host in /etc/httpd.conf (of course, you need a similar setup for all other hosts as well):
    +
     server "foo.zone" {
       listen on * port 80
    @@ -148,11 +167,17 @@ server "foo.zone" {
       }
     }
     
    -

    As you see, plain HTTP only serves the ACME challenge path. Otherwise, it redirects the requests to TLS. The TLS section then attempts to use the Let's Encrypt certificates.

    -

    It is worth noticing that httpd will start without the certificates being present. This will cause a certificate error when you try to reach the HTTPS endpoint, but it helps to bootstrap Let's Encrypt. As you saw in the config snippet above, Let's Encrypt only requests the plain HTTP endpoint for the verification process, so HTTPS doesn't need to be operational yet at this stage. But once the certificates are generated, you will have to reload or restart httpd to use any new certificate.

    -

    CRON job

    -

    You could now run doas acme-client foo.zone to generate the certificate or to renew it. Or you could automate it with CRON.

    -

    I have created a script /usr/local/bin/acme.sh for that for all of my domains:

    +
    +As you see, plain HTTP only serves the ACME challenge path. Otherwise, it redirects the requests to TLS. The TLS section then attempts to use the Let's Encrypt certificates.
    +
    +It is worth noticing that httpd will start without the certificates being present. This will cause a certificate error when you try to reach the HTTPS endpoint, but it helps to bootstrap Let's Encrypt. As you saw in the config snippet above, Let's Encrypt only requests the plain HTTP endpoint for the verification process, so HTTPS doesn't need to be operational yet at this stage. But once the certificates are generated, you will have to reload or restart httpd to use any new certificate.
    +
    +

    CRON job


    +
    +You could now run doas acme-client foo.zone to generate the certificate or to renew it. Or you could automate it with CRON.
    +
    +I have created a script /usr/local/bin/acme.sh for that for all of my domains:
    +
     #!/bin/sh
     
    @@ -205,11 +230,15 @@ if [ $has_update = yes ]; then
         /usr/sbin/rcctl restart smtpd
     fi
     
    -

    And added the following line to /etc/daily.local to run the script once daily so that certificates will be renewed fully automatically:

    +
    +And added the following line to /etc/daily.local to run the script once daily so that certificates will be renewed fully automatically:
    +
     /usr/local/bin/acme.sh
     
    -

    I am receiving a daily output via E-Mail like this now:

    +
    +I am receiving a daily output via E-Mail like this now:
    +
     Running daily.local:
     acme-client: /etc/ssl/buetow.org.fullchain.pem: certificate valid: 80 days left
    @@ -220,21 +249,33 @@ acme-client: /etc/ssl/foo.zone.fullchain.pem: certificate valid: 80 days left
     acme-client: /etc/ssl/irregular.ninja.fullchain.pem: certificate valid: 80 days left
     acme-client: /etc/ssl/snonux.land.fullchain.pem: certificate valid: 79 days left
     
    -

    relayd.conf and smtpd.conf

    -

    Besides httpd, relayd (mainly for Gemini) and smtpd (for mail, of course) also use TLS certificates. And as you can see in acme.sh, the services are reloaded or restarted (smtpd doesn't support reload) whenever a certificate is generated or updated.

    -

    Rexification

    -

    I didn't write all these configuration files by hand. As a matter of fact, everything is automated with the Rex configuration management system.

    -https://www.rexify.org
    -

    At the top of the Rexfile I define all my hosts:

    +
    +

    relayd.conf and smtpd.conf


    +
    +Besides httpd, relayd (mainly for Gemini) and smtpd (for mail, of course) also use TLS certificates. And as you can see in acme.sh, the services are reloaded or restarted (smtpd doesn't support reload) whenever a certificate is generated or updated.
    +
    +

    Rexification


    +
    +I didn't write all these configuration files by hand. As a matter of fact, everything is automated with the Rex configuration management system.
    +
    +https://www.rexify.org
    +
    +At the top of the Rexfile I define all my hosts:
    +
     our @acme_hosts = qw/buetow.org paul.buetow.org tmp.buetow.org dtail.dev foo.zone irregular.ninja snonux.land/;
     
    -

    General ACME client configuration

    -

    ACME will be installed into the frontend group of hosts. Here, blowfish is the primary, and twofish is the secondary OpenBSD box.

    +
    +

    General ACME client configuration


    +
    +ACME will be installed into the frontend group of hosts. Here, blowfish is the primary, and twofish is the secondary OpenBSD box.
    +
     group frontends => 'blowfish.buetow.org', 'twofish.buetow.org';
     
    -

    This is my Rex task for the general ACME configuration:

    +
    +This is my Rex task for the general ACME configuration:
    +
     desc 'Configure ACME client';
     task 'acme', group => 'frontends',
    @@ -264,7 +305,9 @@ task 'acme', group => 'frontends',
         append_if_no_such_line '/etc/daily.local', '/usr/local/bin/acme.sh';
       };
     
    -

    And there is also a Rex task just to run the ACME script remotely:

    +
    +And there is also a Rex task just to run the ACME script remotely:
    +
     desc 'Invoke ACME client';
     task 'acme_invoke', group => 'frontends',
    @@ -273,7 +316,9 @@ task 'acme_invoke', group => 'frontends',
       };
     
     
    -

    Furthermore, this snippet (also at the top of the Rexfile) helps to determine whether the current server is the primary server (all hosts will be without the www. prefix) or the secondary server (all hosts will be with the www. prefix):

    +
    +Furthermore, this snippet (also at the top of the Rexfile) helps to determine whether the current server is the primary server (all hosts will be without the www. prefix) or the secondary server (all hosts will be with the www. prefix):
    +
     # Bootstrapping the FQDN based on the server IP as the hostname and domain
     # facts aren't set yet due to the myname file in the first place.
    @@ -291,7 +336,9 @@ our $is_primary = sub {
       $fqdns->($ipv4) eq 'blowfish.buetow.org';
     };
     
    -

    The following is the acme-client.conf.tpl Rex template file used for the automation. You see that the www. prefix isn't sent for the primary server. E.g. foo.zone will be served by the primary server (in my case, a server located in Germany) and www.foo.zone by the secondary server (in my case, a server located in Japan):

    +
    +The following is the acme-client.conf.tpl Rex template file used for the automation. You see that the www. prefix isn't sent for the primary server. E.g. foo.zone will be served by the primary server (in my case, a server located in Germany) and www.foo.zone by the secondary server (in my case, a server located in Japan):
    +
     #
     # $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
    @@ -332,7 +379,9 @@ domain <%= $prefix.$host %> {
     <% } %>
     
     
    -

    And this is the acme.sh.tpl:

    +
    +And this is the acme.sh.tpl:
    +
     #!/bin/sh
     
    @@ -368,8 +417,11 @@ if [ $has_update = yes ]; then
         /usr/sbin/rcctl restart smtpd
     fi
     
    -

    Service rexification

    -

    These are the Rex tasks setting up httpd, relayd and smtpd services:

    +
    +

    Service rexification


    +
    +These are the Rex tasks setting up httpd, relayd and smtpd services:
    +
     desc 'Setup httpd';
     task 'httpd', group => 'frontends',
    @@ -445,7 +497,9 @@ task 'smtpd', group => 'frontends',
       };
     
     
    -

    This is the httpd.conf.tpl:

    +
    +This is the httpd.conf.tpl:
    +
     <%
       our $primary = $is_primary->($vio0_ip);
    @@ -535,7 +589,9 @@ server "<%= $prefix %>tmp.buetow.org" {
       directory auto index
     }
     
    -

    and this the relayd.conf.tpl:

    +
    +and this the relayd.conf.tpl:
    +
     <%
       our $primary = $is_primary->($vio0_ip);
    @@ -561,7 +617,9 @@ relay "gemini6" {
         forward to 127.0.0.1 port 11965
     }
     
    -

    And last but not least, this is the smtpd.conf.tpl:

    +
    +And last but not least, this is the smtpd.conf.tpl:
    +
     <%
       our $primary = $is_primary->($vio0_ip);
    @@ -587,20 +645,32 @@ match from any for domain <virtualdomains> action receive
     match from local for local action localmail
     match from local for any action outbound
     
    -

    All pieces together

    -

    For the complete Rexfile example and all the templates, please look at the Git repository:

    -https://codeberg.org/snonux/rexfiles
    -

    Besides ACME, other things, such as DNS servers, are also rexified. The following command will run all the Rex tasks and configure everything on my frontend machines automatically:

    +
    +

    All pieces together


    +
    +For the complete Rexfile example and all the templates, please look at the Git repository:
    +
    +https://codeberg.org/snonux/rexfiles
    +
    +Besides ACME, other things, such as DNS servers, are also rexified. The following command will run all the Rex tasks and configure everything on my frontend machines automatically:
    +
     rex commons
     
    -

    The commons is a group of tasks I specified which combines a set of common tasks I always want to execute on all frontend machines. This also includes the ACME tasks mentioned in this article!

    -

    Conclusion

    -

    ACME and Let's Encrypt greatly help reduce recurring manual maintenance work (creating and renewing certificates). Furthermore, all the certificates are free of cost! I love to use OpenBSD and Rex to automate all of this.

    -

    OpenBSD suits perfectly here as all the tools are already part of the base installation. But I like underdogs. Rex is not as powerful and popular as other configuration management systems (e.g. Puppet, Chef, SALT or even Ansible). It is more of an underdog, and the community is small.

    -

    Why re-inventing the wheel? I love that a Rexfile is just a Perl DSL. Also, OpenBSD comes with Perl in the base system. So no new programming language had to be added to my mix for the configuration management system. Also, the acme.sh shell script is not a Bash but a standard Bourne shell script, so I didn't have to install an additional shell as OpenBSD does not come with the Bash pre-installed.

    -

    E-Mail your comments to hi@paul.cyou :-)

    -Back to the main site
    +
    +The commons is a group of tasks I specified which combines a set of common tasks I always want to execute on all frontend machines. This also includes the ACME tasks mentioned in this article!
    +
    +

    Conclusion


    +
    +ACME and Let's Encrypt greatly help reduce recurring manual maintenance work (creating and renewing certificates). Furthermore, all the certificates are free of cost! I love to use OpenBSD and Rex to automate all of this.
    +
    +OpenBSD suits perfectly here as all the tools are already part of the base installation. But I like underdogs. Rex is not as powerful and popular as other configuration management systems (e.g. Puppet, Chef, SALT or even Ansible). It is more of an underdog, and the community is small.
    +
    +Why re-inventing the wheel? I love that a Rexfile is just a Perl DSL. Also, OpenBSD comes with Perl in the base system. So no new programming language had to be added to my mix for the configuration management system. Also, the acme.sh shell script is not a Bash but a standard Bourne shell script, so I didn't have to install an additional shell as OpenBSD does not come with the Bash pre-installed.
    +
    +E-Mail your comments to hi@paul.cyou :-)
    +
    +Back to the main site