mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-10 15:47:36 +02:00
add support for TCP routes (#1695)
This commit is contained in:
parent
64816720c8
commit
ad828c6e84
7 changed files with 86 additions and 13 deletions
|
@ -153,7 +153,7 @@ allowed_route_regex(input_url_obj, policy) {
|
||||||
|
|
||||||
parse_url(str) = { "scheme": scheme, "host": host, "path": path } {
|
parse_url(str) = { "scheme": scheme, "host": host, "path": path } {
|
||||||
[_, scheme, host, rawpath] = regex.find_all_string_submatch_n(
|
[_, scheme, host, rawpath] = regex.find_all_string_submatch_n(
|
||||||
`(?:(http[s]?)://)?([^/]+)([^?#]*)`,
|
`(?:((?:tcp[+])?http[s]?)://)?([^/]+)([^?#]*)`,
|
||||||
str, 1)[0]
|
str, 1)[0]
|
||||||
path = normalize_url_path(rawpath)
|
path = normalize_url_path(rawpath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,6 +301,13 @@ test_parse_url {
|
||||||
url.path == "/some/path"
|
url.path == "/some/path"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_parse_tcp_url {
|
||||||
|
url := parse_url("tcp+http://example.com/some/path?qs")
|
||||||
|
url.scheme == "tcp+http"
|
||||||
|
url.host == "example.com"
|
||||||
|
url.path == "/some/path"
|
||||||
|
}
|
||||||
|
|
||||||
test_allowed_route_source {
|
test_allowed_route_source {
|
||||||
allowed_route("http://example.com", {"source": "example.com"})
|
allowed_route("http://example.com", {"source": "example.com"})
|
||||||
allowed_route("http://example.com", {"source": "http://example.com"})
|
allowed_route("http://example.com", {"source": "http://example.com"})
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -257,7 +257,7 @@ func (p *Policy) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there's no path set on the from url
|
// Make sure there's no path set on the from url
|
||||||
if !(source.Path == "" || source.Path == "/") {
|
if (source.Scheme == "http" || source.Scheme == "https") && !(source.Path == "" || source.Path == "/") {
|
||||||
return fmt.Errorf("config: policy source url (%s) contains a path, but it should be set using the path field instead",
|
return fmt.Errorf("config: policy source url (%s) contains a path, but it should be set using the path field instead",
|
||||||
source.String())
|
source.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,11 +192,7 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
|
||||||
routeTimeout := getRouteTimeout(options, &policy)
|
routeTimeout := getRouteTimeout(options, &policy)
|
||||||
prefixRewrite, regexRewrite := getRewriteOptions(&policy)
|
prefixRewrite, regexRewrite := getRewriteOptions(&policy)
|
||||||
|
|
||||||
routeAction := &envoy_config_route_v3.RouteAction{
|
upgradeConfigs := []*envoy_config_route_v3.RouteAction_UpgradeConfig{
|
||||||
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
|
||||||
Cluster: clusterName,
|
|
||||||
},
|
|
||||||
UpgradeConfigs: []*envoy_config_route_v3.RouteAction_UpgradeConfig{
|
|
||||||
{
|
{
|
||||||
UpgradeType: "websocket",
|
UpgradeType: "websocket",
|
||||||
Enabled: &wrappers.BoolValue{Value: policy.AllowWebsockets},
|
Enabled: &wrappers.BoolValue{Value: policy.AllowWebsockets},
|
||||||
|
@ -205,7 +201,20 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
|
||||||
UpgradeType: "spdy/3.1",
|
UpgradeType: "spdy/3.1",
|
||||||
Enabled: &wrappers.BoolValue{Value: policy.AllowSPDY},
|
Enabled: &wrappers.BoolValue{Value: policy.AllowSPDY},
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
if urlutil.IsTCP(policy.Source.URL) {
|
||||||
|
upgradeConfigs = append(upgradeConfigs, &envoy_config_route_v3.RouteAction_UpgradeConfig{
|
||||||
|
UpgradeType: "CONNECT",
|
||||||
|
Enabled: &wrappers.BoolValue{Value: true},
|
||||||
|
ConnectConfig: &envoy_config_route_v3.RouteAction_UpgradeConfig_ConnectConfig{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
routeAction := &envoy_config_route_v3.RouteAction{
|
||||||
|
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
||||||
|
Cluster: clusterName,
|
||||||
},
|
},
|
||||||
|
UpgradeConfigs: upgradeConfigs,
|
||||||
HostRewriteSpecifier: &envoy_config_route_v3.RouteAction_AutoHostRewrite{
|
HostRewriteSpecifier: &envoy_config_route_v3.RouteAction_AutoHostRewrite{
|
||||||
AutoHostRewrite: &wrappers.BoolValue{Value: !policy.PreserveHostHeader},
|
AutoHostRewrite: &wrappers.BoolValue{Value: !policy.PreserveHostHeader},
|
||||||
},
|
},
|
||||||
|
@ -271,6 +280,10 @@ func toEnvoyHeaders(headers map[string]string) []*envoy_config_core_v3.HeaderVal
|
||||||
func mkRouteMatch(policy *config.Policy) *envoy_config_route_v3.RouteMatch {
|
func mkRouteMatch(policy *config.Policy) *envoy_config_route_v3.RouteMatch {
|
||||||
match := &envoy_config_route_v3.RouteMatch{}
|
match := &envoy_config_route_v3.RouteMatch{}
|
||||||
switch {
|
switch {
|
||||||
|
case urlutil.IsTCP(policy.Source.URL):
|
||||||
|
match.PathSpecifier = &envoy_config_route_v3.RouteMatch_ConnectMatcher_{
|
||||||
|
ConnectMatcher: &envoy_config_route_v3.RouteMatch_ConnectMatcher{},
|
||||||
|
}
|
||||||
case policy.Regex != "":
|
case policy.Regex != "":
|
||||||
match.PathSpecifier = &envoy_config_route_v3.RouteMatch_SafeRegex{
|
match.PathSpecifier = &envoy_config_route_v3.RouteMatch_SafeRegex{
|
||||||
SafeRegex: &envoy_type_matcher_v3.RegexMatcher{
|
SafeRegex: &envoy_type_matcher_v3.RegexMatcher{
|
||||||
|
|
|
@ -464,6 +464,50 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
`, routes)
|
`, routes)
|
||||||
|
|
||||||
|
t.Run("tcp", func(t *testing.T) {
|
||||||
|
routes = buildPolicyRoutes(&config.Options{
|
||||||
|
CookieName: "pomerium",
|
||||||
|
DefaultUpstreamTimeout: time.Second * 3,
|
||||||
|
Policies: []config.Policy{
|
||||||
|
{
|
||||||
|
Source: &config.StringURL{URL: mustParseURL("tcp+https://example.com:22")},
|
||||||
|
PassIdentityHeaders: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, "example.com:22")
|
||||||
|
|
||||||
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "policy-0",
|
||||||
|
"match": {
|
||||||
|
"connectMatcher": {}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"filterMetadata": {
|
||||||
|
"envoy.filters.http.lua": {
|
||||||
|
"remove_impersonate_headers": false,
|
||||||
|
"remove_pomerium_authorization": true,
|
||||||
|
"remove_pomerium_cookie": "pomerium"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"autoHostRewrite": true,
|
||||||
|
"cluster": "policy-9",
|
||||||
|
"timeout": "3s",
|
||||||
|
"upgradeConfigs": [
|
||||||
|
{ "enabled": false, "upgradeType": "websocket"},
|
||||||
|
{ "enabled": false, "upgradeType": "spdy/3.1"},
|
||||||
|
{ "enabled": true, "upgradeType": "CONNECT", "connectConfig": {} }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`, routes)
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure default Headers are set for response.
|
// Make sure default Headers are set for response.
|
||||||
|
|
|
@ -84,6 +84,10 @@ func GetAbsoluteURL(r *http.Request) *url.URL {
|
||||||
// For standard HTTP (80)/HTTPS (443) ports, it returns `example.com` and `example.com:<port>`.
|
// For standard HTTP (80)/HTTPS (443) ports, it returns `example.com` and `example.com:<port>`.
|
||||||
// Otherwise, return the URL.Host value.
|
// Otherwise, return the URL.Host value.
|
||||||
func GetDomainsForURL(u *url.URL) []string {
|
func GetDomainsForURL(u *url.URL) []string {
|
||||||
|
if IsTCP(u) {
|
||||||
|
return []string{u.Host}
|
||||||
|
}
|
||||||
|
|
||||||
var defaultPort string
|
var defaultPort string
|
||||||
if u.Scheme == "http" {
|
if u.Scheme == "http" {
|
||||||
defaultPort = "80"
|
defaultPort = "80"
|
||||||
|
@ -102,6 +106,11 @@ func GetDomainsForURL(u *url.URL) []string {
|
||||||
return []string{u.Hostname(), net.JoinHostPort(u.Hostname(), defaultPort)}
|
return []string{u.Hostname(), net.JoinHostPort(u.Hostname(), defaultPort)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsTCP returns whether or not the given URL is for TCP via HTTP Connect.
|
||||||
|
func IsTCP(u *url.URL) bool {
|
||||||
|
return u.Scheme == "tcp+http" || u.Scheme == "tcp+https"
|
||||||
|
}
|
||||||
|
|
||||||
// ParseEnvoyQueryParams returns a new URL with queryparams parsed from envoy format.
|
// ParseEnvoyQueryParams returns a new URL with queryparams parsed from envoy format.
|
||||||
func ParseEnvoyQueryParams(u *url.URL) *url.URL {
|
func ParseEnvoyQueryParams(u *url.URL) *url.URL {
|
||||||
nu := &url.URL{
|
nu := &url.URL{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue