Skip to content

Commit

Permalink
Specify type for matching Subject Alternative Name. (#18628)
Browse files Browse the repository at this point in the history
Signed-off-by: Pradeep Rao <pcrao@google.com>
  • Loading branch information
pradeepcrao committed Nov 24, 2021
1 parent 25bf301 commit bb95af8
Show file tree
Hide file tree
Showing 45 changed files with 666 additions and 172 deletions.
41 changes: 35 additions & 6 deletions api/envoy/extensions/transport_sockets/tls/v3/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "envoy/type/matcher/v3/string.proto";
import "google/protobuf/any.proto";
import "google/protobuf/wrappers.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/migrate.proto";
import "udpa/annotations/sensitive.proto";
import "udpa/annotations/status.proto";
Expand Down Expand Up @@ -268,7 +269,26 @@ message CertificateProviderPluginInstance {
string certificate_name = 2;
}

// [#next-free-field: 15]
// Matcher for subject alternative names, to match both type and value of the SAN.
message SubjectAltNameMatcher {
// Indicates the choice of GeneralName as defined in section 4.2.1.5 of RFC 5280 to match
// against.
enum SanType {
SAN_TYPE_UNSPECIFIED = 0;
EMAIL = 1;
DNS = 2;
URI = 3;
IP_ADDRESS = 4;
}

// Specification of type of SAN. Note that the default enum value is an invalid choice.
SanType san_type = 1 [(validate.rules).enum = {defined_only: true not_in: 0}];

// Matcher for SAN value.
type.matcher.v3.StringMatcher matcher = 2 [(validate.rules).message = {required: true}];
}

// [#next-free-field: 16]
message CertificateValidationContext {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.auth.CertificateValidationContext";
Expand Down Expand Up @@ -298,8 +318,8 @@ message CertificateValidationContext {
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.verify_certificate_spki>`,
// :ref:`verify_certificate_hash
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.verify_certificate_hash>`, or
// :ref:`match_subject_alt_names
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_subject_alt_names>`) is also
// :ref:`match_typed_subject_alt_names
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>`) is also
// specified.
//
// It can optionally contain certificate revocation lists, in which case Envoy will verify
Expand Down Expand Up @@ -406,6 +426,8 @@ message CertificateValidationContext {

// An optional list of Subject Alternative name matchers. If specified, Envoy will verify that the
// Subject Alternative Name of the presented certificate matches one of the specified matchers.
// The matching uses "any" semantics, that is to say, the SAN is verified if at least one matcher is
// matched.
//
// When a certificate has wildcard DNS SAN entries, to match a specific client, it should be
// configured with exact match type in the :ref:`string matcher <envoy_v3_api_msg_type.matcher.v3.StringMatcher>`.
Expand All @@ -414,15 +436,22 @@ message CertificateValidationContext {
//
// .. code-block:: yaml
//
// match_subject_alt_names:
// exact: "api.example.com"
// match_typed_subject_alt_names:
// - san_type: DNS
// matcher:
// exact: "api.example.com"
//
// .. attention::
//
// Subject Alternative Names are easily spoofable and verifying only them is insecure,
// therefore this option must be used together with :ref:`trusted_ca
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.trusted_ca>`.
repeated type.matcher.v3.StringMatcher match_subject_alt_names = 9;
repeated SubjectAltNameMatcher match_typed_subject_alt_names = 15;

// This field is deprecated in favor of ref:`match_typed_subject_alt_names
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>`
repeated type.matcher.v3.StringMatcher match_subject_alt_names = 9
[deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

// [#not-implemented-hide:] Must present signed certificate time-stamp.
google.protobuf.BoolValue require_signed_certificate_timestamp = 6;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Note that SPIFFE validator inherits and uses the following options from :ref:`CertificateValidationContext <envoy_v3_api_msg_extensions.transport_sockets.tls.v3.CertificateValidationContext>`.
//
// - :ref:`allow_expired_certificate <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.allow_expired_certificate>` to allow expired certificates.
// - :ref:`match_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_subject_alt_names>` to match **URI** SAN of certificates. Unlike the default validator, SPIFFE validator only matches **URI** SAN (which equals to SVID in SPIFFE terminology) and ignore other SAN types.
// - :ref:`match_typed_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>` to match **URI** SAN of certificates. Unlike the default validator, SPIFFE validator only matches **URI** SAN (which equals to SVID in SPIFFE terminology) and ignore other SAN types.
//
message SPIFFECertValidatorConfig {
message TrustDomain {
Expand Down
12 changes: 8 additions & 4 deletions configs/envoy_double_proxy.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ static_resources:
validation_context:
trusted_ca:
filename: certs/cacert.pem
match_subject_alt_names:
exact: "front-proxy.yourcompany.net"
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "front-proxy.yourcompany.net"
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
Expand Down Expand Up @@ -188,8 +190,10 @@ static_resources:
validation_context:
trusted_ca:
filename: certs/cacert.pem
match_subject_alt_names:
exact: "collector-grpc.lightstep.com"
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "collector-grpc.lightstep.com"
flags_path: "/etc/envoy/flags"
stats_sinks:
- name: envoy.stat_sinks.statsd
Expand Down
12 changes: 8 additions & 4 deletions configs/envoy_service_to_service.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,10 @@ static_resources:
trusted_ca:
filename: certs/cacert.pem
{% if host.get('verify_subject_alt_name', False) %}
match_subject_alt_names:
exact: "{{host['verify_subject_alt_name'] }}"
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "{{host['verify_subject_alt_name'] }}"
{% endif %}
{% if host.get('sni', False) %}
sni: "{{ host['sni'] }}"
Expand Down Expand Up @@ -520,8 +522,10 @@ static_resources:
validation_context:
trusted_ca:
filename: certs/cacert.pem
match_subject_alt_names:
exact: "collector-grpc.lightstep.com"
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "collector-grpc.lightstep.com"
- name: cds_cluster
connect_timeout: 0.25s
type: STRICT_DNS
Expand Down
6 changes: 4 additions & 2 deletions docs/root/intro/arch_overview/security/_include/ssl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ static_resources:
private_key: {"filename": "certs/serverkey.pem"}
ocsp_staple: {"filename": "certs/server_ocsp_resp.der"}
validation_context:
match_subject_alt_names:
- exact: "foo"
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "foo"
trusted_ca:
filename: /etc/ssl/certs/ca-certificates.crt
2 changes: 1 addition & 1 deletion docs/root/intro/arch_overview/security/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Example configuration

*/etc/ssl/certs/ca-certificates.crt* is the default path for the system CA bundle on Debian systems.
:ref:`trusted_ca <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.trusted_ca>` along with
:ref:`match_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_subject_alt_names>`
:ref:`match_typed_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>`
makes Envoy verify the server identity of *127.0.0.1:1234* as "foo" in the same way as e.g. cURL
does on standard Debian installations. Common paths for system CA bundles on Linux and BSD are:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ static_resources:
validation_context:
trusted_ca:
filename: certs/cacert.pem
match_subject_alt_names:
- exact: proxy-postgres-frontend.example.com
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: proxy-postgres-frontend.example.com
tls_certificates:
- certificate_chain:
filename: certs/servercert.pem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ static_resources:
validation_context:
trusted_ca:
filename: certs/cacert.pem
match_subject_alt_names:
- exact: proxy-postgres-backend.example.com
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: proxy-postgres-backend.example.com
12 changes: 6 additions & 6 deletions docs/root/start/quick-start/securing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ certificate is valid for.
.. note::

If the "Subject Alternative Names" for a certificate are for a wildcard domain, eg ``*.example.com``,
this is what you should use when matching with ``match_subject_alt_names``.
this is what you should use when matching with ``match_typed_subject_alt_names``.

.. note::

Expand All @@ -122,20 +122,20 @@ and specify a mutually trusted certificate authority:
:language: yaml
:linenos:
:lineno-start: 27
:lines: 27-39
:lines: 27-41
:emphasize-lines: 6, 8-10
:caption: :download:`envoy-demo-tls-client-auth.yaml <_include/envoy-demo-tls-client-auth.yaml>`

You can further restrict the authentication of connecting clients by specifying the allowed
"Subject Alternative Names" in
:ref:`match_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_subject_alt_names>`,
:ref:`match_typed_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>`,
similar to validating upstream certificates :ref:`described above <start_quick_start_securing_validation>`.

.. literalinclude:: _include/envoy-demo-tls-client-auth.yaml
:language: yaml
:linenos:
:lineno-start: 27
:lines: 27-39
:lines: 27-41
:emphasize-lines: 7, 11-12
:caption: :download:`envoy-demo-tls-client-auth.yaml <_include/envoy-demo-tls-client-auth.yaml>`

Expand All @@ -154,8 +154,8 @@ When connecting to an upstream with client certificates you can set them as foll
.. literalinclude:: _include/envoy-demo-tls-client-auth.yaml
:language: yaml
:linenos:
:lineno-start: 44
:lines: 44-68
:lineno-start: 46
:lines: 46-70
:emphasize-lines: 20-25
:caption: :download:`envoy-demo-tls-client-auth.yaml <_include/envoy-demo-tls-client-auth.yaml>`

Expand Down
2 changes: 2 additions & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ New Features
* thrift_proxy: add host level success/error metrics where success is a reply of type success and error is any other response to a call.
* thrift_proxy: support header flags.
* thrift_proxy: support subset lb when using request or route metadata.
* tls: added support for :ref:`match_typed_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>` for subject alternative names to enforce specifying the subject alternative name type for the matcher to prevent matching against an unintended type in the certificate.
* tls: added support for only verifying the leaf CRL in the certificate chain with :ref:`only_verify_leaf_cert_crl <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.only_verify_leaf_cert_crl>`.
* tls: support loading certificate chain and private key via :ref:`pkcs12 <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.pkcs12>`.
* tls_inspector filter: added :ref:`enable_ja3_fingerprinting <envoy_v3_api_field_extensions.filters.listener.tls_inspector.v3.TlsInspector.enable_ja3_fingerprinting>` to create JA3 fingerprint hash from Client Hello message.
Expand All @@ -95,4 +96,5 @@ Deprecated
* bootstrap: :ref:`dns_resolution_config <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.dns_resolution_config>` is deprecated in favor of :ref:`typed_dns_resolver_config <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.typed_dns_resolver_config>`.
* cluster: :ref:`dns_resolution_config <envoy_v3_api_field_config.cluster.v3.Cluster.dns_resolution_config>` is deprecated in favor of :ref:`typed_dns_resolver_config <envoy_v3_api_field_config.cluster.v3.Cluster.typed_dns_resolver_config>`.
* dns_cache: :ref:`dns_resolution_config <envoy_v3_api_field_extensions.common.dynamic_forward_proxy.v3.DnsCacheConfig.dns_resolution_config>` is deprecated in favor of :ref:`typed_dns_resolver_config <envoy_v3_api_field_extensions.common.dynamic_forward_proxy.v3.DnsCacheConfig.typed_dns_resolver_config>`.
* tls: :ref:`match_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_subject_alt_names>` has been deprecated in favor of the :ref:`match_typed_subject_alt_names <envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.match_typed_subject_alt_names>`.
* dns_filter: :ref:`dns_resolution_config <envoy_v3_api_field_extensions.filters.udp.dns_filter.v3.DnsFilterConfig.ClientContextConfig.dns_resolution_config>` is deprecated in favor of :ref:`typed_dns_resolver_config <envoy_v3_api_field_extensions.filters.udp.dns_filter.v3.DnsFilterConfig.ClientContextConfig.typed_dns_resolver_config>`.
3 changes: 2 additions & 1 deletion envoy/ssl/certificate_validation_context_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "envoy/api/api.h"
#include "envoy/common/pure.h"
#include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h"
#include "envoy/extensions/transport_sockets/tls/v3/common.pb.h"
#include "envoy/type/matcher/v3/string.pb.h"

#include "absl/types/optional.h"
Expand Down Expand Up @@ -43,7 +44,7 @@ class CertificateValidationContextConfig {
/**
* @return The subject alt name matchers to be verified, if enabled.
*/
virtual const std::vector<envoy::type::matcher::v3::StringMatcher>&
virtual const std::vector<envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher>&
subjectAltNameMatchers() const PURE;

/**
Expand Down
6 changes: 4 additions & 2 deletions examples/double-proxy/envoy-backend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ static_resources:
private_key:
filename: certs/serverkey.pem
validation_context:
match_subject_alt_names:
- exact: proxy-postgres-frontend.example.com
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: proxy-postgres-frontend.example.com
trusted_ca:
filename: certs/cacert.pem

Expand Down
6 changes: 4 additions & 2 deletions examples/double-proxy/envoy-frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ static_resources:
private_key:
filename: certs/clientkey.pem
validation_context:
match_subject_alt_names:
- exact: proxy-postgres-backend.example.com
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: proxy-postgres-backend.example.com
trusted_ca:
filename: certs/cacert.pem
1 change: 1 addition & 0 deletions source/common/ssl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ envoy_cc_library(
"//envoy/ssl:certificate_validation_context_config_interface",
"//source/common/common:empty_string",
"//source/common/config:datasource_lib",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/transport_sockets/tls/v3:pkg_cc_proto",
"@envoy_api//envoy/type/matcher/v3:pkg_cc_proto",
],
Expand Down
35 changes: 33 additions & 2 deletions source/common/ssl/certificate_validation_context_config_impl.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#include "source/common/ssl/certificate_validation_context_config_impl.h"

#include "envoy/common/exception.h"
#include "envoy/config/core/v3/extension.pb.h"
#include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h"
#include "envoy/extensions/transport_sockets/tls/v3/common.pb.h"

#include "source/common/common/empty_string.h"
#include "source/common/common/fmt.h"
#include "source/common/common/logger.h"
#include "source/common/config/datasource.h"

namespace Envoy {
Expand All @@ -22,8 +25,7 @@ CertificateValidationContextConfigImpl::CertificateValidationContextConfigImpl(
certificate_revocation_list_path_(
Config::DataSource::getPath(config.crl())
.value_or(certificate_revocation_list_.empty() ? EMPTY_STRING : INLINE_STRING)),
subject_alt_name_matchers_(config.match_subject_alt_names().begin(),
config.match_subject_alt_names().end()),
subject_alt_name_matchers_(getSubjectAltNameMatchers(config)),
verify_certificate_hash_list_(config.verify_certificate_hash().begin(),
config.verify_certificate_hash().end()),
verify_certificate_spki_list_(config.verify_certificate_spki().begin(),
Expand Down Expand Up @@ -51,5 +53,34 @@ CertificateValidationContextConfigImpl::CertificateValidationContextConfigImpl(
}
}

std::vector<envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher>
CertificateValidationContextConfigImpl::getSubjectAltNameMatchers(
const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext& config) {
if (!config.match_typed_subject_alt_names().empty() &&
!config.match_subject_alt_names().empty()) {
throw EnvoyException("SAN-based verification using both match_typed_subject_alt_names and "
"the deprecated match_subject_alt_names is not allowed");
}
std::vector<envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher>
subject_alt_name_matchers(config.match_typed_subject_alt_names().begin(),
config.match_typed_subject_alt_names().end());
// Handle deprecated string type san matchers without san type specified, by
// creating a matcher for each supported type.
for (const envoy::type::matcher::v3::StringMatcher& matcher : config.match_subject_alt_names()) {
static constexpr std::array<
envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::SanType, 4>
san_types{envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::DNS,
envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::URI,
envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::EMAIL,
envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::IP_ADDRESS};
for (const auto san_type : san_types) {
subject_alt_name_matchers.emplace_back();
subject_alt_name_matchers.back().set_san_type(san_type);
*subject_alt_name_matchers.back().mutable_matcher() = matcher;
}
}
return subject_alt_name_matchers;
}

} // namespace Ssl
} // namespace Envoy
Loading

0 comments on commit bb95af8

Please sign in to comment.