Redis Kerberos票据认证(.net 6)

Kerberos认证介绍

Kerberos 是一种“可信第三方”的网络认证协议,最初由 MIT 开发,现已成为 Windows AD、Hadoop、NFS、HTTP SSO 等场景的核心身份验证机制。它的设计目标只有一句话:在不安全的网络里,让双方都能证明“我是谁”,却从不传输密码而是使用票据。 详细资料请自行网络搜索

认证流程图

在这里插入图片描述

测试环境搭建

配置 Kerberos Server

执行以下命令,安装ubuntu镜像

docker pull docker.1ms.run/library/ubuntu:latest

在这里插入图片描述

启动容器

执行以下命令

 docker run -it ubuntu /bin/bash

在这里插入图片描述

安装Kerberos Server

执行以下命令安装kerberos服务端和kdc;
需要注意的是我们这个命令实在容器内部执行的哦。也就是上一步之后执行的

apt install -y krb5-kdc krb5-admin-server krb5-config

在这里插入图片描述
安装过程中需要填写一些参数
在这里插入图片描述
按以下参数填写即可

Default Kerberos version 5 realm : LAN
Kerberos servers for your realm : kdc.lan
Administrative server : kdc.lan

配置数据库

命令行执行

krb5_newrealm

执行后会让你设置Realm 的主密码;我这里输入的是root;简单又好记
在这里插入图片描述

创建管理员主体

输入以下命令创建管理员主题

kadmin.local

创建管理员

addprinc root/admin

输入了之后又会让你设置管理员密码这里我也是设置的root;简单又好记
在这里插入图片描述
设置完了之后输入:q ;退出
在这里插入图片描述

安装vim

安装一个vim 后面需要修改配置文件用得到它
注意 server容器和client容器都需要安装一个因为都要设置配置文件

apt install vim

在这里插入图片描述
这里直接输入:5
接着会让选时间区域,这里我选的重庆也就是输入:19;这里输入完之后vim就安装完成了
在这里插入图片描述

配置访问控制列表 (ACL)

执行以下命令查看账户权限是否正常

cat /etc/krb5kdc/kadm5.acl

在这里插入图片描述
出现上面的内容就说明我们的账号的权限是正常的

重启相关服务

service krb5-kdc restart
service krb5-admin-server restart
查看ip

这里查看ip主要是给后面客户端配置文件中使用
执行以下命令安装一个ip查看工具

apt install -y iproute2

使用工具查看ip

ip -4 -o addr show scope global

在这里插入图片描述

修改配置文件

修改配置文件中的LAN

vi /etc/krb5.conf

将LAN设置为本机IP

LAN = {
kdc = 172.17.0.2
admin_server = 172.17.0.2
}

修改后重新启动服务

service krb5-kdc restart
安装redis服务

执行以下命令安装redis服务供客户端通过票据来连接redis

apt-get install redis-server -y

检查redis服务是否正常

 service redis-server status

在这里插入图片描述

创建Redis服务主体

在Kerberos服务端容器中创建Redis的SPN

 kadmin.local -q "addprinc -randkey redis/redis-server.172.17.0.2"

再将Kerberos服务主体(SPN)的密钥提取到keytab文件中

kadmin.local -q "ktadd -k /etc/redis/redis.keytab -norandkey redis/redis-server.172.17.0.2"

执行后会提示创建成功
在这里插入图片描述

模拟通过Kerberos认证连接redis环境

需要注意的是redis只有企业版才有对Kerberos的直接支持,我们没有企业版我搜索了一下AI说可以通过HAProxy+SASL插件来实现,也可以使用nginx代理来实现,这里我选择使用nginx来实现

  1. 安装编译环境
apt-get install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev wget
  1. 下载源码
wget http://nginx.org/download/nginx-1.15.0.tar.gz && \
    tar -xzf nginx-1.15.0.tar.gz

3.下载spnego模块
这个库很久没有更新了最后更新说名文档里说的是支持1.15.0

git clone https://github.com/stnoonan/spnego-http-auth-nginx-module.git

这里需要在宿主机上下载下载好了再拷贝进容器,因为容器可能访问不了github.com
在这里插入图片描述
在这里插入图片描述
安装开发包:

