Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
userguide:let_s_encrypt_acme-dns [2018/06/26 20:06]
Dan Brown [Installing acme-dns] Add installation from RPMs
userguide:let_s_encrypt_acme-dns [2020/03/19 08:17] (current)
Marc [Conclusion]
Line 9: Line 9:
 The effect of this is that if you can create NS and CNAME records on your DNS provider, you can then use acme-dns to automate the DNS updates needed to get and renew your certificates (whether wildcard or not). The effect of this is that if you can create NS and CNAME records on your DNS provider, you can then use acme-dns to automate the DNS updates needed to get and renew your certificates (whether wildcard or not).
 ==== Background and Theory ==== ==== Background and Theory ====
-acme-dns will act as the authoritative DNS server for a subdomain of your domain. ​ If your domain is ''​example.com'',​ that subdomain will be ''​acme.example.com''​. ​ The acme-dns software will generate random hostnames within this subdomain (one random hostname for each FQDN you want to obtain a cer for), of the form ''​32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com''​. ​ You'll add a CNAME record for ''​%%_acme-challenge.example.com%%'',​ pointing to the random hostname. ​ When Let's Encrypt tries to validate domain control over example.com,​ it'll look for DNS records for %%_acme-challenge.example.com%%,​ see the CNAME to 32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com,​ and then query for text records for %%_acme-challenge.32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com%%. ​ At that point, acme-dns will serve the challenge that your client told it to serve, validation will succeed, and Let's Encrypt will issue the cert.+acme-dns will act as the authoritative DNS server for a subdomain of your domain. ​ If your domain is ''​example.com'',​ that subdomain will be ''​acme.example.com''​. ​ The acme-dns software will generate random hostnames within this subdomain (one random hostname for each FQDN you want to obtain a cert for), of the form ''​32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com''​. ​ You'll add a CNAME record for ''​%%_acme-challenge.example.com%%'',​ pointing to the random hostname. ​ When Let's Encrypt tries to validate domain control over example.com,​ it'll look for DNS records for %%_acme-challenge.example.com%%,​ see the CNAME to 32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com,​ and then query for text records for %%_acme-challenge.32f5274d-51e3-466d-bf38-eb9980e7bcf3.acme.example.com%%. ​ At that point, acme-dns will serve the challenge that your client told it to serve, validation will succeed, and Let's Encrypt will issue the cert.
  
 **Note:** Once you've set up acme-dns, you can use it for any domain you control. ​ In other words, you can use a single instance to validate control over any number of domains or subdomains, just by setting individual CNAME records for each desired (sub)domain. **Note:** Once you've set up acme-dns, you can use it for any domain you control. ​ In other words, you can use a single instance to validate control over any number of domains or subdomains, just by setting individual CNAME records for each desired (sub)domain.
Line 25: Line 25:
 </​code>​ </​code>​
 You're done with DNS records for the time being. You're done with DNS records for the time being.
 +
 +==== Important Upgrade Note ====
 +If you've installed a previous version (before version 0.8) of acme-dns, and activated HTTPS for the API, you **must** remove the DNS CNAME record you created for %%_acme-challenge.acme.example.com%%. ​ Acme-dns now handles its own certificate using DNS validation, but this record will conflict with that process.
  
 ==== Installing acme-dns ==== ==== Installing acme-dns ====
  
-=== From RPMs === 
 Install the [[:​danb35_repository|danb35 repo]], then run: Install the [[:​danb35_repository|danb35 repo]], then run:
 <​code>​ <​code>​
Line 34: Line 36:
 </​code>​ </​code>​
  
-== Configuration ==+=== Configuration ​===
 The nethserver-acme-dns RPM should configure everything properly, with the possible exception of your external IP address. ​  If all of the following are true, then the templates should set this correctly: The nethserver-acme-dns RPM should configure everything properly, with the possible exception of your external IP address. ​  If all of the following are true, then the templates should set this correctly:
  
Line 44: Line 46:
 If any of these is not true, you’ll need to set the address manually. To do this, do ''​config setprop acme-dns ExternalIP 1.2.3.4'',​ replacing 1.2.3.4 with your public IP address. Then do ''​signal-event nethserver-acme-dns-update''​. If any of these is not true, you’ll need to set the address manually. To do this, do ''​config setprop acme-dns ExternalIP 1.2.3.4'',​ replacing 1.2.3.4 with your public IP address. Then do ''​signal-event nethserver-acme-dns-update''​.
  
