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

[v15] Set CommonName to first DNS SAN when issuing X509 SVIDs #40180

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,8 @@
"SVIDs",
"Ghostunnel",
"Linkerd",
"Istio"
"Istio",
"mydb"
],
"flagWords": [
"hte"
Expand Down
21 changes: 20 additions & 1 deletion docs/pages/machine-id/workload-identity/best-practices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,23 @@ yourself.

One such proxy is [Ghostunnel](https://github.com/ghostunnel/ghostunnel).


## X509 SVID Subject

When the X509 SVIDs are issued by Teleport Workload Identity, the subject
distinguished name of the certificate is determined by the following criteria:

- If no DNS SANs have been requested, the subject is unset.
- If DNS SANs have been requested, the first DNS SAN is set as the subject
common name.

This behavior exists to support interoperability with legacy systems which are
not able to parse DNS SANs or which are not SPIFFE aware.

An example of one such legacy system is Postgres. Postgres supports client
authentication using certificates, but only allows the common name to be used
to determine which database user access should be granted to. To integrate
Teleport Workload Identity with Postgres, you can issue X509 SVIDs with a DNS
SAN which can then be mapped to database user. For example, you could issue
a certificate with a DNS SAN of `myuser.mydb.db-access.example.com`. The
behavior described above will then set the common name to this DNS SAN, and you
can then configure Postgres to map this common name to `myuser`.
9 changes: 9 additions & 0 deletions lib/auth/machineid/machineidv1/workload_identity_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ func signx509SVID(
IPAddresses: ipSANS,
}

// For legacy compatibility, we set the subject common name to the first
// DNS SAN. This allows interoperability with non-SPIFFE aware clients that
// trust the CA, or interoperability with servers like Postgres which can
// only inspect the common name when making authz/authn decisions.
// Eventually, we may wish to make this behavior more configurable.
if len(dnsSANs) > 0 {
template.Subject.CommonName = dnsSANs[0]
}

certBytes, err := x509.CreateCertificate(
rand.Reader, template, ca.Cert, pubKey, ca.Signer,
)
Expand Down
13 changes: 10 additions & 3 deletions lib/auth/machineid/machineidv1/workload_identity_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ func TestWorkloadIdentityService_SignX509SVIDs(t *testing.T) {
PublicKey: pubBytes,
Hint: "llamas",
Ttl: durationpb.New(30 * time.Minute),
DnsSans: []string{"foo.alpha.example.com"},
IpSans: []string{"10.42.42.42"},
DnsSans: []string{
"foo.alpha.example.com",
"bar.alpha.example.com",
},
IpSans: []string{"10.42.42.42"},
},
},
},
Expand Down Expand Up @@ -143,8 +146,9 @@ func TestWorkloadIdentityService_SignX509SVIDs(t *testing.T) {
require.Equal(t, wantSPIFFEID, cert.URIs[0].String())
// 2: An X.509 SVID MAY contain any number of other SAN field types, including DNS SANs.
// Here we validate against what was requested
require.Len(t, cert.DNSNames, 1)
require.Len(t, cert.DNSNames, 2)
require.Equal(t, "foo.alpha.example.com", cert.DNSNames[0])
require.Equal(t, "bar.alpha.example.com", cert.DNSNames[1])
require.Len(t, cert.IPAddresses, 1)
require.Equal(t, "10.42.42.42", cert.IPAddresses[0].String())
// 4.1: leaf certificates MUST set the cA field to false.
Expand All @@ -160,6 +164,9 @@ func TestWorkloadIdentityService_SignX509SVIDs(t *testing.T) {
// 4.4: When included, fields id-kp-serverAuth and id-kp-clientAuth MUST be set.
require.Contains(t, cert.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
require.Contains(t, cert.ExtKeyUsage, x509.ExtKeyUsageClientAuth)

// Check that the Common Name is set to the first DNS SAN.
require.Equal(t, "foo.alpha.example.com", cert.Subject.CommonName)
},
},
{
Expand Down