Skip to content

Commit

Permalink
[NET-1151 NET-11228] api: Add fields for HTTP request normalization a…
Browse files Browse the repository at this point in the history
…nd L7 intentions header additions (1.15) (#21842)

api: Add fields for HTTP request normalization and L7 intentions header additions

This feature is available in Consul CE 1.20.1 and Consul Enterprise 1.19.3, 1.18.4, and 1.15.15.
  • Loading branch information
zalimeni authored Oct 17, 2024
1 parent 619c288 commit 400c6a8
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 9 deletions.
16 changes: 9 additions & 7 deletions api/config_entry_intentions.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ 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"`
}
41 changes: 41 additions & 0 deletions api/config_entry_mesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,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
124 changes: 122 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,7 @@ func TestParseConfigEntry(t *testing.T) {
transparent_proxy {
mesh_destinations_only = true
}
validate_clusters = true
tls {
incoming {
tls_min_version = "TLSv1_1"
Expand All @@ -2747,6 +2793,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 +2817,7 @@ func TestParseConfigEntry(t *testing.T) {
TransparentProxy {
MeshDestinationsOnly = true
}
ValidateClusters = true
TLS {
Incoming {
TLSMinVersion = "TLSv1_1"
Expand All @@ -2775,6 +2836,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 +2861,7 @@ func TestParseConfigEntry(t *testing.T) {
"transparent_proxy": {
"mesh_destinations_only": true
},
"validate_clusters": true,
"tls": {
"incoming": {
"tls_min_version": "TLSv1_1",
Expand All @@ -2803,6 +2879,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 +2906,7 @@ func TestParseConfigEntry(t *testing.T) {
"TransparentProxy": {
"MeshDestinationsOnly": true
},
"ValidateClusters": true,
"TLS": {
"Incoming": {
"TLSMinVersion": "TLSv1_1",
Expand All @@ -2833,6 +2924,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 +2949,7 @@ func TestParseConfigEntry(t *testing.T) {
TransparentProxy: api.TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
ValidateClusters: true,
TLS: &api.MeshTLSConfig{
Incoming: &api.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_1",
Expand All @@ -2862,6 +2968,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

0 comments on commit 400c6a8

Please sign in to comment.