mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-10 23:57:34 +02:00
- all: prefer `FormValues` to `ParseForm` with subsequent `Form.Get`s - all: refactor authentication stack to be checked by middleware, and accessible via request context. - all: replace http.ServeMux with gorilla/mux’s router - all: replace custom CSRF checks with gorilla/csrf middleware - authenticate: extract callback path as constant. - internal/config: implement stringer interface for policy - internal/cryptutil: add helper func `NewBase64Key` - internal/cryptutil: rename `GenerateKey` to `NewKey` - internal/cryptutil: rename `GenerateRandomString` to `NewRandomStringN` - internal/middleware: removed alice in favor of gorilla/mux - internal/sessions: remove unused `ValidateRedirectURI` and `ValidateClientSecret` - internal/sessions: replace custom CSRF with gorilla/csrf fork that supports custom handler protection - internal/urlutil: add `SignedRedirectURL` to create hmac'd URLs - internal/urlutil: add `ValidateURL` helper to parse URL options - internal/urlutil: add `GetAbsoluteURL` which takes a request and returns its absolute URL. - proxy: remove holdover state verification checks; we no longer are setting sessions in any proxy routes so we don’t need them. - proxy: replace un-named http.ServeMux with named domain routes. Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
206 lines
6.1 KiB
Go
206 lines
6.1 KiB
Go
package main // import "github.com/pomerium/pomerium/cmd/pomerium"
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/gorilla/mux"
|
|
"github.com/spf13/viper"
|
|
"google.golang.org/grpc"
|
|
|
|
"github.com/pomerium/pomerium/authenticate"
|
|
"github.com/pomerium/pomerium/authorize"
|
|
"github.com/pomerium/pomerium/internal/config"
|
|
"github.com/pomerium/pomerium/internal/httputil"
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/middleware"
|
|
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
|
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
|
"github.com/pomerium/pomerium/internal/urlutil"
|
|
"github.com/pomerium/pomerium/internal/version"
|
|
pbAuthorize "github.com/pomerium/pomerium/proto/authorize"
|
|
"github.com/pomerium/pomerium/proxy"
|
|
)
|
|
|
|
var versionFlag = flag.Bool("version", false, "prints the version")
|
|
var configFile = flag.String("config", "", "Specify configuration file location")
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if *versionFlag {
|
|
fmt.Println(version.FullVersion())
|
|
os.Exit(0)
|
|
}
|
|
opt, err := config.ParseOptions(*configFile)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cmd/pomerium: options")
|
|
}
|
|
log.Info().Str("version", version.FullVersion()).Msg("cmd/pomerium")
|
|
|
|
setupMetrics(opt)
|
|
setupTracing(opt)
|
|
setupHTTPRedirectServer(opt)
|
|
|
|
r := newGlobalRouter(opt)
|
|
grpcServer := setupGRPCServer(opt)
|
|
_, err = newAuthenticateService(*opt, r.Host(urlutil.StripPort(opt.AuthenticateURL.Host)).Subrouter())
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cmd/pomerium: authenticate")
|
|
}
|
|
|
|
authz, err := newAuthorizeService(*opt, grpcServer)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cmd/pomerium: authorize")
|
|
}
|
|
|
|
proxy, err := newProxyService(*opt, r)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cmd/pomerium: proxy")
|
|
}
|
|
if proxy != nil {
|
|
defer proxy.AuthorizeClient.Close()
|
|
}
|
|
|
|
go viper.WatchConfig()
|
|
|
|
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
log.Info().Str("file", e.Name).Msg("cmd/pomerium: config file changed")
|
|
opt = config.HandleConfigUpdate(*configFile, opt, []config.OptionsUpdater{authz, proxy})
|
|
})
|
|
srv, err := httputil.NewTLSServer(configToServerOptions(opt), r, grpcServer)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cmd/pomerium: couldn't start pomerium")
|
|
}
|
|
httputil.Shutdown(srv)
|
|
|
|
os.Exit(0)
|
|
}
|
|
|
|
func newAuthenticateService(opt config.Options, r *mux.Router) (*authenticate.Authenticate, error) {
|
|
if !config.IsAuthenticate(opt.Services) {
|
|
return nil, nil
|
|
}
|
|
service, err := authenticate.New(opt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.PathPrefix("/").Handler(service.Handler())
|
|
return service, nil
|
|
}
|
|
|
|
func newAuthorizeService(opt config.Options, rpc *grpc.Server) (*authorize.Authorize, error) {
|
|
if !config.IsAuthorize(opt.Services) {
|
|
return nil, nil
|
|
}
|
|
service, err := authorize.New(opt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pbAuthorize.RegisterAuthorizerServer(rpc, service)
|
|
return service, nil
|
|
}
|
|
|
|
func newProxyService(opt config.Options, r *mux.Router) (*proxy.Proxy, error) {
|
|
if !config.IsProxy(opt.Services) {
|
|
return nil, nil
|
|
}
|
|
service, err := proxy.New(opt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.PathPrefix("/").Handler(service.Handler())
|
|
return service, nil
|
|
}
|
|
|
|
func newGlobalRouter(o *config.Options) *mux.Router {
|
|
mux := httputil.NewRouter()
|
|
mux.Use(metrics.HTTPMetricsHandler(o.Services))
|
|
mux.Use(log.NewHandler(log.Logger))
|
|
mux.Use(log.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
|
log.FromRequest(r).Debug().
|
|
Dur("duration", duration).
|
|
Int("size", size).
|
|
Int("status", status).
|
|
Str("email", r.Header.Get(proxy.HeaderEmail)).
|
|
Str("group", r.Header.Get(proxy.HeaderGroups)).
|
|
Str("method", r.Method).
|
|
Str("service", o.Services).
|
|
Str("url", r.URL.String()).
|
|
Msg("http-request")
|
|
}))
|
|
if len(o.Headers) != 0 {
|
|
mux.Use(middleware.SetHeaders(o.Headers))
|
|
}
|
|
mux.Use(log.ForwardedAddrHandler("fwd_ip"))
|
|
mux.Use(log.RemoteAddrHandler("ip"))
|
|
mux.Use(log.UserAgentHandler("user_agent"))
|
|
mux.Use(log.RefererHandler("referer"))
|
|
mux.Use(log.RequestIDHandler("req_id", "Request-Id"))
|
|
mux.Use(middleware.Healthcheck("/ping", version.UserAgent()))
|
|
return mux
|
|
}
|
|
|
|
func configToServerOptions(opt *config.Options) *httputil.ServerOptions {
|
|
return &httputil.ServerOptions{
|
|
Addr: opt.Addr,
|
|
Cert: opt.Cert,
|
|
Key: opt.Key,
|
|
CertFile: opt.CertFile,
|
|
KeyFile: opt.KeyFile,
|
|
ReadTimeout: opt.ReadTimeout,
|
|
WriteTimeout: opt.WriteTimeout,
|
|
ReadHeaderTimeout: opt.ReadHeaderTimeout,
|
|
IdleTimeout: opt.IdleTimeout,
|
|
}
|
|
}
|
|
|
|
func setupMetrics(opt *config.Options) {
|
|
if opt.MetricsAddr != "" {
|
|
if handler, err := metrics.PrometheusHandler(); err != nil {
|
|
log.Error().Err(err).Msg("cmd/pomerium: metrics failed to start")
|
|
} else {
|
|
metrics.SetBuildInfo(opt.Services)
|
|
metrics.RegisterInfoMetrics()
|
|
serverOpts := &httputil.ServerOptions{Addr: opt.MetricsAddr}
|
|
srv := httputil.NewHTTPServer(serverOpts, handler)
|
|
go httputil.Shutdown(srv)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupTracing(opt *config.Options) {
|
|
if opt.TracingProvider != "" {
|
|
tracingOpts := &trace.TracingOptions{
|
|
Provider: opt.TracingProvider,
|
|
Service: opt.Services,
|
|
Debug: opt.TracingDebug,
|
|
JaegerAgentEndpoint: opt.TracingJaegerAgentEndpoint,
|
|
JaegerCollectorEndpoint: opt.TracingJaegerCollectorEndpoint,
|
|
}
|
|
if err := trace.RegisterTracing(tracingOpts); err != nil {
|
|
log.Error().Err(err).Msg("cmd/pomerium: couldn't register tracing")
|
|
} else {
|
|
log.Info().Interface("options", tracingOpts).Msg("cmd/pomerium: metrics configured")
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupHTTPRedirectServer(opt *config.Options) {
|
|
if opt.HTTPRedirectAddr != "" {
|
|
serverOpts := httputil.ServerOptions{Addr: opt.HTTPRedirectAddr}
|
|
srv := httputil.NewHTTPServer(&serverOpts, httputil.RedirectHandler())
|
|
go httputil.Shutdown(srv)
|
|
}
|
|
}
|
|
|
|
func setupGRPCServer(opt *config.Options) *grpc.Server {
|
|
grpcAuth := middleware.NewSharedSecretCred(opt.SharedKey)
|
|
grpcOpts := []grpc.ServerOption{
|
|
grpc.UnaryInterceptor(grpcAuth.ValidateRequest),
|
|
grpc.StatsHandler(metrics.NewGRPCServerStatsHandler(opt.Services))}
|
|
return grpc.NewServer(grpcOpts...)
|
|
}
|