core/config: implement direct response (#4960)

* implement direct response

* proto

* fix tests

* update
This commit is contained in:
Caleb Doxsey 2024-02-15 14:33:56 -07:00 committed by GitHub
parent 2db2bd09a1
commit 513d8bf615
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 967 additions and 843 deletions

View file

@ -20,7 +20,7 @@ var (
errHostnameMustBeSpecified = errors.New("endpoint hostname must be specified")
errSchemeMustBeSpecified = errors.New("url scheme must be provided")
errEmptyUrls = errors.New("url list is empty")
errEitherToOrRedirectRequired = errors.New("policy should have either `to` or `redirect` defined")
errEitherToOrRedirectOrResponseRequired = errors.New("policy should have either `to` or `redirect` or `response` defined")
)
var protoPartial = protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}

View file

@ -77,7 +77,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
],
"route": {
"autoHostRewrite": true,
"cluster": "route-5feb9fe8bd89aa97",
"cluster": "route-5d678ee30d16332b",
"hashPolicy": [
{ "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true },
{ "connectionProperties": { "sourceIp": true }, "terminal": true }
@ -94,7 +94,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "6911793875091303063"
"route_id": "6730505273956774699"
}
}
}
@ -130,7 +130,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
],
"route": {
"autoHostRewrite": true,
"cluster": "route-5feb9fe8bd89aa97",
"cluster": "route-5d678ee30d16332b",
"hashPolicy": [
{ "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true },
{ "connectionProperties": { "sourceIp": true }, "terminal": true }
@ -147,7 +147,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "6911793875091303063"
"route_id": "6730505273956774699"
}
}
}

View file

@ -282,6 +282,9 @@ func (b *Builder) buildRouteForPolicyAndMatch(
return nil, err
}
route.Action = &envoy_config_route_v3.Route_Redirect{Redirect: action}
} else if policy.Response != nil {
action := b.buildPolicyRouteDirectResponseAction(policy.Response)
route.Action = &envoy_config_route_v3.Route_DirectResponse{DirectResponse: action}
} else {
action, err := b.buildPolicyRouteRouteAction(cfg.Options, policy)
if err != nil {
@ -343,6 +346,17 @@ func (b *Builder) buildRouteForPolicyAndMatch(
return route, nil
}
func (b *Builder) buildPolicyRouteDirectResponseAction(r *config.DirectResponse) *envoy_config_route_v3.DirectResponseAction {
return &envoy_config_route_v3.DirectResponseAction{
Status: uint32(r.Status),
Body: &envoy_config_core_v3.DataSource{
Specifier: &envoy_config_core_v3.DataSource_InlineString{
InlineString: r.Body,
},
},
}
}
func (b *Builder) buildPolicyRouteRedirectAction(r *config.PolicyRedirect) (*envoy_config_route_v3.RedirectAction, error) {
action := &envoy_config_route_v3.RedirectAction{}
switch {

View file

@ -444,7 +444,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "11444765232398592404"
"route_id": "16913502743845432363"
}
}
}
@ -515,7 +515,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2990091139764155677"
"route_id": "911713133804109577"
}
}
}
@ -585,7 +585,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2544588842279234006"
"route_id": "6407864870815560799"
}
}
}
@ -657,7 +657,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "10244970664102670752"
"route_id": "1103677309004574500"
}
}
}
@ -728,7 +728,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2544588842279234006"
"route_id": "6407864870815560799"
}
}
}
@ -798,7 +798,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2990091139764155677"
"route_id": "911713133804109577"
}
}
}
@ -869,7 +869,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2990091139764155677"
"route_id": "911713133804109577"
}
}
}
@ -940,7 +940,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "1052418080698022187"
"route_id": "17831746838845374842"
}
}
}
@ -1123,7 +1123,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2226589900561460978"
"route_id": "15730681265277585877"
}
}
}
@ -1195,7 +1195,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "2226589900561460978"
"route_id": "15730681265277585877"
}
}
}
@ -1293,7 +1293,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "15508081512033148378"
"route_id": "16598125949405432745"
}
}
}
@ -1423,7 +1423,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}
@ -1494,7 +1494,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}
@ -1570,7 +1570,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}
@ -1641,7 +1641,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}
@ -1712,7 +1712,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}
@ -1788,7 +1788,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
"checkSettings": {
"contextExtensions": {
"internal": "false",
"route_id": "285016060542193864"
"route_id": "13828028232508831592"
}
}
}

