about summary refs log tree commit diff
path: root/nixos/modules/security/acme/default.xml
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/security/acme/default.xml')
-rw-r--r--nixos/modules/security/acme/default.xml395
1 files changed, 0 insertions, 395 deletions
diff --git a/nixos/modules/security/acme/default.xml b/nixos/modules/security/acme/default.xml
deleted file mode 100644
index e80ce3b6a4943..0000000000000
--- a/nixos/modules/security/acme/default.xml
+++ /dev/null
@@ -1,395 +0,0 @@
-<!-- Do not edit this file directly, edit its companion .md instead
-     and regenerate this file using nixos/doc/manual/md-to-db.sh -->
-<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="module-security-acme">
-  <title>SSL/TLS Certificates with ACME</title>
-  <para>
-    NixOS supports automatic domain validation &amp; certificate
-    retrieval and renewal using the ACME protocol. Any provider can be
-    used, but by default NixOS uses Let’s Encrypt. The alternative ACME
-    client
-    <link xlink:href="https://go-acme.github.io/lego/">lego</link> is
-    used under the hood.
-  </para>
-  <para>
-    Automatic cert validation and configuration for Apache and Nginx
-    virtual hosts is included in NixOS, however if you would like to
-    generate a wildcard cert or you are not using a web server you will
-    have to configure DNS based validation.
-  </para>
-  <section xml:id="module-security-acme-prerequisites">
-    <title>Prerequisites</title>
-    <para>
-      To use the ACME module, you must accept the provider’s terms of
-      service by setting
-      <xref linkend="opt-security.acme.acceptTerms" /> to
-      <literal>true</literal>. The Let’s Encrypt ToS can be found
-      <link xlink:href="https://letsencrypt.org/repository/">here</link>.
-    </para>
-    <para>
-      You must also set an email address to be used when creating
-      accounts with Let’s Encrypt. You can set this for all certs with
-      <xref linkend="opt-security.acme.defaults.email" /> and/or on a
-      per-cert basis with
-      <xref linkend="opt-security.acme.certs._name_.email" />. This
-      address is only used for registration and renewal reminders, and
-      cannot be used to administer the certificates in any way.
-    </para>
-    <para>
-      Alternatively, you can use a different ACME server by changing the
-      <xref linkend="opt-security.acme.defaults.server" /> option to a
-      provider of your choosing, or just change the server for one cert
-      with <xref linkend="opt-security.acme.certs._name_.server" />.
-    </para>
-    <para>
-      You will need an HTTP server or DNS server for verification. For
-      HTTP, the server must have a webroot defined that can serve
-      <filename>.well-known/acme-challenge</filename>. This directory
-      must be writeable by the user that will run the ACME client. For
-      DNS, you must set up credentials with your provider/server for use
-      with lego.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-nginx">
-    <title>Using ACME certificates in Nginx</title>
-    <para>
-      NixOS supports fetching ACME certificates for you by setting
-      <literal>enableACME = true;</literal> in a virtualHost config. We
-      first create self-signed placeholder certificates in place of the
-      real ACME certs. The placeholder certs are overwritten when the
-      ACME certs arrive. For <literal>foo.example.com</literal> the
-      config would look like this:
-    </para>
-    <programlisting>
-security.acme.acceptTerms = true;
-security.acme.defaults.email = &quot;admin+acme@example.com&quot;;
-services.nginx = {
-  enable = true;
-  virtualHosts = {
-    &quot;foo.example.com&quot; = {
-      forceSSL = true;
-      enableACME = true;
-      # All serverAliases will be added as extra domain names on the certificate.
-      serverAliases = [ &quot;bar.example.com&quot; ];
-      locations.&quot;/&quot; = {
-        root = &quot;/var/www&quot;;
-      };
-    };
-
-    # We can also add a different vhost and reuse the same certificate
-    # but we have to append extraDomainNames manually beforehand:
-    # security.acme.certs.&quot;foo.example.com&quot;.extraDomainNames = [ &quot;baz.example.com&quot; ];
-    &quot;baz.example.com&quot; = {
-      forceSSL = true;
-      useACMEHost = &quot;foo.example.com&quot;;
-      locations.&quot;/&quot; = {
-        root = &quot;/var/www&quot;;
-      };
-    };
-  };
-}
-</programlisting>
-  </section>
-  <section xml:id="module-security-acme-httpd">
-    <title>Using ACME certificates in Apache/httpd</title>
-    <para>
-      Using ACME certificates with Apache virtual hosts is identical to
-      using them with Nginx. The attribute names are all the same, just
-      replace <quote>nginx</quote> with <quote>httpd</quote> where
-      appropriate.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-configuring">
-    <title>Manual configuration of HTTP-01 validation</title>
-    <para>
-      First off you will need to set up a virtual host to serve the
-      challenges. This example uses a vhost called
-      <literal>certs.example.com</literal>, with the intent that you
-      will generate certs for all your vhosts and redirect everyone to
-      HTTPS.
-    </para>
-    <programlisting>
-security.acme.acceptTerms = true;
-security.acme.defaults.email = &quot;admin+acme@example.com&quot;;
-
-# /var/lib/acme/.challenges must be writable by the ACME user
-# and readable by the Nginx user. The easiest way to achieve
-# this is to add the Nginx user to the ACME group.
-users.users.nginx.extraGroups = [ &quot;acme&quot; ];
-
-services.nginx = {
-  enable = true;
-  virtualHosts = {
-    &quot;acmechallenge.example.com&quot; = {
-      # Catchall vhost, will redirect users to HTTPS for all vhosts
-      serverAliases = [ &quot;*.example.com&quot; ];
-      locations.&quot;/.well-known/acme-challenge&quot; = {
-        root = &quot;/var/lib/acme/.challenges&quot;;
-      };
-      locations.&quot;/&quot; = {
-        return = &quot;301 https://$host$request_uri&quot;;
-      };
-    };
-  };
-}
-# Alternative config for Apache
-users.users.wwwrun.extraGroups = [ &quot;acme&quot; ];
-services.httpd = {
-  enable = true;
-  virtualHosts = {
-    &quot;acmechallenge.example.com&quot; = {
-      # Catchall vhost, will redirect users to HTTPS for all vhosts
-      serverAliases = [ &quot;*.example.com&quot; ];
-      # /var/lib/acme/.challenges must be writable by the ACME user and readable by the Apache user.
-      # By default, this is the case.
-      documentRoot = &quot;/var/lib/acme/.challenges&quot;;
-      extraConfig = ''
-        RewriteEngine On
-        RewriteCond %{HTTPS} off
-        RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge [NC]
-        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301]
-      '';
-    };
-  };
-}
-</programlisting>
-    <para>
-      Now you need to configure ACME to generate a certificate.
-    </para>
-    <programlisting>
-security.acme.certs.&quot;foo.example.com&quot; = {
-  webroot = &quot;/var/lib/acme/.challenges&quot;;
-  email = &quot;foo@example.com&quot;;
-  # Ensure that the web server you use can read the generated certs
-  # Take a look at the group option for the web server you choose.
-  group = &quot;nginx&quot;;
-  # Since we have a wildcard vhost to handle port 80,
-  # we can generate certs for anything!
-  # Just make sure your DNS resolves them.
-  extraDomainNames = [ &quot;mail.example.com&quot; ];
-};
-</programlisting>
-    <para>
-      The private key <filename>key.pem</filename> and certificate
-      <filename>fullchain.pem</filename> will be put into
-      <filename>/var/lib/acme/foo.example.com</filename>.
-    </para>
-    <para>
-      Refer to <xref linkend="ch-options" /> for all available
-      configuration options for the
-      <link linkend="opt-security.acme.certs">security.acme</link>
-      module.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-config-dns">
-    <title>Configuring ACME for DNS validation</title>
-    <para>
-      This is useful if you want to generate a wildcard certificate,
-      since ACME servers will only hand out wildcard certs over DNS
-      validation. There are a number of supported DNS providers and
-      servers you can utilise, see the
-      <link xlink:href="https://go-acme.github.io/lego/dns/">lego
-      docs</link> for provider/server specific configuration values. For
-      the sake of these docs, we will provide a fully self-hosted
-      example using bind.
-    </para>
-    <programlisting>
-services.bind = {
-  enable = true;
-  extraConfig = ''
-    include &quot;/var/lib/secrets/dnskeys.conf&quot;;
-  '';
-  zones = [
-    rec {
-      name = &quot;example.com&quot;;
-      file = &quot;/var/db/bind/${name}&quot;;
-      master = true;
-      extraConfig = &quot;allow-update { key rfc2136key.example.com.; };&quot;;
-    }
-  ];
-}
-
-# Now we can configure ACME
-security.acme.acceptTerms = true;
-security.acme.defaults.email = &quot;admin+acme@example.com&quot;;
-security.acme.certs.&quot;example.com&quot; = {
-  domain = &quot;*.example.com&quot;;
-  dnsProvider = &quot;rfc2136&quot;;
-  credentialsFile = &quot;/var/lib/secrets/certs.secret&quot;;
-  # We don't need to wait for propagation since this is a local DNS server
-  dnsPropagationCheck = false;
-};
-</programlisting>
-    <para>
-      The <filename>dnskeys.conf</filename> and
-      <filename>certs.secret</filename> must be kept secure and thus you
-      should not keep their contents in your Nix config. Instead,
-      generate them one time with a systemd service:
-    </para>
-    <programlisting>
-systemd.services.dns-rfc2136-conf = {
-  requiredBy = [&quot;acme-example.com.service&quot; &quot;bind.service&quot;];
-  before = [&quot;acme-example.com.service&quot; &quot;bind.service&quot;];
-  unitConfig = {
-    ConditionPathExists = &quot;!/var/lib/secrets/dnskeys.conf&quot;;
-  };
-  serviceConfig = {
-    Type = &quot;oneshot&quot;;
-    UMask = 0077;
-  };
-  path = [ pkgs.bind ];
-  script = ''
-    mkdir -p /var/lib/secrets
-    chmod 755 /var/lib/secrets
-    tsig-keygen rfc2136key.example.com &gt; /var/lib/secrets/dnskeys.conf
-    chown named:root /var/lib/secrets/dnskeys.conf
-    chmod 400 /var/lib/secrets/dnskeys.conf
-
-    # extract secret value from the dnskeys.conf
-    while read x y; do if [ &quot;$x&quot; = &quot;secret&quot; ]; then secret=&quot;''${y:1:''${#y}-3}&quot;; fi; done &lt; /var/lib/secrets/dnskeys.conf
-
-    cat &gt; /var/lib/secrets/certs.secret &lt;&lt; EOF
-    RFC2136_NAMESERVER='127.0.0.1:53'
-    RFC2136_TSIG_ALGORITHM='hmac-sha256.'
-    RFC2136_TSIG_KEY='rfc2136key.example.com'
-    RFC2136_TSIG_SECRET='$secret'
-    EOF
-    chmod 400 /var/lib/secrets/certs.secret
-  '';
-};
-</programlisting>
-    <para>
-      Now you’re all set to generate certs! You should monitor the first
-      invocation by running
-      <literal>systemctl start acme-example.com.service &amp; journalctl -fu acme-example.com.service</literal>
-      and watching its log output.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-config-dns-with-vhosts">
-    <title>Using DNS validation with web server virtual hosts</title>
-    <para>
-      It is possible to use DNS-01 validation with all certificates,
-      including those automatically configured via the Nginx/Apache
-      <link linkend="opt-services.nginx.virtualHosts._name_.enableACME"><literal>enableACME</literal></link>
-      option. This configuration pattern is fully supported and part of
-      the module’s test suite for Nginx + Apache.
-    </para>
-    <para>
-      You must follow the guide above on configuring DNS-01 validation
-      first, however instead of setting the options for one certificate
-      (e.g.
-      <xref linkend="opt-security.acme.certs._name_.dnsProvider" />) you
-      will set them as defaults (e.g.
-      <xref linkend="opt-security.acme.defaults.dnsProvider" />).
-    </para>
-    <programlisting>
-# Configure ACME appropriately
-security.acme.acceptTerms = true;
-security.acme.defaults.email = &quot;admin+acme@example.com&quot;;
-security.acme.defaults = {
-  dnsProvider = &quot;rfc2136&quot;;
-  credentialsFile = &quot;/var/lib/secrets/certs.secret&quot;;
-  # We don't need to wait for propagation since this is a local DNS server
-  dnsPropagationCheck = false;
-};
-
-# For each virtual host you would like to use DNS-01 validation with,
-# set acmeRoot = null
-services.nginx = {
-  enable = true;
-  virtualHosts = {
-    &quot;foo.example.com&quot; = {
-      enableACME = true;
-      acmeRoot = null;
-    };
-  };
-}
-</programlisting>
-    <para>
-      And that’s it! Next time your configuration is rebuilt, or when
-      you add a new virtualHost, it will be DNS-01 validated.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-root-owned">
-    <title>Using ACME with services demanding root owned
-    certificates</title>
-    <para>
-      Some services refuse to start if the configured certificate files
-      are not owned by root. PostgreSQL and OpenSMTPD are examples of
-      these. There is no way to change the user the ACME module uses (it
-      will always be <literal>acme</literal>), however you can use
-      systemd’s <literal>LoadCredential</literal> feature to resolve
-      this elegantly. Below is an example configuration for OpenSMTPD,
-      but this pattern can be applied to any service.
-    </para>
-    <programlisting>
-# Configure ACME however you like (DNS or HTTP validation), adding
-# the following configuration for the relevant certificate.
-# Note: You cannot use `systemctl reload` here as that would mean
-# the LoadCredential configuration below would be skipped and
-# the service would continue to use old certificates.
-security.acme.certs.&quot;mail.example.com&quot;.postRun = ''
-  systemctl restart opensmtpd
-'';
-
-# Now you must augment OpenSMTPD's systemd service to load
-# the certificate files.
-systemd.services.opensmtpd.requires = [&quot;acme-finished-mail.example.com.target&quot;];
-systemd.services.opensmtpd.serviceConfig.LoadCredential = let
-  certDir = config.security.acme.certs.&quot;mail.example.com&quot;.directory;
-in [
-  &quot;cert.pem:${certDir}/cert.pem&quot;
-  &quot;key.pem:${certDir}/key.pem&quot;
-];
-
-# Finally, configure OpenSMTPD to use these certs.
-services.opensmtpd = let
-  credsDir = &quot;/run/credentials/opensmtpd.service&quot;;
-in {
-  enable = true;
-  setSendmail = false;
-  serverConfiguration = ''
-    pki mail.example.com cert &quot;${credsDir}/cert.pem&quot;
-    pki mail.example.com key &quot;${credsDir}/key.pem&quot;
-    listen on localhost tls pki mail.example.com
-    action act1 relay host smtp://127.0.0.1:10027
-    match for local action act1
-  '';
-};
-</programlisting>
-  </section>
-  <section xml:id="module-security-acme-regenerate">
-    <title>Regenerating certificates</title>
-    <para>
-      Should you need to regenerate a particular certificate in a hurry,
-      such as when a vulnerability is found in Let’s Encrypt, there is
-      now a convenient mechanism for doing so. Running
-      <literal>systemctl clean --what=state acme-example.com.service</literal>
-      will remove all certificate files and the account data for the
-      given domain, allowing you to then
-      <literal>systemctl start acme-example.com.service</literal> to
-      generate fresh ones.
-    </para>
-  </section>
-  <section xml:id="module-security-acme-fix-jws">
-    <title>Fixing JWS Verification error</title>
-    <para>
-      It is possible that your account credentials file may become
-      corrupt and need to be regenerated. In this scenario lego will
-      produce the error <literal>JWS verification error</literal>. The
-      solution is to simply delete the associated accounts file and
-      re-run the affected service(s).
-    </para>
-    <programlisting>
-# Find the accounts folder for the certificate
-systemctl cat acme-example.com.service | grep -Po 'accounts/[^:]*'
-export accountdir=&quot;$(!!)&quot;
-# Move this folder to some place else
-mv /var/lib/acme/.lego/$accountdir{,.bak}
-# Recreate the folder using systemd-tmpfiles
-systemd-tmpfiles --create
-# Get a new account and reissue certificates
-# Note: Do this for all certs that share the same account email address
-systemctl start acme-example.com.service
-</programlisting>
-  </section>
-</chapter>