详谈kerberos
详谈kerberos
背景
依客户需求,产品部署需使用客户的cdh版且通过kerberos授权的hdfs。目前产品中已知需要配对的服务为ftpserver,故提前测试更改hdfs-over-ftp项目。
kerberos
首先介绍kerberos作为授权服务的基本概念、流程、原理。
基本概念
1)Realm:Kerberos所管理的一个领域或范围,称之为一个Realm。
2)principal:Kerberos所管理的一个用户或者一个服务,可以理解为Kerberos中保存的一个账号,其格式通常如下:primary/instance\@realm
3)keytab:Kerberos中的用户认证,可通过密码或者密钥文件证明身份,keytab指密钥文件。
认证原理
KDC(Key Distribute Center):密钥分发中心,负责存储用户信息,管理发放票据,提供AS和TGS两个服务。
AS(authentication service):为client生成TGT的服务。
TGS(Ticket Granting Service):为client生成某个服务的ticket 。
AD(account database):存储所有client的白名单,只有存在于白名单的client才能顺利申请到TGT。
TGT(ticket granting tickets):验证ticket的凭证,临时票据。
第一二步:
客户端向kerberos申请某个服务的权限,并携带client自身的host、username的身份信息,kerberos得到消息之后,首先通过AD查找是否是白名单用户,若是则从AD中继续查找该用户的公钥hash,加密随机生成的Sessionkey,和通过kdc hash加密的TGT一起返回。该过程就是AS服务完成的。
第三四步:
首先客户端得到AS给的通过公钥加密的sessionkey和TGT。然后客户端解密得到sessionkey,通过sessiokey加密自己的客户端信息和时间戳,并和原封不动的TGT以及要访问服务的server info一起返回给kerberos。kerberos收到消息后,先解密通过KDC hash加密的TGT,得到sessionkey和客户端的身份信息,然后通过sessionkey去解密客户端的信息和时间戳,由此比较前后两个客户端信息是否一致,且时间戳是否失效。若均满足,则从AD中查找server info中计算机名对应的hash去加密ticket,和通过session key加密随机生成的Server Seesion Key 一起返回给客户端,其中ticket的内容包含Server Seesion Key,client info,ticket的到期时间。以上是通过TGS服务完成的。
第五步:
首先客户端得到TGS给的通过server hash加密的ticket和通过session key加密的Server Session Key,然后解密得到Server Session Key。接着客户端拿着原封不动的ticket和用Server Session Key加密的客户端信息和时间戳去访问最终要请求的Server。server得到消息后去解密ticket得到客户端信息,Server Seesion Key和ticket的到期时间,然后拿着Server Seesion Key去解密客户端信息和时间戳,比较前后的客户端信息是否一致以及对应的时间戳是否到期,若均满足,则client可以真正的访问server。
总结:
以上步骤可简化为:
client向kerberos服务请求某个server的权限,kerberos首先通过AS查找AD判断该client是否存在于白名单,若是则返回TGT。
client拿着刚拿到的TGT,继续请求kerberos。kerberos拿到TGT,通过TGS判断client是否拥有这个权限,若有则返回ticket
client拿到ticket后,就可以访问server。一个ticket只是针对一个server,其他server需要向kerberos申请。
每次client得到的都是两份消息,一份是可解密,一份是不可解密并且原封不动返回,可解密的消息说明kerberos拥有和client一样的公钥对其进行了加密,从而认证了请求的kerberos是安全的。然后kerberos每次解密两个消息得到两份client信息,比较这两份消息确认client是否是安全的。以此达到双向认证。
任务:
代码API方式接入Kerberos认证(ftpoverhdfs, data-service)
spark适配集成kerberos。
本地适配流程
运行docker镜像
一个安装了 MIT KDC,另一个安装了单节点 kerberized Hadoop 集群。
核心配置
Kdc配置文件/var/kerberos/krb5kdc/kdc.conf
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
[realms]
EXAMPLE.COM = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab #admin的keytab地址
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal #支持的加密算法
}
client配置文件/etc/krb5.conf
#日志目录
[logging]
default = FILE:/var/log/kerberos/krb5libs.log
kdc = FILE:/var/log/kerberos/krb5kdc.log
admin_server = FILE:/var/log/kerberos/kadmind.log
[libdefaults]
default_realm = EXAMPLE.COM #默认的realm
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h #ticket的超时时间
renew_lifetime = 7d
forwardable = true
udp_preference_limit = 1 #禁用udp协议使用tcp
[realms]
EXAMPLE.COM = {
kdc = kdc.kerberos.com #kdc的host
admin_server = kdc.kerberos.com #admin_server主要负责操作AD数据库
}
[domain_realm] #主机名到realm的映射
.kdc.kerberos.com = EXAMPLE.COM
kdc.kerberos.com = EXAMPLE.COM
core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop.docker.com:9000</value>
</property>
<!-- 启用Hadoop集群Kerberos安全认证 -->
<property>
<name>hadoop.security.authentication</name>
<value>kerberos</value>
<description> Set the authentication for the cluster.
Valid values are: simple or kerberos.</description>
</property>
<!-- 启用Hadoop集群授权管理 -->
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
<description>Enable authorization for different protocols.</description>
</property>
<!-- Kerberos主体到系统用户的具体映射规则 -->
<property>
<name>hadoop.security.auth_to_local</name>
<value>
RULE:[2:$1@$0]([jt]t@.*EXAMPLE.COM)s/.*/root/
RULE:[2:$1@$0]([nd]n@.*EXAMPLE.COM)s/.*/root/
RULE:[2:$1@$0](hm@.*EXAMPLE.COM)s/.*/root/
RULE:[2:$1@$0](rs@.*EXAMPLE.COM)s/.*/root/
RULE:[2:$1@$0](rm@.*EXAMPLE.COM)s/.*/root/
RULE:[2:$1@$0](jhs@.*EXAMPLE.COM)s/.*/root/
DEFAULT
</value>
<description>The mapping from kerberos principal names
to local OS user names.</description>
</property>
<property>
<name>hadoop.ssl.require.client.cert</name>
<value>false</value>
</property>
<property>
<name>hadoop.ssl.hostname.verifier</name>
<value>DEFAULT</value>
</property>
<property>
<name>hadoop.ssl.keystores.factory.class</name>
<value>org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory</value>
</property>
<property>
<name>hadoop.ssl.server.conf</name>
<value>ssl-server.xml</value>
</property>
<property>
<name>hadoop.ssl.client.conf</name>
<value>ssl-client.xml</value>
</property>
<property>
<name>hadoop.rpc.protection</name>
<value>privacy</value>
</property>
</configuration>
hdfs-site.xml 部分kerberos相关的关键配置
<!-- NameNode服务的Kerberos主体,_HOST会自动解析为服务所在的主机名 -->
<property>
<name>dfs.namenode.kerberos.principal</name>
<value>nn/_HOST@EXAMPLE.COM</value>
<description> Kerberos principal name for the NameNode </description>
</property>
<!-- NameNode服务的Kerberos密钥文件路径 -->
<property>
<name>dfs.namenode.keytab.file</name>
<value>/etc/security/keytabs/nn.service.keytab</value>
<description>
Combined keytab file containing the namenode service and host
principals.
</description>
</property>
<!-- 配置NameNode Web UI 使用HTTPS协议 -->
<property>
<name>dfs.http.policy</name>
<value>HTTPS_ONLY</value>
</property>
<!-- 配置DataNode数据传输保护策略为仅认证模式 -->
<property>
<name>dfs.data.transfer.protection</name>
<value>authentication</value>
</property>
获取相关配置
为root用户创建keytab:在hadoop集群执行kadmin -padmin/admin -wadmin -q"xst -k /root.keytab root"
或者在kdc环境执行 kadmin.local -q" xst -k /root.keytab root"
本机执行docker cp 将docker环境中的core-site.xml、hdfs-site.xml、krb5.conf、root.keytab复制到hdfs-over-ftp的resources目录中
修改hdfs-over-ftp代码
核心代码
UserGroupInformation.setConfiguration(conf);
UserGroupInformation.loginUserFromKeytab(KrbUser, KrbKey);
本地测试
修改项目中配置文件
访问docker中的环境需通过端口映射暴露出来的端口连接,修改core-site.xml、hdfs-site.xml中所有的 host为 hadoop.docker.com的 改为localhost。将krb5.conf中kdc服务的host kdc.kerberos.com改为localhost。将hdfs-over-ftp.properties的hdfs-uri改为目标hdfs的urhdfs-uri = hdfs://127.0.0.1:9000/tmp/
运行ftpserver
通过FileZilla访问ftp,账号通过项目中users.properties配置,账号admin密码admin。
创建目录
验证是否成功
进入hadoop集群运行kinit -kt ./root.keytab root 通过root用户使用keytab获取ticket
查看目录是否创建
目录成功创建