mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-28 14:08:43 +02:00
internal/sessions: session state is domain scoped internal/sessions: infer csrf cookie, route scoped proxy & authenticate: use shared cookie name proxy & authenticate: prevent resaving unchanged session proxy & authenticate: redirect instead of error for no session on login internal/config: merge cookies proxy: remove favicon specific route proxy: use mock server for tests proxy: add tests for failures
224 lines
7.3 KiB
Go
224 lines
7.3 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/pomerium/envconfig"
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/policy"
|
|
)
|
|
|
|
// DisableHeaderKey is the key used to check whether to disable setting header
|
|
const DisableHeaderKey = "disable"
|
|
|
|
// Options are the global environmental flags used to set up pomerium's services.
|
|
// If a base64 encoded certificate and key are not provided as environmental variables,
|
|
// or if a file location is not provided, the server will attempt to find a matching keypair
|
|
// in the local directory as `./cert.pem` and `./privkey.pem` respectively.
|
|
type Options struct {
|
|
// Debug outputs human-readable logs to Stdout.
|
|
Debug bool `envconfig:"POMERIUM_DEBUG"`
|
|
|
|
// LogLevel sets the global override for log level. All Loggers will use at least this value.
|
|
// Possible options are "info","warn", and "error". Defaults to "debug".
|
|
LogLevel string `envconfig:"LOG_LEVEL"`
|
|
|
|
// SharedKey is the shared secret authorization key used to mutually authenticate
|
|
// requests between services.
|
|
SharedKey string `envconfig:"SHARED_SECRET"`
|
|
|
|
// Services is a list enabled service mode. If none are selected, "all" is used.
|
|
// Available options are : "all", "authenticate", "proxy".
|
|
Services string `envconfig:"SERVICES"`
|
|
|
|
// Addr specifies the host and port on which the server should serve
|
|
// HTTPS requests. If empty, ":https" is used.
|
|
Addr string `envconfig:"ADDRESS"`
|
|
|
|
// Cert and Key specifies the base64 encoded TLS certificates to use.
|
|
Cert string `envconfig:"CERTIFICATE"`
|
|
Key string `envconfig:"CERTIFICATE_KEY"`
|
|
|
|
// CertFile and KeyFile specifies the TLS certificates to use.
|
|
CertFile string `envconfig:"CERTIFICATE_FILE"`
|
|
KeyFile string `envconfig:"CERTIFICATE_KEY_FILE"`
|
|
|
|
// HttpRedirectAddr, if set, specifies the host and port to run the HTTP
|
|
// to HTTPS redirect server on. For example, ":http" would start a server
|
|
// on port 80. If empty, no redirect server is started.
|
|
HTTPRedirectAddr string `envconfig:"HTTP_REDIRECT_ADDR"`
|
|
|
|
// Timeout settings : https://github.com/pomerium/pomerium/issues/40
|
|
ReadTimeout time.Duration `envconfig:"TIMEOUT_READ"`
|
|
WriteTimeout time.Duration `envconfig:"TIMEOUT_WRITE"`
|
|
ReadHeaderTimeout time.Duration `envconfig:"TIMEOUT_READ_HEADER"`
|
|
IdleTimeout time.Duration `envconfig:"TIMEOUT_IDLE"`
|
|
|
|
// Policy is a base64 encoded yaml blob which enumerates
|
|
// per-route access control policies.
|
|
Policy string `envconfig:"POLICY"`
|
|
PolicyFile string `envconfig:"POLICY_FILE"`
|
|
|
|
// AuthenticateURL represents the externally accessible http endpoints
|
|
// used for authentication requests and callbacks
|
|
AuthenticateURL *url.URL `envconfig:"AUTHENTICATE_SERVICE_URL"`
|
|
|
|
// Session/Cookie management
|
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
|
CookieName string `envconfig:"COOKIE_NAME"`
|
|
CookieSecret string `envconfig:"COOKIE_SECRET"`
|
|
CookieDomain string `envconfig:"COOKIE_DOMAIN"`
|
|
CookieSecure bool `envconfig:"COOKIE_SECURE"`
|
|
CookieHTTPOnly bool `envconfig:"COOKIE_HTTP_ONLY"`
|
|
CookieExpire time.Duration `envconfig:"COOKIE_EXPIRE"`
|
|
CookieRefresh time.Duration `envconfig:"COOKIE_REFRESH"`
|
|
|
|
// Identity provider configuration variables as specified by RFC6749
|
|
// https://openid.net/specs/openid-connect-basic-1_0.html#RFC6749
|
|
ClientID string `envconfig:"IDP_CLIENT_ID"`
|
|
ClientSecret string `envconfig:"IDP_CLIENT_SECRET"`
|
|
Provider string `envconfig:"IDP_PROVIDER"`
|
|
ProviderURL string `envconfig:"IDP_PROVIDER_URL"`
|
|
Scopes []string `envconfig:"IDP_SCOPES"`
|
|
ServiceAccount string `envconfig:"IDP_SERVICE_ACCOUNT"`
|
|
|
|
Policies []policy.Policy `envconfig:"POLICY"`
|
|
|
|
// AuthenticateInternalAddr is used as an override when using a load balancer
|
|
// or ingress that does not natively support routing gRPC.
|
|
AuthenticateInternalAddr string `envconfig:"AUTHENTICATE_INTERNAL_URL"`
|
|
|
|
// AuthorizeURL is the routable destination of the authorize service's
|
|
// gRPC endpoint. NOTE: As above, many load balancers do not support
|
|
// externally routed gRPC so this may be an internal location.
|
|
AuthorizeURL *url.URL `envconfig:"AUTHORIZE_SERVICE_URL"`
|
|
|
|
// Settings to enable custom behind-the-ingress service communication
|
|
OverrideCertificateName string `envconfig:"OVERRIDE_CERTIFICATE_NAME"`
|
|
CA string `envconfig:"CERTIFICATE_AUTHORITY"`
|
|
CAFile string `envconfig:"CERTIFICATE_AUTHORITY_FILE"`
|
|
|
|
// SigningKey is a base64 encoded private key used to add a JWT-signature.
|
|
// https://www.pomerium.io/docs/signed-headers.html
|
|
SigningKey string `envconfig:"SIGNING_KEY"`
|
|
|
|
// Headers to set on all proxied requests. Add a 'disable' key map to turn off.
|
|
Headers map[string]string `envconfig:"HEADERS"`
|
|
|
|
// Sub-routes
|
|
Routes map[string]string `envconfig:"ROUTES"`
|
|
DefaultUpstreamTimeout time.Duration `envconfig:"DEFAULT_UPSTREAM_TIMEOUT"`
|
|
}
|
|
|
|
// NewOptions returns a new options struct with default vaules
|
|
func NewOptions() *Options {
|
|
o := &Options{
|
|
Debug: false,
|
|
LogLevel: "debug",
|
|
Services: "all",
|
|
CookieHTTPOnly: true,
|
|
CookieSecure: true,
|
|
CookieExpire: time.Duration(14) * time.Hour,
|
|
CookieRefresh: time.Duration(30) * time.Minute,
|
|
CookieName: "_pomerium",
|
|
DefaultUpstreamTimeout: time.Duration(30) * time.Second,
|
|
Headers: map[string]string{
|
|
"X-Content-Type-Options": "nosniff",
|
|
"X-Frame-Options": "SAMEORIGIN",
|
|
"X-XSS-Protection": "1; mode=block",
|
|
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
|
},
|
|
Addr: ":https",
|
|
CertFile: filepath.Join(findPwd(), "cert.pem"),
|
|
KeyFile: filepath.Join(findPwd(), "privkey.pem"),
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 0, // support streaming by default
|
|
IdleTimeout: 5 * time.Minute,
|
|
AuthenticateURL: new(url.URL),
|
|
AuthorizeURL: new(url.URL),
|
|
}
|
|
return o
|
|
}
|
|
|
|
// OptionsFromEnvConfig builds the main binary's configuration
|
|
// options from provided environmental variables
|
|
func OptionsFromEnvConfig() (*Options, error) {
|
|
o := NewOptions()
|
|
if err := envconfig.Process("", o); err != nil {
|
|
return nil, err
|
|
}
|
|
if !IsValidService(o.Services) {
|
|
return nil, fmt.Errorf("%s is an invalid service type", o.Services)
|
|
}
|
|
if o.SharedKey == "" {
|
|
return nil, errors.New("shared-key cannot be empty")
|
|
}
|
|
if o.Debug {
|
|
log.SetDebugMode()
|
|
}
|
|
if o.LogLevel != "" {
|
|
log.SetLevel(o.LogLevel)
|
|
}
|
|
if _, disable := o.Headers[DisableHeaderKey]; disable {
|
|
o.Headers = make(map[string]string)
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
// findPwd returns best guess at current working directory
|
|
func findPwd() string {
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
return "."
|
|
}
|
|
return p
|
|
}
|
|
|
|
// isValidService checks to see if a service is a valid service mode
|
|
func IsValidService(s string) bool {
|
|
switch s {
|
|
case
|
|
"all",
|
|
"proxy",
|
|
"authorize",
|
|
"authenticate":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsAuthenticate(s string) bool {
|
|
switch s {
|
|
case
|
|
"all",
|
|
"authenticate":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsAuthorize(s string) bool {
|
|
switch s {
|
|
case
|
|
"all",
|
|
"authorize":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsProxy(s string) bool {
|
|
switch s {
|
|
case
|
|
"all",
|
|
"proxy":
|
|
return true
|
|
}
|
|
return false
|
|
}
|