proxy: remove unused setting AuthorizeInternalAddr (#93)

- Added unit tests for policy validation.
- Removed extraneous policy validation for URLs.
- Add dependency caching to dockerfile.
This commit is contained in:
Bobby DeSimone 2019-04-24 13:28:29 -07:00 committed by GitHub
parent 96f4b8bd61
commit fbe1cae482
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 61 additions and 56 deletions

View file

@ -6,8 +6,9 @@
### CHANGED
- Removed `PROXY_ROOT_DOMAIN` config option which is now inferred from `AUTHENTICATE_SERVICE_URL`. Only callback requests originating from a URL on the same sub-domain are permitted.
- Removed `REDIRECT_URL` config option which is now inferred from `AUTHENTICATE_SERVICE_URL` (e.g. `https://$AUTHENTICATE_SERVICE_URL/oauth2/callback`).
- Removed extraneous `AUTHORIZE_INTERNAL_URL` config option since authorization has no publica http handlers, only a gRPC service endpoint. [GH-93]
- Removed `PROXY_ROOT_DOMAIN` config option which is now inferred from `AUTHENTICATE_SERVICE_URL`. Only callback requests originating from a URL on the same sub-domain are permitted. [GH-83]
- Removed `REDIRECT_URL` config option which is now inferred from `AUTHENTICATE_SERVICE_URL` (e.g. `https://$AUTHENTICATE_SERVICE_URL/oauth2/callback`). [GH-83]
### FIXED

View file

@ -4,6 +4,11 @@ ENV CGO_ENABLED=0
ENV GO111MODULE=on
WORKDIR /go/src/github.com/pomerium/pomerium
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN make

View file

@ -12,7 +12,7 @@ Pomerium uses [environmental variables] to set configuration settings. If you ar
## Global settings
Global settings are configuration variables that are shared by all services.
These are configuration variables shared by all services, in all service modes.
### Service Mode
@ -21,7 +21,7 @@ Global settings are configuration variables that are shared by all services.
- Default: `all`
- Options: `all` `authenticate` `authorize` or `proxy`
Service mode sets the pomerium service(s) to run. If testing, you may want to set to `all` and run pomerium in "all-in-one mode." In production, you'll likely want to spin of several instances of each service mode for high availability.
Service mode sets the pomerium service(s) to run. If testing, you may want to set to `all` and run pomerium in "all-in-one mode." In production, you'll likely want to spin up several instances of each service mode for high availability.
### Address
@ -29,7 +29,7 @@ Service mode sets the pomerium service(s) to run. If testing, you may want to se
- Type: `string`
- Default: `:https`
Address specifies the host and port to serve HTTPS and gRPC requests from. If empty, `:https` is used.
Address specifies the host and port to serve HTTPS and gRPC requests from. If empty, `:https`/`:443` is used.
### Shared Secret
@ -194,25 +194,18 @@ Authenticate Service URL is the externally accessible URL for the authenticate s
- Optional
- Example: `pomerium-authenticate-service.pomerium.svc.cluster.local`
Authenticate Internal Service URL is the internally routed dns name of the authenticate service. This setting is used to override the authenticate service url for when you need to do "behind-the-ingress" inter-service communication. This is typically required for ingresses and load balancers that do not support HTTP/2 or gRPC termination.
Authenticate Internal Service URL is the internally routed dns name of the authenticate service. This setting is typically used with load balancers that do not gRPC, thus allowying you to specificy an internally routable name.
### Authorize Service URL
- Environmental Variable: `AUTHORIZE_SERVICE_URL`
- Type: `URL`
- Required
- Example: `https://access.corp.example.com`
- Example: `https://access.corp.example.com` or `pomerium-authorize-service.pomerium.svc.cluster.local`
Authorize Service URL is the externally accessible URL for the authorize service.
Authorize Service URL is the location of the internally routable authorize service. NOTE: Unlike authenticate, authorize has no publically acccessible http handlers so this setting is purely for gRPC communicaiton.
### Authorize Internal Service URL
- Environmental Variable: `AUTHORIZE_INTERNAL_URL`
- Type: `string`
- Optional
- Example: `pomerium-authorize-service.pomerium.svc.cluster.local`
Authorize Internal Service URL is the internally routed dns name of the authorize service. This setting is used to override the authorize service url for when you need to do "behind-the-ingress" inter-service communication. This is typically required for ingresses and load balancers that do not support HTTP/2 or gRPC termination.
If your load balancer does not support gRPC passthrough you'll need to set this value to an internally routable location (`pomerium-authorize-service.pomerium.svc.cluster.local`) instead of an externally routable one (`https://access.corp.example.com`).
### Override Certificate Name

View file

@ -60,8 +60,9 @@ Customize for your identity provider run `docker-compose up -f nginx.docker-comp
- Uses Google Kubernetes Engine's built-in ingress to do [HTTPS load balancing]
- HTTPS (TLS) between client, load balancer, and services
- gRPC requests are routed behind the load balancer
- Routes default to hosted version of httpbin.org
- Includes all-in-one script
- Includes installer script
#### helm_gke.sh
@ -71,8 +72,9 @@ Customize for your identity provider run `docker-compose up -f nginx.docker-comp
- Uses Google Kubernetes Engine's built-in ingress to do [HTTPS load balancing]
- HTTPS (TLS) between client, load balancer, and services
- gRPC requests are routed behind the load balancer
- Routes default to hosted version of httpbin.org
- Includes all-in-one script
- Includes installer script
#### kubernetes_gke

View file

@ -44,11 +44,10 @@ services:
- SERVICES=proxy
- POLICY_FILE=policy.yaml
- AUTHENTICATE_SERVICE_URL=https://authenticate.corp.beyondperimeter.com
- AUTHORIZE_SERVICE_URL=https://authorize.corp.beyondperimeter.com
# IMPORTANT! If you are running pomerium behind another ingress (loadbalancer/firewall/etc)
# you must tell pomerium proxy how to communicate using an internal hostname for RPC
- AUTHENTICATE_INTERNAL_URL=pomerium-authenticate:443
- AUTHORIZE_INTERNAL_URL=pomerium-authorize:443
- AUTHENTICATE_INTERNAL_URL=pomerium-authenticate
- AUTHORIZE_SERVICE_URL=https://pomerium-authorize
# When communicating internally, rPC is going to get a name conflict expecting an external
# facing certificate name (i.e. authenticate-service.local vs *.corp.example.com).
- OVERRIDE_CERTIFICATE_NAME=*.corp.beyondperimeter.com

View file

@ -26,9 +26,7 @@ spec:
- name: SERVICES
value: proxy
- name: AUTHORIZE_SERVICE_URL
value: https://authorize.corp.beyondperimeter.com
- name: AUTHORIZE_INTERNAL_URL
value: "pomerium-authorize-service.pomerium.svc.cluster.local"
value: https://pomerium-authorize-service.pomerium.svc.cluster.local
- name: AUTHENTICATE_SERVICE_URL
value: https://authenticate.corp.beyondperimeter.com
- name: AUTHENTICATE_INTERNAL_URL

View file

@ -175,10 +175,9 @@ IDP_CLIENT_ID | Values from setting up your [identity provider]
IDP_PROVIDER | Values from setting up your [identity provider] (e.g. `google`)
COOKIE_SECRET | output of `head -c32 /dev/urandom | base64`
SHARED_SECRET | output of `head -c32 /dev/urandom | base64`
AUTHORIZE_SERVICE_URL | `https://authorize.int.nas.example.com`
AUTHORIZE_SERVICE_URL | `https://localhost`
AUTHENTICATE_SERVICE_URL | `https://authenticate.int.nas.example.com`
AUTHORIZE_INTERNAL_URL | `localhost:443`
AUTHENTICATE_INTERNAL_URL | `localhost:443`
AUTHENTICATE_INTERNAL_URL | `localhost`
For a detailed explanation, and additional options, please refer to the [configuration variable docs].

View file

@ -35,7 +35,7 @@ type StateParameter struct {
RedirectURI string `json:"redirect_uri"`
}
// Handler returns a http handler for an Proxy
// Handler returns a http handler for a Proxy
func (p *Proxy) Handler() http.Handler {
// routes
mux := http.NewServeMux()
@ -71,10 +71,9 @@ func (p *Proxy) Handler() http.Handler {
c = c.Append(middleware.ValidateHost(p.mux))
// serve the middleware and mux
h := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
return c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mux.ServeHTTP(w, r)
}))
return h
}
// RobotsTxt sets the User-Agent header in the response to be "Disallow"