apt install -y libkrb5-dev

验证开发包是否安装完成

dpkg -L libkrb5-dev | grep gssapi.h

出现以下界面就说明安装完成了
在这里插入图片描述

安装nginx

cd nginx-1.15.0
./configure --prefix=/usr/local/nginx
make
make install

之后执行编译:

make clean
./configure \
        --prefix=/usr/local/nginx \
        --with-http_ssl_module \
        --with-cc-opt="-Wno-error=deprecated-declarations" \
        --add-module=../spnego-http-auth-nginx-module
make -j$(nproc) && make install

出现以下内容就说明编译成功了
在这里插入图片描述

如果提示: Syntax error: end of file unexpected (expecting “then”)
这是因为Windows 风格换行符(CRLF),Unix shell 读到 \r 后把整行命令截断导致的
就进入到spnego-http-auth-nginx-module文件夹里执行以下脚本

apt install -y dos2unix
find . -type f -exec dos2unix {} \+

修改nginx配置文件
在http模块里新增以下内容

 server{
           listen 6380;
           server_name redis-kerberos-proxy;
           location /{
                auth_gss on;
                auth_gss_keytab /etc/redis/redis.keytab;
                auth_gss_service_name "redis/redis-server.172.17.0.2";
                auth_gss_allow_basic_fallback off;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_pass http://127.0.0.1:6379;
           }



        }

启动nginx服务

/usr/local/nginx/sbin/nginx 

出现master和worker就说明成功启动了
在这里插入图片描述
检查kerberos支持是否正常

/usr/local/nginx/sbin/nginx -V 2>&1 | tr ' ' '\n' | grep spnego

出现以下内容说明运行正常
在这里插入图片描述

到这里我们nginx的配置就成功了;这里我耗费了两天的时间才成功,好几种方式都测试了只有nginx这种方式成功了。


修改redis

修改redis使其支持网络ip连接

vim /etc/redis/redis.conf

修改内容如下

  • 绑定地址

bind 0.0.0.0

  • 关闭保护模式

protected-mode no

修改后执行以下命令重启服务

redis-cli shutdown
redis-server /etc/redis/redis.conf
service redis-server restart

到这一步管理端基本上就已经配置完成了


容器网络连通

在控制台输入以下命令创建一个网络

docker network create mynet

检查是否成功

docker network ls

在这里插入图片描述
把服务端和客户端加入网络

docker network connect mynet 2bb
docker network connect mynet e15
验证网络是否畅通

客户端安装一个ping

apt-get update && apt-get install -y iputils-ping
ping 服务器ip

出现以下内容就说明网络通了
在这里插入图片描述

验证redis 是否能正常连接
redis-cli -h 172.17.0.2 -p 6379

在这里插入图片描述

配置Kerberos Client

此时我们重新打开一个cmd命令行窗口
执行以下命令创建一个新的客户端容器

docker run -itd --name kerberos_client ubuntu:latest tail -f /dev/null

执行之后会返回一个md5字符串,然后我们执行以下命令查看容器

docker ps -a

在这里插入图片描述
进入容器

docker exec -it kerberos_client /bin/bash

执行以下命令安装客户端

apt install -y krb5-user libkrb5-3

在这里插入图片描述
安装过程中同样需要填写一些参数
按以下参数填写即可

Default Kerberos version 5 realm : LAN
Kerberos servers for your realm : kdc.lan
Administrative server : kdc.lan

编辑客户端配置文件

注意这里需要按照上面的教程给client容器也安装一个vim

 vi etc/krb5.conf

把这个配置文件修改为以下内容
注意: 172.17.0.2是Kerberos管理端容器的IP

[libdefaults]
        default_realm = LAN

# The following krb5.conf variables are only for MIT Kerberos.
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true
        rdns = false
        ticket_lifetime=24h
        dns_lookup_kdc=false
        dns_lookup_realm=false

# The following libdefaults parameters are only for Heimdal Kerberos.
        fcc-mit-ticketflags = true

