diff options
| author | Paul Buetow <paul@buetow.org> | 2023-05-28 00:01:27 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2023-05-28 00:01:27 +0300 |
| commit | 5b2deaa0e51468a04a3c7c72ad8e5181a8e804e2 (patch) | |
| tree | 5e4437db2debeecd31686916c2b3bd79d0c78ae5 /gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html | |
| parent | de7e5d7c4c6f85a1516b573f471351e6db5c1334 (diff) | |
Update content for html
Diffstat (limited to 'gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html')
| -rw-r--r-- | gemfeed/2022-07-30-lets-encrypt-with-openbsd-and-rex.html | 208 |
1 files changed, 104 insertions, 104 deletions
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 eaba5d83..b2d1dd05 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,7 +8,7 @@ <link rel="stylesheet" href="style-override.css" /> </head> <body> -<h1 style='display: inline'>Let's Encrypt with OpenBSD and Rex</h1><br /> +<h1 style='display: inline'>Let's Encrypt with OpenBSD and Rex</h1><br /> <br /> <span class='quote'>Published at 2022-07-30T12:14:31+01:00</span><br /> <br /> @@ -39,13 +39,13 @@ ASCII Art by John Savard </pre> <br /> -<span>I was amazed at how easy it is to automatically generate and update Let's Encrypt certificates with OpenBSD.</span><br /> +<span>I was amazed at how easy it is to automatically generate and update Let's Encrypt certificates with OpenBSD.</span><br /> <br /> -<h2 style='display: inline'>What's Let's Encrypt?</h2><br /> +<h2 style='display: inline'>What's Let's Encrypt?</h2><br /> <br /> -<span class='quote'>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.</span><br /> +<span class='quote'>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.</span><br /> <br /> -<a class='textlink' href='https://en.wikipedia.org/wiki/Let's_Encrypt'>Source: Wikipedia</a><br /> +<a class='textlink' href='https://en.wikipedia.org/wiki/Let's_Encrypt'>Source: Wikipedia</a><br /> <br /> <span>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.</span><br /> <br /> @@ -58,16 +58,16 @@ <ul> <li>It first checks whether a certificate already exists; if not, it will attempt to generate a new one.</li> <li>If the certificate already exists but expires within the next 30 days, it will renew it.</li> -<li>Otherwise, <span class='inlinecode'>acme-client</span> won't do anything.</li> +<li>Otherwise, <span class='inlinecode'>acme-client</span> won't do anything.</li> </ul><br /> <span>Oversimplified, the following steps are undertaken by <span class='inlinecode'>acme-client</span> for generating a new certificate:</span><br /> <br /> <ul> <li>Reading its config file <span class='inlinecode'>/etc/acme-client.conf</span> for a list of hosts (and their alternative names) to generate certificates. So it means you can also have certificates for arbitrary subdomains!</li> <li>Automatic generation of the private certificate part (the certificate key) and the certificate signing request (CSR) to <span class='inlinecode'>/etc/ssl/...</span>.</li> -<li>Requesting Let's Encrypt to sign the certificate. This also includes providing a set of temporary files requested by Let's Encrypt in the next step for verification.</li> -<li>Let's Encrypt then will contact the hostname for the certificate through a particular URL (e.g. <span class='inlinecode'>http://foo.zone/.well-known/acme-challenge/...</span>) to verify that the requester is the valid owner of the host.</li> -<li>Let's Encrypt generates a certificate, which then is downloaded to <span class='inlinecode'>/etc/ssl/...</span>.</li> +<li>Requesting Let's Encrypt to sign the certificate. This also includes providing a set of temporary files requested by Let's Encrypt in the next step for verification.</li> +<li>Let's Encrypt then will contact the hostname for the certificate through a particular URL (e.g. <span class='inlinecode'>http://foo.zone/.well-known/acme-challenge/...</span>) to verify that the requester is the valid owner of the host.</li> +<li>Let's Encrypt generates a certificate, which then is downloaded to <span class='inlinecode'>/etc/ssl/...</span>.</li> </ul><br /> <h2 style='display: inline'>Configuration</h2><br /> <br /> @@ -141,7 +141,7 @@ domain snonux.land { <br /> <h3 style='display: inline'>httpd.conf</h3><br /> <br /> -<span>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 <span class='inlinecode'>httpd</span> here. These are the snippets I use for the <span class='inlinecode'>foo.zone</span> host in <span class='inlinecode'>/etc/httpd.conf</span> (of course, you need a similar setup for all other hosts as well):</span><br /> +<span>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 <span class='inlinecode'>httpd</span> here. These are the snippets I use for the <span class='inlinecode'>foo.zone</span> host in <span class='inlinecode'>/etc/httpd.conf</span> (of course, you need a similar setup for all other hosts as well):</span><br /> <br /> <pre> server "foo.zone" { @@ -168,9 +168,9 @@ server "foo.zone" { } </pre> <br /> -<span>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.</span><br /> +<span>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.</span><br /> <br /> -<span>It is worth noticing that <span class='inlinecode'>httpd</span> 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 <span class='inlinecode'>httpd</span> to use any new certificate.</span><br /> +<span>It is worth noticing that <span class='inlinecode'>httpd</span> 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 <span class='inlinecode'>httpd</span> to use any new certificate.</span><br /> <br /> <h3 style='display: inline'>CRON job</h3><br /> <br /> @@ -252,11 +252,11 @@ acme-client: /etc/ssl/snonux.land.fullchain.pem: certificate valid: 79 days left <br /> <h2 style='display: inline'>relayd.conf and smtpd.conf</h2><br /> <br /> -<span>Besides <span class='inlinecode'>httpd</span>, <span class='inlinecode'>relayd</span> (mainly for Gemini) and <span class='inlinecode'>smtpd</span> (for mail, of course) also use TLS certificates. And as you can see in <span class='inlinecode'>acme.sh</span>, the services are reloaded or restarted (<span class='inlinecode'>smtpd</span> doesn't support reload) whenever a certificate is generated or updated.</span><br /> +<span>Besides <span class='inlinecode'>httpd</span>, <span class='inlinecode'>relayd</span> (mainly for Gemini) and <span class='inlinecode'>smtpd</span> (for mail, of course) also use TLS certificates. And as you can see in <span class='inlinecode'>acme.sh</span>, the services are reloaded or restarted (<span class='inlinecode'>smtpd</span> doesn't support reload) whenever a certificate is generated or updated.</span><br /> <br /> <h2 style='display: inline'>Rexification</h2><br /> <br /> -<span>I didn't write all these configuration files by hand. As a matter of fact, everything is automated with the Rex configuration management system.</span><br /> +<span>I didn't write all these configuration files by hand. As a matter of fact, everything is automated with the Rex configuration management system.</span><br /> <br /> <a class='textlink' href='https://www.rexify.org'>https://www.rexify.org</a><br /> <br /> @@ -271,48 +271,48 @@ our @acme_hosts = qw/buetow.org paul.buetow.org tmp.buetow.org dtail.dev foo.zon <span>ACME will be installed into the frontend group of hosts. Here, blowfish is the primary, and twofish is the secondary OpenBSD box.</span><br /> <br /> <pre> -group frontends => 'blowfish.buetow.org', 'twofish.buetow.org'; +group frontends => 'blowfish.buetow.org', 'twofish.buetow.org'; </pre> <br /> <span>This is my Rex task for the general ACME configuration:</span><br /> <br /> <pre> -desc 'Configure ACME client'; -task 'acme', group => 'frontends', +desc 'Configure ACME client'; +task 'acme', group => 'frontends', sub { - file '/etc/acme-client.conf', - content => template('./etc/acme-client.conf.tpl', + file '/etc/acme-client.conf', + content => template('./etc/acme-client.conf.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), - owner => 'root', - group => 'wheel', - mode => '644'; + owner => 'root', + group => 'wheel', + mode => '644'; - file '/usr/local/bin/acme.sh', - content => template('./scripts/acme.sh.tpl', + file '/usr/local/bin/acme.sh', + content => template('./scripts/acme.sh.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), - owner => 'root', - group => 'wheel', - mode => '744'; + owner => 'root', + group => 'wheel', + mode => '744'; - file '/etc/daily.local', - ensure => 'present', - owner => 'root', - group => 'wheel', - mode => '644'; + file '/etc/daily.local', + ensure => 'present', + owner => 'root', + group => 'wheel', + mode => '644'; - append_if_no_such_line '/etc/daily.local', '/usr/local/bin/acme.sh'; + append_if_no_such_line '/etc/daily.local', '/usr/local/bin/acme.sh'; }; </pre> <br /> <span>And there is also a Rex task just to run the ACME script remotely:</span><br /> <br /> <pre> -desc 'Invoke ACME client'; -task 'acme_invoke', group => 'frontends', +desc 'Invoke ACME client'; +task 'acme_invoke', group => 'frontends', sub { - say run '/usr/local/bin/acme.sh'; + say run '/usr/local/bin/acme.sh'; }; </pre> @@ -321,23 +321,23 @@ task 'acme_invoke', group => 'frontends', <br /> <pre> # 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. +# facts aren't set yet due to the myname file in the first place. our $fqdns = sub { my $ipv4 = shift; - return 'blowfish.buetow.org' if $ipv4 eq '23.88.35.144'; - return 'twofish.buetow.org' if $ipv4 eq '108.160.134.135'; - Rex::Logger::info("Unable to determine hostname for $ipv4", 'error'); - return 'HOSTNAME-UNKNOWN.buetow.org'; + return 'blowfish.buetow.org' if $ipv4 eq '23.88.35.144'; + return 'twofish.buetow.org' if $ipv4 eq '108.160.134.135'; + Rex::Logger::info("Unable to determine hostname for $ipv4", 'error'); + return 'HOSTNAME-UNKNOWN.buetow.org'; }; # To determine whether the server is the primary or the secondary. our $is_primary = sub { my $ipv4 = shift; - $fqdns->($ipv4) eq 'blowfish.buetow.org'; + $fqdns->($ipv4) eq 'blowfish.buetow.org'; }; </pre> <br /> -<span>The following is the <span class='inlinecode'>acme-client.conf.tpl</span> Rex template file used for the automation. You see that the <span class='inlinecode'>www.</span> prefix isn't sent for the primary server. E.g. <span class='inlinecode'>foo.zone</span> will be served by the primary server (in my case, a server located in Germany) and <span class='inlinecode'>www.foo.zone</span> by the secondary server (in my case, a server located in Japan):</span><br /> +<span>The following is the <span class='inlinecode'>acme-client.conf.tpl</span> Rex template file used for the automation. You see that the <span class='inlinecode'>www.</span> prefix isn't sent for the primary server. E.g. <span class='inlinecode'>foo.zone</span> will be served by the primary server (in my case, a server located in Germany) and <span class='inlinecode'>www.foo.zone</span> by the secondary server (in my case, a server located in Japan):</span><br /> <br /> <pre> # @@ -367,7 +367,7 @@ authority buypass-test { <% our $primary = $is_primary->($vio0_ip); - our $prefix = $primary ? '' : 'www.'; + our $prefix = $primary ? '' : 'www.'; %> <% for my $host (@$acme_hosts) { %> @@ -387,7 +387,7 @@ domain <%= $prefix.$host %> { <% our $primary = $is_primary->($vio0_ip); - our $prefix = $primary ? '' : 'www.'; + our $prefix = $primary ? '' : 'www.'; -%> function handle_cert { @@ -423,77 +423,77 @@ fi <span>These are the Rex tasks setting up <span class='inlinecode'>httpd</span>, <span class='inlinecode'>relayd</span> and <span class='inlinecode'>smtpd</span> services:</span><br /> <br /> <pre> -desc 'Setup httpd'; -task 'httpd', group => 'frontends', +desc 'Setup httpd'; +task 'httpd', group => 'frontends', sub { - append_if_no_such_line '/etc/rc.conf.local', 'httpd_flags='; + append_if_no_such_line '/etc/rc.conf.local', 'httpd_flags='; - file '/etc/httpd.conf', - content => template('./etc/httpd.conf.tpl', + file '/etc/httpd.conf', + content => template('./etc/httpd.conf.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), - owner => 'root', - group => 'wheel', - mode => '644', - on_change => sub { service 'httpd' => 'restart' }; + owner => 'root', + group => 'wheel', + mode => '644', + on_change => sub { service 'httpd' => 'restart' }; - service 'httpd', ensure => 'started'; + service 'httpd', ensure => 'started'; }; -desc 'Setup relayd'; -task 'relayd', group => 'frontends', +desc 'Setup relayd'; +task 'relayd', group => 'frontends', sub { - append_if_no_such_line '/etc/rc.conf.local', 'relayd_flags='; + append_if_no_such_line '/etc/rc.conf.local', 'relayd_flags='; - file '/etc/relayd.conf', - content => template('./etc/relayd.conf.tpl', + file '/etc/relayd.conf', + content => template('./etc/relayd.conf.tpl', ipv6address => $ipv6address, is_primary => $is_primary), - owner => 'root', - group => 'wheel', - mode => '600', - on_change => sub { service 'relayd' => 'restart' }; + owner => 'root', + group => 'wheel', + mode => '600', + on_change => sub { service 'relayd' => 'restart' }; - service 'relayd', ensure => 'started'; + service 'relayd', ensure => 'started'; }; -desc 'Setup OpenSMTPD'; -task 'smtpd', group => 'frontends', +desc 'Setup OpenSMTPD'; +task 'smtpd', group => 'frontends', sub { - Rex::Logger::info('Dealing with mail aliases'); - file '/etc/mail/aliases', - source => './etc/mail/aliases', - owner => 'root', - group => 'wheel', - mode => '644', - on_change => sub { say run 'newaliases' }; - - Rex::Logger::info('Dealing with mail virtual domains'); - file '/etc/mail/virtualdomains', - source => './etc/mail/virtualdomains', - owner => 'root', - group => 'wheel', - mode => '644', - on_change => sub { service 'smtpd' => 'restart' }; - - Rex::Logger::info('Dealing with mail virtual users'); - file '/etc/mail/virtualusers', - source => './etc/mail/virtualusers', - owner => 'root', - group => 'wheel', - mode => '644', - on_change => sub { service 'smtpd' => 'restart' }; - - Rex::Logger::info('Dealing with smtpd.conf'); - file '/etc/mail/smtpd.conf', - content => template('./etc/mail/smtpd.conf.tpl', + Rex::Logger::info('Dealing with mail aliases'); + file '/etc/mail/aliases', + source => './etc/mail/aliases', + owner => 'root', + group => 'wheel', + mode => '644', + on_change => sub { say run 'newaliases' }; + + Rex::Logger::info('Dealing with mail virtual domains'); + file '/etc/mail/virtualdomains', + source => './etc/mail/virtualdomains', + owner => 'root', + group => 'wheel', + mode => '644', + on_change => sub { service 'smtpd' => 'restart' }; + + Rex::Logger::info('Dealing with mail virtual users'); + file '/etc/mail/virtualusers', + source => './etc/mail/virtualusers', + owner => 'root', + group => 'wheel', + mode => '644', + on_change => sub { service 'smtpd' => 'restart' }; + + Rex::Logger::info('Dealing with smtpd.conf'); + file '/etc/mail/smtpd.conf', + content => template('./etc/mail/smtpd.conf.tpl', is_primary => $is_primary), - owner => 'root', - group => 'wheel', - mode => '644', - on_change => sub { service 'smtpd' => 'restart' }; + owner => 'root', + group => 'wheel', + mode => '644', + on_change => sub { service 'smtpd' => 'restart' }; - service 'smtpd', ensure => 'started'; + service 'smtpd', ensure => 'started'; }; </pre> @@ -503,7 +503,7 @@ task 'smtpd', group => 'frontends', <pre> <% our $primary = $is_primary->($vio0_ip); - our $prefix = $primary ? '' : 'www.'; + our $prefix = $primary ? '' : 'www.'; %> # Plain HTTP for ACME and HTTPS redirect @@ -595,7 +595,7 @@ server "<%= $prefix %>tmp.buetow.org" { <pre> <% our $primary = $is_primary->($vio0_ip); - our $prefix = $primary ? '' : 'www.'; + our $prefix = $primary ? '' : 'www.'; %> log connection @@ -623,7 +623,7 @@ relay "gemini6" { <pre> <% our $primary = $is_primary->($vio0_ip); - our $prefix = $primary ? '' : 'www.'; + our $prefix = $primary ? '' : 'www.'; %> pki "buetow_org_tls" cert "/etc/ssl/<%= $prefix %>buetow.org.fullchain.pem" @@ -662,11 +662,11 @@ rex commons <br /> <h2 style='display: inline'>Conclusion</h2><br /> <br /> -<span>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.</span><br /> +<span>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.</span><br /> <br /> <span>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.</span><br /> <br /> -<span>Why re-inventing the wheel? I love that a <span class='inlinecode'>Rexfile</span> 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 <span class='inlinecode'>acme.sh</span> 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.</span><br /> +<span>Why re-inventing the wheel? I love that a <span class='inlinecode'>Rexfile</span> 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 <span class='inlinecode'>acme.sh</span> 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.</span><br /> <br /> <span>E-Mail your comments to hi@foo.zone :-)</span><br /> <br /> |
