Skip to content

Commit

Permalink
api: Add fields for HTTP request normalization and L7 intentions head…
Browse files Browse the repository at this point in the history
…er 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 committed Oct 16, 2024
1 parent 619c288 commit 42584a1
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,

Check failure on line 2952 in command/helpers/helpers_test.go

View workflow job for this annotation

GitHub Actions / lint / lint

File is not `gofmt`-ed with `-s` (gofmt)

Check failure on line 2952 in command/helpers/helpers_test.go

View workflow job for this annotation

GitHub Actions / lint-32bit / lint

File is not `gofmt`-ed with `-s` (gofmt)
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 42584a1

Please sign in to comment.