mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-28 16:37:24 +02:00
Added gif to the readme.
Simplified, and de-duplicated many of the configuration settings. Removed configuration settings that could be deduced from other settings. Added some basic documentation. Removed the (duplicate?) user email domain validation check in proxy. Removed the ClientID middleware check. Added a shared key option to be used as a PSK instead of using the IDPs ClientID and ClientSecret. Removed the CookieSecure setting as we only support secure. Added a letsencrypt script to generate a wildcard certificate. Removed the argument in proxy's constructor that allowed arbitrary fucntions to be passed in as validators. Updated proxy's authenticator client to match the server implementation of just using a PSK. Moved debug-mode logging into the log package. Removed unused approval prompt setting. Fixed a bug where identity provider urls were hardcoded. Removed a bunch of unit tests. There have been so many changes many of these tests don't make sense and will need to be re-thought.
This commit is contained in:
parent
52a87b6e46
commit
90ab756de1
40 changed files with 409 additions and 1440 deletions
|
@ -23,14 +23,10 @@ import (
|
|||
// Options represents the configuration options for the proxy service.
|
||||
type Options struct {
|
||||
// AuthenticateServiceURL specifies the url to the pomerium authenticate http service.
|
||||
AuthenticateServiceURL *url.URL `envconfig:"PROVIDER_URL"`
|
||||
AuthenticateServiceURL *url.URL `envconfig:"AUTHENTICATE_SERVICE_URL"`
|
||||
|
||||
// EmailDomains is a string slice of valid domains to proxy
|
||||
EmailDomains []string `envconfig:"EMAIL_DOMAIN"`
|
||||
// todo(bdd): ClientID and ClientSecret are used are a hacky pre shared key
|
||||
// prefer certificates and mutual tls
|
||||
ClientID string `envconfig:"PROXY_CLIENT_ID"`
|
||||
ClientSecret string `envconfig:"PROXY_CLIENT_SECRET"`
|
||||
// todo(bdd) : replace with certificate based mTLS
|
||||
SharedKey string `envconfig:"SHARED_SECRET"`
|
||||
|
||||
DefaultUpstreamTimeout time.Duration `envconfig:"DEFAULT_UPSTREAM_TIMEOUT"`
|
||||
|
||||
|
@ -38,7 +34,6 @@ type Options struct {
|
|||
CookieSecret string `envconfig:"COOKIE_SECRET"`
|
||||
CookieDomain string `envconfig:"COOKIE_DOMAIN"`
|
||||
CookieExpire time.Duration `envconfig:"COOKIE_EXPIRE"`
|
||||
CookieSecure bool `envconfig:"COOKIE_SECURE" `
|
||||
CookieHTTPOnly bool `envconfig:"COOKIE_HTTP_ONLY"`
|
||||
|
||||
PassAccessToken bool `envconfig:"PASS_ACCESS_TOKEN"`
|
||||
|
@ -54,12 +49,11 @@ type Options struct {
|
|||
// NewOptions returns a new options struct
|
||||
var defaultOptions = &Options{
|
||||
CookieName: "_pomerium_proxy",
|
||||
CookieSecure: true,
|
||||
CookieHTTPOnly: true,
|
||||
CookieHTTPOnly: false,
|
||||
CookieExpire: time.Duration(168) * time.Hour,
|
||||
DefaultUpstreamTimeout: time.Duration(10) * time.Second,
|
||||
SessionLifetimeTTL: time.Duration(720) * time.Hour,
|
||||
SessionValidTTL: time.Duration(1) * time.Minute,
|
||||
SessionValidTTL: time.Duration(10) * time.Minute,
|
||||
GracePeriodTTL: time.Duration(3) * time.Hour,
|
||||
PassAccessToken: false,
|
||||
}
|
||||
|
@ -91,22 +85,20 @@ func (o *Options) Validate() error {
|
|||
if o.AuthenticateServiceURL == nil {
|
||||
return errors.New("missing setting: provider-url")
|
||||
}
|
||||
if o.AuthenticateServiceURL.Scheme != "https" {
|
||||
return errors.New("provider-url must be a valid https url")
|
||||
}
|
||||
if o.CookieSecret == "" {
|
||||
return errors.New("missing setting: cookie-secret")
|
||||
}
|
||||
if o.ClientID == "" {
|
||||
return errors.New("missing setting: client-id")
|
||||
}
|
||||
if o.ClientSecret == "" {
|
||||
|
||||
if o.SharedKey == "" {
|
||||
return errors.New("missing setting: client-secret")
|
||||
}
|
||||
if len(o.EmailDomains) == 0 {
|
||||
return errors.New("missing setting: email-domain")
|
||||
}
|
||||
|
||||
decodedCookieSecret, err := base64.StdEncoding.DecodeString(o.CookieSecret)
|
||||
if err != nil {
|
||||
return errors.New("cookie secret is invalid (e.g. `head -c33 /dev/urandom | base64`) ")
|
||||
return errors.New("cookie secret is invalid (e.g. `head -c32 /dev/urandom | base64`) ")
|
||||
}
|
||||
validCookieSecretLength := false
|
||||
for _, i := range []int{32, 64} {
|
||||
|
@ -122,24 +114,14 @@ func (o *Options) Validate() error {
|
|||
|
||||
// Proxy stores all the information associated with proxying a request.
|
||||
type Proxy struct {
|
||||
CookieCipher aead.Cipher
|
||||
CookieDomain string
|
||||
CookieExpire time.Duration
|
||||
CookieHTTPOnly bool
|
||||
CookieName string
|
||||
CookieSecure bool
|
||||
CookieSeed string
|
||||
CSRFCookieName string
|
||||
EmailValidator func(string) bool
|
||||
|
||||
PassAccessToken bool
|
||||
|
||||
// services
|
||||
authenticateClient *authenticator.AuthenticateClient
|
||||
// session
|
||||
cipher aead.Cipher
|
||||
csrfStore sessions.CSRFStore
|
||||
sessionStore sessions.SessionStore
|
||||
cipher aead.Cipher
|
||||
|
||||
redirectURL *url.URL // the url to receive requests at
|
||||
templates *template.Template
|
||||
|
@ -154,13 +136,14 @@ type StateParameter struct {
|
|||
|
||||
// NewProxy takes a Proxy service from options and a validation function.
|
||||
// Function returns an error if options fail to validate.
|
||||
func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
||||
func NewProxy(opts *Options) (*Proxy, error) {
|
||||
if opts == nil {
|
||||
return nil, errors.New("options cannot be nil")
|
||||
}
|
||||
if err := opts.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// error explicitly handled by validate
|
||||
decodedSecret, _ := base64.StdEncoding.DecodeString(opts.CookieSecret)
|
||||
cipher, err := aead.NewMiscreantCipher(decodedSecret)
|
||||
|
@ -174,7 +157,6 @@ func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
|||
c.CookieDomain = opts.CookieDomain
|
||||
c.CookieHTTPOnly = opts.CookieHTTPOnly
|
||||
c.CookieExpire = opts.CookieExpire
|
||||
c.CookieSecure = opts.CookieSecure
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -184,9 +166,7 @@ func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
|||
|
||||
authClient := authenticator.NewAuthenticateClient(
|
||||
opts.AuthenticateServiceURL,
|
||||
// todo(bdd): fields below can be dropped as Client data provides redudent auth
|
||||
opts.ClientID,
|
||||
opts.ClientSecret,
|
||||
opts.SharedKey,
|
||||
// todo(bdd): fields below should be passed as function args
|
||||
opts.SessionLifetimeTTL,
|
||||
opts.SessionValidTTL,
|
||||
|
@ -194,21 +174,12 @@ func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
|||
)
|
||||
|
||||
p := &Proxy{
|
||||
CookieCipher: cipher,
|
||||
CookieDomain: opts.CookieDomain,
|
||||
CookieExpire: opts.CookieExpire,
|
||||
CookieHTTPOnly: opts.CookieHTTPOnly,
|
||||
CookieName: opts.CookieName,
|
||||
CookieSecure: opts.CookieSecure,
|
||||
CookieSeed: string(decodedSecret),
|
||||
CSRFCookieName: fmt.Sprintf("%v_%v", opts.CookieName, "csrf"),
|
||||
|
||||
// these fields make up the routing mechanism
|
||||
mux: make(map[string]*http.Handler),
|
||||
// session state
|
||||
cipher: cipher,
|
||||
csrfStore: cookieStore,
|
||||
sessionStore: cookieStore,
|
||||
cipher: cipher,
|
||||
|
||||
authenticateClient: authClient,
|
||||
redirectURL: &url.URL{Path: "/.pomerium/callback"},
|
||||
|
@ -216,13 +187,6 @@ func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
|||
PassAccessToken: opts.PassAccessToken,
|
||||
}
|
||||
|
||||
for _, optFunc := range optFuncs {
|
||||
err := optFunc(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for from, to := range opts.Routes {
|
||||
fromURL, _ := urlParse(from)
|
||||
toURL, _ := urlParse(to)
|
||||
|
@ -232,16 +196,6 @@ func NewProxy(opts *Options, optFuncs ...func(*Proxy) error) (*Proxy, error) {
|
|||
log.Info().Str("from", fromURL.Host).Str("to", toURL.String()).Msg("proxy.NewProxy : route")
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("CookieName", p.CookieName).
|
||||
Str("redirectURL", p.redirectURL.String()).
|
||||
Str("CSRFCookieName", p.CSRFCookieName).
|
||||
Bool("CookieSecure", p.CookieSecure).
|
||||
Str("CookieDomain", p.CookieDomain).
|
||||
Bool("CookieHTTPOnly", p.CookieHTTPOnly).
|
||||
Dur("CookieExpire", opts.CookieExpire).
|
||||
Msg("proxy.NewProxy")
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
|
@ -261,7 +215,7 @@ var defaultUpstreamTransport = &http.Transport{
|
|||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
|
@ -279,13 +233,8 @@ func deleteSSOCookieHeader(req *http.Request, cookieName string) {
|
|||
// ServeHTTP signs the http request and deletes cookie headers
|
||||
// before calling the upstream's ServeHTTP function.
|
||||
func (u *UpstreamProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
requestLog := log.WithRequest(r, "proxy.ServeHTTP")
|
||||
deleteSSOCookieHeader(r, u.cookieName)
|
||||
start := time.Now()
|
||||
u.handler.ServeHTTP(w, r)
|
||||
duration := time.Since(start)
|
||||
|
||||
requestLog.Debug().Dur("duration", duration).Msg("proxy-request")
|
||||
}
|
||||
|
||||
// NewReverseProxy creates a reverse proxy to a specified url.
|
||||
|
@ -295,17 +244,18 @@ func (u *UpstreamProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
func NewReverseProxy(to *url.URL) *httputil.ReverseProxy {
|
||||
proxy := httputil.NewSingleHostReverseProxy(to)
|
||||
proxy.Transport = defaultUpstreamTransport
|
||||
|
||||
director := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
req.Header.Add("X-Forwarded-Host", req.Host)
|
||||
|
||||
director(req)
|
||||
req.Host = to.Host
|
||||
}
|
||||
return proxy
|
||||
}
|
||||
|
||||
// NewReverseProxyHandler applies handler specific options to a given
|
||||
// route.
|
||||
// NewReverseProxyHandler applies handler specific options to a given route.
|
||||
func NewReverseProxyHandler(opts *Options, reverseProxy *httputil.ReverseProxy, serviceName string) http.Handler {
|
||||
upstreamProxy := &UpstreamProxy{
|
||||
name: serviceName,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue