Skip to content

Commit

Permalink
Support https
Browse files Browse the repository at this point in the history
  • Loading branch information
wzshiming committed Jun 25, 2024
1 parent d67ba65 commit 51b9d31
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 10 deletions.
21 changes: 12 additions & 9 deletions cmd/crproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"io"
"log"
"net"
"net/http"
"net/http/pprof"
"net/url"
Expand All @@ -27,6 +26,7 @@ import (
_ "github.com/distribution/distribution/v3/registry/storage/driver/s3-aws"

"github.com/daocloud/crproxy"
"github.com/daocloud/crproxy/internal/server"
)

var (
Expand Down Expand Up @@ -56,6 +56,11 @@ var (
overrideDefaultRegistry map[string]string
simpleAuth bool
tokenURL string

acmeHosts []string
acmeCacheDir string
certFile string
privateKeyFile string
)

func init() {
Expand Down Expand Up @@ -85,6 +90,11 @@ func init() {
pflag.StringToStringVar(&overrideDefaultRegistry, "override-default-registry", nil, "override default registry")
pflag.BoolVar(&simpleAuth, "simple-auth", false, "enable simple auth")
pflag.StringVar(&tokenURL, "token-url", "", "token url")

pflag.StringSliceVar(&acmeHosts, "acme-hosts", nil, "acme hosts")
pflag.StringVar(&acmeCacheDir, "acme-cache-dir", "", "acme cache dir")
pflag.StringVar(&certFile, "cert-file", "", "cert file")
pflag.StringVar(&privateKeyFile, "private-key-file", "", "private key file")
pflag.Parse()
}

Expand Down Expand Up @@ -324,15 +334,8 @@ func main() {
if behind {
handler = handlers.ProxyHeaders(handler)
}
server := http.Server{
BaseContext: func(listener net.Listener) context.Context {
return ctx
},
Handler: handler,
Addr: address,
}

err = server.ListenAndServe()
err = server.Run(ctx, address, handler, acmeHosts, acmeCacheDir, certFile, privateKeyFile)
if err != nil {
logger.Println("failed to ListenAndServe:", err)
os.Exit(1)
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ require (
github.com/gorilla/handlers v1.5.1
github.com/opencontainers/go-digest v1.0.0
github.com/spf13/pflag v1.0.3
github.com/wzshiming/cmux v0.3.3
github.com/wzshiming/geario v0.0.0-20220512063849-ddc203ba7487
github.com/wzshiming/hostmatcher v0.0.3
github.com/wzshiming/httpseek v0.1.0
github.com/wzshiming/lru v0.1.0
golang.org/x/crypto v0.24.0
)

require (
Expand Down Expand Up @@ -50,8 +52,8 @@ require (
github.com/prometheus/procfs v0.11.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/wzshiming/trie v0.1.1 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/sys v0.21.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaO
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/wzshiming/cmux v0.3.3 h1:WlcKUwSN4vpClnHiyX9I4RtZ4xJeAqfrf4ltxSWuPoQ=
github.com/wzshiming/cmux v0.3.3/go.mod h1:lPhqJN2E3frzkxrPdjesxL09z7nTcuZ6i8Is+2G/Xw4=
github.com/wzshiming/geario v0.0.0-20220512063849-ddc203ba7487 h1:5YN2BY58L2/5N7olluOPqJmmybcio0+DFY6nwH5gc8c=
github.com/wzshiming/geario v0.0.0-20220512063849-ddc203ba7487/go.mod h1:Fodw3HJvNUS+/MgqXCRp9iYLQfynAu/LKXGOWoX+D/Q=
github.com/wzshiming/hostmatcher v0.0.3 h1:+JYAq6vUZXDEQ1Ipfdc/D7HmaIMngcc71ftonyCQVQk=
Expand All @@ -209,6 +211,8 @@ github.com/wzshiming/httpseek v0.1.0 h1:lEgL7EBELT/VV9UaTp+m3kw5Pe1KOUdY+IPnKkag
github.com/wzshiming/httpseek v0.1.0/go.mod h1:YoZhlLIwNjTBDXIT8NpK5zRjOgZouRXPaBfjVXdqMMs=
github.com/wzshiming/lru v0.1.0 h1:937SBBo9lDBRMivJqF46eVK2Q3omRWnN7hWpr2i3xZg=
github.com/wzshiming/lru v0.1.0/go.mod h1:uaI2W/Gx3r1gHIc3FG38PKK1idvMXhgY8lToXaBsDIQ=
github.com/wzshiming/trie v0.1.1 h1:02AaBSZGhs6Aqljp8fz4xq/Mg8omFBPIlrUS0pJ11ks=
github.com/wzshiming/trie v0.1.1/go.mod h1:c9thxXTh4KcGkejt4sUsO4c5GUmWpxeWzOJ7AZJaI+8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
Expand Down
69 changes: 69 additions & 0 deletions internal/acme/acme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package acme

import (
"context"
"crypto/tls"
"fmt"
"os"
"path/filepath"
"runtime"

"github.com/wzshiming/hostmatcher"
"golang.org/x/crypto/acme/autocert"
)

func hostWhitelist(hosts ...string) autocert.HostPolicy {
matcher := hostmatcher.NewMatcher(hosts)
return func(_ context.Context, host string) error {
if !matcher.Match(host) {
return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
}
return nil
}
}

func NewAcme(domains []string, dir string) *tls.Config {
m := &autocert.Manager{
Prompt: autocert.AcceptTOS,
}
if len(domains) > 0 {
m.HostPolicy = hostWhitelist(domains...)
}
if dir == "" {
dir = cacheDir()
}
m.Cache = autocert.DirCache(dir)

tlsConfig := m.TLSConfig()
return tlsConfig
}

func homeDir() string {
if runtime.GOOS == "windows" {
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
}
if h := os.Getenv("HOME"); h != "" {
return h
}
return "/"
}

func cacheDir() string {
const base = "autocert"
switch runtime.GOOS {
case "darwin":
return filepath.Join(homeDir(), "Library", "Caches", base)
case "windows":
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
if v := os.Getenv(ev); v != "" {
return filepath.Join(v, base)
}
}
// Worst case:
return filepath.Join(homeDir(), base)
}
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
return filepath.Join(xdg, base)
}
return filepath.Join(homeDir(), ".cache", base)
}
92 changes: 92 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package server

import (
"context"
"fmt"
"net"
"net/http"
"net/http/httptest"
"time"

"github.com/daocloud/crproxy/internal/acme"
"github.com/wzshiming/cmux"
"github.com/wzshiming/cmux/pattern"
)

func Run(ctx context.Context, address string, handler http.Handler, acmeHosts []string, acmeCache string, certFile, privateKeyFile string) error {
listener, err := net.Listen("tcp", address)
if err != nil {
return err
}

muxListener := cmux.NewMuxListener(listener)
tlsListener, err := muxListener.MatchPrefix(pattern.Pattern[pattern.TLS]...)
if err != nil {
return fmt.Errorf("match tls listener: %w", err)
}
unmatchedListener, err := muxListener.Unmatched()
if err != nil {
return fmt.Errorf("unmatched listener: %w", err)
}

ctx, cancel := context.WithCancel(ctx)
defer cancel()

errCh := make(chan error, 1)

if (certFile != "" && privateKeyFile != "") || len(acmeHosts) != 0 {
go func() {
svc := &http.Server{
ReadHeaderTimeout: 5 * time.Second,
BaseContext: func(_ net.Listener) context.Context {
return ctx
},
Addr: address,
Handler: handler,
}
if len(acmeHosts) != 0 {
svc.TLSConfig = acme.NewAcme(acmeHosts, acmeCache)
}
err = svc.ServeTLS(tlsListener, certFile, privateKeyFile)
if err != nil {
errCh <- fmt.Errorf("serve https: %w", err)
}
}()
} else {
svc := httptest.Server{
Listener: tlsListener,
Config: &http.Server{
ReadHeaderTimeout: 5 * time.Second,
BaseContext: func(_ net.Listener) context.Context {
return ctx
},
Addr: address,
Handler: handler,
},
}
svc.StartTLS()
}

go func() {
svc := &http.Server{
ReadHeaderTimeout: 5 * time.Second,
BaseContext: func(_ net.Listener) context.Context {
return ctx
},
Addr: address,
Handler: handler,
}
err = svc.Serve(unmatchedListener)
if err != nil {
errCh <- fmt.Errorf("serve http: %w", err)
}
}()

select {
case err = <-errCh:
case <-ctx.Done():
err = ctx.Err()
}

return err
}

0 comments on commit 51b9d31

Please sign in to comment.