From 593c47f8ac1a8197e4d152b5497428f48663bda2 Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Mon, 11 May 2020 18:01:10 -0600 Subject: [PATCH] proxy: remove pomerium cookie and authorization from upstream requests (#687) * proxy: remove pomerium cookie and authorization from upstream requests * fix typo --- go.mod | 1 + .../luascripts/clean-upstream.lua | 34 ++++++++++++ .../luascripts/ext-authz-set-cookie.lua | 18 +++++++ internal/controlplane/luascripts/statik.go | 15 ++++++ internal/controlplane/xds_listeners.go | 33 +++++------- internal/controlplane/xds_lua.go | 53 +++++++++++++++++++ internal/controlplane/xds_routes.go | 19 +++++++ 7 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 internal/controlplane/luascripts/clean-upstream.lua create mode 100644 internal/controlplane/luascripts/ext-authz-set-cookie.lua create mode 100644 internal/controlplane/luascripts/statik.go create mode 100644 internal/controlplane/xds_lua.go diff --git a/go.mod b/go.mod index 1c8168924..bc7926e61 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( google.golang.org/appengine v1.6.5 // indirect google.golang.org/genproto v0.0.0-20200204235621-fb4a7afc5178 google.golang.org/grpc v1.27.1 + google.golang.org/protobuf v1.21.0 gopkg.in/cookieo9/resources-go.v2 v2.0.0-20150225115733-d27c04069d0d gopkg.in/ini.v1 v1.51.1 // indirect gopkg.in/square/go-jose.v2 v2.5.1 diff --git a/internal/controlplane/luascripts/clean-upstream.lua b/internal/controlplane/luascripts/clean-upstream.lua new file mode 100644 index 000000000..932d55e01 --- /dev/null +++ b/internal/controlplane/luascripts/clean-upstream.lua @@ -0,0 +1,34 @@ +function remove_pomerium_cookie(cookie_name, cookie) + -- lua doesn't support optional capture groups + -- so we replace twice to handle pomerium=xyz at the end of the string + cookie = cookie:gsub(cookie_name .. "=[^;]+; ", "") + cookie = cookie:gsub(cookie_name .. "=[^;]+", "") + return cookie +end + +function has_prefix(str, prefix) + return str ~= nil and str:sub(1, #prefix) == prefix +end + +function envoy_on_request(request_handle) + local headers = request_handle:headers() + local metadata = request_handle:metadata() + + local remove_cookie_name = metadata:get("remove_pomerium_cookie") + if remove_cookie_name then + local cookie = headers:get("cookie") + if cookie ~= nil then + newcookie = remove_pomerium_cookie(remove_cookie_name, cookie) + headers:replace("cookie", newcookie) + end + end + + local remove_authorization = metadata:get("remove_pomerium_authorization") + if remove_authorization then + local authorization = headers:get("authorization") + local authorization_prefix = "Pomerium " + if has_prefix(authorization, authorization_prefix) then + headers:remove("authorization") + end + end +end diff --git a/internal/controlplane/luascripts/ext-authz-set-cookie.lua b/internal/controlplane/luascripts/ext-authz-set-cookie.lua new file mode 100644 index 000000000..f51990624 --- /dev/null +++ b/internal/controlplane/luascripts/ext-authz-set-cookie.lua @@ -0,0 +1,18 @@ +function envoy_on_request(request_handle) + local headers = request_handle:headers() + local dynamic_meta = request_handle:streamInfo():dynamicMetadata() + if headers:get("x-pomerium-set-cookie") ~= nil then + dynamic_meta:set("envoy.filters.http.lua", "pomerium_set_cookie", + headers:get("x-pomerium-set-cookie")) + headers:remove("x-pomerium-set-cookie") + end +end + +function envoy_on_response(response_handle) + local headers = response_handle:headers() + local dynamic_meta = response_handle:streamInfo():dynamicMetadata() + local tbl = dynamic_meta:get("envoy.filters.http.lua") + if tbl ~= nil and tbl["pomerium_set_cookie"] ~= nil then + headers:add("set-cookie", tbl["pomerium_set_cookie"]) + end +end diff --git a/internal/controlplane/luascripts/statik.go b/internal/controlplane/luascripts/statik.go new file mode 100644 index 000000000..6fdbc7366 --- /dev/null +++ b/internal/controlplane/luascripts/statik.go @@ -0,0 +1,15 @@ +// Code generated by statik. DO NOT EDIT. + +package luascripts + +import ( + "github.com/rakyll/statik/fs" +) + + +const Luascripts = "luascripts" // static asset namespace + +func init() { + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x19\x90\xabP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x00clean-upstream.luaUT\x05\x00\x01\xd3\x92\xb9^\x94S\xd1\x8e\x9b0\x10|\xe7+F\xf4\xa1D\xe5N\xeakN\xfe\x87\xbeW-ra\x13\xac\x82\x97\xda\xeb\xcb\xdd=\xf4\xdb+\x82!\xf8 \xaa\xceRb[\x9e\x99\x9d\xccnN\xc1\xd6b\xd8\xc2Q\xcf\xcfT\x0d\xdc\x933\xa1\xafj\xe6\xdf\x86\x8ai\xab\xac\xee\xa9\xc4t9d\x00\xf0\xf0\x80.h4L\xde~\x16\xf80\x0c\xec\x04<\x8cj\xbaC\xad\x07 \x8epv\x1c\x06?S<\xe3Bp4t\xba&\xc8\xc5\x8c\xdf\x8cV\xdb\xa6#\xcc\xc5\xd5\xcb\xeb\x1b\xb4@Z\x02\xd9\x06|\xba\x1e\xbd8c\xcfW\xa9\xc9 T<\x1c\xcf>\xfcZ{\xc5\xe3#r\xf5\xfd\xe7\xd3\x8f/O\xc8K\xe4\xf9\xe1\xa3\xbc\x15\xcb\x91\x04g#'#\xdbd\xd9\x92[\xab}58:\x99\x97\xc2\x8b+1\x9d\x13\x9e\x17\x87\xbf\n\xd6t\xd0\xb6\x19\xaf\xc7\xb1\xec\xd7\x12\x9f\"\x1aJE\xe2;u\xb2\xcf\xfcZ\xb1\xad\x1c\xfd \xe4\xa5\x88{5%6\x95\xe9\xb8\xd6\x1dZ\xd2\x0d9\x0f\x85\x14s\x8c\x0f\xc5\x1a\xdc\x93\xe8F\x8b\xde\xa2\xe7\x97\xe2\x90\xad\xf0q:\xd6I\xa9E\xe4x&)\xf2\xfd\x01\x8a \x9a\xd3\x9e\x84\xb4d\xaf\xcf\xb7BK\x83\xa2\xebI;\xd1\x8az\x11\x19\x83M\xa4\xc6e\xe9\xb2h\xdd\x99\xed\xad\xa3t\xc4\xe75[\x89c\xbb\xd8)oEn\x84\xb1\x7f\xf3\xbe\x0dP\x07i\xd9\x997}\xed\xee\xff\"L\xd0\x9b$S\xad\x9d,\xdf\x17K\"\xdd\xd3\xbeC\x8d\xf3\x0d\x85\xfc[\xb4\x86|\xdd\x8a\xd5\x7f !\x96\xbb:\x87m\xb3n \x8f\xbf\xec\xbe\xb9u\xb8\xe3\xe7_\x00\x00\x00\xff\xffPK\x07\x08\x9d]\x11\x8f\x98\x01\x00\x00\xbe\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x004\x90\xabP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x00ext-authz-set-cookie.luaUT\x05\x00\x01\x04\x93\xb9^\x8c\x91An\x830\x10E\xf7\x9cb\xc4\xcaHI\x0e\x80\x94\x03t\xd1\x13T\x955\xc5C\xb0j\x8fS{\x88\x9aM\xcf^AM\x04\x0dM\x19 \x01\xe2\xff?\xf8\xbf\xb6\xe7Fl` \xbe\x84\xab\x0e\xac#}\xf4\x94D\xe5\xbb\xee\x90\x8d\xa3\xaa\x00\x00p\xa1A\x07\x1d\xa1\xa1\x98\xe0\x08KM\x9d?\xa8\xb9\xd8\\\x19\xbdm\xb4'\xc1{G\x92H\xe8\x9f\xb8\x0d\xaa\xaa\xb3\xf4\x99\x04\x0d\n\xe6\x18\xdbN\x0b\xeb\x13\x89*?\xf7\xe7\xe0)\xda\xde\xef\x13\xc9\xbe \xe1\xddRY\xc1\xd7\x11\xd8:\x90\x8ex\xf4\x0d3_^\xa7\xc1=\x1e\xf3\xd0Z'\x14\xd3\xa1\x139\x1f\\\x8f\xe5\x0e\xca)U'\x12\x9dSw\xb7\xa4\xbb\xd9\xf2OU\xf1[\x1d\xc9\x87\x0b\xfdi\x18\xf5\xc4\xa6\x18\xaeb\x8dM:\x07N\xa4\xa6\x87\x7f\xe8,D\xdb\xf0,-\x1b\xf8\xfc\xe4\xc8\x9b\x83\xe3\xb2\xef\xd3\x83\xbeoh\x07_&\x87l\x86\xd7\x97U\x12\xaf\xab|\xa7Z\xd1\x18U\xce\x8a\xdc=\x08Z\x96\xfc\x1d\x00\x00\xff\xffPK\x07\x08\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x19\x90\xabP\x9d]\x11\x8f\x98\x01\x00\x00\xbe\x04\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00clean-upstream.luaUT\x05\x00\x01\xd3\x92\xb9^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x004\x90\xabP\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\xe1\x01\x00\x00ext-authz-set-cookie.luaUT\x05\x00\x01\x04\x93\xb9^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x007\x03\x00\x00\x00\x00" + fs.RegisterWithNamespace("luascripts", data) + } diff --git a/internal/controlplane/xds_listeners.go b/internal/controlplane/xds_listeners.go index d40460e9d..641773174 100644 --- a/internal/controlplane/xds_listeners.go +++ b/internal/controlplane/xds_listeners.go @@ -100,26 +100,11 @@ func (srv *Server) buildHTTPListener(options config.Options) *envoy_config_liste }, }) - luaConfig, _ := ptypes.MarshalAny(&envoy_extensions_filters_http_lua_v3.Lua{ - InlineCode: ` -function envoy_on_request(request_handle) - local headers = request_handle:headers() - local dynamic_meta = request_handle:streamInfo():dynamicMetadata() - if headers:get("x-pomerium-set-cookie") ~= nil then - dynamic_meta:set("envoy.filters.http.lua", "pomerium_set_cookie", headers:get("x-pomerium-set-cookie")) - headers:remove("x-pomerium-set-cookie") - end -end - -function envoy_on_response(response_handle) - local headers = response_handle:headers() - local dynamic_meta = response_handle:streamInfo():dynamicMetadata() - local tbl = dynamic_meta:get("envoy.filters.http.lua") - if tbl ~= nil and tbl["pomerium_set_cookie"] ~= nil then - headers:add("set-cookie", tbl["pomerium_set_cookie"]) - end -end -`, + extAuthzSetCookieLua, _ := ptypes.MarshalAny(&envoy_extensions_filters_http_lua_v3.Lua{ + InlineCode: luascripts.ExtAuthzSetCookie, + }) + cleanUpstreamLua, _ := ptypes.MarshalAny(&envoy_extensions_filters_http_lua_v3.Lua{ + InlineCode: luascripts.CleanUpstream, }) tc, _ := ptypes.MarshalAny(&envoy_http_connection_manager.HttpConnectionManager{ @@ -141,7 +126,13 @@ end { Name: "envoy.filters.http.lua", ConfigType: &envoy_http_connection_manager.HttpFilter_TypedConfig{ - TypedConfig: luaConfig, + TypedConfig: extAuthzSetCookieLua, + }, + }, + { + Name: "envoy.filters.http.lua", + ConfigType: &envoy_http_connection_manager.HttpFilter_TypedConfig{ + TypedConfig: cleanUpstreamLua, }, }, { diff --git a/internal/controlplane/xds_lua.go b/internal/controlplane/xds_lua.go new file mode 100644 index 000000000..e2cbccfd4 --- /dev/null +++ b/internal/controlplane/xds_lua.go @@ -0,0 +1,53 @@ +package controlplane + +import ( + "os" + + "github.com/rakyll/statik/fs" + + // include luascripts source code + _ "github.com/pomerium/pomerium/internal/controlplane/luascripts" +) + +//go:generate go run github.com/rakyll/statik -src=./luascripts -include=*.lua -p luascripts -ns luascripts + +var luascripts struct { + ExtAuthzSetCookie string + CleanUpstream string +} + +func init() { + hfs, err := fs.NewWithNamespace("luascripts") + if err != nil { + panic(err) + } + + fileToField := map[string]*string{ + "/clean-upstream.lua": &luascripts.CleanUpstream, + "/ext-authz-set-cookie.lua": &luascripts.ExtAuthzSetCookie, + } + + err = fs.Walk(hfs, "/", func(p string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if fi.IsDir() { + return nil + } + + bs, err := fs.ReadFile(hfs, p) + if err != nil { + return err + } + + if ptr, ok := fileToField[p]; ok { + *ptr = string(bs) + } + + return nil + }) + if err != nil { + panic(err) + } +} diff --git a/internal/controlplane/xds_routes.go b/internal/controlplane/xds_routes.go index 3f521a260..986bc0bc8 100644 --- a/internal/controlplane/xds_routes.go +++ b/internal/controlplane/xds_routes.go @@ -8,6 +8,7 @@ import ( envoy_type_matcher_v3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" "github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/wrappers" + "google.golang.org/protobuf/types/known/structpb" "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/urlutil" @@ -136,6 +137,24 @@ func (srv *Server) buildPolicyRoutes(options config.Options, domain string) []*e routes = append(routes, &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, + }, + }, + }, + }, + }, + }, Action: &envoy_config_route_v3.Route_Route{ Route: &envoy_config_route_v3.RouteAction{ ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{