mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
config: support redirect actions (#1776)
* add route redirect options * add xds support for redirect * add test * handle nil destinations * remove unchanged statik files * remove unchanged statik files * update docs * Update docs/reference/settings.yaml Co-authored-by: Travis Groth <travisgroth@users.noreply.github.com> Co-authored-by: Travis Groth <travisgroth@users.noreply.github.com>
This commit is contained in:
parent
6466efddd5
commit
c99994bed8
8 changed files with 968 additions and 527 deletions
|
@ -25,6 +25,10 @@ import (
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
From string `mapstructure:"from" yaml:"from"`
|
From string `mapstructure:"from" yaml:"from"`
|
||||||
To string `mapstructure:"to" yaml:"to"`
|
To string `mapstructure:"to" yaml:"to"`
|
||||||
|
|
||||||
|
// Redirect is used for a redirect action instead of `To`
|
||||||
|
Redirect *PolicyRedirect `mapstructure:"redirect" yaml:"redirect"`
|
||||||
|
|
||||||
// Identity related policy
|
// Identity related policy
|
||||||
AllowedUsers []string `mapstructure:"allowed_users" yaml:"allowed_users,omitempty" json:"allowed_users,omitempty"`
|
AllowedUsers []string `mapstructure:"allowed_users" yaml:"allowed_users,omitempty" json:"allowed_users,omitempty"`
|
||||||
AllowedGroups []string `mapstructure:"allowed_groups" yaml:"allowed_groups,omitempty" json:"allowed_groups,omitempty"`
|
AllowedGroups []string `mapstructure:"allowed_groups" yaml:"allowed_groups,omitempty" json:"allowed_groups,omitempty"`
|
||||||
|
@ -147,6 +151,18 @@ type SubPolicy struct {
|
||||||
Rego []string `mapstructure:"rego" yaml:"rego" json:"rego,omitempty"`
|
Rego []string `mapstructure:"rego" yaml:"rego" json:"rego,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PolicyRedirect is a route redirect action.
|
||||||
|
type PolicyRedirect struct {
|
||||||
|
HTTPSRedirect *bool `mapstructure:"https_redirect" yaml:"https_redirect,omitempty" json:"https_redirect,omitempty"`
|
||||||
|
SchemeRedirect *string `mapstructure:"scheme_redirect" yaml:"scheme_redirect,omitempty" json:"scheme_redirect,omitempty"`
|
||||||
|
HostRedirect *string `mapstructure:"host_redirect" yaml:"host_redirect,omitempty" json:"host_redirect,omitempty"`
|
||||||
|
PortRedirect *uint32 `mapstructure:"port_redirect" yaml:"port_redirect,omitempty" json:"port_redirect,omitempty"`
|
||||||
|
PathRedirect *string `mapstructure:"path_redirect" yaml:"path_redirect,omitempty" json:"path_redirect,omitempty"`
|
||||||
|
PrefixRewrite *string `mapstructure:"prefix_rewrite" yaml:"prefix_rewrite,omitempty" json:"prefix_rewrite,omitempty"`
|
||||||
|
ResponseCode *int32 `mapstructure:"response_code" yaml:"response_code,omitempty" json:"response_code,omitempty"`
|
||||||
|
StripQuery *bool `mapstructure:"strip_query" yaml:"strip_query,omitempty" json:"strip_query,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewPolicyFromProto creates a new Policy from a protobuf policy config route.
|
// NewPolicyFromProto creates a new Policy from a protobuf policy config route.
|
||||||
func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
||||||
timeout, _ := ptypes.Duration(pb.GetTimeout())
|
timeout, _ := ptypes.Duration(pb.GetTimeout())
|
||||||
|
@ -183,6 +199,18 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
||||||
PassIdentityHeaders: pb.GetPassIdentityHeaders(),
|
PassIdentityHeaders: pb.GetPassIdentityHeaders(),
|
||||||
KubernetesServiceAccountToken: pb.GetKubernetesServiceAccountToken(),
|
KubernetesServiceAccountToken: pb.GetKubernetesServiceAccountToken(),
|
||||||
}
|
}
|
||||||
|
if pb.Redirect != nil {
|
||||||
|
p.Redirect = &PolicyRedirect{
|
||||||
|
HTTPSRedirect: pb.Redirect.HttpsRedirect,
|
||||||
|
SchemeRedirect: pb.Redirect.SchemeRedirect,
|
||||||
|
HostRedirect: pb.Redirect.HostRedirect,
|
||||||
|
PortRedirect: pb.Redirect.PortRedirect,
|
||||||
|
PathRedirect: pb.Redirect.PathRedirect,
|
||||||
|
PrefixRewrite: pb.Redirect.PrefixRewrite,
|
||||||
|
ResponseCode: pb.Redirect.ResponseCode,
|
||||||
|
StripQuery: pb.Redirect.StripQuery,
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, sp := range pb.GetPolicies() {
|
for _, sp := range pb.GetPolicies() {
|
||||||
p.SubPolicies = append(p.SubPolicies, SubPolicy{
|
p.SubPolicies = append(p.SubPolicies, SubPolicy{
|
||||||
ID: sp.GetId(),
|
ID: sp.GetId(),
|
||||||
|
@ -212,7 +240,7 @@ func (p *Policy) ToProto() *configpb.Route {
|
||||||
Rego: sp.Rego,
|
Rego: sp.Rego,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return &configpb.Route{
|
pb := &configpb.Route{
|
||||||
Name: fmt.Sprint(p.RouteID()),
|
Name: fmt.Sprint(p.RouteID()),
|
||||||
From: p.From,
|
From: p.From,
|
||||||
To: p.To,
|
To: p.To,
|
||||||
|
@ -246,6 +274,19 @@ func (p *Policy) ToProto() *configpb.Route {
|
||||||
KubernetesServiceAccountToken: p.KubernetesServiceAccountToken,
|
KubernetesServiceAccountToken: p.KubernetesServiceAccountToken,
|
||||||
Policies: sps,
|
Policies: sps,
|
||||||
}
|
}
|
||||||
|
if p.Redirect != nil {
|
||||||
|
pb.Redirect = &configpb.RouteRedirect{
|
||||||
|
HttpsRedirect: p.Redirect.HTTPSRedirect,
|
||||||
|
SchemeRedirect: p.Redirect.SchemeRedirect,
|
||||||
|
HostRedirect: p.Redirect.HostRedirect,
|
||||||
|
PortRedirect: p.Redirect.PortRedirect,
|
||||||
|
PathRedirect: p.Redirect.PathRedirect,
|
||||||
|
PrefixRewrite: p.Redirect.PrefixRewrite,
|
||||||
|
ResponseCode: p.Redirect.ResponseCode,
|
||||||
|
StripQuery: p.Redirect.StripQuery,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pb
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks the validity of a policy.
|
// Validate checks the validity of a policy.
|
||||||
|
@ -264,10 +305,16 @@ func (p *Policy) Validate() error {
|
||||||
|
|
||||||
p.Source = &StringURL{source}
|
p.Source = &StringURL{source}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case p.To != "":
|
||||||
p.Destination, err = urlutil.ParseAndValidateURL(p.To)
|
p.Destination, err = urlutil.ParseAndValidateURL(p.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("config: policy bad destination url %w", err)
|
return fmt.Errorf("config: policy bad destination url %w", err)
|
||||||
}
|
}
|
||||||
|
case p.Redirect != nil:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("config: policy must have either a `to` or `redirect`")
|
||||||
|
}
|
||||||
|
|
||||||
// Only allow public access if no other whitelists are in place
|
// Only allow public access if no other whitelists are in place
|
||||||
if p.AllowPublicUnauthenticatedAccess && (p.AllowAnyAuthenticatedUser || p.AllowedDomains != nil || p.AllowedGroups != nil || p.AllowedUsers != nil) {
|
if p.AllowPublicUnauthenticatedAccess && (p.AllowAnyAuthenticatedUser || p.AllowedDomains != nil || p.AllowedGroups != nil || p.AllowedUsers != nil) {
|
||||||
|
|
|
@ -1221,11 +1221,33 @@ Remove Request Headers allows you to remove given request headers. This can be u
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Redirect
|
||||||
|
- `yaml`/`json` setting: 'redirect'
|
||||||
|
- Type: object
|
||||||
|
- Optional
|
||||||
|
- Example: `{ "host_redirect": "example.com" }`
|
||||||
|
|
||||||
|
`Redirect` is used to redirect incoming requests to a new URL. The `redirect` field is an object with several optional,
|
||||||
|
options:
|
||||||
|
|
||||||
|
- `https_redirect` (boolean): the incoming scheme will be swapped with "https".
|
||||||
|
- `scheme_redirect` (string): the incoming scheme will be swapped with the given value.
|
||||||
|
- `host_redirect` (string): the incoming host will be swapped with the given value.
|
||||||
|
- `port_redirect` (integer): the incoming port will be swapped with the given value.
|
||||||
|
- `path_redirect` (string): the incoming path portion of the URL will be swapped with the given value.
|
||||||
|
- `prefix_rewrite` (string): the incoming matched prefix will be swapped with the given value.
|
||||||
|
- `regex_rewrite_pattern`, `regex_rewrite_substitution` (string): the incoming matched regex will be swapped with this value.
|
||||||
|
- `response_code` (integer): the response code to use for the redirect. Defaults to 301.
|
||||||
|
- `strip_query` (boolean): indicates that during redirection, the query portion of the URL will be removed. Defaults to false.
|
||||||
|
|
||||||
|
Either `redirect` or `to` must be set.
|
||||||
|
|
||||||
|
|
||||||
### To
|
### To
|
||||||
- `yaml`/`json` setting: `to`
|
- `yaml`/`json` setting: `to`
|
||||||
- Type: `URL` (must contain a scheme and hostname)
|
- Type: `URL` (must contain a scheme and hostname)
|
||||||
- Schemes: `http`, `https`, `tcp`
|
- Schemes: `http`, `https`, `tcp`
|
||||||
- Required
|
- Optional
|
||||||
- Example: `http://verify` , `https://192.1.20.12:8080`, `http://neverssl.com`, `https://verify.pomerium.com/anything/`
|
- Example: `http://verify` , `https://192.1.20.12:8080`, `http://neverssl.com`, `https://verify.pomerium.com/anything/`
|
||||||
|
|
||||||
`To` is the destination of a proxied request. It can be an internal resource, or an external resource.
|
`To` is the destination of a proxied request. It can be an internal resource, or an external resource.
|
||||||
|
@ -1254,6 +1276,8 @@ While the rule:
|
||||||
|
|
||||||
All requests to `https://verify.corp.example.com/*` will be forwarded to `https://verify.pomerium.com/anything/*`. That means accessing to `https://verify.corp.example.com` will be forwarded to `https://verify.pomerium.com/anything/`. That said, if your application does not handle trailing slash, the request will end up with 404 not found.
|
All requests to `https://verify.corp.example.com/*` will be forwarded to `https://verify.pomerium.com/anything/*`. That means accessing to `https://verify.corp.example.com` will be forwarded to `https://verify.pomerium.com/anything/`. That said, if your application does not handle trailing slash, the request will end up with 404 not found.
|
||||||
|
|
||||||
|
Either `redirect` or `to` must be set.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1345,13 +1345,34 @@ settings:
|
||||||
- X-Email
|
- X-Email
|
||||||
- X-Username
|
- X-Username
|
||||||
```
|
```
|
||||||
|
- name: "Redirect"
|
||||||
|
keys: ["redirect"]
|
||||||
|
attributes: |
|
||||||
|
- `yaml`/`json` setting: 'redirect'
|
||||||
|
- Type: object
|
||||||
|
- Optional
|
||||||
|
- Example: `{ "host_redirect": "example.com" }`
|
||||||
|
doc: |
|
||||||
|
`Redirect` is used to redirect incoming requests to a new URL. The `redirect` field is an object with several possible
|
||||||
|
options:
|
||||||
|
|
||||||
|
- `https_redirect` (boolean): the incoming scheme will be swapped with "https".
|
||||||
|
- `scheme_redirect` (string): the incoming scheme will be swapped with the given value.
|
||||||
|
- `host_redirect` (string): the incoming host will be swapped with the given value.
|
||||||
|
- `port_redirect` (integer): the incoming port will be swapped with the given value.
|
||||||
|
- `path_redirect` (string): the incoming path portion of the URL will be swapped with the given value.
|
||||||
|
- `prefix_rewrite` (string): the incoming matched prefix will be swapped with the given value.
|
||||||
|
- `response_code` (integer): the response code to use for the redirect. Defaults to 301.
|
||||||
|
- `strip_query` (boolean): indicates that during redirection, the query portion of the URL will be removed. Defaults to false.
|
||||||
|
|
||||||
|
Either `redirect` or `to` must be set.
|
||||||
- name: "To"
|
- name: "To"
|
||||||
keys: ["to"]
|
keys: ["to"]
|
||||||
attributes: |
|
attributes: |
|
||||||
- `yaml`/`json` setting: `to`
|
- `yaml`/`json` setting: `to`
|
||||||
- Type: `URL` (must contain a scheme and hostname)
|
- Type: `URL` (must contain a scheme and hostname)
|
||||||
- Schemes: `http`, `https`, `tcp`
|
- Schemes: `http`, `https`, `tcp`
|
||||||
- Required
|
- Optional
|
||||||
- Example: `http://verify` , `https://192.1.20.12:8080`, `http://neverssl.com`, `https://verify.pomerium.com/anything/`
|
- Example: `http://verify` , `https://192.1.20.12:8080`, `http://neverssl.com`, `https://verify.pomerium.com/anything/`
|
||||||
doc: |
|
doc: |
|
||||||
`To` is the destination of a proxied request. It can be an internal resource, or an external resource.
|
`To` is the destination of a proxied request. It can be an internal resource, or an external resource.
|
||||||
|
@ -1380,6 +1401,8 @@ settings:
|
||||||
|
|
||||||
All requests to `https://verify.corp.example.com/*` will be forwarded to `https://verify.pomerium.com/anything/*`. That means accessing to `https://verify.corp.example.com` will be forwarded to `https://verify.pomerium.com/anything/`. That said, if your application does not handle trailing slash, the request will end up with 404 not found.
|
All requests to `https://verify.corp.example.com/*` will be forwarded to `https://verify.pomerium.com/anything/*`. That means accessing to `https://verify.corp.example.com` will be forwarded to `https://verify.pomerium.com/anything/`. That said, if your application does not handle trailing slash, the request will end up with 404 not found.
|
||||||
|
|
||||||
|
Either `redirect` or `to` must be set.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
- name: "TLS Skip Verification"
|
- name: "TLS Skip Verification"
|
||||||
keys: ["tls_skip_verify"]
|
keys: ["tls_skip_verify"]
|
||||||
|
|
|
@ -43,9 +43,11 @@ func (srv *Server) buildClusters(options *config.Options) []*envoy_config_cluste
|
||||||
if config.IsProxy(options.Services) {
|
if config.IsProxy(options.Services) {
|
||||||
for i := range options.Policies {
|
for i := range options.Policies {
|
||||||
policy := options.Policies[i]
|
policy := options.Policies[i]
|
||||||
|
if policy.Destination != nil {
|
||||||
clusters = append(clusters, buildPolicyCluster(options, &policy))
|
clusters = append(clusters, buildPolicyCluster(options, &policy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return clusters
|
return clusters
|
||||||
}
|
}
|
||||||
|
@ -114,7 +116,7 @@ func buildInternalTransportSocket(options *config.Options, endpoint *url.URL) *e
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPolicyTransportSocket(policy *config.Policy) *envoy_config_core_v3.TransportSocket {
|
func buildPolicyTransportSocket(policy *config.Policy) *envoy_config_core_v3.TransportSocket {
|
||||||
if policy.Destination.Scheme != "https" {
|
if policy.Destination == nil || policy.Destination.Scheme != "https" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +156,10 @@ func buildPolicyTransportSocket(policy *config.Policy) *envoy_config_core_v3.Tra
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPolicyValidationContext(policy *config.Policy) *envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext {
|
func buildPolicyValidationContext(policy *config.Policy) *envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext {
|
||||||
|
if policy.Destination == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
sni := policy.Destination.Hostname()
|
sni := policy.Destination.Hostname()
|
||||||
if policy.TLSServerName != "" {
|
if policy.TLSServerName != "" {
|
||||||
sni = policy.TLSServerName
|
sni = policy.TLSServerName
|
||||||
|
@ -196,6 +202,10 @@ func buildCluster(
|
||||||
forceHTTP2 bool,
|
forceHTTP2 bool,
|
||||||
dnsLookupFamily envoy_config_cluster_v3.Cluster_DnsLookupFamily,
|
dnsLookupFamily envoy_config_cluster_v3.Cluster_DnsLookupFamily,
|
||||||
) *envoy_config_cluster_v3.Cluster {
|
) *envoy_config_cluster_v3.Cluster {
|
||||||
|
if endpoint == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
defaultPort := 80
|
defaultPort := 80
|
||||||
if transportSocket != nil && transportSocket.Name == "tls" {
|
if transportSocket != nil && transportSocket.Name == "tls" {
|
||||||
defaultPort = 443
|
defaultPort = 443
|
||||||
|
|
|
@ -188,47 +188,10 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
|
||||||
}
|
}
|
||||||
|
|
||||||
match := mkRouteMatch(&policy)
|
match := mkRouteMatch(&policy)
|
||||||
clusterName := getPolicyName(&policy)
|
|
||||||
requestHeadersToAdd := toEnvoyHeaders(policy.SetRequestHeaders)
|
requestHeadersToAdd := toEnvoyHeaders(policy.SetRequestHeaders)
|
||||||
requestHeadersToRemove := getRequestHeadersToRemove(options, &policy)
|
requestHeadersToRemove := getRequestHeadersToRemove(options, &policy)
|
||||||
routeTimeout := getRouteTimeout(options, &policy)
|
|
||||||
idleTimeout := getRouteIdleTimeout(&policy)
|
|
||||||
prefixRewrite, regexRewrite := getRewriteOptions(&policy)
|
|
||||||
|
|
||||||
upgradeConfigs := []*envoy_config_route_v3.RouteAction_UpgradeConfig{
|
envoyRoute := &envoy_config_route_v3.Route{
|
||||||
{
|
|
||||||
UpgradeType: "websocket",
|
|
||||||
Enabled: &wrappers.BoolValue{Value: policy.AllowWebsockets},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
UpgradeType: "spdy/3.1",
|
|
||||||
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{
|
|
||||||
AutoHostRewrite: &wrappers.BoolValue{Value: !policy.PreserveHostHeader},
|
|
||||||
},
|
|
||||||
Timeout: routeTimeout,
|
|
||||||
IdleTimeout: idleTimeout,
|
|
||||||
PrefixRewrite: prefixRewrite,
|
|
||||||
RegexRewrite: regexRewrite,
|
|
||||||
}
|
|
||||||
setHostRewriteOptions(&policy, routeAction)
|
|
||||||
|
|
||||||
routes = append(routes, &envoy_config_route_v3.Route{
|
|
||||||
Name: fmt.Sprintf("policy-%d", i),
|
Name: fmt.Sprintf("policy-%d", i),
|
||||||
Match: match,
|
Match: match,
|
||||||
Metadata: &envoy_config_core_v3.Metadata{
|
Metadata: &envoy_config_core_v3.Metadata{
|
||||||
|
@ -254,15 +217,99 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: &envoy_config_route_v3.Route_Route{Route: routeAction},
|
|
||||||
RequestHeadersToAdd: requestHeadersToAdd,
|
RequestHeadersToAdd: requestHeadersToAdd,
|
||||||
RequestHeadersToRemove: requestHeadersToRemove,
|
RequestHeadersToRemove: requestHeadersToRemove,
|
||||||
ResponseHeadersToAdd: responseHeadersToAdd,
|
ResponseHeadersToAdd: responseHeadersToAdd,
|
||||||
})
|
}
|
||||||
|
if policy.Redirect != nil {
|
||||||
|
envoyRoute.Action = &envoy_config_route_v3.Route_Redirect{
|
||||||
|
Redirect: buildPolicyRouteRedirectAction(policy.Redirect),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: buildPolicyRouteRouteAction(options, &policy)}
|
||||||
|
}
|
||||||
|
|
||||||
|
routes = append(routes, envoyRoute)
|
||||||
}
|
}
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildPolicyRouteRedirectAction(r *config.PolicyRedirect) *envoy_config_route_v3.RedirectAction {
|
||||||
|
action := &envoy_config_route_v3.RedirectAction{}
|
||||||
|
switch {
|
||||||
|
case r.HTTPSRedirect != nil:
|
||||||
|
action.SchemeRewriteSpecifier = &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
||||||
|
HttpsRedirect: *r.HTTPSRedirect,
|
||||||
|
}
|
||||||
|
case r.SchemeRedirect != nil:
|
||||||
|
action.SchemeRewriteSpecifier = &envoy_config_route_v3.RedirectAction_SchemeRedirect{
|
||||||
|
SchemeRedirect: *r.SchemeRedirect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.HostRedirect != nil {
|
||||||
|
action.HostRedirect = *r.HostRedirect
|
||||||
|
}
|
||||||
|
if r.PortRedirect != nil {
|
||||||
|
action.PortRedirect = *r.PortRedirect
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case r.PathRedirect != nil:
|
||||||
|
action.PathRewriteSpecifier = &envoy_config_route_v3.RedirectAction_PathRedirect{
|
||||||
|
PathRedirect: *r.PathRedirect,
|
||||||
|
}
|
||||||
|
case r.PrefixRewrite != nil:
|
||||||
|
action.PathRewriteSpecifier = &envoy_config_route_v3.RedirectAction_PrefixRewrite{
|
||||||
|
PrefixRewrite: *r.PrefixRewrite,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.ResponseCode != nil {
|
||||||
|
action.ResponseCode = envoy_config_route_v3.RedirectAction_RedirectResponseCode(*r.ResponseCode)
|
||||||
|
}
|
||||||
|
if r.StripQuery != nil {
|
||||||
|
action.StripQuery = *r.StripQuery
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPolicyRouteRouteAction(options *config.Options, policy *config.Policy) *envoy_config_route_v3.RouteAction {
|
||||||
|
clusterName := getPolicyName(policy)
|
||||||
|
routeTimeout := getRouteTimeout(options, policy)
|
||||||
|
idleTimeout := getRouteIdleTimeout(policy)
|
||||||
|
prefixRewrite, regexRewrite := getRewriteOptions(policy)
|
||||||
|
upgradeConfigs := []*envoy_config_route_v3.RouteAction_UpgradeConfig{
|
||||||
|
{
|
||||||
|
UpgradeType: "websocket",
|
||||||
|
Enabled: &wrappers.BoolValue{Value: policy.AllowWebsockets},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UpgradeType: "spdy/3.1",
|
||||||
|
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{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
action := &envoy_config_route_v3.RouteAction{
|
||||||
|
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
||||||
|
Cluster: clusterName,
|
||||||
|
},
|
||||||
|
UpgradeConfigs: upgradeConfigs,
|
||||||
|
HostRewriteSpecifier: &envoy_config_route_v3.RouteAction_AutoHostRewrite{
|
||||||
|
AutoHostRewrite: &wrappers.BoolValue{Value: !policy.PreserveHostHeader},
|
||||||
|
},
|
||||||
|
Timeout: routeTimeout,
|
||||||
|
IdleTimeout: idleTimeout,
|
||||||
|
PrefixRewrite: prefixRewrite,
|
||||||
|
RegexRewrite: regexRewrite,
|
||||||
|
}
|
||||||
|
setHostRewriteOptions(policy, action)
|
||||||
|
return action
|
||||||
|
}
|
||||||
|
|
||||||
func mkEnvoyHeader(k, v string) *envoy_config_core_v3.HeaderValueOption {
|
func mkEnvoyHeader(k, v string) *envoy_config_core_v3.HeaderValueOption {
|
||||||
return &envoy_config_core_v3.HeaderValueOption{
|
return &envoy_config_core_v3.HeaderValueOption{
|
||||||
Header: &envoy_config_core_v3.HeaderValue{
|
Header: &envoy_config_core_v3.HeaderValue{
|
||||||
|
|
|
@ -5,6 +5,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
"github.com/pomerium/pomerium/internal/testutil"
|
"github.com/pomerium/pomerium/internal/testutil"
|
||||||
)
|
)
|
||||||
|
@ -816,3 +820,87 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
]
|
]
|
||||||
`, routes)
|
`, routes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
|
t.Run("HTTPSRedirect", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
HTTPSRedirect: proto.Bool(true),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
||||||
|
HttpsRedirect: true,
|
||||||
|
},
|
||||||
|
}, action)
|
||||||
|
|
||||||
|
action = buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
HTTPSRedirect: proto.Bool(false),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
||||||
|
HttpsRedirect: false,
|
||||||
|
},
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("SchemeRedirect", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
SchemeRedirect: proto.String("https"),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_SchemeRedirect{
|
||||||
|
SchemeRedirect: "https",
|
||||||
|
},
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("HostRedirect", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
HostRedirect: proto.String("HOST"),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
HostRedirect: "HOST",
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("PortRedirect", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
PortRedirect: proto.Uint32(1234),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
PortRedirect: 1234,
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("PathRedirect", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
PathRedirect: proto.String("PATH"),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PathRedirect{
|
||||||
|
PathRedirect: "PATH",
|
||||||
|
},
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("PrefixRewrite", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
PrefixRewrite: proto.String("PREFIX_REWRITE"),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PrefixRewrite{
|
||||||
|
PrefixRewrite: "PREFIX_REWRITE",
|
||||||
|
},
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("ResponseCode", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
ResponseCode: proto.Int32(301),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
ResponseCode: 301,
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
t.Run("StripQuery", func(t *testing.T) {
|
||||||
|
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
|
StripQuery: proto.Bool(true),
|
||||||
|
})
|
||||||
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
|
StripQuery: true,
|
||||||
|
}, action)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,12 +12,25 @@ message Config {
|
||||||
Settings settings = 3;
|
Settings settings = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RouteRedirect {
|
||||||
|
optional bool https_redirect = 1;
|
||||||
|
optional string scheme_redirect = 2;
|
||||||
|
optional string host_redirect = 3;
|
||||||
|
optional uint32 port_redirect = 4;
|
||||||
|
optional string path_redirect = 5;
|
||||||
|
optional string prefix_rewrite = 6;
|
||||||
|
optional int32 response_code = 7;
|
||||||
|
optional bool strip_query = 8;
|
||||||
|
}
|
||||||
|
|
||||||
message Route {
|
message Route {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
|
|
||||||
string from = 2;
|
string from = 2;
|
||||||
string to = 3;
|
string to = 3;
|
||||||
|
|
||||||
|
RouteRedirect redirect = 34;
|
||||||
|
|
||||||
repeated string allowed_users = 4 [ deprecated = true ];
|
repeated string allowed_users = 4 [ deprecated = true ];
|
||||||
repeated string allowed_groups = 5 [ deprecated = true ];
|
repeated string allowed_groups = 5 [ deprecated = true ];
|
||||||
repeated string allowed_domains = 6 [ deprecated = true ];
|
repeated string allowed_domains = 6 [ deprecated = true ];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue