From d2ea21d0d8103986b2ce53c17b7b99b1ce6828b0 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sun, 24 Jan 2021 18:37:35 -0500 Subject: Use caddy's certmagic library for extensible/robust ACME handling (#14177) * use certmagic for more extensible/robust ACME cert handling * accept TOS based on config option Signed-off-by: Andrew Thornton Co-authored-by: zeripath Co-authored-by: Lauris BH --- cmd/web.go | 31 ----------------------- cmd/web_letsencrypt.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 31 deletions(-) create mode 100644 cmd/web_letsencrypt.go (limited to 'cmd') diff --git a/cmd/web.go b/cmd/web.go index 063e41c946..2e8c45a76e 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -22,7 +22,6 @@ import ( context2 "github.com/gorilla/context" "github.com/urfave/cli" - "golang.org/x/crypto/acme/autocert" ini "gopkg.in/ini.v1" ) @@ -72,36 +71,6 @@ func runHTTPRedirector() { } } -func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error { - certManager := autocert.Manager{ - Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist(domain), - Cache: autocert.DirCache(directory), - Email: email, - } - go func() { - log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect) - // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here) - var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) - if err != nil { - log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err) - } - }() - return runHTTPSWithTLSConfig("tcp", listenAddr, certManager.TLSConfig(), context2.ClearHandler(m)) -} - -func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" && r.Method != "HEAD" { - http.Error(w, "Use HTTPS", http.StatusBadRequest) - return - } - // Remove the trailing slash at the end of setting.AppURL, the request - // URI always contains a leading slash, which would result in a double - // slash - target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI() - http.Redirect(w, r, target, http.StatusFound) -} - func runWeb(ctx *cli.Context) error { managerCtx, cancel := context.WithCancel(context.Background()) graceful.InitManager(managerCtx) diff --git a/cmd/web_letsencrypt.go b/cmd/web_letsencrypt.go new file mode 100644 index 0000000000..cded53a49d --- /dev/null +++ b/cmd/web_letsencrypt.go @@ -0,0 +1,69 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package cmd + +import ( + "net/http" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/caddyserver/certmagic" + context2 "github.com/gorilla/context" +) + +func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error { + + // If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443. + // Due to docker port mapping this can't be checked programatically + // TODO: these are placeholders until we add options for each in settings with appropriate warning + enableHTTPChallenge := true + enableTLSALPNChallenge := true + + magic := certmagic.NewDefault() + magic.Storage = &certmagic.FileStorage{Path: directory} + myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ + Email: email, + Agreed: setting.LetsEncryptTOS, + DisableHTTPChallenge: !enableHTTPChallenge, + DisableTLSALPNChallenge: !enableTLSALPNChallenge, + }) + + magic.Issuer = myACME + + // this obtains certificates or renews them if necessary + err := magic.ManageSync([]string{domain}) + if err != nil { + return err + } + + tlsConfig := magic.TLSConfig() + + if enableHTTPChallenge { + go func() { + log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect) + // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here) + var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) + if err != nil { + log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err) + } + }() + } + + return runHTTPSWithTLSConfig("tcp", listenAddr, tlsConfig, context2.ClearHandler(m)) +} + +func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" && r.Method != "HEAD" { + http.Error(w, "Use HTTPS", http.StatusBadRequest) + return + } + // Remove the trailing slash at the end of setting.AppURL, the request + // URI always contains a leading slash, which would result in a double + // slash + target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI() + http.Redirect(w, r, target, http.StatusFound) +} -- cgit v1.2.3