mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-19 20:17:30 +02:00
config: add rewrite_response_headers option (#1961)
* add lua script to rewrite response headers * add policy config * update docs
This commit is contained in:
parent
b6ec01f377
commit
7f6107051f
12 changed files with 348 additions and 35 deletions
|
@ -148,6 +148,16 @@ type Policy struct {
|
||||||
SubPolicies []SubPolicy `mapstructure:"sub_policies" yaml:"sub_policies,omitempty" json:"sub_policies,omitempty"`
|
SubPolicies []SubPolicy `mapstructure:"sub_policies" yaml:"sub_policies,omitempty" json:"sub_policies,omitempty"`
|
||||||
|
|
||||||
EnvoyOpts *envoy_config_cluster_v3.Cluster `mapstructure:"_envoy_opts" yaml:"-" json:"-"`
|
EnvoyOpts *envoy_config_cluster_v3.Cluster `mapstructure:"_envoy_opts" yaml:"-" json:"-"`
|
||||||
|
|
||||||
|
// RewriteResponseHeaders rewrites response headers. This can be used to change the Location header.
|
||||||
|
RewriteResponseHeaders []RewriteHeader `mapstructure:"rewrite_response_headers" yaml:"rewrite_response_headers,omitempty" json:"rewrite_response_headers,omitempty"` //nolint
|
||||||
|
}
|
||||||
|
|
||||||
|
// RewriteHeader is a policy configuration option to rewrite an HTTP header.
|
||||||
|
type RewriteHeader struct {
|
||||||
|
Header string `mapstructure:"header" yaml:"header" json:"header"`
|
||||||
|
Prefix string `mapstructure:"prefix" yaml:"prefix,omitempty" json:"prefix,omitempty"`
|
||||||
|
Value string `mapstructure:"value" yaml:"value,omitempty" json:"value,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SubPolicy is a protobuf Policy within a protobuf Route.
|
// A SubPolicy is a protobuf Policy within a protobuf Route.
|
||||||
|
|
|
@ -1294,6 +1294,30 @@ Remove Request Headers allows you to remove given request headers. This can be u
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Rewrite Response Headers
|
||||||
|
- Config File Key: `rewrite_response_headers`
|
||||||
|
- Type: `object`
|
||||||
|
- Optional
|
||||||
|
- Example: `[{ "header": "Location", "prefix": "http://localhost:8000/two/", "value": "http://frontend/one/" }]`
|
||||||
|
|
||||||
|
Rewrite Response Headers allows you to modify response headers before they are returned to the client. The `header` field will match the HTTP header name, and `prefix` will be replaced with `value`. For example, if the downstream server returns a header:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Location: http://localhost:8000/two/some/path/
|
||||||
|
```
|
||||||
|
|
||||||
|
And the policy has this config:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
rewrite_response_headers:
|
||||||
|
- header: Location
|
||||||
|
prefix: http://localhost:8000/two/
|
||||||
|
value: http://frontend/one/
|
||||||
|
```
|
||||||
|
|
||||||
|
The browser would be redirected to: `http://frontend/one/some/path/`. This is similar to nginx's [`proxy_redirect` option](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect), but can be used for any header.
|
||||||
|
|
||||||
|
|
||||||
### Redirect
|
### Redirect
|
||||||
- `yaml`/`json` setting: 'redirect'
|
- `yaml`/`json` setting: 'redirect'
|
||||||
- Type: object
|
- Type: object
|
||||||
|
|
|
@ -1427,6 +1427,30 @@ settings:
|
||||||
- X-Email
|
- X-Email
|
||||||
- X-Username
|
- X-Username
|
||||||
```
|
```
|
||||||
|
- name: "Rewrite Response Headers"
|
||||||
|
keys: ["rewrite_response_headers"]
|
||||||
|
attributes: |
|
||||||
|
- Config File Key: `rewrite_response_headers`
|
||||||
|
- Type: `object`
|
||||||
|
- Optional
|
||||||
|
- Example: `[{ "header": "Location", "prefix": "http://localhost:8000/two/", "value": "http://frontend/one/" }]`
|
||||||
|
doc: |
|
||||||
|
Rewrite Response Headers allows you to modify response headers before they are returned to the client. The `header` field will match the HTTP header name, and `prefix` will be replaced with `value`. For example, if the downstream server returns a header:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Location: http://localhost:8000/two/some/path/
|
||||||
|
```
|
||||||
|
|
||||||
|
And the policy has this config:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
rewrite_response_headers:
|
||||||
|
- header: Location
|
||||||
|
prefix: http://localhost:8000/two/
|
||||||
|
value: http://frontend/one/
|
||||||
|
```
|
||||||
|
|
||||||
|
The browser would be redirected to: `http://frontend/one/some/path/`. This is similar to nginx's [`proxy_redirect` option](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect), but can be used for any header.
|
||||||
- name: "Redirect"
|
- name: "Redirect"
|
||||||
keys: ["redirect"]
|
keys: ["redirect"]
|
||||||
attributes: |
|
attributes: |
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -56,6 +56,7 @@ require (
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||||
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
|
||||||
go.opencensus.io v0.23.0
|
go.opencensus.io v0.23.0
|
||||||
go.uber.org/zap v1.16.0
|
go.uber.org/zap v1.16.0
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -618,6 +618,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=
|
||||||
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
@ -780,6 +782,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
28
internal/controlplane/luascripts/rewrite-headers.lua
Normal file
28
internal/controlplane/luascripts/rewrite-headers.lua
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
function replace_prefix(str, prefix, value)
|
||||||
|
return str:gsub("^"..prefix, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function envoy_on_request(request_handle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function envoy_on_response(response_handle)
|
||||||
|
local headers = response_handle:headers()
|
||||||
|
local metadata = response_handle:metadata()
|
||||||
|
|
||||||
|
-- should be in the form:
|
||||||
|
-- [{
|
||||||
|
-- "header":"Location",
|
||||||
|
-- "prefix":"http://localhost:8000/two/",
|
||||||
|
-- "value":"http://frontend/one/"
|
||||||
|
-- }]
|
||||||
|
local rewrite_response_headers = metadata:get("rewrite_response_headers")
|
||||||
|
if rewrite_response_headers then
|
||||||
|
for _, obj in pairs(rewrite_response_headers) do
|
||||||
|
local hdr = headers:get(obj.header)
|
||||||
|
if hdr ~= nil then
|
||||||
|
local newhdr = replace_prefix(hdr, obj.prefix, obj.value)
|
||||||
|
headers:replace(obj.header, newhdr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -373,6 +373,9 @@ func (srv *Server) buildMainHTTPConnectionManagerFilter(
|
||||||
removeImpersonateHeadersLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
|
removeImpersonateHeadersLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
|
||||||
InlineCode: luascripts.RemoveImpersonateHeaders,
|
InlineCode: luascripts.RemoveImpersonateHeaders,
|
||||||
})
|
})
|
||||||
|
rewriteHeadersLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
|
||||||
|
InlineCode: luascripts.RewriteHeaders,
|
||||||
|
})
|
||||||
|
|
||||||
filters := []*envoy_http_connection_manager.HttpFilter{
|
filters := []*envoy_http_connection_manager.HttpFilter{
|
||||||
{
|
{
|
||||||
|
@ -399,6 +402,12 @@ func (srv *Server) buildMainHTTPConnectionManagerFilter(
|
||||||
TypedConfig: cleanUpstreamLua,
|
TypedConfig: cleanUpstreamLua,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "envoy.filters.http.lua",
|
||||||
|
ConfigType: &envoy_http_connection_manager.HttpFilter_TypedConfig{
|
||||||
|
TypedConfig: rewriteHeadersLua,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if tlsDomain != "" && tlsDomain != "*" {
|
if tlsDomain != "" && tlsDomain != "*" {
|
||||||
fixMisdirectedLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
|
fixMisdirectedLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
|
||||||
|
|
|
@ -173,6 +173,13 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
|
||||||
"inlineCode": "function remove_pomerium_cookie(cookie_name, cookie)\n -- lua doesn't support optional capture groups\n -- so we replace twice to handle pomerium=xyz at the end of the string\n cookie = cookie:gsub(cookie_name .. \"=[^;]+; \", \"\")\n cookie = cookie:gsub(cookie_name .. \"=[^;]+\", \"\")\n return cookie\nend\n\nfunction has_prefix(str, prefix)\n return str ~= nil and str:sub(1, #prefix) == prefix\nend\n\nfunction envoy_on_request(request_handle)\n local headers = request_handle:headers()\n local metadata = request_handle:metadata()\n\n local remove_cookie_name = metadata:get(\"remove_pomerium_cookie\")\n if remove_cookie_name then\n local cookie = headers:get(\"cookie\")\n if cookie ~= nil then\n newcookie = remove_pomerium_cookie(remove_cookie_name, cookie)\n headers:replace(\"cookie\", newcookie)\n end\n end\n\n local remove_authorization = metadata:get(\"remove_pomerium_authorization\")\n if remove_authorization then\n local authorization = headers:get(\"authorization\")\n local authorization_prefix = \"Pomerium \"\n if has_prefix(authorization, authorization_prefix) then\n headers:remove(\"authorization\")\n end\n end\nend\n\nfunction envoy_on_response(response_handle)\n\nend\n"
|
"inlineCode": "function remove_pomerium_cookie(cookie_name, cookie)\n -- lua doesn't support optional capture groups\n -- so we replace twice to handle pomerium=xyz at the end of the string\n cookie = cookie:gsub(cookie_name .. \"=[^;]+; \", \"\")\n cookie = cookie:gsub(cookie_name .. \"=[^;]+\", \"\")\n return cookie\nend\n\nfunction has_prefix(str, prefix)\n return str ~= nil and str:sub(1, #prefix) == prefix\nend\n\nfunction envoy_on_request(request_handle)\n local headers = request_handle:headers()\n local metadata = request_handle:metadata()\n\n local remove_cookie_name = metadata:get(\"remove_pomerium_cookie\")\n if remove_cookie_name then\n local cookie = headers:get(\"cookie\")\n if cookie ~= nil then\n newcookie = remove_pomerium_cookie(remove_cookie_name, cookie)\n headers:replace(\"cookie\", newcookie)\n end\n end\n\n local remove_authorization = metadata:get(\"remove_pomerium_authorization\")\n if remove_authorization then\n local authorization = headers:get(\"authorization\")\n local authorization_prefix = \"Pomerium \"\n if has_prefix(authorization, authorization_prefix) then\n headers:remove(\"authorization\")\n end\n end\nend\n\nfunction envoy_on_response(response_handle)\n\nend\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.lua",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua",
|
||||||
|
"inlineCode": "function replace_prefix(str, prefix, value)\n return str:gsub(\"^\"..prefix, value)\nend\n\nfunction envoy_on_request(request_handle)\nend\n\nfunction envoy_on_response(response_handle)\n local headers = response_handle:headers()\n local metadata = response_handle:metadata()\n\n -- should be in the form:\n -- [{\n -- \"header\":\"Location\",\n -- \"prefix\":\"http://localhost:8000/two/\",\n -- \"value\":\"http://frontend/one/\"\n -- }]\n local rewrite_response_headers = metadata:get(\"rewrite_response_headers\")\n if rewrite_response_headers then\n for _, obj in pairs(rewrite_response_headers) do\n local hdr = headers:get(obj.header)\n if hdr ~= nil then\n local newhdr = replace_prefix(hdr, obj.prefix, obj.value)\n headers:replace(obj.header, newhdr)\n end\n end\n end\nend\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "envoy.filters.http.router"
|
"name": "envoy.filters.http.router"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ var luascripts struct {
|
||||||
ExtAuthzSetCookie string
|
ExtAuthzSetCookie string
|
||||||
CleanUpstream string
|
CleanUpstream string
|
||||||
RemoveImpersonateHeaders string
|
RemoveImpersonateHeaders string
|
||||||
|
RewriteHeaders string
|
||||||
FixMisdirected string
|
FixMisdirected string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ func init() {
|
||||||
"luascripts/clean-upstream.lua": &luascripts.CleanUpstream,
|
"luascripts/clean-upstream.lua": &luascripts.CleanUpstream,
|
||||||
"luascripts/ext-authz-set-cookie.lua": &luascripts.ExtAuthzSetCookie,
|
"luascripts/ext-authz-set-cookie.lua": &luascripts.ExtAuthzSetCookie,
|
||||||
"luascripts/remove-impersonate-headers.lua": &luascripts.RemoveImpersonateHeaders,
|
"luascripts/remove-impersonate-headers.lua": &luascripts.RemoveImpersonateHeaders,
|
||||||
|
"luascripts/rewrite-headers.lua": &luascripts.RewriteHeaders,
|
||||||
"luascripts/fix-misdirected.lua": &luascripts.FixMisdirected,
|
"luascripts/fix-misdirected.lua": &luascripts.FixMisdirected,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
166
internal/controlplane/xds_lua_test.go
Normal file
166
internal/controlplane/xds_lua_test.go
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
package controlplane
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLuaRewriteHeaders(t *testing.T) {
|
||||||
|
L := lua.NewState()
|
||||||
|
defer L.Close()
|
||||||
|
|
||||||
|
bs, err := luaFS.ReadFile("luascripts/rewrite-headers.lua")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = L.DoString(string(bs))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Location": "https://localhost:8080/two/some/uri/",
|
||||||
|
}
|
||||||
|
metadata := map[string]interface{}{
|
||||||
|
"rewrite_response_headers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"header": "Location",
|
||||||
|
"prefix": "https://localhost:8080/two/",
|
||||||
|
"value": "https://frontend/one/",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"header": "SomeOtherHeader",
|
||||||
|
"prefix": "x",
|
||||||
|
"value": "y",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handle := newLuaResponseHandle(L, headers, metadata)
|
||||||
|
|
||||||
|
err = L.CallByParam(lua.P{
|
||||||
|
Fn: L.GetGlobal("envoy_on_response"),
|
||||||
|
NRet: 0,
|
||||||
|
Protect: true,
|
||||||
|
}, handle)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "https://frontend/one/some/uri/", headers["Location"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLuaResponseHandle(L *lua.LState, headers map[string]string, metadata map[string]interface{}) lua.LValue {
|
||||||
|
typ := L.NewTable()
|
||||||
|
L.SetFuncs(typ, map[string]lua.LGFunction{
|
||||||
|
"headers": func(L *lua.LState) int {
|
||||||
|
L.Push(newLuaHeaders(L, headers))
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
"metadata": func(L *lua.LState) int {
|
||||||
|
L.Push(newLuaMetadata(L, metadata))
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
})
|
||||||
|
L.SetField(typ, "__index", typ)
|
||||||
|
|
||||||
|
tbl := L.NewTable()
|
||||||
|
L.SetMetatable(tbl, typ)
|
||||||
|
return tbl
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLuaHeaders(L *lua.LState, headers map[string]string) lua.LValue {
|
||||||
|
typ := L.NewTable()
|
||||||
|
L.SetFuncs(typ, map[string]lua.LGFunction{
|
||||||
|
"get": func(L *lua.LState) int {
|
||||||
|
_ = L.CheckTable(1)
|
||||||
|
key := L.CheckString(2)
|
||||||
|
|
||||||
|
str, ok := headers[key]
|
||||||
|
if !ok {
|
||||||
|
L.Push(lua.LNil)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
L.Push(lua.LString(str))
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
"replace": func(L *lua.LState) int {
|
||||||
|
_ = L.CheckTable(1)
|
||||||
|
key := L.CheckString(2)
|
||||||
|
value := L.CheckString(3)
|
||||||
|
|
||||||
|
headers[key] = value
|
||||||
|
|
||||||
|
return 0
|
||||||
|
},
|
||||||
|
})
|
||||||
|
L.SetField(typ, "__index", typ)
|
||||||
|
|
||||||
|
tbl := L.NewTable()
|
||||||
|
L.SetMetatable(tbl, typ)
|
||||||
|
return tbl
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLuaMetadata(L *lua.LState, metadata map[string]interface{}) lua.LValue {
|
||||||
|
typ := L.NewTable()
|
||||||
|
L.SetFuncs(typ, map[string]lua.LGFunction{
|
||||||
|
"get": func(L *lua.LState) int {
|
||||||
|
_ = L.CheckTable(1)
|
||||||
|
key := L.CheckString(2)
|
||||||
|
|
||||||
|
obj, ok := metadata[key]
|
||||||
|
if !ok {
|
||||||
|
L.Push(lua.LNil)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
L.Push(toLua(L, obj))
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
})
|
||||||
|
L.SetField(typ, "__index", typ)
|
||||||
|
|
||||||
|
tbl := L.NewTable()
|
||||||
|
L.SetMetatable(tbl, typ)
|
||||||
|
return tbl
|
||||||
|
}
|
||||||
|
|
||||||
|
func toLua(L *lua.LState, obj interface{}) lua.LValue {
|
||||||
|
// send the object through JSON to remove custom types
|
||||||
|
var normalized interface{}
|
||||||
|
bs, err := json.Marshal(obj)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(bs, &normalized)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if normalized == nil {
|
||||||
|
return lua.LNil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := normalized.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
tbl := L.NewTable()
|
||||||
|
for _, v := range t {
|
||||||
|
tbl.Append(toLua(L, v))
|
||||||
|
}
|
||||||
|
return tbl
|
||||||
|
case map[string]interface{}:
|
||||||
|
tbl := L.NewTable()
|
||||||
|
for k, v := range t {
|
||||||
|
L.SetField(tbl, k, toLua(L, v))
|
||||||
|
}
|
||||||
|
return tbl
|
||||||
|
case bool:
|
||||||
|
return lua.LBool(t)
|
||||||
|
case float64:
|
||||||
|
return lua.LNumber(t)
|
||||||
|
case string:
|
||||||
|
return lua.LString(t)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("%T not supported for toLua", obj))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package controlplane
|
package controlplane
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -290,6 +291,10 @@ func (srv *Server) buildPolicyRoutes(options *config.Options, domain string) ([]
|
||||||
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: action}
|
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: action}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaMetadata := map[string]*structpb.Value{
|
||||||
|
"rewrite_response_headers": getRewriteHeadersMetadata(policy.RewriteResponseHeaders),
|
||||||
|
}
|
||||||
|
|
||||||
// disable authentication entirely when the proxy is fronting authenticate
|
// disable authentication entirely when the proxy is fronting authenticate
|
||||||
isFrontingAuthenticate, err := isProxyFrontingAuthenticate(options, domain)
|
isFrontingAuthenticate, err := isProxyFrontingAuthenticate(options, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -300,29 +305,27 @@ func (srv *Server) buildPolicyRoutes(options *config.Options, domain string) ([]
|
||||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
envoyRoute.Metadata.FilterMetadata = map[string]*structpb.Struct{
|
luaMetadata["remove_pomerium_cookie"] = &structpb.Value{
|
||||||
"envoy.filters.http.lua": {
|
|
||||||
Fields: map[string]*structpb.Value{
|
|
||||||
"remove_pomerium_cookie": {
|
|
||||||
Kind: &structpb.Value_StringValue{
|
Kind: &structpb.Value_StringValue{
|
||||||
StringValue: options.CookieName,
|
StringValue: options.CookieName,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
"remove_pomerium_authorization": {
|
luaMetadata["remove_pomerium_authorization"] = &structpb.Value{
|
||||||
Kind: &structpb.Value_BoolValue{
|
Kind: &structpb.Value_BoolValue{
|
||||||
BoolValue: true,
|
BoolValue: true,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
"remove_impersonate_headers": {
|
luaMetadata["remove_impersonate_headers"] = &structpb.Value{
|
||||||
Kind: &structpb.Value_BoolValue{
|
Kind: &structpb.Value_BoolValue{
|
||||||
BoolValue: policy.KubernetesServiceAccountTokenFile != "" || policy.KubernetesServiceAccountToken != "",
|
BoolValue: policy.KubernetesServiceAccountTokenFile != "" || policy.KubernetesServiceAccountToken != "",
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envoyRoute.Metadata.FilterMetadata = map[string]*structpb.Struct{
|
||||||
|
"envoy.filters.http.lua": {Fields: luaMetadata},
|
||||||
|
}
|
||||||
|
|
||||||
routes = append(routes, envoyRoute)
|
routes = append(routes, envoyRoute)
|
||||||
}
|
}
|
||||||
return routes, nil
|
return routes, nil
|
||||||
|
@ -559,3 +562,18 @@ func isProxyFrontingAuthenticate(options *config.Options, domain string) (bool,
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRewriteHeadersMetadata(headers []config.RewriteHeader) *structpb.Value {
|
||||||
|
if len(headers) == 0 {
|
||||||
|
return &structpb.Value{
|
||||||
|
Kind: &structpb.Value_ListValue{
|
||||||
|
ListValue: new(structpb.ListValue),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var obj interface{}
|
||||||
|
bs, _ := json.Marshal(headers)
|
||||||
|
_ = json.Unmarshal(bs, &obj)
|
||||||
|
v, _ := structpb.NewValue(obj)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
|
@ -295,7 +295,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -319,7 +320,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -344,7 +346,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -378,7 +381,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -402,7 +406,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -427,7 +432,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -451,7 +457,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -476,7 +483,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -517,6 +525,11 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"prefix": "/"
|
"prefix": "/"
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
"filterMetadata": {
|
||||||
|
"envoy.filters.http.lua": {
|
||||||
|
"rewrite_response_headers": []
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"autoHostRewrite": true,
|
"autoHostRewrite": true,
|
||||||
|
@ -568,7 +581,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -594,7 +608,8 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -678,7 +693,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -703,7 +719,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -728,7 +745,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -759,7 +777,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -784,7 +803,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -809,7 +829,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
"envoy.filters.http.lua": {
|
"envoy.filters.http.lua": {
|
||||||
"remove_impersonate_headers": false,
|
"remove_impersonate_headers": false,
|
||||||
"remove_pomerium_authorization": true,
|
"remove_pomerium_authorization": true,
|
||||||
"remove_pomerium_cookie": "pomerium"
|
"remove_pomerium_cookie": "pomerium",
|
||||||
|
"rewrite_response_headers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue