Kerberos协议及Habase相关参数

Kerberos

Kerberos是一种计算机网络认证协议,它允许某实体在非安全网络环境下通信,向另一个实体以一种安全的方式证明自己的身份,协议基于对称密码学,并需要一个值得信赖的第三方(KDC)。
它主要包含:认证服务器(AS)和票据授权服务器(TGS)组成的密钥分发中心(KDC),以及提供特定服务的SS。相关概念描述:

  • AS(Authentication Server)= 认证服务器
  • KDC(Key Distribution Center)= 密钥分发中心
  • TGT(Ticket Granting Ticket)= 授权票据
  • TGS(Ticket Granting Server)= 票据授权服务器
  • SS(Service Server)= 特定服务提供端

KDC持有一个密钥数据库;每个网络实体——无论是客户还是服务器——共享一套只有他自己和KDC知道的密钥。密钥的内容用于证明实体的身份。对于两个实体间的通信,KDC产生一个会话密钥,用来加密他们之间的交互信息。

Kerberos认证流程

image.png
image.png
  1. 客户端认证
  • 客户端将clientID(Principal)以明文消息发送给AS,以代表用户请求服务,密码(keytab)不会发送,AS能够从本地数据库中查询到。
  • AS会查询该用户名是否存在本地数据库,如果存在则使用该用户密码,发送两条加密消息给客户端。
    • Message A: 用户密码加密的会话密钥Client/TGS Session Key 。
    • Message B: 使用TGS加密的TGT,TGT包含了( client ID, client network address, ticket validity period, and the client/TGS session key)。
  • 一旦客户端收到消息A和B,它就会使用密码生成的密钥解密消息A。如果用户输入的密码与AS数据库中的密码不匹配,则无法解密消息A。解密后的会话密钥用于与TGS进行进一步的通信,客户端无法解密消息B,因为它是使用TGS的密钥加密的。此时,客户端具有足够的信息来向TGS进行身份验证。
  1. 服务授权
  • 请求服务时,客户端将以下消息发送到TGS。
    • Message C: 由消息B的TGT和请求的服务的ID组成。
    • Message D: 使用Client/TGS Session Key加密的authenticator (which is composed of the client ID and the timestamp)。
  • 收到消息C和消息D后,TGS首先检查KDC数据库中是否存在所需的服务,查找到之后,TGS用自己的密钥解密消息C中的消息B(也就是TGT),从而得到之前生成的Client/TGS Session Key。TGS再用这个Session Key解密消息D得到包含用户ID和时间戳的Authenticator,并对TGT和Authenticator进行验证,验证通过之后返回两条消息:
    • Message E: 由服务端SS加密的Client-to-server ticket(客户端到服务端票据),包含了(Client ID, client network address, validity period and Client/Server Session Key)。
    • Message F:由Client/TGS Session Key加密的Client/Server Session Key
  1. 服务请求
  • 当获得Client/Server Session Key之后,Client就能够使用服务器提供的服务了。Client向指定服务器发出2条消息:
    • Message E: 服务端ss加密的Client-to-server ticket
    • Message G: 新的Authenticator,包含使用Client/Server Session Key加密的client ID, timestamp。
  • 服务端解密消息E进而获得Client/Server Session Key,再用这个Client/Server Session Key解密消息G得到Authenticator,同TGS一样对Ticket和Authenticator进行验证,验证通过则服务器将以下消息发送给客户端,以确认其真实身份和接收客户端请求。
    • Message H: 通过Client/Server Session Key加密的,在客户的身份验证器中找到的时间戳。
  • 客户端使用Client/Server Session Key解密确认(消息H),并检查时间戳是否正确。如果正确,则客户端可以信任服务器并可以开始向服务器发出服务请求。
  • 服务器向客户端提供请求的服务。

kdc集群:

安装包

  • krb5-server:Kerberos服务端程序,KDC所在节点。
  • krb5-workstation: 包含一些基本Kerberos程序,比如(kinit, klist, kdestroy,kpasswd),使用Kerberos的所有节点都应该部署。
  • krb5-devel: 包含编译Kerberos程序的头文件和一些类库,所有节点部署。

相关文件:

  • /etc/krb5.conf : 客户端根据该文件中的信息取访问KDC
