86 lines
1.8 KiB
Go
86 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
|
|
"tailscale.com/client/tailscale"
|
|
"tailscale.com/tsnet"
|
|
)
|
|
|
|
var (
|
|
target = flag.String("target", "http://127.0.0.1:3000", "target HTTP server for Grafana")
|
|
hostname = flag.String("hostname", "grafana", "the hostname to use on the tailnet")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
ctx := context.Background()
|
|
|
|
u, err := url.Parse(*target)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
hdlr := tsAuthMiddleware{
|
|
next: httputil.NewSingleHostReverseProxy(u),
|
|
}
|
|
|
|
srv := &tsnet.Server{
|
|
Hostname: *hostname,
|
|
Logf: log.Printf,
|
|
}
|
|
|
|
selfFQDN, ok := tailscale.ExpandSNIName(ctx, *hostname)
|
|
if !ok {
|
|
log.Fatal("could not get sni name")
|
|
}
|
|
|
|
l, err := srv.Listen("tcp", ":443")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
l = tls.NewListener(l, &tls.Config{
|
|
GetCertificate: func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
if chi.ServerName != selfFQDN {
|
|
return nil, fmt.Errorf("wanted hostname %s, got: %s", selfFQDN, chi.ServerName)
|
|
}
|
|
|
|
c, err := tailscale.GetCertificate(chi)
|
|
if err != nil {
|
|
log.Printf("%s: %v", chi.Conn.RemoteAddr(), err)
|
|
}
|
|
|
|
return c, err
|
|
},
|
|
})
|
|
|
|
log.Printf("listening on https://%s", selfFQDN)
|
|
log.Fatal(http.Serve(l, hdlr))
|
|
}
|
|
|
|
type tsAuthMiddleware struct {
|
|
next http.Handler
|
|
}
|
|
|
|
func (t tsAuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
userInfo, err := tailscale.WhoIs(r.Context(), r.RemoteAddr)
|
|
if err != nil {
|
|
log.Printf("can't get whois response: %v", err)
|
|
http.Error(w, "can't get whois response: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
r.Header.Set("X-WebAuth-User", userInfo.UserProfile.LoginName)
|
|
r.Header.Set("X-WebAuth-Name", userInfo.UserProfile.DisplayName)
|
|
|
|
t.next.ServeHTTP(w, r)
|
|
}
|