diff --git a/lib/auth/windows/certificate_authority.go b/lib/auth/windows/certificate_authority.go index 3067200f10e8f..6f4d1cc43c46e 100644 --- a/lib/auth/windows/certificate_authority.go +++ b/lib/auth/windows/certificate_authority.go @@ -59,8 +59,9 @@ func (c *CertificateStoreClient) Update(ctx context.Context) error { // have to do it here. // // TODO(zmb3): support multiple CA certs per cluster (such as with HSMs). + caType := types.UserCA ca, err := c.cfg.AccessPoint.GetCertAuthority(ctx, types.CertAuthID{ - Type: types.UserCA, + Type: caType, DomainName: c.cfg.ClusterName, }, false) if err != nil { @@ -90,7 +91,7 @@ func (c *CertificateStoreClient) Update(ctx context.Context) error { if err := c.updateCAInNTAuthStore(ctx, caDER); err != nil { return trace.Wrap(err, "updating NTAuth store over LDAP: %v", err) } - if err := c.updateCRL(ctx, crlDER); err != nil { + if err := c.updateCRL(ctx, crlDER, caType); err != nil { return trace.Wrap(err, "updating CRL over LDAP: %v", err) } return nil @@ -156,7 +157,7 @@ func (c *CertificateStoreClient) updateCAInNTAuthStore(ctx context.Context, caDE return nil } -func (c *CertificateStoreClient) updateCRL(ctx context.Context, crlDER []byte) error { +func (c *CertificateStoreClient) updateCRL(ctx context.Context, crlDER []byte, caType types.CertAuthType) error { // Publish the CRL for current cluster CA. For trusted clusters, their // respective windows_desktop_services will publish CRLs of their CAs so we // don't have to do it here. @@ -165,12 +166,13 @@ func (c *CertificateStoreClient) updateCRL(ctx context.Context, crlDER []byte) e // another nested container with the CA name, I think, and then multiple // separate CRL objects in that container. // - // We name our parent container "Teleport" and the CRL object is named - // after the Teleport cluster name. For example, CRL for cluster "prod" - // will be placed at: + // We name our parent container based on the CA type (for example, for User + // CA, it is called "Teleport"), and the CRL object is named after the + // Teleport cluster name. So, for instance, CRL for cluster "prod" and User + // CA will be placed at: // ... > CDP > Teleport > prod - containerDN := crlContainerDN(c.cfg.LDAPConfig) - crlDN := crlDN(c.cfg.ClusterName, c.cfg.LDAPConfig) + containerDN := crlContainerDN(c.cfg.LDAPConfig, caType) + crlDN := crlDN(c.cfg.ClusterName, c.cfg.LDAPConfig, caType) // Create the parent container. if err := c.cfg.LC.CreateContainer(containerDN); err != nil { diff --git a/lib/auth/windows/ldap.go b/lib/auth/windows/ldap.go index 1f328db4e1c6b..f896e188130f2 100644 --- a/lib/auth/windows/ldap.go +++ b/lib/auth/windows/ldap.go @@ -24,6 +24,8 @@ import ( "github.com/go-ldap/ldap/v3" "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/types" ) // LDAPConfig contains parameters for connecting to an LDAP server. @@ -276,10 +278,22 @@ func CombineLDAPFilters(filters []string) string { return "(&" + strings.Join(filters, "") + ")" } -func crlContainerDN(config LDAPConfig) string { - return "CN=Teleport,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration," + config.DomainDN() +func crlContainerDN(config LDAPConfig, caType types.CertAuthType) string { + return fmt.Sprintf("CN=%s,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,%s", crlKeyName(caType), config.DomainDN()) +} + +func crlDN(clusterName string, config LDAPConfig, caType types.CertAuthType) string { + return "CN=" + clusterName + "," + crlContainerDN(config, caType) } -func crlDN(clusterName string, config LDAPConfig) string { - return "CN=" + clusterName + "," + crlContainerDN(config) +// crlKeyName returns the appropriate LDAP key given the CA type. +// +// Note: UserCA must use "Teleport" to keep backwards compatibility. +func crlKeyName(caType types.CertAuthType) string { + switch caType { + case types.DatabaseCA: + return "TeleportDB" + default: + return "Teleport" + } } diff --git a/lib/auth/windows/windows.go b/lib/auth/windows/windows.go index 0f9cbf90fb63f..f8f7dea91b319 100644 --- a/lib/auth/windows/windows.go +++ b/lib/auth/windows/windows.go @@ -107,7 +107,7 @@ func getCertRequest(req *GenerateCredentialsRequest) (*certRequest, error) { // CRLs in it. Each service can also handle RDP connections for a different // domain, with the assumption that some other windows_desktop_service // published a CRL there. - crlDN := crlDN(req.ClusterName, req.LDAPConfig) + crlDN := crlDN(req.ClusterName, req.LDAPConfig, req.CAType) return &certRequest{csrPEM: csrPEM, crlEndpoint: fmt.Sprintf("ldap:///%s?certificateRevocationList?base?objectClass=cRLDistributionPoint", crlDN), keyDER: keyDER}, nil } @@ -142,6 +142,9 @@ type GenerateCredentialsRequest struct { LDAPConfig LDAPConfig // AuthClient is the windows AuthInterface AuthClient AuthInterface + // CAType is the certificate authority type used to generate the certificate. + // This is used to proper generate the CRL LDAP path. + CAType types.CertAuthType } // GenerateWindowsDesktopCredentials generates a private key / certificate pair for the given diff --git a/lib/auth/windows/windows_test.go b/lib/auth/windows/windows_test.go index 7104c74547058..ed2c1c7ca238f 100644 --- a/lib/auth/windows/windows_test.go +++ b/lib/auth/windows/windows_test.go @@ -139,23 +139,39 @@ func TestGenerateCredentials(t *testing.T) { func TestCRLDN(t *testing.T) { for _, test := range []struct { + name string clusterName string crlDN string + caType types.CertAuthType }{ { + name: "test cluster name", clusterName: "test", crlDN: "CN=test,CN=Teleport,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=test,DC=goteleport,DC=com", }, { + name: "full cluster name", clusterName: "cluster.goteleport.com", crlDN: "CN=cluster.goteleport.com,CN=Teleport,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=test,DC=goteleport,DC=com", }, + { + name: "database CA", + clusterName: "cluster.goteleport.com", + caType: types.DatabaseCA, + crlDN: "CN=cluster.goteleport.com,CN=TeleportDB,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=test,DC=goteleport,DC=com", + }, + { + name: "user CA", + clusterName: "cluster.goteleport.com", + caType: types.UserCA, + crlDN: "CN=cluster.goteleport.com,CN=Teleport,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=test,DC=goteleport,DC=com", + }, } { - t.Run(test.clusterName, func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { cfg := LDAPConfig{ Domain: "test.goteleport.com", } - require.Equal(t, test.crlDN, crlDN(test.clusterName, cfg)) + require.Equal(t, test.crlDN, crlDN(test.clusterName, cfg, test.caType)) }) } } diff --git a/lib/srv/db/sqlserver/kinit/kinit.go b/lib/srv/db/sqlserver/kinit/kinit.go index b7fc77bc6c0b5..a0a80264d4060 100644 --- a/lib/srv/db/sqlserver/kinit/kinit.go +++ b/lib/srv/db/sqlserver/kinit/kinit.go @@ -31,6 +31,7 @@ import ( "github.com/jcmturner/gokrb5/v8/credentials" "github.com/sirupsen/logrus" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth/windows" ) @@ -208,6 +209,7 @@ func (d *DBCertGetter) GetCertificateBytes(ctx context.Context) (*WindowsCAAndKe } certPEM, keyPEM, caCerts, err := windows.CertKeyPEM(ctx, &windows.GenerateCredentialsRequest{ + CAType: types.DatabaseCA, Username: d.UserName, Domain: d.RealmName, TTL: certTTL, diff --git a/lib/srv/desktop/windows_server.go b/lib/srv/desktop/windows_server.go index c17b854c86f80..10b10e28530de 100644 --- a/lib/srv/desktop/windows_server.go +++ b/lib/srv/desktop/windows_server.go @@ -1140,6 +1140,7 @@ func (s *WindowsService) generateUserCert(ctx context.Context, username string, // https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration func (s *WindowsService) generateCredentials(ctx context.Context, username, domain string, ttl time.Duration, activeDirectorySID string) (certDER, keyDER []byte, err error) { return windows.GenerateWindowsDesktopCredentials(ctx, &windows.GenerateCredentialsRequest{ + CAType: types.UserCA, Username: username, Domain: domain, TTL: ttl, diff --git a/tool/tctl/common/auth_command.go b/tool/tctl/common/auth_command.go index 93696b0eed27f..785c55aaeeac8 100644 --- a/tool/tctl/common/auth_command.go +++ b/tool/tctl/common/auth_command.go @@ -292,6 +292,7 @@ func (a *AuthCommand) generateWindowsCert(ctx context.Context, clusterAPI auth.C } certDER, _, err := windows.GenerateWindowsDesktopCredentials(ctx, &windows.GenerateCredentialsRequest{ + CAType: types.UserCA, Username: a.windowsUser, Domain: a.windowsDomain, ActiveDirectorySID: a.windowsSID,