Skip to content

Commit

Permalink
config: add support for wildcard from addresses (#4131)
Browse files Browse the repository at this point in the history
* config: add support for wildcards

* update policy matching, header generation

* remove deprecated field

* fix test
  • Loading branch information
calebdoxsey committed Apr 25, 2023
1 parent 949454e commit 18bc86d
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 104 deletions.
4 changes: 3 additions & 1 deletion authorize/evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Request struct {
// RequestHTTP is the HTTP field in the request.
type RequestHTTP struct {
Method string `json:"method"`
Hostname string `json:"hostname"`
Path string `json:"path"`
URL string `json:"url"`
Headers map[string]string `json:"headers"`
Expand All @@ -55,6 +56,7 @@ func NewRequestHTTP(
) RequestHTTP {
return RequestHTTP{
Method: method,
Hostname: requestURL.Hostname(),
Path: requestURL.Path,
URL: requestURL.String(),
Headers: headers,
Expand Down Expand Up @@ -162,7 +164,7 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error)

var headersOutput *HeadersResponse
eg.Go(func() error {
headersReq := NewHeadersRequestFromPolicy(req.Policy)
headersReq := NewHeadersRequestFromPolicy(req.Policy, req.HTTP.Hostname)
headersReq.Session = req.Session
var err error
headersOutput, err = e.headersEvaluators.Evaluate(ectx, headersReq)
Expand Down
7 changes: 2 additions & 5 deletions authorize/evaluator/headers_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/pomerium/pomerium/authorize/internal/store"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/telemetry/trace"
"github.com/pomerium/pomerium/internal/urlutil"
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
)

Expand All @@ -29,14 +28,12 @@ type HeadersRequest struct {
}

// NewHeadersRequestFromPolicy creates a new HeadersRequest from a policy.
func NewHeadersRequestFromPolicy(policy *config.Policy) *HeadersRequest {
func NewHeadersRequestFromPolicy(policy *config.Policy, hostname string) *HeadersRequest {
input := new(HeadersRequest)
input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication
input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH ||
policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV
if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil {
input.Issuer = u.Hostname()
}
input.Issuer = hostname
input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken
for _, wu := range policy.To {
input.ToAudience = "https://" + wu.URL.Hostname()
Expand Down
4 changes: 2 additions & 2 deletions authorize/evaluator/headers_evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import (
func TestNewHeadersRequestFromPolicy(t *testing.T) {
req := NewHeadersRequestFromPolicy(&config.Policy{
EnableGoogleCloudServerlessAuthentication: true,
From: "https://from.example.com",
From: "https://*.example.com",
To: config.WeightedURLs{
{
URL: *mustParseURL("http://to.example.com"),
},
},
})
}, "from.example.com")
assert.Equal(t, &HeadersRequest{
EnableGoogleCloudServerlessAuthentication: true,
Issuer: "from.example.com",
Expand Down
9 changes: 8 additions & 1 deletion config/envoyconfig/listeners.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net"
"net/url"
"strings"
"time"

envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
Expand Down Expand Up @@ -570,7 +571,13 @@ func getAllRouteableHosts(options *config.Options, addr string) ([]string, error
allHosts.Add(hosts...)
}

return allHosts.ToSlice(), nil
var filtered []string
for _, host := range allHosts.ToSlice() {
if !strings.Contains(host, "*") {
filtered = append(filtered, host)
}
}
return filtered, nil
}

func urlsMatchHost(urls []*url.URL, host string) bool {
Expand Down
10 changes: 9 additions & 1 deletion config/envoyconfig/route_configurations.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (b *Builder) buildMainRouteConfiguration(

// if we're the proxy, add all the policy routes
if config.IsProxy(cfg.Options.Services) {
rs, err := b.buildPolicyRoutes(cfg.Options, host, requireStrictTransportSecurity)
rs, err := b.buildRoutesForPoliciesWithHost(cfg, host)
if err != nil {
return nil, err
}
Expand All @@ -94,6 +94,14 @@ func (b *Builder) buildMainRouteConfiguration(
if err != nil {
return nil, err
}
if config.IsProxy(cfg.Options.Services) {
rs, err := b.buildRoutesForPoliciesWithCatchAll(cfg)
if err != nil {
return nil, err
}
vh.Routes = append(vh.Routes, rs...)
}

virtualHosts = append(virtualHosts, vh)

rc, err := b.buildRouteConfiguration("main", virtualHosts)
Expand Down
141 changes: 141 additions & 0 deletions config/envoyconfig/route_configurations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package envoyconfig

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/encoding/protojson"

"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/config/envoyconfig/filemgr"
"github.com/pomerium/pomerium/internal/testutil"
"github.com/pomerium/pomerium/pkg/cryptutil"
)

func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
t.Parallel()

ctx := context.Background()
cfg := &config.Config{Options: &config.Options{
CookieName: "pomerium",
DefaultUpstreamTimeout: time.Second * 3,
SharedKey: cryptutil.NewBase64Key(),
Services: "proxy",
Policies: []config.Policy{
{
From: "https://*.example.com",
},
},
}}
b := New("grpc", "http", "metrics", filemgr.NewManager(), nil)
routeConfiguration, err := b.buildMainRouteConfiguration(ctx, cfg)
assert.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"name": "main",
"validateClusters": false,
"virtualHosts": [
{
"name": "catch-all",
"domains": ["*"],
"routes": [
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium/jwt", true, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium/webauthn", true, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/ping", false, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/healthz", false, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium", false, false))+`,
`+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.pomerium/", false, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.well-known/pomerium", false, false))+`,
`+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.well-known/pomerium/", false, false))+`,
`+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/robots.txt", false, false))+`,
{
"name": "policy-0",
"match": {
"headers": [
{ "name": ":authority", "stringMatch": { "safeRegex": { "regex": "^(.*)\\.example\\.com$" } }}
],
"prefix": "/"
},
"metadata": {
"filterMetadata": {
"envoy.filters.http.lua": {
"remove_impersonate_headers": false,
"remove_pomerium_authorization": true,
"remove_pomerium_cookie": "pomerium",
"rewrite_response_headers": []
}
}
},
"requestHeadersToRemove": [
"x-pomerium-jwt-assertion",
"x-pomerium-jwt-assertion-for",
"x-pomerium-reproxy-policy",
"x-pomerium-reproxy-policy-hmac"
],
"responseHeadersToAdd": [
{ "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", "header": { "key": "X-Frame-Options", "value": "SAMEORIGIN" } },
{ "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", "header": { "key": "X-XSS-Protection", "value": "1; mode=block" } }
],
"route": {
"autoHostRewrite": true,
"cluster": "route-0",
"hashPolicy": [
{ "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true },
{ "connectionProperties": { "sourceIp": true }, "terminal": true }
],
"timeout": "3s",
"upgradeConfigs": [
{ "enabled": false, "upgradeType": "websocket" },
{ "enabled": false, "upgradeType": "spdy/3.1" }
]
}
},
{
"name": "policy-0",
"match": {
"headers": [
{ "name": ":authority", "stringMatch": { "safeRegex": { "regex": "^(.*)\\.example\\.com:443$" } }}
],
"prefix": "/"
},
"metadata": {
"filterMetadata": {
"envoy.filters.http.lua": {
"remove_impersonate_headers": false,
"remove_pomerium_authorization": true,
"remove_pomerium_cookie": "pomerium",
"rewrite_response_headers": []
}
}
},
"requestHeadersToRemove": [
"x-pomerium-jwt-assertion",
"x-pomerium-jwt-assertion-for",
"x-pomerium-reproxy-policy",
"x-pomerium-reproxy-policy-hmac"
],
"responseHeadersToAdd": [
{ "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", "header": { "key": "X-Frame-Options", "value": "SAMEORIGIN" } },
{ "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", "header": { "key": "X-XSS-Protection", "value": "1; mode=block" } }
],
"route": {
"autoHostRewrite": true,
"cluster": "route-0",
"hashPolicy": [
{ "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true },
{ "connectionProperties": { "sourceIp": true }, "terminal": true }
],
"timeout": "3s",
"upgradeConfigs": [
{ "enabled": false, "upgradeType": "websocket" },
{ "enabled": false, "upgradeType": "spdy/3.1" }
]
}
}
]
}
]
}`, routeConfiguration)
}
Loading

0 comments on commit 18bc86d

Please sign in to comment.