View file

@ -30,14 +30,14 @@ type Policy struct {
From string `mapstructure:"from" yaml:"from"`
To WeightedURLs `mapstructure:"to" yaml:"to"`
// Redirect is used for a redirect action instead of `To`
Redirect *PolicyRedirect `mapstructure:"redirect" yaml:"redirect"`
Response *DirectResponse `mapstructure:"response" yaml:"response,omitempty" json:"response,omitempty"`
// LbWeights are optional load balancing weights applied to endpoints specified in To
// this field exists for compatibility with mapstructure
LbWeights []uint32 `mapstructure:"_to_weights,omitempty" json:"-" yaml:"-"`
// Redirect is used for a redirect action instead of `To`
Redirect *PolicyRedirect `mapstructure:"redirect" yaml:"redirect"`
// Identity related policy
AllowedUsers []string `mapstructure:"allowed_users" yaml:"allowed_users,omitempty" json:"allowed_users,omitempty"`
AllowedDomains []string `mapstructure:"allowed_domains" yaml:"allowed_domains,omitempty" json:"allowed_domains,omitempty"`
@ -213,6 +213,12 @@ type PolicyRedirect struct {
StripQuery *bool `mapstructure:"strip_query" yaml:"strip_query,omitempty" json:"strip_query,omitempty"`
}
// A DirectResponse is the response to an HTTP request.
type DirectResponse struct {
Status int `mapstructure:"status" yaml:"status,omitempty" json:"status,omitempty"`
Body string `mapstructure:"body" yaml:"body,omitempty" json:"body,omitempty"`
}
// NewPolicyFromProto creates a new Policy from a protobuf policy config route.
func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
var timeout *time.Duration
@ -284,6 +290,11 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
ResponseCode: pb.Redirect.ResponseCode,
StripQuery: pb.Redirect.StripQuery,
}
} else if pb.Response != nil {
p.Response = &DirectResponse{
Status: int(pb.Response.GetStatus()),
Body: pb.Response.GetBody(),
}
} else {
to, err := ParseWeightedUrls(pb.GetTo()...)
if err != nil {
@ -405,6 +416,11 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
ResponseCode: p.Redirect.ResponseCode,
StripQuery: p.Redirect.StripQuery,
}
} else if p.Response != nil {
pb.Response = &configpb.RouteDirectResponse{
Status: uint32(p.Response.Status),
Body: p.Response.Body,
}
} else {
to, weights, err := p.To.Flatten()
if err != nil {
@ -446,8 +462,8 @@ func (p *Policy) Validate() error {
source.String())
}
if len(p.To) == 0 && p.Redirect == nil {
return errEitherToOrRedirectRequired
if len(p.To) == 0 && p.Redirect == nil && p.Response == nil {
return errEitherToOrRedirectOrResponseRequired
}
for _, u := range p.To {
@ -567,8 +583,10 @@ func (p *Policy) RouteID() (uint64, error) {
id.To = dst
} else if p.Redirect != nil {
id.Redirect = p.Redirect
} else if p.Response != nil {
id.Response = p.Response
} else {
return 0, errEitherToOrRedirectRequired
return 0, errEitherToOrRedirectOrResponseRequired
}
return hashutil.Hash(id)
@ -685,6 +703,7 @@ type routeID struct {
Path string
Regex string
Redirect *PolicyRedirect
Response *DirectResponse
}
/*

File diff suppressed because it is too large Load diff

View file

@ -33,12 +33,19 @@ message RouteRedirect {
optional bool strip_query = 8;
}
// Next ID: 62.
message RouteDirectResponse {
uint32 status = 1;
string body = 2;
}
// Next ID: 63.
message Route {
string name = 1;
string from = 2;
repeated string to = 3;
RouteRedirect redirect = 34;
RouteDirectResponse response = 62;
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/endpoint/v3/endpoint_components.proto#envoy-v3-api-msg-config-endpoint-v3-lbendpoint
// optional load balancing weights assigned to upstream servers defined in TO
@ -47,8 +54,6 @@ message Route {
// len(load_balancing_weights)
repeated uint32 load_balancing_weights = 37;
RouteRedirect redirect = 34;
repeated string allowed_users = 4 [ deprecated = true ];
// repeated string allowed_groups = 5 [ deprecated = true ];
repeated string allowed_domains = 6 [ deprecated = true ];