更多精彩内容,请关注微信公众号:后端技术小屋

原文:https://altinity.com/blog/integrating-clickhouse-with-ldap-part-two 作者:Vitaliy Zakaznikov

之前我们发布了Clickhouse与LDAP集成(一),这是确保Clickhouse帐户安全的重要一步。我们研究了如何将使用LDAP服务器对Clickhouse用户进行认证,而非在 XML配置文件中手动指定用户名密码。

在本文中,我们将继续研究如何将ClickHouse和LDAP集成使用。我们将讨论如何将二者的集成提升到一个新的水平。我们将LDAP服务器作为Clickhouse的外部用户目录,通过在Clickhouse中添加LDAP相关配置,Clickhouse会自动从LDAP中查找用户并认证,这样我们就避免了在ClickHouse中直接定义用户。接下是的内容讲述如何将LDAP的用户组映射到Clickhouse RBAC中的角色,以动态控制所有LDAP定义的用户的访问管理。

这非常有趣,所以让我们开始吧!

准备工作

我们将使用与第一部分(Clickhouse与LDAP集成(一))中完全相同的配置,因此如果您想继续,请设置您的测试环境,然后添加LDAP配置并检查配置是否生效。

LDAP用户角色

在我们配置作为Clickhouse外部目录的LDAP之前,我们需要在Clickhouse中定义一个或多个绑定到LDAP用户的RBAC角色。否则LDAP用户将没有任何权限。

现在为LDAP用户创建一个RBAC角色。

docker-compose exec clickhouse1 bash -c 'clickhouse client -q "CREATE ROLE ldap_user_role"'

检查该角色是否已创建。

docker-compose exec clickhouse1 bash -c 'clickhouse client -q "SHOW ROLES"'
ldap_user_role

为了方便测试,现在我们将所有权限授予ldap_user_role这个角色。

docker-compose exec clickhouse1 bash -c 'clickhouse client -q "GRANT ALL ON *.* TO ldap_user_role"'

检查权限是否设置成功

docker-compose exec clickhouse1 bash -c 'clickhouse client -q "SHOW ACCESS" | grep ldap_user_role'
CREATE ROLE ldap_user_role
GRANT ALL ON *.* TO ldap_user_role

看起来正常。现在我们继续下一部分:使用LDAP外部用户目录

使用LDAP外部用户目录

在启动docker-compose环境和Clickhouse中配置好LDAP之后,修改config.xml中的 <user_directories>中的配置,ClickHouse就可以使用LDAP服务器作为外部用户目录了。

但是在最佳实践中,我们不会config.xml直接修改,而是将单独的配置文件添加到/etc/clickhouse-server/config.d目录下。

请注意,如果您刚刚完成了第一部分(Clickhouse与LDAP集成(一))的工作,那么您需要删除ldapuser.xml文件,避免它与我们设置的LDAP外部目录冲突

docker-compose exec clickhouse1 bash -c 'rm -rf /etc/clickhouse-server/users.d/ldapuser.xml'

然后确保我们无法使用ldapuser账户登录Clickhouse

docker-compose exec clickhouse1 bash -c 'clickhouse client -n --user "ldapuser" --password "ldapuser" -q "SELECT user()"'

结果符合预期,登录失败。

Code: 516. DB::Exception: Received from localhost:9000. DB::Exception: ldapuser: Authentication failed: password is incorrect or there is no user with such name.

现在我们添加LDAP外部用户目录。

docker-compose exec clickhouse1 bash -c 'cat <<HEREDOC > /etc/clickhouse-server/config.d/ldap_external_user_directory.xml
<?xml version="1.0" encoding="utf-8"?>
<yandex>
    <!--LDAP external user directory da296a1c-7874-11eb-998e-ddba30bbed5d -->
    <user_directories>
        <ldap>
            <server>openldap1</server>
            <roles>
                <ldap_user_role/>
            </roles>
        </ldap>
    </user_directories>
</yandex>
HEREDOC'

要注意,在配置中,我们指定了要分配给所有LDAP用户的角色。这里我们只定义了一个ldap_user_role角色,但您可以根据需要添加多个角色。这些角色将始终被分配给LDAP用户,并且在Clickhouse认证时必须存在。如果其中某个角色不存在,则在Clickhouse添加该角色角色之前,LDAP用户将无法通过认证,并且您将收到类似这样的报错:

Code: 516. DB::Exception: Received from localhost:9000. DB::Exception: ldapuser: Authentication failed: password is incorrect or there is no user with such name. 

现在重新启动ClickHouse使得上述配置生效。注意:添加或删除外部用户目录需要重新启动Clickhouse