[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 dns_lookup_realm = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true
 rdns = false
 pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt
 default_realm = EXAMPLE.COM
 default_ccache_name = KEYRING:persistent:%{uid}

[realms]
 EXAMPLE.COM = {
  kdc = k8s01:88
  admin_server = k8s01
 }

[domain_realm]
 .example.com = EXAMPLE.COM
  example.com = EXAMPLE.COM
  • [logging]:表示 server 端的日志的打印位置
  • [libdefaults]:每种连接的默认配置,需要注意以下几个关键的小配置
    • default_realm = EXAMPLE.COM:设置 Kerberos 应用程序的默认领域。如果您有多个领域,只需向 [realms] 节添加其他的语句。
    • ticket_lifetime: 表明凭证生效的时限,一般为24小时。
    • renew_lifetime: 表明凭证最长可以被延期的时限,一般为一个礼拜。当凭证过期之后,对安全认证的服务的后续访问则会失败。
    • clockskew:时钟偏差是不完全符合主机系统时钟的票据时戳的容差,超过此容差将不接受此票据。通常,将时钟扭斜设置为 300 秒(5 分钟)。这意味着从服务器的角度看,票证的时间戳与它的偏差可以是在前后 5 分钟内。
    • udp_preference_limit= 1:禁止使用 udp 可以防止一个 Hadoop 中的错误
  • [realms]:列举使用的 realm。
    • kdc:代表要 kdc 的位置。格式是 机器:端口
    • admin_server:代表 admin 的位置。格式是 机器:端口
    • default_domain:代表默认的域名
  • [appdefaults]:可以设定一些针对特定应用的配置,覆盖默认配置。
  • /var/kerberos/krb5kdc/kdc.conf:kdc的专属配置,可以根据自己的需求修改下kdc数据库的存放目录。
[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
  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
 }
  • /var/kerberos/krb5kdc/kadm5.acl: 权限相关配置
其中前一个*号是通配符,表示像名为“abc/admin”或“xxx/admin”的人都可以使用此工具(远程或本地)
管理kerberos数据库,后一个*跟权限有关,*表示所有权限

*/admin@EXAMPLE.COM *

术语

  • principal :认证的主体,简单来说就是"用户名"。 格式: 服务/主机@域
  • realm:域,类似于namespace的作用,可以看成是principal的一个"容器"或者"空间"。 在kerberos, 大家都约定成俗用大写来命名realm, 比如"EXAMPLE.COM"
  • keytab文件:存储了多个principal的加密密码。

相关指令

创建完KDC数据库以及管理员后,从server端操作KDC.

  • kinit : 登录,测试账户有效性
  • klist
    • klist: 查询登录状态
    • klist -ket /root/maqi1.keytab : 查看keytab记录的主体
  • kdestroy: 退出登录
  • kadmin.local:登录KDC后台,只有安装krb5-server节点才能登录
    • listprincs: 查看用户列表
    • change_password admin/admin@EXAMPLE.COM :修改密码
    • add_principal maqi : 创建用户,输入密码
    • add_principal -randkey maqi1: 随机生成密码
    • get_principal :获取凭证信息
    • delete_principal maqi: 删除用户
    • xst -k admin.keytab -norandkey admin/admin@EXAMPLE.COM :导出用户keytab文件(并且不要修改密码)
    • xst -k maqi1.keytab maqi maqi1 : 导出用户keytab文件,将多个认证主体写入一个keytab文件

Hbase认证参数

同步模式

必填参数:

  • hbase.security.authentication= kerberos
  • hbase.security.authorization = true
  • hbase.master.kerberos.principal = hbase/_HOST@TDH #hbase服务端principal
  • hbase.regionserver.kerberos.principal = hbase/_HOST@TDH
  • 客户端认证参数:clientPrincipal = 'dfs@TDH''
  • 客户端认证参数:clientKeytabFile = 'hdfs.keytab'

选填参数:

  • 环境变量:java.security.krb5.conf = krb5.conf
  • zk是否开启sasl认证:zookeeper.sasl.client = true

FlinkStreamsql使用注意事项:

  • keytab文件通过FlinkShipfile模式已经上传,通过("user.dir")进行全路径拼接
  • 同步方式,zookeeper.znode.parent参数没有hase前缀,而异步则需要hbase前缀需要特别注意。

认证部分代码:

conf = HBaseConfiguration.create();     
conf.set("hbase.zookeeper.quorum", host);
// 注意没有hbase前缀,否则使用默认/hbase路径
conf.set("zookeeper.znode.parent", zkParent);

fillSyncKerberosConfig(conf, regionserverPrincipal, zookeeperSaslClient, securityKrb5Conf);

clientKeytabFile = System.getProperty("user.dir") + File.separator + clientKeytabFile;
clientPrincipal = !StringUtils.isEmpty(clientPrincipal) ? clientPrincipal : regionserverPrincipal;

// 使用客户端clientKeytabFile,clientPrincipal
UserGroupInformation userGroupInformation = HbaseConfigUtils.loginAndReturnUGI(conf, clientPrincipal, clientKeytabFile);
org.apache.hadoop.conf.Configuration finalConf = conf;
conn = userGroupInformation.doAs(new PrivilegedAction<Connection>() {
    @Override
    public Connection run() {
        try {
            // 服务端授权时,取出hbase/host@TDH中的  服务ID和host构建SASLClient
            // RpcClientImpl#Connection
            // HBaseSaslRpcClient
            return ConnectionFactory.createConnection(finalConf);
        } catch (IOException e) {
            LOG.error("Get connection fail with config:{}", finalConf);
            throw new RuntimeException(e);
        }
    }
});

private void fillSyncKerberosConfig(org.apache.hadoop.conf.Configuration config, String regionserverPrincipal,
                                    String zookeeperSaslClient, String securityKrb5Conf) throws IOException {

    config.set("hbase.master.kerberos.principal", regionserverPrincipal);
    config.set("hbase.regionserver.kerberos.principal", regionserverPrincipal);
    config.set("hbase.security.authorization", "true");
    config.set("hbase.security.authentication", "kerberos");

    if (!StringUtils.isEmpty(zookeeperSaslClient)) {
        System.setProperty("zookeeper.sasl.client", zookeeperSaslClient);
    }

    if (!StringUtils.isEmpty(securityKrb5Conf)) {
        // 默认已经上传到container
        String krb5ConfPath = System.getProperty("user.dir") + File.separator + securityKrb5Conf;
        System.setProperty("java.security.krb5.conf", krb5ConfPath);
    }
}

异步模式

必填参数

  • hbase.sasl.clientconfig=Client
  • hbase.security.auth.enable=true
  • hbase.security.authentication=kerberos
  • hbase.kerberos.regionserver.principa=hbase/_HOST@TDH #hbase服务端principal
  • hbase.sasl.clientconfig=/xxx/jaas.conf

jaas.conf文件格式样例:
Client {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
useTicketCache=false
keyTab="/path/to/keytab.keytab" ## 客户端认证参数
principal="myhbaseuser@MY.HADOOP.DOMAIN"; ## 客户端认证参数
};

选填参数:

  • 环境变量:java.security.krb5.conf = krb5.conf
  • zk是否开启sasl认证:zookeeper.sasl.client = true

flinkStreamsql使用注意事项:

  • keytab文件通过FlinkShipfile模式已经上传,通过("user.dir")进行全路径拼接。
  • 异步模式下Hbase在ZK的根路径参数hbase.zookeeper.znode.parent有hase前缀。
  • jaas.conf文件根据参数进行构建,并保存在("user.dir")下。

认证部分代码:

Config config = new Config();
config.overrideConfig("hbase.zookeeper.quorum", hbaseSideTableInfo.getHost());
config.overrideConfig("hbase.zookeeper.znode.parent", hbaseSideTableInfo.getParent());
fillAsyncKerberosConfig(config, hbaseSideTableInfo);
hBaseClient = new HBaseClient(config, executorService);

private void fillAsyncKerberosConfig(Config config, HbaseSideTableInfo hbaseSideTableInfo) throws IOException {
    AuthUtil.JAASConfig jaasConfig = HbaseConfigUtils.buildJaasConfig(hbaseSideTableInfo);

    String jaasFilePath = AuthUtil.creatJaasFile("JAAS", ".conf", jaasConfig);
    config.overrideConfig("java.security.auth.login.config", jaasFilePath);
    config.overrideConfig("hbase.security.auth.enable", "true");
    config.overrideConfig("hbase.sasl.clientconfig", "Client");
    config.overrideConfig("hbase.security.authentication" "kerberos");

    String regionserverPrincipal = hbaseSideTableInfo.getRegionserverPrincipal();
    config.overrideConfig("hbase.kerberos.regionserver.principal", regionserverPrincipal);

    if (!StringUtils.isEmpty(hbaseSideTableInfo.getZookeeperSaslClient())) {
        System.setProperty("zookeeper.sasl.client", hbaseSideTableInfo.getZookeeperSaslClient());
    }

    if (!StringUtils.isEmpty(hbaseSideTableInfo.getSecurityKrb5Conf())) {
        String krb5ConfPath = System.getProperty("user.dir") + File.separator + hbaseSideTableInfo.getSecurityKrb5Conf();
        LOG.info("krb5ConfPath:{}", krb5ConfPath);
        System.setProperty("java.security.krb5.conf", krb5ConfPath);
    }
}

相关问题记录

  1. 从IDEA提交到Kerberos集群异常。需要从当前环境变量配置krb5.conf路径。
image.png
image.png
  1. /hbase节点找不到,同步模式下zookeeper.znode.parent默认路径为Hbase,确认参数没有hbase.前缀.
image.png
image.png
  1. 服务授权阶段hbase.master.kerberos.principal使用的principal和client的principal为一个,且格式不正确,必须为xxxx/_HOST@XXX格式。
image.png
image.png

推荐阅读更多精彩内容