[realms]
        LAN = {
                kdc = 172.17.0.2
                admin_server = 172.17.0.2
        }
        ATHENA.MIT.EDU = {
                kdc = kerberos.mit.edu
                kdc = kerberos-1.mit.edu
                kdc = kerberos-2.mit.edu:88
                admin_server = kerberos.mit.edu
                default_domain = mit.edu
        }
        ZONE.MIT.EDU = {
                kdc = casio.mit.edu
                kdc = seiko.mit.edu
                admin_server = casio.mit.edu
        }
        CSAIL.MIT.EDU = {
                admin_server = kerberos.csail.mit.edu
                default_domain = csail.mit.edu
        }
        IHTFP.ORG = {
                kdc = kerberos.ihtfp.org
                admin_server = kerberos.ihtfp.org
        }
        1TS.ORG = {
                kdc = kerberos.1ts.org
                admin_server = kerberos.1ts.org
        }
        ANDREW.CMU.EDU = {
                admin_server = kerberos.andrew.cmu.edu
                default_domain = andrew.cmu.edu
        }
        CS.CMU.EDU = {
                kdc = kerberos-1.srv.cs.cmu.edu
                kdc = kerberos-2.srv.cs.cmu.edu
                kdc = kerberos-3.srv.cs.cmu.edu
                admin_server = kerberos.cs.cmu.edu
        }
        DEMENTIA.ORG = {
                kdc = kerberos.dementix.org
                kdc = kerberos2.dementix.org
                admin_server = kerberos.dementix.org
        }
        stanford.edu = {
                kdc = krb5auth1.stanford.edu
                kdc = krb5auth2.stanford.edu
                kdc = krb5auth3.stanford.edu
                master_kdc = krb5auth1.stanford.edu
                admin_server = krb5-admin.stanford.edu
                default_domain = stanford.edu
        }
        UTORONTO.CA = {
                kdc = kerberos1.utoronto.ca
                kdc = kerberos2.utoronto.ca
                kdc = kerberos3.utoronto.ca
                admin_server = kerberos1.utoronto.ca
                default_domain = utoronto.ca
        }

[domain_realm]
        .mit.edu = ATHENA.MIT.EDU
        mit.edu = ATHENA.MIT.EDU
        .media.mit.edu = MEDIA-LAB.MIT.EDU
        media.mit.edu = MEDIA-LAB.MIT.EDU
        .csail.mit.edu = CSAIL.MIT.EDU
        csail.mit.edu = CSAIL.MIT.EDU
        .whoi.edu = ATHENA.MIT.EDU
        whoi.edu = ATHENA.MIT.EDU
        .stanford.edu = stanford.edu
        .slac.stanford.edu = SLAC.STANFORD.EDU
        .toronto.edu = UTORONTO.CA
        .utoronto.ca = UTORONTO.CA
        .lan=LAN
        lan=LAN
[logging]
        kdc=FILE:/var/log/krb5kdc.log
        admin_server=FILE:/var/log/kadmin.log
        default=FILE:/var/log/krb5lib.log

默认配置文件相比主要增加的内容有以下几点:

  • libdefaults

ticket_lifetime=24h
dns_lookup_kdc=false
dns_lookup_realm=false

  • domain_realm

LAN = {
kdc = 172.17.0.2
admin_server = 172.17.0.2
}
.lan=LAN
lan=LAN

  • logging(这个模块是新加的用于日志打印)

[logging]
kdc=FILE:/var/log/krb5kdc.log
admin_server=FILE:/var/log/kadmin.log
default=FILE:/var/log/krb5lib.log

设置完之后咱们再去把存储日志的文件夹建一下

mkdir -p /var/log/kerberos

授权

chmod 750 /var/log/kerberos

在这里插入图片描述
配置完成之后执行,获取票据

票据获取
kinit root/admin

执行完之后查看票据

 klist

在这里插入图片描述
出现以上内容就是票据获取成功了,这里因为我们配置文件里设置的过期时间是24小时所有Expires时间就到明天去了。

验证票据

执行以下脚本

curl -v --negotiate -u : http://172.17.0.2:6380/

返回以下内容则说明成功了;kerberos票据校验通过了
在这里插入图片描述

返回 200 且响应头里可见 WWW-Authenticate: Negotiate → Kerberos 认证成功。
返回 401 且无 Negotiate → 模块没启或 keytab 无效。
返回 502/504 → 认证已通过,但后端 proxy_pass 地址不通。


