Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NET-1151 NET-11228] api: Add fields for HTTP request normalization and L7 intentions header additions (1.19) #21840

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions api/config_entry_intentions.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ type IntentionHTTPPermission struct {
}

type IntentionHTTPHeaderPermission struct {
Name string
Present bool `json:",omitempty"`
Exact string `json:",omitempty"`
Prefix string `json:",omitempty"`
Suffix string `json:",omitempty"`
Regex string `json:",omitempty"`
Invert bool `json:",omitempty"`
Name string
Present bool `json:",omitempty"`
Exact string `json:",omitempty"`
Prefix string `json:",omitempty"`
Suffix string `json:",omitempty"`
Contains string `json:",omitempty"`
Regex string `json:",omitempty"`
Invert bool `json:",omitempty"`
IgnoreCase bool `json:",omitempty" alias:"ignore_case"`
}

type IntentionJWTRequirement struct {
Expand Down
41 changes: 41 additions & 0 deletions api/config_entry_mesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,53 @@ type MeshDirectionalTLSConfig struct {

type MeshHTTPConfig struct {
SanitizeXForwardedClientCert bool `alias:"sanitize_x_forwarded_client_cert"`
// Incoming configures settings for incoming HTTP traffic to mesh proxies.
Incoming *MeshDirectionalHTTPConfig `json:",omitempty"`
}

// MeshDirectionalHTTPConfig holds mesh configuration specific to HTTP
// requests for a given traffic direction.
type MeshDirectionalHTTPConfig struct {
RequestNormalization *RequestNormalizationMeshConfig `json:",omitempty" alias:"request_normalization"`
}

type PeeringMeshConfig struct {
PeerThroughMeshGateways bool `json:",omitempty" alias:"peer_through_mesh_gateways"`
}

// RequestNormalizationMeshConfig contains options pertaining to the
// normalization of HTTP requests processed by mesh proxies.
type RequestNormalizationMeshConfig struct {
// InsecureDisablePathNormalization sets the value of the \`normalize_path\` option in the Envoy listener's
// `HttpConnectionManager`. The default value is \`false\`. When set to \`true\` in Consul, \`normalize_path\` is
// set to \`false\` for the Envoy proxy. This parameter disables the normalization of request URL paths according to
// RFC 3986, conversion of \`\\\` to \`/\`, and decoding non-reserved %-encoded characters. When using L7 intentions
// with path match rules, we recommend enabling path normalization in order to avoid match rule circumvention with
// non-normalized path values.
InsecureDisablePathNormalization bool `json:",omitempty" alias:"insecure_disable_path_normalization"`
// MergeSlashes sets the value of the \`merge_slashes\` option in the Envoy listener's \`HttpConnectionManager\`.
// The default value is \`false\`. This option controls the normalization of request URL paths by merging
// consecutive \`/\` characters. This normalization is not part of RFC 3986. When using L7 intentions with path
// match rules, we recommend enabling this setting to avoid match rule circumvention through non-normalized path
// values, unless legitimate service traffic depends on allowing for repeat \`/\` characters, or upstream services
// are configured to differentiate between single and multiple slashes.
MergeSlashes bool `json:",omitempty" alias:"merge_slashes"`
// PathWithEscapedSlashesAction sets the value of the \`path_with_escaped_slashes_action\` option in the Envoy
// listener's \`HttpConnectionManager\`. The default value of this option is empty, which is equivalent to
// \`IMPLEMENTATION_SPECIFIC_DEFAULT\`. This parameter controls the action taken in response to request URL paths
// with escaped slashes in the path. When using L7 intentions with path match rules, we recommend enabling this
// setting to avoid match rule circumvention through non-normalized path values, unless legitimate service traffic
// depends on allowing for escaped \`/\` or \`\\\` characters, or upstream services are configured to differentiate
// between escaped and unescaped slashes. Refer to the Envoy documentation for more information on available
// options.
PathWithEscapedSlashesAction string `json:",omitempty" alias:"path_with_escaped_slashes_action"`
// HeadersWithUnderscoresAction sets the value of the \`headers_with_underscores_action\` option in the Envoy
// listener's \`HttpConnectionManager\` under \`common_http_protocol_options\`. The default value of this option is
// empty, which is equivalent to \`ALLOW\`. Refer to the Envoy documentation for more information on available
// options.
HeadersWithUnderscoresAction string `json:",omitempty" alias:"headers_with_underscores_action"`
}

func (e *MeshConfigEntry) GetKind() string { return MeshConfig }
func (e *MeshConfigEntry) GetName() string { return MeshConfigMesh }
func (e *MeshConfigEntry) GetPartition() string { return e.Partition }
Expand Down
129 changes: 127 additions & 2 deletions command/helpers/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,10 @@ func TestParseConfigEntry(t *testing.T) {
name = "hdr-suffix"
suffix = "suffix"
},
{
name = "hdr-contains"
contains = "contains"
},
{
name = "hdr-regex"
regex = "regex"
Expand All @@ -2313,7 +2317,12 @@ func TestParseConfigEntry(t *testing.T) {
name = "hdr-absent"
present = true
invert = true
}
},
{
name = "hdr-ignore-case"
exact = "exact"
ignore_case = true
},
]
}
},
Expand Down Expand Up @@ -2382,6 +2391,10 @@ func TestParseConfigEntry(t *testing.T) {
Name = "hdr-suffix"
Suffix = "suffix"
},
{
Name = "hdr-contains"
Contains = "contains"
},
{
Name = "hdr-regex"
Regex = "regex"
Expand All @@ -2390,6 +2403,11 @@ func TestParseConfigEntry(t *testing.T) {
Name = "hdr-absent"
Present = true
Invert = true
},
{
Name = "hdr-ignore-case"
Exact = "exact"
IgnoreCase = true
}
]
}
Expand Down Expand Up @@ -2460,6 +2478,10 @@ func TestParseConfigEntry(t *testing.T) {
"name": "hdr-suffix",
"suffix": "suffix"
},
{
"name": "hdr-contains",
"contains": "contains"
},
{
"name": "hdr-regex",
"regex": "regex"
Expand All @@ -2468,6 +2490,11 @@ func TestParseConfigEntry(t *testing.T) {
"name": "hdr-absent",
"present": true,
"invert": true
},
{
"name": "hdr-ignore-case",
"exact": "exact",
"ignore_case": true
}
]
}
Expand Down Expand Up @@ -2542,6 +2569,10 @@ func TestParseConfigEntry(t *testing.T) {
"Name": "hdr-suffix",
"Suffix": "suffix"
},
{
"Name": "hdr-contains",
"Contains": "contains"
},
{
"Name": "hdr-regex",
"Regex": "regex"
Expand All @@ -2550,6 +2581,11 @@ func TestParseConfigEntry(t *testing.T) {
"Name": "hdr-absent",
"Present": true,
"Invert": true
},
{
"Name": "hdr-ignore-case",
"Exact": "exact",
"IgnoreCase": true
}
]
}
Expand Down Expand Up @@ -2623,6 +2659,10 @@ func TestParseConfigEntry(t *testing.T) {
Name: "hdr-suffix",
Suffix: "suffix",
},
{
Name: "hdr-contains",
Contains: "contains",
},
{
Name: "hdr-regex",
Regex: "regex",
Expand All @@ -2632,6 +2672,11 @@ func TestParseConfigEntry(t *testing.T) {
Present: true,
Invert: true,
},
{
Name: "hdr-ignore-case",
Exact: "exact",
IgnoreCase: true,
},
},
},
},
Expand Down Expand Up @@ -2719,7 +2764,7 @@ func TestParseConfigEntry(t *testing.T) {
},
},
{
name: "mesh",
name: "mesh: kitchen sink",
snake: `
kind = "mesh"
meta {
Expand All @@ -2729,6 +2774,8 @@ func TestParseConfigEntry(t *testing.T) {
transparent_proxy {
mesh_destinations_only = true
}
allow_enabling_permissive_mutual_tls = true
validate_clusters = true
tls {
incoming {
tls_min_version = "TLSv1_1"
Expand All @@ -2747,6 +2794,20 @@ func TestParseConfigEntry(t *testing.T) {
]
}
}
http {
sanitize_x_forwarded_client_cert = true
incoming {
request_normalization {
insecure_disable_path_normalization = true
merge_slashes = true
path_with_escaped_slashes_action = "UNESCAPE_AND_FORWARD"
headers_with_underscores_action = "DROP_HEADER"
}
}
}
peering {
peer_through_mesh_gateways = true
}
`,
camel: `
Kind = "mesh"
Expand All @@ -2757,6 +2818,8 @@ func TestParseConfigEntry(t *testing.T) {
TransparentProxy {
MeshDestinationsOnly = true
}
AllowEnablingPermissiveMutualTLS = true
ValidateClusters = true
TLS {
Incoming {
TLSMinVersion = "TLSv1_1"
Expand All @@ -2775,6 +2838,20 @@ func TestParseConfigEntry(t *testing.T) {
]
}
}
HTTP {
SanitizeXForwardedClientCert = true
Incoming {
RequestNormalization {
InsecureDisablePathNormalization = true
MergeSlashes = true
PathWithEscapedSlashesAction = "UNESCAPE_AND_FORWARD"
HeadersWithUnderscoresAction = "DROP_HEADER"
}
}
}
Peering {
PeerThroughMeshGateways = true
}
`,
snakeJSON: `
{
Expand All @@ -2786,6 +2863,8 @@ func TestParseConfigEntry(t *testing.T) {
"transparent_proxy": {
"mesh_destinations_only": true
},
"allow_enabling_permissive_mutual_tls": true,
"validate_clusters": true,
"tls": {
"incoming": {
"tls_min_version": "TLSv1_1",
Expand All @@ -2803,6 +2882,20 @@ func TestParseConfigEntry(t *testing.T) {
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
},
"http": {
"sanitize_x_forwarded_client_cert": true,
"incoming": {
"request_normalization": {
"insecure_disable_path_normalization": true,
"merge_slashes": true,
"path_with_escaped_slashes_action": "UNESCAPE_AND_FORWARD",
"headers_with_underscores_action": "DROP_HEADER"
}
}
},
"peering": {
"peer_through_mesh_gateways": true
}
}
`,
Expand All @@ -2816,6 +2909,8 @@ func TestParseConfigEntry(t *testing.T) {
"TransparentProxy": {
"MeshDestinationsOnly": true
},
"AllowEnablingPermissiveMutualTLS": true,
"ValidateClusters": true,
"TLS": {
"Incoming": {
"TLSMinVersion": "TLSv1_1",
Expand All @@ -2833,6 +2928,20 @@ func TestParseConfigEntry(t *testing.T) {
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
},
"HTTP": {
"SanitizeXForwardedClientCert": true,
"Incoming": {
"RequestNormalization": {
"InsecureDisablePathNormalization": true,
"MergeSlashes": true,
"PathWithEscapedSlashesAction": "UNESCAPE_AND_FORWARD",
"HeadersWithUnderscoresAction": "DROP_HEADER"
}
}
},
"Peering": {
"PeerThroughMeshGateways": true
}
}
`,
Expand All @@ -2844,6 +2953,8 @@ func TestParseConfigEntry(t *testing.T) {
TransparentProxy: api.TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
AllowEnablingPermissiveMutualTLS: true,
ValidateClusters: true,
TLS: &api.MeshTLSConfig{
Incoming: &api.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_1",
Expand All @@ -2862,6 +2973,20 @@ func TestParseConfigEntry(t *testing.T) {
},
},
},
HTTP: &api.MeshHTTPConfig{
SanitizeXForwardedClientCert: true,
Incoming: &api.MeshDirectionalHTTPConfig{
RequestNormalization: &api.RequestNormalizationMeshConfig{
InsecureDisablePathNormalization: true,
MergeSlashes: true,
PathWithEscapedSlashesAction: "UNESCAPE_AND_FORWARD",
HeadersWithUnderscoresAction: "DROP_HEADER",
},
},
},
Peering: &api.PeeringMeshConfig{
PeerThroughMeshGateways: true,
},
},
},
{
Expand Down
Loading