-=== From Source ​=== +=== Testing ​=== 
-acme-dns ​is not available as an RPM in any of the standard repositories (to my knowledge), but its author does have precompiled binary available for [[https://​github.com/​joohoi/​acme-dns/​releases/​download/​v0.4/​acme-dns_0.4_linux_amd64.tar.gz|download]]. Download this package onto your server, ​extract it using ''​tar zxf'',​ and move the acme-dns binary to ''/​usr/​local/​acme-dns/​acme-dns'​'. +== TLS Certificate == 
- +By default, this module ​is configured ​to obtain ​TLS certificate from the Let's Encrypt staging ​server, ​in order to avoid exceeding ​the Let's Encrypt rate limits To ensure that certificate has been issued, run ''​%%openssl s_client ​-connect localhost:​8675%%''​. ​ At the beginning of the output, you should ​see this:
-Create ​configuration file at ''​/etc/acme-dns/​config.cfg'' ​using your favorite text editorIts contents ​should ​look like this:+
 <​code>​ <​code>​
-[general] +[root@neth staging]# openssl s_client -connect ​acme.example.com:8675 
-dns interface +CONNECTED(00000003) 
-listen = "​$EXTERNAL_IP:​1053"​ +depth=1 CN Fake LE Intermediate X1 
-# protocol, "​udp",​ "​udp4",​ "​udp6"​ or "​tcp",​ "​tcp4",​ "​tcp6"​ +verify error:num=20:​unable ​to get local issuer certificate 
-protocol = "​udp"​ +--- 
-# domain name to serve the requests off of +Certificate chain 
-domain = "acme.example.com" + 0 s:/CN=acme.example.com 
-# zone name server +   i:/CN=Fake LE Intermediate X1 
-nsname ​"​ns1.acme.example.com"​ + 1 s:/CN=Fake LE Intermediate X1 
-# admin email address, where @ is substituted with . +   i:/CN=Fake LE Root X1 
-nsadmin ​"​admin.example.com"​ +---
-# predefined records served in addition to the TXT +
-records ​+
-    # default A +
-    "​acme.example.com. A $EXTERNAL_IP",​ +
-    # A +
-    "​ns1.acme.example.com. A $EXTERNAL_IP",​ +
-    "​ns2.acme.example.com. A $EXTERNAL_IP",​ +
-    # NS +
-    "​acme.example.com. NS ns1.acme.example.com.",​ +
-    "​acme.example.com. NS ns2.acme.example.com.",​ +
-+
-# debug messages from CORS etc +
-debug = false +
- +
-[database] +
-# Database engine ​to use, sqlite3 or postgres +
-engine = "​sqlite3"​ +
-# Connection string, filename for sqlite3 and postgres://​$username:​$password@$host/​$db_name for postgres +
-# Please note that the default Docker image uses path /​var/​lib/​acme-dns/acme-dns.db for sqlite3 +
-connection = "/​etc/​acme-dns/​acme-dns.db"​ +
-# connection = "​postgres://​user:​password@localhost/​acmedns_db"​ +
- +
-[api] +
-# domain name to listen requests for, mandatory if using tls = "​letsencrypt"​ +
-api_domain = ""​ +
-# listen ip eg. 127.0.0.1 +
-ip = "​0.0.0.0"​ +
-# disable registration endpoint +
-disable_registration = false +
-# autocert HTTP port, eg. 80 for answering Let'Encrypt HTTP-01 challenges. Mandatory if using tls = "​letsencrypt"​. +
-# autocert_port = "​80"​ +
-# listen port, eg. 443 for default HTTPS +
-port = "​8675"​ +
-# possible values"​letsencrypt",​ "​cert",​ "​none"​ +
-tls "​none"​ +
-# only used if tls = "​cert"​ +
-#​tls_cert_privkey = "/​etc/​tls/​example.org/​privkey.pem"​ +
-#​tls_cert_fullchain = "/​etc/​tls/​example.org/​fullchain.pem"​ +
-# CORS AllowOrigins,​ wildcards can be used +
-corsorigins = [ +
-    "​*"​ +
-+
-# use HTTP header to get the client ip +
-use_header = false +
-# header name to pull the ip address ​list of ip addresses from +
-header_name ​"​X-Forwarded-For"​ +
- +
-[logconfig] +
-# logging level"​error",​ "​warning",​ "​info"​ or "​debug"​ +
-loglevel ​"​debug"​ +
-# possible valuesstdout, TODO file & integrations +
-logtype ​"​stdout"​ +
-# file path for logfile TODO +
-# logfile = "​./​acme-dns.log"​ +
-# format, either "​json"​ or "​text"​ +
-logformat = "​text"​+
 </​code>​ </​code>​
- +The inclusion of "Fake LE Root X1" and "Fake LE Intermediate X1" in the certificate chain shows that acme-dns is using a certificate from the staging environmentwhich further shows that all the steps in the issuance process are working. ​ To change ​to using "​production"​ certificaterun ''​config setprop ​acme-dns-api TLSType letsencrypt'' ​followed by ''​signal-event nethserver-acme-dns-update''​. ​ Then re-run ​the ''​openssl''​ command from above. ​ The output should now look like this:
-Nextyou’ll need to create ​service file for systemd. Using your favorite text editorcreate ​''​/​etc/​systemd/​system/​acme-dns.service'' ​with the contents below:+
 <​code>​ <​code>​
-[Unit+[root@neth ~]# openssl s_client -connect localhost:​8675 
-Description=acme-dns Service +CONNECTED(00000003) 
-After=network.target +depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 
- +verify return:1 
-[Service] +depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 
-Type=simple +verify return:1 
-ExecStart=/usr/local/acme-dns/acme-dns +depth=0 CN = acme.example.com 
- +verify return:1 
-[Install] +--- 
-WantedBy=multi-user.target+Certificate chain 
 + 0 s:/CN=acme.example.com 
 +   i:/C=US/O=Let'​s Encrypt/CN=Let'​s Encrypt Authority X3 
 + 1 s:/C=US/O=Let'​s Encrypt/​CN=Let'​s Encrypt Authority X3 
 +   i:/O=Digital Signature Trust Co./CN=DST Root CA X3 
 +---
 </​code>​ </​code>​
 +The presence of "​Let'​s Encrypt Authority X3" shows that you now have a certificate from the production server.
  
-You can then enable and start the service by running ''​systemctl enable --now acme-dns''​.+== Testing ​the API ==
  
-Next, we’ll need to open port 53 on the Internet (red) interface and redirect it to port 1053 for acme-dns to listen to it. Create ''/​etc/​e-smith/​templates-custom/​etc/​shorewall/​rules/​95acme''​ with the following contents: +To confirm that your acme-dns instance is up and running, run ''​%%curl -s -X POST https://acme.example.com:​8675/​register | python -m json.tool%%''​. You should get something like this as your output:
-<​code>​ +
-REDIRECT ​ net  1053  tcp  53 +
-REDIRECT ​ net  1053  udp  53 +
-</​code>​ +
- +
-Then run +
-<​code>​ +
-config set fw_acme-dns service status enabled UDPPort 53 TCPPort 53 access red +
-signal-event firewall-adjust +
-</​code>​ +
- +
-=== Testing === +
-To confirm that your acme-dns instance is up and running, run ''​%%curl -s -X POST http://localhost:​8675/​register | python -m json.tool%%''​. You should get something like this as your output:+
 <​code>​ <​code>​
 { {
Line 163: Line 100:
 Certbot doesn’t know, on its own, how to set DNS entries on acme-dns. Fortunately,​ the author of acme-dns has provided a [[https://​github.com/​joohoi/​acme-dns-certbot-joohoi|script]] to handle this. Download the script by doing ''​%%curl -o /​etc/​letsencrypt/​acme-dns-auth.py https://​raw.githubusercontent.com/​joohoi/​acme-dns-certbot-joohoi/​master/​acme-dns-auth.py%%''​ followed by ''​chmod 0700 /​etc/​letsencrypt/​acme-dns-auth.py''​. Certbot doesn’t know, on its own, how to set DNS entries on acme-dns. Fortunately,​ the author of acme-dns has provided a [[https://​github.com/​joohoi/​acme-dns-certbot-joohoi|script]] to handle this. Download the script by doing ''​%%curl -o /​etc/​letsencrypt/​acme-dns-auth.py https://​raw.githubusercontent.com/​joohoi/​acme-dns-certbot-joohoi/​master/​acme-dns-auth.py%%''​ followed by ''​chmod 0700 /​etc/​letsencrypt/​acme-dns-auth.py''​.
  
-You’ll need to edit the script. Near the top, change ACMEDNS_URL to ''​%%http://localhost:​8675%%''​. No other changes need to be made.+You’ll need to edit the script. Near the top, change ACMEDNS_URL to ''​%%https://acme.example.com:​8675%%''​. No other changes need to be made.
  
 ==== Issuing the certificate ==== ==== Issuing the certificate ====
Line 169: Line 106:
 <​code>​ <​code>​
 certbot certonly --manual --manual-auth-hook /​etc/​letsencrypt/​acme-dns-auth.py \ certbot certonly --manual --manual-auth-hook /​etc/​letsencrypt/​acme-dns-auth.py \
-   ​--preferred-challenges dns --debug-challenges --post-hook "​signal-event certificate-update"​ \+   ​--preferred-challenges dns --debug-challenges --post-hook "/​sbin/​e-smith/​signal-event certificate-update"​ \
    -d example.com -d \*.example.com    -d example.com -d \*.example.com
 </​code>​ </​code>​
Line 187: Line 124:
 </​code>​ </​code>​
 You’ll need to once again log into your DNS host and add the record specified. ​ You'll only need to do this once for each hostname. ​ Wait a few minutes, then press Enter. You’ll need to once again log into your DNS host and add the record specified. ​ You'll only need to do this once for each hostname. ​ Wait a few minutes, then press Enter.
- 
-===== Enabling HTTPS for the acme-dns API ===== 
-As noted above, once you have acme-dns running, you can use it to validate any domain you control, as long as you can set the appropriate CNAME records. ​ But if you're going to be accessing its API remotely, you should really secure its API using HTTPS. 
- 
-==== Get a certificate ==== 
-We just created a wildcard certificate above, so we could use that, but it's better practice to use a unique certificate for this service. ​ To issue that certificate,​ run the following: 
-<​code>​ 
-certbot certonly --manual --manual-auth-hook /​etc/​letsencrypt/​acme-dns-auth.py \ 
-   ​--preferred-challenges dns --debug-challenges --post-hook "​systemctl restart acme-dns"​ \ 
-   -d acme.example.com 
-</​code>​ 
-Also as above, you’ll be told to create a CNAME record with your DNS host. Do that, wait a couple of minutes, then press Enter. Your certificate will be generated. 
- 
-==== Configure acme-dns for HTTPS ==== 
- 
-You’ll need to make just a few changes to /​etc/​acme-dns/​config.cfg:​ 
-<​code>​ 
-tls = "​cert"​ 
-tls_cert_privkey = "/​etc/​letsencrypt/​live/​acme.example.com/​privkey.pem"​ 
-tls_cert_fullchain = "/​etc/​letsencrypt/​live/​acme.example.com/​fullchain.pem"​ 
-</​code>​ 
- 
-Then restart the service: ''​systemctl restart acme-dns''​. 
- 
-==== Configure the hook script ==== 
- 
-You’ll also need to update the hook script. Edit ''/​etc/​letsencrypt/​acme-dns-auth.py''​ and change ''​ACMEDNS_URL''​ to ''​%%https://​acme.example.com:​8675%%'',​ then save and exit. 
- 
-==== Adjust the firewall settings ==== 
- 
-We need to open another port in the firewall for this: 
-<​code>​ 
-config set fw_acme-dns-api service status enabled TCPPort 8675 access red,green 
-signal-event firewall-adjust 
-</​code>​ 
  
 ===== Renewal ===== ===== Renewal =====
Line 237: Line 139:
 Note that, in this configuration,​ anyone on the Internet can access the API of your acme-dns instance. If the other hosts that might be using it are on your LAN, you might want to change the access property above to just green rather than red,green. Note that, in this configuration,​ anyone on the Internet can access the API of your acme-dns instance. If the other hosts that might be using it are on your LAN, you might want to change the access property above to just green rather than red,green.
  
-{{tag>​userguide ht_v7 ht_application}}+{{tag>​userguide ht_v7 ht_application ​module}}