Skip to content

Commit

Permalink
Merge branch 'master' into flynn/dev/v1.10-xfcc
Browse files Browse the repository at this point in the history
  • Loading branch information
Flynn committed Dec 21, 2020
2 parents ecf10cc + 2ceba4b commit c10e232
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/topics/running/ambassador.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ spec:
| `envoy_log_type` | Defines the type of log envoy will use, currently only support json or text. | `envoy_log_type: text` |
| `envoy_validation_timeout` | Defines the timeout, in seconds, for validating a new Envoy configuration. The default is 10; a value of 0 disables Envoy configuration validation. Most installations will not need to use this setting. | `envoy_validation_timeout: 30` |
| `error_response_overrides` | Defines error response overrides for 4XX and 5XX response codes. By default, Ambassador will pass through error responses without modification, and errors generated locally will use Envoy's default response body, if any. | See [this page](../custom-error-responses) for usage details.
| `forward_client_cert_details` | Add the X-Forwarded-Client-Cert header on upstream requests, which contains information about the TLS client certificate verified by Ambassador. See the Envoy documentation on [X-Forwarded-Client-Cert](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html?highlight=xfcc#x-forwarded-client-cert) and [SetCurrentClientCertDetails](https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/network/http_connection_manager/v2/http_connection_manager.proto#envoy-api-msg-config-filter-network-http-connection-manager-v2-httpconnectionmanager-setcurrentclientcertdetails) for more information. | |
| `ip_allow` | Defines HTTP source IP address ranges to allow; all others will be denied. `ip_allow` and `ip_deny` may not both be specified. See below for more details. | None |
| `ip_deny` | Defines HTTP source IP address ranges to deny; all others will be allowed. `ip_allow` and `ip_deny` may not both be specified. See below for more details. | None |
| `listener_idle_timeout_ms` | Controls how Envoy configures the tcp idle timeout on the http listener. Default is 1 hour. | `listener_idle_timeout_ms: 30000` |
Expand All @@ -49,6 +50,7 @@ spec:
| `regex_type` | Set which regular expression engine to use. See the "Regular Expressions" section below. | `regex_type: safe` |
| `server_name` | By default Envoy sets server_name response header to `envoy`. Override it with this variable. | `server_name: envoy` |
| `service_port` | If present, service_port will be the port Ambassador listens on for microservice access. If not present, Ambassador will use 8443 if TLS is configured, 8080 otherwise. | `service_port: 8080` |
| `set_current_client_cert_details` | Specify how to handle the X-Forwarded-Client-Cert header. See the Envoy documentation on [X-Forwarded-Client-Cert](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html?highlight=xfcc#x-forwarded-client-cert) and [SetCurrentClientCertDetails](https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/network/http_connection_manager/v2/http_connection_manager.proto.html?highlight=xfcc#envoy-api-enum-config-filter-network-http-connection-manager-v2-httpconnectionmanager-forwardclientcertdetails) for more information. | `set_current_client_cert_details: SANITIZE` |
| `statsd` | Configures Ambassador statistics. These values can be set in the Ambassador module or in an environment variable. For more information, see the [Statistics reference](../statistics#exposing-statistics-via-statsd). | None |
| `use_proxy_proto` | Controls whether Envoy will honor the PROXY protocol on incoming requests. | `use_proxy_proto: false` |
| `use_remote_address` | Controls whether Envoy will trust the remote address of incoming connections or rely exclusively on the X-Forwarded-For header. | `use_remote_address: true` |
Expand Down
6 changes: 6 additions & 0 deletions python/ambassador/envoy/v2/v2listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,12 @@ def __init__(self, config: 'V2Config', service_port: int) -> None:
if 'preserve_external_request_id' in self.config.ir.ambassador_module:
self.base_http_config["preserve_external_request_id"] = self.config.ir.ambassador_module.preserve_external_request_id

if 'forward_client_cert_details' in self.config.ir.ambassador_module:
self.base_http_config["forward_client_cert_details"] = self.config.ir.ambassador_module.forward_client_cert_details

if 'set_current_client_cert_details' in self.config.ir.ambassador_module:
self.base_http_config["set_current_client_cert_details"] = self.config.ir.ambassador_module.set_current_client_cert_details

if self.config.ir.tracing:
self.base_http_config["generate_request_id"] = True

Expand Down
4 changes: 4 additions & 0 deletions python/ambassador/envoy/v2/v2tls.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ def update_tls_cipher(self, key: str, value: List[str]) -> None:

def update_validation(self, key: str, value: str) -> None:
empty_context: EnvoyValidationContext = {}

# This looks weirder than you might expect, because self.get_common().setdefault() is a truly
# crazy Union type, so we need to cast it to an EnvoyValidationContext to be able to work
# with it.
validation = typecast(EnvoyValidationContext, self.get_common().setdefault('validation_context', empty_context))

src: EnvoyCoreSource = { 'filename': value }
Expand Down
30 changes: 30 additions & 0 deletions python/ambassador/ir/irambassador.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class IRAmbassador (IRResource):
'envoy_log_format',
'envoy_log_path',
'envoy_log_type',
'forward_client_cert_details',
# Do not include envoy_validation_timeout; we let finalize() type-check it.
# Do not include ip_allow or ip_deny; we let finalize() type-check them.
'keepalive',
Expand All @@ -62,6 +63,7 @@ class IRAmbassador (IRResource):
'header_case_overrides',
'server_name',
'service_port',
'set_current_client_cert_details',
'statsd',
'use_ambassador_namespace_for_service_resolution',
'use_proxy_proto',
Expand Down Expand Up @@ -361,6 +363,34 @@ def finalize(self, ir: 'IR', aconf: Config) -> bool:
self.post_error("Invalid log_type specified: {}. Supported: json, text".format(self.get('envoy_log_type')))
return False

if self.get('forward_client_cert_details') is not None:
# https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-enum-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-forwardclientcertdetails
valid_values = ('SANITIZE', 'FORWARD_ONLY', 'APPEND_FORWARD', 'SANITIZE_SET', 'ALWAYS_FORWARD_ONLY')

value = self.get('forward_client_cert_details')
if value not in valid_values:
self.post_error(
"'forward_client_cert_details' may not be set to '{}'; it may only be set to one of: {}".format(
value, ', '.join(valid_values)))
return False

cert_details = self.get('set_current_client_cert_details')
if cert_details:
# https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-msg-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-setcurrentclientcertdetails
valid_keys = ('subject', 'cert', 'chain', 'dns', 'uri')

for k, v in cert_details.items():
if k not in valid_keys:
self.post_error(
"'set_current_client_cert_details' may not contain key '{}'; it may only contain keys: {}".format(
k, ', '.join(valid_keys)))
return False

if v not in (True, False):
self.post_error(
"'set_current_client_cert_details' value for key '{}' may only be 'true' or 'false', not '{}'".format(k, v))
return False

return True

def add_mappings(self, ir: 'IR', aconf: Config):
Expand Down
4 changes: 3 additions & 1 deletion python/ambassador/ir/irlistener.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ def load_all(cls, ir: 'IR', aconf: Config) -> None:
context=ctx,
secure_action='Route',
insecure_action=insecure_action,
insecure_addl_port=insecure_addl_port
insecure_addl_port=insecure_addl_port,
forward_client_cert_details=amod.get('forward_client_cert_details'),
set_current_client_cert_details=amod.get('set_current_client_cert_details')
)

listeners[hostname] = listener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
}
}
],
"forward_client_cert_details": "SANITIZE_SET",
"http_filters": [
{
"name": "envoy.filters.http.cors"
Expand Down Expand Up @@ -225,6 +226,9 @@
]
},
"server_name": "envoy",
"set_current_client_cert_details": {
"subject": true
},
"stat_prefix": "ingress_http",
"use_remote_address": true,
"xff_num_trusted_hops": 0
Expand Down
14 changes: 13 additions & 1 deletion python/tests/t_tls.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,15 @@ def config(self):
yield self, self.format("""
---
apiVersion: ambassador/v0
kind: Module
kind: Module
name: ambassador
config:
forward_client_cert_details: SANITIZE_SET
set_current_client_cert_details:
subject: true
---
apiVersion: ambassador/v0
kind: Module
ambassador_id: {self.ambassador_id}
name: tls
config:
Expand Down Expand Up @@ -143,6 +151,10 @@ def queries(self):
# TLS 1.3 added a dedicated alert=116 ("certificate_required") for that scenario.
yield Query(self.url(self.name + "/"), insecure=True, minTLSv="v1.3", error="tls: certificate required")

def check(self):
assert self.results[0].backend.request.headers["x-forwarded-client-cert"] == \
["Hash=c2d41a5977dcd28a3ba21f59ed5508cc6538defa810843d8a593e668306c8c4f;Subject=\"CN=presto.example.com,OU=Engineering,O=Presto,L=Bangalore,ST=KA,C=IN\""]

def requirements(self):
for r in super().requirements():
query = r[1]
Expand Down

0 comments on commit c10e232

Please sign in to comment.