使用kerberos认证方式连接redis集群

水滴石穿,万事功到自然成。

常学习,勤记录,我爱学习。

概要

正常情况下,连接redis集群只需要使用账号密码方式即可连接,但由于公司的项目上线时使用的某大厂的redis集群,该集群供多家厂商进行使用,故集群账号和密码不可能泄露给我们,所以大厂就提供了kerberos认证方式已供连接。

整体架构流程

kerberos认证流程可参考以下文章,写得非常详细,值得学习

Kerberos认证原理与使用教程-CSDN博客

技术细节

 连接redis集群的方式有三种,可参考以下链接:

huaweicloud-mrs-example/src/redis-examples/src/main/java/com/huawei/redis at mrs-3.2.0 · huaweicloud/huaweicloud-mrs-example · GitHub

/**
 * 安全认证使用方式四: API设置独立认证信息,可以在一个应用里面使用多个认证用户访问多个Redis集群
 * <p>
 * 1、通过krb5.conf、keytab路径、principal、服务端域名等初始化认证配置对象
 * 2、创建JedisCluster对象,需要将独立的认证配置对象传入
 *
 * @since 2022-02-16
 */
public class SecureJedisClusterDemo4 {

    /**
     * 默认连接超时时间
     */
    private static final Integer TIMEOUT = 3000;

    /**
     * 最大重试次数
     */
    private static final Integer MAX_ATTEMPTS = 1;

    public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException {
        // 初始化kerberos认证对象
        AuthConfiguration authConfiguration = new AuthConfiguration("path1/krb5.conf", "path1/user.keytab",
                "user@HADOOP1.COM");
        authConfiguration.setServerRealm("HADOOP1.COM");
        authConfiguration.setLocalRealm("HADOOP1.COM");
        AuthConfiguration authConfiguration2 = new AuthConfiguration("path2/krb5.conf", "path2/user.keytab",
                "user@HADOOP.COM");
        authConfiguration.setServerRealm("HADOOP.COM");
        authConfiguration.setLocalRealm("HADOOP.COM");
        // 初始化第二套集群的认证信息
        Set<HostAndPort> hosts = new HashSet<>();
        hosts.add(new HostAndPort("ip1", 22400));
        Set<HostAndPort> hosts2 = new HashSet<>();
        hosts2.add(new HostAndPort("ip2", 22400));

        // 初始化连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMinIdle(3);
        jedisPoolConfig.setMaxTotal(100);
        jedisPoolConfig.setMaxIdle(100);

        // 创建ssl连接新消息
        boolean ssl = false;
        final SSLSocketFactory socketFactory = SslSocketFactoryUtil.createTrustALLSslSocketFactory();

        // 初始化jedisCluster连接
        writeCluster(hosts, jedisPoolConfig, socketFactory, ssl, authConfiguration);
        // 连接第二个集群的JedisCluster连接
        writeCluster(hosts2, jedisPoolConfig, socketFactory, ssl, authConfiguration2);

    }

    /**
     * 连接Redis集群
     *
     * @param hosts             主实例列表
     * @param jedisPoolConfig   连接池配置
     * @param socketFactory     ssl 忽略证书的SSLSocketFactory
     * @param ssl               是否开启ssl
     * @param authConfiguration 安全认证配置信息
     */
    private static void writeCluster(Set<HostAndPort> hsots, JedisPoolConfig jedisPoolConfig,
            SSLSocketFactory socketFactory, boolean ssl, AuthConfiguration authConfiguration) {
        JedisCluster client = new JedisCluster(hosts, TIMEOUT, TIMEOUT, TIMEOUT, MAX_ATTEMPTS, jedisPoolConfig, ssl,
                socketFactory, authConfiguration);
        client.set("test-key", System.currentTimeMillis() + "");
        System.out.println(client.get("test-key"));
        client.del("test-key");
        client.close();
    }
}
/**
 * 安全认证使用方式二: API设置方式
 *
 * 1. 构造AuthConfiguration对象,指定keytab文件路径,principal,krb5.conf文件路径
 *    若krb5.conf文件路径不指定,默认读取java.security.krb5.conf系统参数的值
 *
 * 2. GlobalConfig.setAuthConfiguration设置为上面创建的AuthConfiguration对象
 *
 * 3. 创建JedisCluster对象,创建方式同非安全一样
 *
 * 4. 若Redis服务是全新安装服务,需要设置SERVER_REALM环境参数,该参数值为KrbServer服务配置项default_realm的值(该配置可到管理页面查询)。
 *    若Redis服务是由低版本升级而来,则不能设置该参数。
 *
 * @since 2020-09-30
 */