docker-compose restart clickhouse1
Restarting docker-compose_clickhouse1_1 ... done

检查配置是否已经被合并

docker-compose exec clickhouse1 bash -c 'cat /var/lib/clickhouse/preprocessed_configs/config.xml | grep da296a1c-7874-11eb-998e-ddba30bbed5d'
    <!--LDAP external user directory da296a1c-7874-11eb-998e-ddba30bbed5d -->

在openldap1容器中,用户ldapuser的密码设置为与用户名相同。现在尝试使用此用户登录 ClickHouse。

docker-compose exec clickhouse1 bash -c 'clickhouse client -n --user "ldapuser" --password "ldapuser" -q "SELECT user()"'
ldapuser

生效了!我们可以使用LDAP中定义的用户登录Clickhouse。现在我们动态地将另一个用户添加到LDAP用户目录中, 并测试不修改任何Clickhouse配置的情况下该用户是否可通过认证

docker-compose exec openldap1 bash -c 'echo -e "dn: cn=new_ldap_user,ou=users,dc=company,dc=com
cn: new_ldap_user
gidnumber: 501
givenname: John
homedirectory: /home/users
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: User
uid: new_ldap_user
uidnumber: 2000
userpassword: new_ldap_user" | ldapadd -x -H ldap://localhost -D "cn=admin,dc=company,dc=com" -w admin'

您应该会看到提示,确认已将新用户条目添加到 LDAP。

adding new entry "cn=new_ldap_user,ou=users,dc=company,dc=com"

现在我们尝试使用这个新的LDAP用户登录。

docker-compose exec clickhouse1 bash -c 'clickhouse-client -n --user "new_ldap_user" --password "new_ldap_user" -q "SELECT user()"'
new_ldap_user

它起作用了,我们可以使用动态添加的LDAP用户成功登陆Clickhouse。现在我们从LDAP中动态删除新用户。

docker-compose exec openldap1 bash -c 'ldapdelete -x -H ldap://localhost -D "cn=admin,dc=company,dc=com" -w admin "cn=new_ldap_user,ou=users,dc=company,dc=com"'

尝试使用已删除的LDAP用户登录,您应该会看到登陆失败。

docker-compose exec clickhouse1 bash -c 'clickhouse-client -n --user "new_ldap_user" --password "new_ldap_user" -q "SELECT user()"'
Code: 516. DB::Exception: Received from localhost:9000. DB::Exception: new_ldap_user: Authentication failed: password is incorrect or there is no user with such name. 

LDAP用户组到RBAC角色的映射

我们之前提到过,当LDAP用户登录时,他们会被绑定在LDAP外部用户目录配置中指定的角色。在我们的例子中,我们只分配了一个角色即ldap_user_role.

当我们尝试用ldapuser登录时,让我们看看为这个用户分配了哪些角色:

docker-compose exec clickhouse1 bash -c 'clickhouse-client -n --user "ldapuser" --password "ldapuser" -q "SHOW ROLES"'
ldap_user_role

如您所见,ldapuser确实被分配了唯一的角色ldap_user_role。在不修改Clickhouse配置的下,您不能向LDAP用户添加任何其他角色,而只能变更配置中指定角色的权限。配置文件中静态分配的角色在某些场景下够用,但鉴于我们使用的是 LDAP,我们不仅要使用LDAP 管理用户,还应当用它来管理用户的角色。通常LDAP用户属于一个或多个LDAP组,因此根据 LDAP用户所属的LDAP组分配RBAC角色是一个很好的选项。事实上,Clickhouse中的角色映射正是这样做的。

我们可以在LDAP外部用户目录配置中的<role_mapping>部分启动角色映射。

docker-compose exec clickhouse1 bash -c 'cat <<HEREDOC > /etc/clickhouse-server/config.d/ldap_external_user_directory.xml
<?xml version="1.0" encoding="utf-8"?>
<yandex>
    <!--LDAP external user directory da296a1c-7874-11eb-998e-ddba30bbed5d -->
    <user_directories>
        <ldap>
            <server>openldap1</server>
            <roles>
                <ldap_user_role/>
            </roles>
            <role_mapping>
                <base_dn>ou=groups,dc=example,dc=com</base_dn>
                <scope>subtree</scope>
                <search_filter>(&amp;(objectClass=groupOfNames)(member={bind_dn}))</search_filter>
                <attribute>cn</attribute>
                <prefix>clickhouse_</prefix>
            </role_mapping>
        </ldap>
    </user_directories>
</yandex>
HEREDOC'

