详谈kerberos

Published: by Creative Commons Licence

详谈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镜像

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

查看目录是否创建

目录成功创建