public class SecureJedisClusterDemo2 {
    public static void main(String[] args) {
        System.setProperty("java.security.krb5.conf", "krb5.conf file path");
        AuthConfiguration authConfiguration = new AuthConfiguration("keytab file path", "principal");
        GlobalConfig.setAuthConfiguration(authConfiguration);
        // System.setProperty("SERVER_REALM","HADOOP.COM");

        Set<HostAndPort> hosts = new HashSet<HostAndPort>();
        hosts.add(new HostAndPort(Const.IP_1, Const.PORT_1));
        JedisCluster client = new JedisCluster(hosts, 5000);

        client.set("test-key", System.currentTimeMillis() + "");
        System.out.println(client.get("test-key"));
        client.del("test-key");
        client.close();
    }
}
/**
 * 安全认证使用方式三: 使用jaas文件配置方式
 *
 * 1. 必须设置redis.authentication.jaas, java.security.auth.login.config, java.security.krb5.conf 3个系统参数
 *   可通过java命令行-D参数设置
 *
 * jaas.conf文件样例:
 * Client{
 * com.sun.security.auth.module.Krb5LoginModule required
 * useKeyTab=true
 * keyTab="/xxx/user.keytab"
 * principal="xxxx"
 * useTicketCache=false
 * storeKey=true
 * debug=false;
 * };
 *
 * 2. 若Redis服务是全新安装服务,需要设置SERVER_REALM环境参数,该参数值为KrbServer服务配置项default_realm的值(该配置可到管理页面查询)。
 *    若Redis服务是由低版本升级而来,则不能设置该参数。
 *
 * @since 2020-09-30
 */
public class SecureJedisClusterDemo3 {
    public static void main(String[] args) {
        System.setProperty("redis.authentication.jaas", "true");
        System.setProperty("java.security.auth.login.config", "jaas.conf file path");
        System.setProperty("java.security.krb5.conf", "krb5.conf file path");
        // jaas.conf文件Section名字,不设置的话默认值为Client, 区分大小写
        // System.setProperty("redis.sasl.clientconfig", "redisClient");
        // System.setProperty("SERVER_REALM","HADOOP.COM");
        Set<HostAndPort> hosts = new HashSet<HostAndPort>();
        hosts.add(new HostAndPort(Const.IP_1, Const.PORT_1));
        JedisCluster client = new JedisCluster(hosts, 5000);

        client.set("test-key", System.currentTimeMillis() + "");
        System.out.println(client.get("test-key"));
        client.del("test-key");
        client.close();
    }
}

我选择了方式二:API认证方式进行连接。其中:krb5.conf文件、keytab文件、principal和SERVER_REALM环境参数需要自行设置。

问题一:不知道SERVER_REALM的值如何查找,principal的值如何查找

SERVER_REALM的值可在krb5.conf文件中查找;

principal为用户名,使用 keytab文件 就是已经生成的票据可查找,使用以下命令:

klist -ket xxxxxx.keytab

问题二:不确定自己是否连接成功redis集群

由于我的项目中既使用了redisTemplate,也使用了Jedis客户端,两种方式都去连接redis集群。项目启动后,一直报如下错误:

这个提示为小白菜连接报错,也就是使用redisTemplate方式连接是需要集群密码的,采用排除法,只需注释调就可以,但是项目使用redisLock做分布式锁,底层使用redisTemplate做的集群连接,所以换一种思路,查看jedis是否连接成功。

        JedisCluster jedisCluster = null;
        try {
            jedisCluster  = new JedisCluster(nodes, timeout, poolConfig);
            
            //简单使用一下jedisCluster即可验证
            client.set("test-key", System.currentTimeMillis() + "");
            System.out.println(client.get("test-key"));
            client.del("test-key");


        }catch (Exception e){
            log.info("kerberos认证失败");
            e.printStackTrace();
        }

通过以上方式,证实jedis方式连接成功,将代码中使用到的redisTemplate方式的代码全部替换为JedisCluster方式。

事情往往不是那么一帆风顺,在替换的过程中,发现reidsLock做分布式锁的核心逻辑如下:

Long res = (Long)jedisCluster.eval(redisScript.getScriptAsString(), keys, args);

 而eval命令由于是高危命令,被redis服务器端禁止了,只能换种方式,使用scheduleLock方式来实现分布式定时任务锁。

小结

与其浪费时间死磕,不如试试排除法、逆向思维,这些都是解决问题的关键。

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值