View file

@ -38,12 +38,18 @@ type Options struct {
Policy string `envconfig:"POLICY"`
PolicyFile string `envconfig:"POLICY_FILE"`
// Authenticate service settings
// AuthenticateURL represents the externally accessible http endpoints
// used for authentication requests and callbacks
AuthenticateURL *url.URL `envconfig:"AUTHENTICATE_SERVICE_URL"`
// 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"`
// Authorize service settings
// 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"`
AuthorizeInternalAddr string `envconfig:"AUTHORIZE_INTERNAL_URL"`
// Settings to enable custom behind-the-ingress service communication
OverrideCertificateName string `envconfig:"OVERRIDE_CERTIFICATE_NAME"`
CA string `envconfig:"CERTIFICATE_AUTHORITY"`
@ -98,32 +104,24 @@ func (o *Options) Validate() error {
if o.Policy == "" && o.PolicyFile == "" {
return errors.New("proxy: either `POLICY` or `POLICY_FILE` must be non-nil")
}
var policies []policy.Policy
var err error
if o.Policy != "" {
confBytes, err := base64.StdEncoding.DecodeString(o.Policy)
if err != nil {
return fmt.Errorf("proxy: `POLICY` is invalid base64 %v", err)
}
policies, err = policy.FromConfig(confBytes)
_, err = policy.FromConfig(confBytes)
if err != nil {
return fmt.Errorf("proxy: `POLICY` %v", err)
}
}
if o.PolicyFile != "" {
policies, err = policy.FromConfigFile(o.PolicyFile)
_, err = policy.FromConfigFile(o.PolicyFile)
if err != nil {
return fmt.Errorf("proxy: `POLICY_FILE` %v", err)
}
}
for _, p := range policies {
if _, err := urlParse(p.To); err != nil {
return fmt.Errorf("could not parse source %s url: %v", p.To, err)
}
if _, err := urlParse(p.From); err != nil {
return fmt.Errorf("could not parse destination %s url: %v", p.From, err)
}
}
if o.AuthenticateURL == nil {
return errors.New("missing setting: authenticate-service-url")
}
@ -253,7 +251,6 @@ func New(opts *Options) (*Proxy, error) {
p.AuthorizeClient, err = clients.NewAuthorizeClient("grpc",
&clients.Options{
Addr: opts.AuthorizeURL.Host,
InternalAddr: opts.AuthorizeInternalAddr,
OverrideCertificateName: opts.OverrideCertificateName,
SharedSecret: opts.SharedKey,
CA: opts.CA,
@ -328,10 +325,7 @@ func NewReverseProxyHandler(o *Options, proxy *httputil.ReverseProxy, route *pol
cookieName: o.CookieName,
}
if len(o.SigningKey) != 0 {
decodedSigningKey, err := base64.StdEncoding.DecodeString(o.SigningKey)
if err != nil {
return nil, err
}
decodedSigningKey, _ := base64.StdEncoding.DecodeString(o.SigningKey)
signer, err := cryptutil.NewES256Signer(decodedSigningKey, route.Source.Host)
if err != nil {
return nil, err

View file

@ -136,8 +136,12 @@ func TestOptions_Validate(t *testing.T) {
badAuthURL := testOptions()
badAuthURL.AuthenticateURL = nil
authurl, _ := url.Parse("http://authenticate.corp.beyondperimeter.com")
httpAuthURL := testOptions()
httpAuthURL.AuthenticateURL = authurl
authenticateBadScheme := testOptions()
authenticateBadScheme.AuthenticateURL = authurl
authorizeBadSCheme := testOptions()
authorizeBadSCheme.AuthorizeURL = authurl
authorizeNil := testOptions()
authorizeNil.AuthorizeURL = nil
emptyCookieSecret := testOptions()
emptyCookieSecret.CookieSecret = ""
invalidCookieSecret := testOptions()
@ -148,6 +152,12 @@ func TestOptions_Validate(t *testing.T) {
invalidSignKey.SigningKey = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw^"
badSharedKey := testOptions()
badSharedKey.SharedKey = ""
policyBadBase64 := testOptions()
policyBadBase64.Policy = "^"
badPolicyToURL := testOptions()
badPolicyToURL.Policy = "LSBmcm9tOiBodHRwYmluLmNvcnAuYmV5b25kcGVyaW1ldGVyLmNvbQogIHRvOiBodHRwOi8vaHR0cGJpbl4KICBhbGxvd2VkX2RvbWFpbnM6CiAgICAtIHBvbWVyaXVtLmlv"
badPolicyFromURL := testOptions()
badPolicyFromURL.Policy = "LSBmcm9tOiBodHRwYmluLmNvcnAuYmV5b25kcGVyaW1ldGVyLmNvbQogIHRvOiBodHRwOi8vaHR0cGJpbl4KICBhbGxvd2VkX2RvbWFpbnM6CiAgICAtIHBvbWVyaXVtLmlv"
tests := []struct {
name string
@ -158,13 +168,18 @@ func TestOptions_Validate(t *testing.T) {
{"nil options", &Options{}, true},
{"from route", badFromRoute, true},
{"to route", badToRoute, true},
{"auth service url", badAuthURL, true},
{"auth service url not https", httpAuthURL, true},
{"authenticate service url", badAuthURL, true},
{"authenticate service url not https", authenticateBadScheme, true},
{"authorize service url not https", authorizeBadSCheme, true},
{"authorize service cannot be nil", authorizeNil, true},
{"no cookie secret", emptyCookieSecret, true},
{"invalid cookie secret", invalidCookieSecret, true},
{"short cookie secret", shortCookieLength, true},
{"no shared secret", badSharedKey, true},
{"invalid signing key", invalidSignKey, true},
{"policy invalid base64", policyBadBase64, true},
{"policy bad to url", badPolicyFromURL, true},
{"policy bad from url", badPolicyFromURL, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {