Implement HTTP-01 challenge

This commit is contained in:
Moritz Marquardt 2021-11-20 21:10:46 +01:00
parent 73c21d0195
commit c99dbb34ce
No known key found for this signature in database
GPG key ID: D5788327BEE388B6
3 changed files with 40 additions and 2 deletions

View file

@ -11,5 +11,6 @@
- `ACME_EMAIL` (default: `noreply@example.email`): Set this to "true" to accept the Terms of Service of your ACME provider. - `ACME_EMAIL` (default: `noreply@example.email`): Set this to "true" to accept the Terms of Service of your ACME provider.
- `ACME_EAB_KID` & `ACME_EAB_HMAC` (default: don't use EAB): EAB credentials, for example for ZeroSSL. - `ACME_EAB_KID` & `ACME_EAB_HMAC` (default: don't use EAB): EAB credentials, for example for ZeroSSL.
- `ACME_ACCEPT_TERMS` (default: use self-signed certificate): Set this to "true" to accept the Terms of Service of your ACME provider. - `ACME_ACCEPT_TERMS` (default: use self-signed certificate): Set this to "true" to accept the Terms of Service of your ACME provider.
- `ENABLE_HTTP_SERVER` (default: false): Set this to true to enable the HTTP-01 challenge and redirect all other HTTP requests to HTTPS. Currently only works with port 80.
- `DNS_PROVIDER` (default: use self-signed certificate): Code of the ACME DNS provider for the main domain wildcard. - `DNS_PROVIDER` (default: use self-signed certificate): Code of the ACME DNS provider for the main domain wildcard.
See https://go-acme.github.io/lego/dns/ for available values & additional environment variables. See https://go-acme.github.io/lego/dns/ for available values & additional environment variables.

View file

@ -131,7 +131,6 @@ var tlsConfig = &tls.Config{
}, },
} }
var challengeCache = mcache.New()
var keyCache = mcache.New() var keyCache = mcache.New()
var keyDatabase *pogreb.DB var keyDatabase *pogreb.DB
@ -189,6 +188,7 @@ var acmeClientOrderLimit = equalizer.NewTokenBucket(25, 15 * time.Minute)
// rate limit is 20 / second, we want 10 / second // rate limit is 20 / second, we want 10 / second
var acmeClientRequestLimit = equalizer.NewTokenBucket(10, 1 * time.Second) var acmeClientRequestLimit = equalizer.NewTokenBucket(10, 1 * time.Second)
var challengeCache = mcache.New()
type AcmeTLSChallengeProvider struct{} type AcmeTLSChallengeProvider struct{}
var _ challenge.Provider = AcmeTLSChallengeProvider{} var _ challenge.Provider = AcmeTLSChallengeProvider{}
func (a AcmeTLSChallengeProvider) Present(domain, _, keyAuth string) error { func (a AcmeTLSChallengeProvider) Present(domain, _, keyAuth string) error {
@ -198,6 +198,15 @@ func (a AcmeTLSChallengeProvider) CleanUp(domain, _, _ string) error {
challengeCache.Remove(domain) challengeCache.Remove(domain)
return nil return nil
} }
type AcmeHTTPChallengeProvider struct{}
var _ challenge.Provider = AcmeHTTPChallengeProvider{}
func (a AcmeHTTPChallengeProvider) Present(domain, token, keyAuth string) error {
return challengeCache.Set(domain + "/" + token, keyAuth, 1*time.Hour)
}
func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error {
challengeCache.Remove(domain + "/" + token)
return nil
}
func retrieveCertFromDB(sni []byte) (tls.Certificate, bool) { func retrieveCertFromDB(sni []byte) (tls.Certificate, bool) {
// parse certificate from database // parse certificate from database
@ -383,7 +392,14 @@ func setupCertificates() {
} }
acmeClient = newAcmeClient(func(challenge *resolver.SolverManager) error { acmeClient = newAcmeClient(func(challenge *resolver.SolverManager) error {
return challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{}) err = challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{})
if err != nil {
return err
}
if os.Getenv("ENABLE_HTTP_SERVER") == "true" {
return challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{})
}
return err
}) })
mainDomainAcmeClient = newAcmeClient(func(challenge *resolver.SolverManager) error { mainDomainAcmeClient = newAcmeClient(func(challenge *resolver.SolverManager) error {
if os.Getenv("DNS_PROVIDER") == "" { if os.Getenv("DNS_PROVIDER") == "" {

21
main.go
View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"log" "log"
"net" "net"
"net/http"
"os" "os"
"time" "time"
@ -103,6 +104,26 @@ func main() {
listener = tls.NewListener(listener, tlsConfig) listener = tls.NewListener(listener, tlsConfig)
setupCertificates() setupCertificates()
if os.Getenv("ENABLE_HTTP_SERVER") == "true" {
go (func() {
challengePath := []byte("/.well-known/acme-challenge/")
err := fasthttp.ListenAndServe("[::]:80", func(ctx *fasthttp.RequestCtx) {
if bytes.HasPrefix(ctx.Path(), challengePath) {
challenge, ok := challengeCache.Get(string(TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath)))
if !ok {
ctx.SetStatusCode(http.StatusNotFound)
ctx.SetBodyString("no challenge for this token")
}
ctx.SetBodyString(challenge.(string))
} else {
ctx.Redirect("https://" + string(ctx.Host()) + string(ctx.RequestURI()), http.StatusMovedPermanently)
}
})
if err != nil {
log.Fatalf("Couldn't start HTTP server: %s", err)
}
})()
}
// Start the web server // Start the web server
err = server.Serve(listener) err = server.Serve(listener)