为了对接上 LDAP,可谓是煞费苦心。网上能找到的对接上 LDAP 的方案,都得在 LDAP 上自定义一个 token 的 schema,然后将在 k8s 集群上已创建好的 service account 的 token 跟 LDAP 绑定起来。这样,在进行 webhook 认证时,便能带着 token 去 LDAP 上进行认证。例如这里所描述的:Kubernetes-LDAP-Authentication。另外,还有些是对接上 OpenID connect token,然后再这些服务提供系统那里对接上 LDAP,例如:Step by step guide to integrate LDAP with Kubernetes。这种办法又觉得太复杂,麻烦了。
使用 webhook 进行 LDAP 认证,平常的用户名密码认证行不通的主要原因是 k8s apiserver 进行认证请求时,带过来只有用户名和 bearer token,没有密码。为了能够使用用户名密码和 bearer token 去 ldap 进行认证,这里做了些 trick 的东西。
如下图所示,客户端通过 nginx 访问 apiserver,在 nginx 一层里,配置了 auth-request,将 basic auth 的请求发送给后端的 ldap 认证代理,ldap 认证代理认证通过后,会随机生成一段 bearer token,并通过相应头部告诉给 nginx。nginx 收到这个响应头部后,就配置使用 bearer token 访问 apiserver。也就是说,请求到达 apiserver 的时候,使用的是 bearer token 这种方式进行认证。apiserver 收到请求后,会同时出发内部认证机制和 webhook 认证机制,webhook 认证在这里同样配置了 nginx 的 ldap 认证代理。由于 ldap 认证代理保存了所有经过 ldap 认证的用户的 bearer token,因此便可以通过 apiserver 带过来的 bearer token 成功认证用户!
如果需要更细粒度的权限控制,可以在 ldap 认证代理那里,接入公司的一些内部系统,根据不同的用户,返回不同的用户组即可。
附 nginx 关键配置
location / {
auth_request /auth-proxy;
# 这里获取从ldap认证服务返回来的bearer token
auth_request_set $bearer_token $upstream_http_x_token;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 设置bearer token认证
proxy_set_header Authorization "Bearer $bearer_token";
proxy_ssl_verify off;
proxy_ssl_session_reuse on;
proxy_pass https://dashboard-k8s;
}
location = /auth-proxy {
internal;
proxy_pass http://k8s-ldap-backend/ldap-auth;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_cache ldap_auth_cache;
proxy_cache_valid 200 30m;
proxy_cache_key "$http_authorization$cookie_nginxauth";
}