From 8190f7ff0cb29e4fca0c06a8f7ef370d6b3c6dd7 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Tue, 3 May 2022 10:51:16 -0600 Subject: [PATCH] Desktop access: add teleport.dev/ou label Automatically label discovered desktops with the LDAP organizational unit they belong to. This expands the ability to define RBAC rules based on OU. Since the organizationalUnit attribute is often unspecified, we compute the OU by trimming the CN from the full DN. Updates #12326 --- lib/srv/desktop/discovery.go | 28 +++++++++++++++++++++------- lib/srv/desktop/discovery_test.go | 11 +++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lib/srv/desktop/discovery.go b/lib/srv/desktop/discovery.go index d89a3135a79c1..c73c4f9361aa2 100644 --- a/lib/srv/desktop/discovery.go +++ b/lib/srv/desktop/discovery.go @@ -34,6 +34,8 @@ import ( // see: https://docs.microsoft.com/en-us/windows/win32/adschema/c-computer#windows-server-2012-attributes var computerAttribtes = []string{ attrName, + attrCommonName, + attrDistinguishedName, attrDNSHostName, attrObjectGUID, attrOS, @@ -53,12 +55,14 @@ const ( writableDomainControllerGroupID = "516" readOnlyDomainControllerGroupID = "521" - attrName = "name" - attrDNSHostName = "dNSHostName" // unusual capitalization is correct - attrObjectGUID = "objectGUID" - attrOS = "operatingSystem" - attrOSVersion = "operatingSystemVersion" - attrPrimaryGroupID = "primaryGroupID" + attrName = "name" + attrCommonName = "cn" + attrDistinguishedName = "distinguishedName" + attrDNSHostName = "dNSHostName" // unusual capitalization is correct + attrObjectGUID = "objectGUID" + attrOS = "operatingSystem" + attrOSVersion = "operatingSystemVersion" + attrPrimaryGroupID = "primaryGroupID" ) // startDesktopDiscovery starts fetching desktops from LDAP, periodically @@ -177,11 +181,21 @@ func (s *WindowsService) deleteDesktop(ctx context.Context, r types.ResourceWith } func applyLabelsFromLDAP(entry *ldap.Entry, labels map[string]string) { + labels[types.OriginLabel] = types.OriginDynamic + labels[types.TeleportNamespace+"/dns_host_name"] = entry.GetAttributeValue(attrDNSHostName) labels[types.TeleportNamespace+"/computer_name"] = entry.GetAttributeValue(attrName) labels[types.TeleportNamespace+"/os"] = entry.GetAttributeValue(attrOS) labels[types.TeleportNamespace+"/os_version"] = entry.GetAttributeValue(attrOSVersion) - labels[types.OriginLabel] = types.OriginDynamic + + dn := entry.GetAttributeValue(attrDistinguishedName) + cn := entry.GetAttributeValue(attrCommonName) + + if len(dn) > 0 && len(cn) > 0 { + ou := strings.TrimPrefix(dn, "CN="+cn+",") + labels[types.TeleportNamespace+"/ou"] = ou + } + switch entry.GetAttributeValue(attrPrimaryGroupID) { case writableDomainControllerGroupID, readOnlyDomainControllerGroupID: labels[types.TeleportNamespace+"/is_domain_controller"] = "true" diff --git a/lib/srv/desktop/discovery_test.go b/lib/srv/desktop/discovery_test.go index 6ad26a602a197..f0491024b17f3 100644 --- a/lib/srv/desktop/discovery_test.go +++ b/lib/srv/desktop/discovery_test.go @@ -63,10 +63,12 @@ func TestDiscoveryLDAPFilter(t *testing.T) { func TestAppliesLDAPLabels(t *testing.T) { l := make(map[string]string) entry := ldap.NewEntry("CN=test,DC=example,DC=com", map[string][]string{ - attrDNSHostName: {"foo.example.com"}, - attrName: {"foo"}, - attrOS: {"Windows Server"}, - attrOSVersion: {"6.1"}, + attrDNSHostName: {"foo.example.com"}, + attrName: {"foo"}, + attrOS: {"Windows Server"}, + attrOSVersion: {"6.1"}, + attrDistinguishedName: {"CN=foo,OU=IT,DC=goteleport,DC=com"}, + attrCommonName: {"foo"}, }) applyLabelsFromLDAP(entry, l) @@ -75,6 +77,7 @@ func TestAppliesLDAPLabels(t *testing.T) { require.Equal(t, l[types.TeleportNamespace+"/computer_name"], "foo") require.Equal(t, l[types.TeleportNamespace+"/os"], "Windows Server") require.Equal(t, l[types.TeleportNamespace+"/os_version"], "6.1") + require.Equal(t, l[types.TeleportNamespace+"/ou"], "OU=IT,DC=goteleport,DC=com") } func TestLabelsDomainControllers(t *testing.T) {