Documentation ¶
Overview ¶
Package bastion runs a reverse proxy service that allows un-addressable applications (for example those running behind a firewall or a NAT, or where the operator doesn't wish to take the DoS risk of being reachable from the Internet) to accept HTTP requests.
Backends are identified by an Ed25519 public key, they authenticate with a self-signed TLS 1.3 certificate, and are reachable at a sub-path prefixed by the key hash.
Read more at https://git.glasklar.is/sigsum/project/documentation/-/blob/main/bastion.md.
Example ¶
package main import ( "crypto/sha256" "io" "log" "net/http" "sync" "time" "filippo.io/litetlog/bastion" "golang.org/x/crypto/acme/autocert" "golang.org/x/net/http2" ) func main() { // This example shows how to serve on the same address both a bastion // endpoint, and an unrelated HTTPS server. m := &autocert.Manager{ Cache: autocert.DirCache("/var/lib/example-autocert/"), Prompt: autocert.AcceptTOS, Email: "acme@example.com", HostPolicy: autocert.HostWhitelist("bastion.example.com", "www.example.com"), } var allowedBackendsMu sync.RWMutex var allowedBackends map[[sha256.Size]byte]bool b, err := bastion.New(&bastion.Config{ AllowedBackend: func(keyHash [sha256.Size]byte) bool { allowedBackendsMu.RLock() defer allowedBackendsMu.RUnlock() return allowedBackends[keyHash] }, GetCertificate: m.GetCertificate, }) if err != nil { log.Fatalf("failed to load bastion: %v", err) } mux := http.NewServeMux() // Note the use of a host-specific pattern to route HTTP requests for the // bastion endpoint to the Bastion implementation. mux.Handle("bastion.example.com/", b) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "<p>Hello, world") }) hs := &http.Server{ Addr: "127.0.0.1:1337", Handler: http.MaxBytesHandler(mux, 10*1024), ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, TLSConfig: m.TLSConfig(), } // ConfigureServer sets up TLSNextProto and a tls.Config.GetConfigForClient // for backend connections. if err := b.ConfigureServer(hs); err != nil { log.Fatalln("failed to configure bastion:", err) } // HTTP/2 needs to be explicitly re-enabled if desired because it's only // configured automatically by net/http if TLSNextProto is nil. if err := http2.ConfigureServer(hs, nil); err != nil { log.Fatalln("failed to configure HTTP/2:", err) } }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bastion ¶
type Bastion struct {
// contains filtered or unexported fields
}
A Bastion keeps track of backend connections, and serves HTTP requests by routing them to the matching backend.
func (*Bastion) ConfigureServer ¶
ConfigureServer sets up srv to handle backend connections to the bastion. It wraps TLSConfig.GetConfigForClient to intercept backend connections, and sets TLSNextProto for the bastion ALPN protocol. The original tls.Config is still used for non-bastion backend connections.
Note that since TLSNextProto won't be nil after a call to ConfigureServer, the caller might want to call http2.ConfigureServer as well.
type Config ¶
type Config struct { // GetCertificate returns the certificate for bastion backend connections. GetCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) // AllowedBackend returns whether the backend is allowed to // serve requests. It's passed the hash of its Ed25519 public key. // // AllowedBackend may be called concurrently. AllowedBackend func(keyHash [sha256.Size]byte) bool // Log is used to log backend connections and errors in forwarding requests. // If nil, [log.Default] is used. Log *log.Logger }
Config provides parameters for a new Bastion.