如上所示,<role_mapping>部分定义了根据LDAP专有名称执行LDAP搜索的参数。在上面的配置中,我们要查找具有基本专有名称:ou=groups,dc=example,dc=com的所有对象,搜索范围为subtree,搜索过滤器设置为(&(objectClass=groupOfNames)(member={bind_dn})),我们将映射到Clickhouse RBAC角色的LDAP节点的属性名称是cn, 属性值必须以clickhouse_开头

这有点复杂,但本质上通过这个配置,我们将分配给LDAP用户的LDAP组名称映射到以clickhouse_前缀开头的RBAC角色。如果您对这些选项感到困惑,那么最好与您的 LDAP 管理员讨论,他们应该能够为您提供正确的配置。ClickHouse使用上述选项来执行LDAP搜索,正如您所见,它们提供了查找和使用不同对象及其属性以映射到RBAC角色的灵活性

我们还必须注意,在我们的XML配置中,&符号需要转义。幸运的是,XML只有少数几个字符需要转义,因此很容易搞定。这是完整的列表。

" —— &quot;
' —— &apos;
< —— &lt;
> —— &gt;
& —— &amp;

现在让我们重新启动 ClickHouse 服务器并启用角色映射。

docker-compose restart clickhouse1

我们现在添加一个新的LDAP组, 并将用户ldapuser作为该组成员。然后添加一个对应的Clickhouse RBAC角色作为新LDAP组的映射目标。因此我们创建一个LDAP组clickhouse_role1

docker-compose exec openldap1 bash -c 'echo -e "dn: cn=clickhouse_role1,ou=groups,dc=company,dc=com
objectclass: top
objectclass: groupOfUniqueNames
uniquemember: cn=admin,dc=company,dc=com" | ldapadd -x -H ldap://localhost -D "cn=admin,dc=company,dc=com" -w admin'

LDAP提示创建成功

adding new entry "cn=clickhouse_role1,ou=groups,dc=company,dc=com"

现在将ldapuser加入到组clickhouse_role1中

docker-compose exec openldap1 bash -c 'echo -e "dn: cn=clickhouse_role1,ou=groups,dc=company,dc=com
changetype: modify
add: uniquemember
uniquemember: cn=ldapuser,ou=users,dc=company,dc=com" | ldapmodify -x -H ldap://localhost -D "cn=admin,dc=company,dc=com" -w admin'

LDAP提示修改成功

modifying entry "cn=clickhouse_role1,ou=groups,dc=company,dc=com"

使用ldapuser账号登陆Clickhouse并检查它拥有的角色

docker-compose exec clickhouse1 bash -c 'clickhouse-client -n --user "ldapuser" --password "ldapuser" -q "SHOW ROLES"'

内容如下:

ldap_user_role

奇怪, 没有任何改变,我们只看到静态分配的角色。哎呀,我们忘记在Clickhouse中添加RBAC角色clickhouse_role1了。

docker-compose exec clickhouse1 bash -c 'clickhouse client -q "CREATE ROLE clickhouse_role1"'

我们再试一次。

docker-compose exec clickhouse1 bash -c 'clickhouse-client -n --user "ldapuser" --password "ldapuser" -q "SHOW ROLES"'

您应该看到,现在ldapuser有两个角色,静态分配的ldap_user_role和映射的clickhouse_role1。

clickhouse_role1
ldap_user_role

以上就是添加LDAP组到RBAC角色映射关系的全部过程。您可以继续添加更多的LDAP组和 RBAC角色并使用它们。

结论

玩转ClickHouse与LDAP集成很有趣。我们看到,一旦我们将LDAP定义添加到ClickHouse配置中,我们就可以验证现有ClickHouse用户或启用LDAP外部用户目录以使用LDAP完全管理 ClickHouse用户认证。我们还研究了如何为LDAP用户分配静态RBAC角色或如何使用角色映射将LDAP组映射到RBAC角色。

总而言之,我们现在可以不再在XML配置文件中定义密码和用户。在大型组织中,Clickhouse管理员可以将他们的ClickHouse与使用LDAP的其他服务集成。因此,如果您的组织正在使用LDAP,那么请与您的LDAP管理员交谈并开始使用LDAP管理您的所有 ClickHouse用户。您的管理员和安全部门肯定会欣赏这一点。

如果您对ClickHouse安全有更多疑问,请随时通过Altinity与我们联系。我们的团队喜欢研究安全主题,并很乐意为您提供帮助。

推荐阅读

更多精彩内容,请扫码关注微信公众号:后端技术小屋。如果觉得文章对你有帮助的话,请多多分享、转发、在看。