都这里我们的环境搭建就结束了,该开始写.net 的票据续期功能了。

.net6 实现redis票据认证

using Kerberos.NET.Client;
using Kerberos.NET.Credentials;
using Kerberos.NET.Crypto;
using System.Net.Sockets;
using System.Text;

namespace RedisKerberosTest
{
    internal class Program
    {

        // ====================================

        private static async Task Main()
        {
            try
            {
				//这部分要更换,根据自己的业务需求替换
                string RedisHost = "172.17.0.2";
                int RedisPort = 6379;
                string RedisPrincipal = "redis/172.17.0.2@HADOOP.COM";
                string Ktb_path = "/opt/test/user.keytab";
                string username = "redis_server";

                Console.WriteLine("请输入用户名称(默认直接回车):");
                string? R_username = Console.ReadLine()?.Trim();
                if (!string.IsNullOrWhiteSpace(R_username))
                {
                    username = R_username;
                }
                Console.WriteLine("请输入主体(默认直接回车):");
                string? R_principal = Console.ReadLine()?.Trim();
                if (!string.IsNullOrWhiteSpace(R_principal))
                {
                    RedisPrincipal = R_principal;
                }
                Console.WriteLine("请输入ktb文件路径(默认直接回车):");
                string? R_ktb_path = Console.ReadLine()?.Trim();
                if (!string.IsNullOrWhiteSpace(R_ktb_path))
                {
                    Ktb_path = R_ktb_path;
                }
                KeyTable keyTable = new KeyTable(File.ReadAllBytes(Ktb_path));
                var kerbCred = new KeytabCredential(username, keyTable);
                Console.WriteLine("解析票据数据");
                using var kerbClient = new KerberosClient();
                await kerbClient.Authenticate(kerbCred);

                var ticket = await kerbClient.GetServiceTicket(RedisPrincipal);

                Console.WriteLine("开始尝试建立 TCP 连接");
                // 2. 建立 TCP 连接
                using var tcp = new TcpClient();
                await tcp.ConnectAsync(RedisHost, RedisPort);
                using var ns = tcp.GetStream();
                Console.WriteLine("发送请求");
                // 3. 发送 AUTH GSSAPI <base64>
                var tokenB64 = Convert.ToBase64String(ticket.EncodeApplication().ToArray());
                await SendRawAsync(ns, $"AUTH GSSAPI {tokenB64}\r\n");

                var resp = await ReadLineAsync(ns);
                if (!resp.StartsWith("+OK"))
                    throw new Exception("AUTH failed: " + resp);

                Console.WriteLine("✅ Kerberos 认证通过");

                // 4. 发送正常 Redis 命令
                await SendRawAsync(ns, "PING\r\n");
                resp = await ReadLineAsync(ns);
                Console.WriteLine("PING 结果: " + resp);

                await SendRawAsync(ns, "SET mykey \"Hello Kerberos\"\r\n");
                resp = await ReadLineAsync(ns);
                Console.WriteLine("SET 结果: " + resp);

                await SendRawAsync(ns, "GET mykey\r\n");
                resp = await ReadLineAsync(ns);
                Console.WriteLine("GET 结果: " + resp);
                Console.ReadKey();

            }
            catch (Exception ex)
            {

                Console.WriteLine("执行发生错误:{0}", ex.Message);
            }
        }

        private static async Task SendRawAsync(NetworkStream ns, string cmd)
        {
            var buf = Encoding.ASCII.GetBytes(cmd);
            await ns.WriteAsync(buf);
            await ns.FlushAsync();
        }

        private static async Task<string> ReadLineAsync(NetworkStream ns)
        {
            var sb = new StringBuilder();
            byte[] b = new byte[1];
            while (true)
            {
                await ns.ReadAsync(b, 0, 1);
                if (b[0] == '\n') break;
                if (b[0] != '\r') sb.Append((char)b[0]);
            }
            return sb.ToString();
        }
    }
}

编译Linux可执行文件

在vs控制台输入以下命令即可

dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -o ../out

执行之后数据的文件路径在你项目的bin/Relsase/net6.0/linux-x64文件夹下

小结

自此通过票据认证方式连接redis教程结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

或与且与或非

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值