mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
proxy: implement pass-through for authenticate backend (#1870)
* proxy: implement pass-through for authenticate backend * address comments
This commit is contained in:
parent
4bf5179bb6
commit
963399b53d
2 changed files with 153 additions and 69 deletions
|
@ -49,51 +49,60 @@ func (srv *Server) buildGRPCRoutes() ([]*envoy_config_route_v3.Route, error) {
|
|||
|
||||
func (srv *Server) buildPomeriumHTTPRoutes(options *config.Options, domain string) ([]*envoy_config_route_v3.Route, error) {
|
||||
var routes []*envoy_config_route_v3.Route
|
||||
// enable ext_authz
|
||||
r, err := srv.buildControlPlanePathRoute("/.pomerium/jwt", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
|
||||
// disable ext_authz and passthrough to proxy handlers
|
||||
r, err = srv.buildControlPlanePathRoute("/ping", false)
|
||||
// if this is the pomerium proxy in front of the the authenticate service, don't add
|
||||
// these routes since they will be handled by authenticate
|
||||
isFrontingAuthenticate, err := isProxyFrontingAuthenticate(options, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/healthz", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/.pomerium", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePrefixRoute("/.pomerium/", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/.well-known/pomerium", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePrefixRoute("/.well-known/pomerium/", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
// per #837, only add robots.txt if there are no unauthenticated routes
|
||||
if !hasPublicPolicyMatchingURL(options, url.URL{Scheme: "https", Host: domain, Path: "/robots.txt"}) {
|
||||
r, err := srv.buildControlPlanePathRoute("/robots.txt", false)
|
||||
if !isFrontingAuthenticate {
|
||||
// enable ext_authz
|
||||
r, err := srv.buildControlPlanePathRoute("/.pomerium/jwt", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
|
||||
// disable ext_authz and passthrough to proxy handlers
|
||||
r, err = srv.buildControlPlanePathRoute("/ping", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/healthz", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/.pomerium", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePrefixRoute("/.pomerium/", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePathRoute("/.well-known/pomerium", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
r, err = srv.buildControlPlanePrefixRoute("/.well-known/pomerium/", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
// per #837, only add robots.txt if there are no unauthenticated routes
|
||||
if !hasPublicPolicyMatchingURL(options, url.URL{Scheme: "https", Host: domain, Path: "/robots.txt"}) {
|
||||
r, err := srv.buildControlPlanePathRoute("/robots.txt", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, r)
|
||||
}
|
||||
}
|
||||
// if we're handling authentication, add the oauth2 callback url
|
||||
authenticateURL, err := options.GetAuthenticateURL()
|
||||
|
@ -260,37 +269,12 @@ func (srv *Server) buildPolicyRoutes(options *config.Options, domain string) ([]
|
|||
}
|
||||
|
||||
match := mkRouteMatch(&policy)
|
||||
requestHeadersToAdd := toEnvoyHeaders(policy.SetRequestHeaders)
|
||||
requestHeadersToRemove := getRequestHeadersToRemove(options, &policy)
|
||||
|
||||
envoyRoute := &envoy_config_route_v3.Route{
|
||||
Name: fmt.Sprintf("policy-%d", i),
|
||||
Match: match,
|
||||
Metadata: &envoy_config_core_v3.Metadata{
|
||||
FilterMetadata: map[string]*structpb.Struct{
|
||||
"envoy.filters.http.lua": {
|
||||
Fields: map[string]*structpb.Value{
|
||||
"remove_pomerium_cookie": {
|
||||
Kind: &structpb.Value_StringValue{
|
||||
StringValue: options.CookieName,
|
||||
},
|
||||
},
|
||||
"remove_pomerium_authorization": {
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
"remove_impersonate_headers": {
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: policy.KubernetesServiceAccountTokenFile != "" || policy.KubernetesServiceAccountToken != "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RequestHeadersToAdd: requestHeadersToAdd,
|
||||
RequestHeadersToRemove: requestHeadersToRemove,
|
||||
Name: fmt.Sprintf("policy-%d", i),
|
||||
Match: match,
|
||||
Metadata: &envoy_config_core_v3.Metadata{},
|
||||
RequestHeadersToAdd: toEnvoyHeaders(policy.SetRequestHeaders),
|
||||
RequestHeadersToRemove: getRequestHeadersToRemove(options, &policy),
|
||||
}
|
||||
if policy.Redirect != nil {
|
||||
action, err := srv.buildPolicyRouteRedirectAction(policy.Redirect)
|
||||
|
@ -306,6 +290,39 @@ func (srv *Server) buildPolicyRoutes(options *config.Options, domain string) ([]
|
|||
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: action}
|
||||
}
|
||||
|
||||
// disable authentication entirely when the proxy is fronting authenticate
|
||||
isFrontingAuthenticate, err := isProxyFrontingAuthenticate(options, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isFrontingAuthenticate {
|
||||
envoyRoute.TypedPerFilterConfig = map[string]*any.Any{
|
||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||
}
|
||||
} else {
|
||||
envoyRoute.Metadata.FilterMetadata = map[string]*structpb.Struct{
|
||||
"envoy.filters.http.lua": {
|
||||
Fields: map[string]*structpb.Value{
|
||||
"remove_pomerium_cookie": {
|
||||
Kind: &structpb.Value_StringValue{
|
||||
StringValue: options.CookieName,
|
||||
},
|
||||
},
|
||||
"remove_pomerium_authorization": {
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
"remove_impersonate_headers": {
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: policy.KubernetesServiceAccountTokenFile != "" || policy.KubernetesServiceAccountToken != "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
routes = append(routes, envoyRoute)
|
||||
}
|
||||
return routes, nil
|
||||
|
@ -529,3 +546,16 @@ func hasPublicPolicyMatchingURL(options *config.Options, requestURL url.URL) boo
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isProxyFrontingAuthenticate(options *config.Options, domain string) (bool, error) {
|
||||
authenticateURL, err := options.GetAuthenticateURL()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !config.IsAuthenticate(options.Services) && hostMatchesDomain(authenticateURL, domain) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -99,6 +99,16 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
|||
`+routeString("path", "/oauth2/callback", false)+`
|
||||
]`, routes)
|
||||
})
|
||||
t.Run("proxy fronting authenticate", func(t *testing.T) {
|
||||
options := &config.Options{
|
||||
Services: "proxy",
|
||||
AuthenticateURL: mustParseURL(t, "https://authenticate.example.com"),
|
||||
AuthenticateCallbackPath: "/oauth2/callback",
|
||||
}
|
||||
routes, err := srv.buildPomeriumHTTPRoutes(options, "authenticate.example.com")
|
||||
require.NoError(t, err)
|
||||
testutil.AssertProtoJSONEqual(t, "null", routes)
|
||||
})
|
||||
|
||||
t.Run("with robots", func(t *testing.T) {
|
||||
options := &config.Options{
|
||||
|
@ -484,6 +494,50 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
|||
]
|
||||
`, routes)
|
||||
|
||||
t.Run("fronting-authenticate", func(t *testing.T) {
|
||||
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||
AuthenticateURL: mustParseURL(t, "https://authenticate.example.com"),
|
||||
Services: "proxy",
|
||||
CookieName: "pomerium",
|
||||
DefaultUpstreamTimeout: time.Second * 3,
|
||||
Policies: []config.Policy{
|
||||
{
|
||||
Source: &config.StringURL{URL: mustParseURL(t, "https://authenticate.example.com")},
|
||||
PassIdentityHeaders: true,
|
||||
},
|
||||
},
|
||||
}, "authenticate.example.com")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.AssertProtoJSONEqual(t, `
|
||||
[
|
||||
{
|
||||
"name": "policy-0",
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"metadata": {
|
||||
},
|
||||
"route": {
|
||||
"autoHostRewrite": true,
|
||||
"cluster": "policy-9",
|
||||
"timeout": "3s",
|
||||
"upgradeConfigs": [
|
||||
{ "enabled": false, "upgradeType": "websocket"},
|
||||
{ "enabled": false, "upgradeType": "spdy/3.1"}
|
||||
]
|
||||
},
|
||||
"typedPerFilterConfig": {
|
||||
"envoy.filters.http.ext_authz": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute",
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
`, routes)
|
||||
})
|
||||
|
||||
t.Run("tcp", func(t *testing.T) {
|
||||
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||
CookieName: "pomerium",
|
||||
|
@ -520,7 +574,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
|||
},
|
||||
"route": {
|
||||
"autoHostRewrite": true,
|
||||
"cluster": "policy-9",
|
||||
"cluster": "policy-10",
|
||||
"idleTimeout": "0s",
|
||||
"timeout": "0s",
|
||||
"upgradeConfigs": [
|
||||
|
@ -546,7 +600,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
|||
},
|
||||
"route": {
|
||||
"autoHostRewrite": true,
|
||||
"cluster": "policy-10",
|
||||
"cluster": "policy-11",
|
||||
"idleTimeout": "0s",
|
||||
"timeout": "10s",
|
||||
"upgradeConfigs": [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue