Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate over to certmagic from using autocert #190

Merged
merged 9 commits into from
Oct 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ $ dig -t txt @auth.example.org d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example
# DNS interface. Note that systemd-resolved may reserve port 53 on 127.0.0.53
# In this case acme-dns will error out and you will need to define the listening interface
# for example: listen = "127.0.0.1:53"
listen = ":53"
listen = "127.0.0.1:53"
# protocol, "both", "both4", "both6", "udp", "udp4", "udp6" or "tcp", "tcp4", "tcp6"
protocol = "both"
# domain name to serve the requests off of
Expand All @@ -249,7 +249,7 @@ nsname = "auth.example.org"
nsadmin = "admin.example.org"
# predefined records served in addition to the TXT
records = [
# domain pointing to the public IP of your acme-dns server
# domain pointing to the public IP of your acme-dns server
"auth.example.org. A 198.51.100.1",
# specify that auth.example.org will resolve any *.auth.example.org records
"auth.example.org. NS auth.example.org.",
Expand All @@ -261,22 +261,19 @@ debug = false
# 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 = "/var/lib/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's Encrypt HTTP-01 challenges. Mandatory if using tls = "letsencrypt".
autocert_port = "80"
# listen ip, default "" listens on all interfaces/addresses
ip = "127.0.0.1"
# listen port, eg. 443 for default HTTPS
port = "8080"
# possible values: "letsencrypt", "cert", "none"
tls = "none"
port = "443"
# possible values: "letsencrypt", "letsencryptstaging", "cert", "none"
tls = "letsencryptstaging"
# only used if tls = "cert"
tls_cert_privkey = "/etc/tls/example.org/privkey.pem"
tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem"
Expand Down Expand Up @@ -346,8 +343,13 @@ use for the renewal.
## Changelog

- v0.8
- NOTE: configuration option: "api_domain" deprecated!
- New
- Automatic HTTP API certificate provisioning using DNS challenges making acme-dns able to acquire certificates even with HTTP api not being accessible from public internet.
- Configuration value for "tls": "letsencryptstaging". Setting it will help you to debug possible issues with HTTP API certificate acquiring process. This is the new default value.
- Changed
- Fixed: EDNS0 support
- Migrated from autocert to [certmagic](https://github.com/mholt/certmagic) for HTTP API certificate handling
- v0.7.2
- Changed
- Fixed: Regression error of not being able to answer to incoming random-case requests.
Expand Down
30 changes: 30 additions & 0 deletions challengeprovider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import "github.com/go-acme/lego/challenge/dns01"

// ChallengeProvider implements go-acme/lego Provider interface which is used for ACME DNS challenge handling
type ChallengeProvider struct {
servers []*DNSServer
}

// NewChallengeProvider creates a new instance of ChallengeProvider
func NewChallengeProvider(servers []*DNSServer) ChallengeProvider {
return ChallengeProvider{servers: servers}
}

// Present is used for making the ACME DNS challenge token available for DNS
func (c *ChallengeProvider) Present(_, _, keyAuth string) error {
_, token := dns01.GetRecord("whatever", keyAuth)
for _, s := range c.servers {
s.PersonalKeyAuth = token
}
return nil
}

// CleanUp is called after the run to remove the ACME DNS challenge tokens from DNS records
func (c *ChallengeProvider) CleanUp(_, _, _ string) error {
for _, s := range c.servers {
s.PersonalKeyAuth = ""
}
return nil
}
10 changes: 3 additions & 7 deletions config.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,14 @@ connection = "/var/lib/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's Encrypt HTTP-01 challenges. Mandatory if using tls = "letsencrypt".
autocert_port = "80"
# listen port, eg. 443 for default HTTPS
port = "80"
# possible values: "letsencrypt", "cert", "none"
tls = "none"
port = "443"
# possible values: "letsencrypt", "letsencryptstaging", "cert", "none"
tls = "letsencryptstaging"
# only used if tls = "cert"
tls_cert_privkey = "/etc/tls/example.org/privkey.pem"
tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem"
Expand Down
55 changes: 48 additions & 7 deletions dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,24 @@ type Records struct {

// DNSServer is the main struct for acme-dns DNS server
type DNSServer struct {
DB database
Server *dns.Server
SOA dns.RR
Domains map[string]Records
DB database
Domain string
Server *dns.Server
SOA dns.RR
PersonalKeyAuth string
Domains map[string]Records
}

// NewDNSServer parses the DNS records from config and returns a new DNSServer struct
func NewDNSServer(db database, addr string, proto string) *DNSServer {
func NewDNSServer(db database, addr string, proto string, domain string) *DNSServer {
var server DNSServer
server.Server = &dns.Server{Addr: addr, Net: proto}
if !strings.HasSuffix(domain, ".") {
domain = domain + "."
}
server.Domain = strings.ToLower(domain)
server.DB = db
server.PersonalKeyAuth = ""
server.Domains = make(map[string]Records)
return &server
}
Expand Down Expand Up @@ -148,6 +155,9 @@ func (d *DNSServer) getRecord(q dns.Question) ([]dns.RR, error) {

// answeringForDomain checks if we have any records for a domain
func (d *DNSServer) answeringForDomain(name string) bool {
if d.Domain == strings.ToLower(name) {
return true
}
_, ok := d.Domains[strings.ToLower(name)]
return ok
}
Expand All @@ -165,15 +175,38 @@ func (d *DNSServer) isAuthoritative(q dns.Question) bool {
return false
}

// isOwnChallenge checks if the query is for the domain of this acme-dns instance. Used for answering its own ACME challenges
func (d *DNSServer) isOwnChallenge(name string) bool {
domainParts := strings.SplitN(name, ".", 2)
if len(domainParts) == 2 {
if strings.ToLower(domainParts[0]) == "_acme-challenge" {
domain := strings.ToLower(domainParts[1])
if !strings.HasSuffix(domain, ".") {
domain = domain + "."
}
if domain == d.Domain {
return true
}
}
}
return false
}

func (d *DNSServer) answer(q dns.Question) ([]dns.RR, int, bool, error) {
var rcode int
var err error
var txtRRs []dns.RR
var authoritative = d.isAuthoritative(q)
if !d.answeringForDomain(q.Name) {
if !d.isOwnChallenge(q.Name) && !d.answeringForDomain(q.Name) {
rcode = dns.RcodeNameError
}
r, _ := d.getRecord(q)
if q.Qtype == dns.TypeTXT {
txtRRs, err := d.answerTXT(q)
if d.isOwnChallenge(q.Name) {
txtRRs, err = d.answerOwnChallenge(q)
} else {
txtRRs, err = d.answerTXT(q)
}
if err == nil {
for _, txtRR := range txtRRs {
r = append(r, txtRR)
Expand Down Expand Up @@ -206,3 +239,11 @@ func (d *DNSServer) answerTXT(q dns.Question) ([]dns.RR, error) {
}
return ra, nil
}

// answerOwnChallenge answers to ACME challenge for acme-dns own certificate
func (d *DNSServer) answerOwnChallenge(q dns.Question) ([]dns.RR, error) {
r := new(dns.TXT)
r.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 1}
r.Txt = append(r.Txt, d.PersonalKeyAuth)
return []dns.RR{r}, nil
}
11 changes: 8 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ require (
github.com/BurntSushi/toml v0.3.1
github.com/DATA-DOG/go-sqlmock v1.3.3
github.com/ajg/form v1.5.1 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5
github.com/fatih/structs v1.1.0 // indirect
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect
github.com/gavv/httpexpect v2.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
github.com/go-acme/lego v2.7.2+incompatible
github.com/go-acme/lego/v3 v3.1.0
github.com/google/uuid v1.1.1
github.com/gorilla/websocket v1.4.1 // indirect
github.com/imkira/go-interpol v1.1.0 // indirect
github.com/julienschmidt/httprouter v1.3.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
github.com/lib/pq v1.2.0
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-sqlite3 v1.11.0
github.com/mholt/certmagic v0.8.1-0.20191019173955-6f9f0e6dd0e8
github.com/miekg/dns v1.1.22
github.com/moul/http2curl v1.0.0 // indirect
github.com/rs/cors v1.7.0
Expand All @@ -27,6 +31,7 @@ require (
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
Expand Down
Loading