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

Add support for SPIFFE TLS Ids #2520

Closed

Conversation

zaharidichev
Copy link
Member

This PR adds support for TLS ids that are in SPIFFE format (URI). Notable changes:

  • san verification logic has been extracted into a separate crate (llinkerd-meshtls-util)
  • tests for ID extraction and validation logic are happening in this crate
  • the linkerd_identity::Id type has been turned into an enum that can be either a DNS URI type
  • the Metadata type now carries both ServerName and ServerId information

Signed-off-by: Zahari Dichev <[email protected]>
@zaharidichev zaharidichev requested a review from a team as a code owner November 16, 2023 14:57
/// well.
/// Practically speaking, this could be:
/// - a DNS-like identity string that matches an x509 DNS SAN
/// - a SPIFFE ID in URI form, that matches an x509
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that matches an x509...what?

Comment on lines +22 to +23
Dns(linkerd_dns_name::Name),
Uri(http::Uri),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit, take it or leave it: consider maybe just moving the bulleted list to comments on the variants?

Suggested change
Dns(linkerd_dns_name::Name),
Uri(http::Uri),
/// A a DNS-like identity string that matches an x509 DNS SAN.
Dns(linkerd_dns_name::Name),
/// A SPIFFE ID in URI form, that matches an x509
Uri(http::Uri),

Comment on lines +22 to +23
Dns(linkerd_dns_name::Name),
Uri(http::Uri),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the Id::Uri variant intended to be SPIFFE-specific? we might want to name the variant something like SpiffeUri or Spiffe, to make that clearer, especially if we later support other identity mechanisms that also use URIs?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that this type shouldn't make any SPIFFE requirements. That seems like more of an x509-handling concern than a restriction we care about in linkerd's core types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that's kind of the question I was getting at --- I wasn't sure whether this variant represented a spiffe-specific thing or not.

// TODO support spiffe:// URIs.
if s.starts_with(SPIFFE_URI_SCHEME) {
// TODO: we need to ensure the SPIFFE id is valid
// according to requirements otlined in:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo:

Suggested change
// according to requirements otlined in:
// according to requirements outlined in:

self.0.as_str().into()
match self {
Self::Dns(dns) => dns.as_str().into(),
Self::Uri(uri) => uri.to_string().into(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's quite unfortunate that this allocates (in to_string()) --- the DNS version just borrows the string. AFAICT there is no way to borrow an underlying string from an http::Uri, as the parts of the URI may have come from different string slices --- it's intended more as a builder for URIs to be sent in HTTP requests.

i wonder if representing the Uri variant using http::Uri is actually the best representation, since we use Id::to_str a lot, and it's a shame to have to allocate a new String to format the URI into every time we want to log it or whatever. we could, alternatively, change the representation to store both an http::Uri and an Arc<str> or something, so that the formatting of the URI into a string representation only happens once, and subsequent to_str calls just borrow that? I dunno...

Comment on lines +116 to +123
let der = cert
.to_der()
.map_err(
|error| tracing::warn!(%error, "Failed to encode client end cert to der"),
)
.ok()?;

util::client_identity(&der).map(ClientId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIOLI: might be nicer as

Suggested change
let der = cert
.to_der()
.map_err(
|error| tracing::warn!(%error, "Failed to encode client end cert to der"),
)
.ok()?;
util::client_identity(&der).map(ClientId)
match cert.to_der() {
Ok(der) => util::client_identity(&der).map(ClientId),
Err(error) => {
tracing::warn!(%error, "Failed to encode client end cert to der");
None
}
}

@@ -1,11 +1,19 @@
[package]
name = "linkerd-meshtls-test-util"
name = "linkerd-meshtls-util"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, take it or leave it: i might have called this linkerd-meshtls-core, following the naming scheme we use elsewhere in the project?

@olix0r olix0r self-assigned this Nov 17, 2023
@@ -18,7 +19,7 @@ pub struct Metadata {
tagged_transport_port: Option<u16>,

/// How to verify TLS for the endpoint.
identity: Option<ServerId>,
identity: Option<(ServerId, ServerName)>,
Copy link
Member

@olix0r olix0r Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we perhaps change this to store a tls::ClientTls? This also opens the option to pass through ALPN settings (later).

    tls: Option<tls::ClientTls>,

I'd hope this makes the handling of names/ids less verbose throughout most of the app code.

Copy link
Member

@olix0r olix0r Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also make sense as a discrete change to help minimize the diff we need to consider for URI handling.


fn extract_ids_from_cert(cert: &[u8]) -> Result<Vec<Id>> {
use x509_parser::prelude::*;
let (_, c) = X509Certificate::from_der(cert)?;
Copy link
Member

@olix0r olix0r Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this changes our DNSName validation, I think we should make this change discretely from the rest of this PR. I.e. a targetted PR that adds a new linkerd-meshtls-verifier crate using x509_parser, without URI handling.

@zaharidichev
Copy link
Member Author

@hawkw @olix0r Thanks for the thoughtful feedback, I am closing this PR now in order to split it into smaller, more focused changes, starting with #2534

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants