此篇文章仅做Kerberos的基本原理和基本使用做说明,本人对Kerberos了解有限,也是通过大量英文文档中翻译过来,

  加上自己对Kerberos的理解所写,本人英文太菜,看文档看的头昏眼花若有写的不通顺的地方,请做参考实验部分,通过

实验部分,可让你对Kerberos有比较直观的认识,由于各方面原因,不能加过多图片,请自行实验看效果.

  希望看客记住一句话: 快就是慢,慢就是快!!

      ---------马帮弟子:zcf

=================================【这部分Kerberos原理,是最新总结,仅做参考】=====================================

Kerberos基本概念:
  1. Kerberos中有三种角色:
    服务器, 客户端
    KDC(认证服务器)
      客户端和服务器要信任KDC
      并且KDC要存储它们每个人的私有密码所生成的Hash密钥.这些hashkey被存储在account database(账号数据库)中。

  2. KDC为了便于查询它们每个人的Hash密钥, 要求他们必须有一个唯一的名字,称为principal.

  3. 安全个体(principal)
    定义:
      1. 凡是可以与账户和口令联系在一起的任何事物都可以被认为是安全个体;
      2. 每个安全个体都有一个可被认证的身份;
      3. 在认证的过程中,正在被证明的是参与各方的安全个体的身份。
    对于以上定义我也理解困难.

      Kerberos原理和基础小结-LMLPHP
      /etc/krb5.keytab中存储的一类条目就是一个pricipal(安全主体),可粗略这样认为.
      一类条目: 是指nfs/[email protected]这个安全主体它的密码(Long-term key)经过多种
          Hash加密分别算法计算出了一个Hash密钥,因为Hash算法的特点就是不可逆!即不能通过密钥还原出
          密码,Kerberos对数据加密时,使用的这些密钥,而不是密码,但密码和密钥具有同等效力,因为
          密钥不可逆,能解密用密钥加密的数据的人,一定是有真实密码的人!
      krb5.keytab: 当你把nfs/rnode22.zczf.com这个安全主体从Account database中导出到一个文件时,
            存储这个安全主体的文件就是keytab,你可以将它命名为其它,但因为系统中大部分借助
            于kerberos认证的服务程序默认都会到/etc/下找krb5.keytab,甚至很多都是写死在
            配置文件中,除非你非常了解这些服务,否则不建议命名成其它!
      Account Database: 它是KDC上的存储安全主体的数据库,简单说就是认证账号的数据库,只不过这些账号
            不同于常见的用户名密码,它里面存储的安全主体的命名格式: [服务名]/完全合格域名@Realm
            服务名:如上面nfs, ssh等,也可以是host,即主机账号, 完全合格域名即DNS名,如:www.a.com
            rnode22.zczf.com 这都是. Realm是KDC的域.就类似于a.com域一样.
            在这个账号数据库中,nfs/[email protected]是一个独立的条目,该条目对应多种
            加密算法计算生成的密钥, 一般host,nfs,,...这些主机账号建议使用随机密码,当然也可手动输入密码,
            而用户账号类的安全主体,要使用手动输入密码, 以便本地验证用户身份.
            通过自动生成密码 或 手动输入密码,最终根据默认生成Hash key的算法列表,依次生成Hash key.

    4. Long-term key , Short-term key ,Session Key
      Long-term key: 即你自己的密码,你的密码可能几年,甚至更久都不会变,在网络世界中,这种密码是不安全的,
            因为没有任何加密算法是100%安全的,即 你用你的密码加密的数据,在网络上传输的话,只要
            黑客捕获足够多的数据包,进行计算,密码是可以被计算出现的,这只是时间问题.因此在网络
            环境中不建议使用这种Long-term key.
      Short-term key:其实就是Session key, 即短期密码,仅在指定时间范围内有效,这样即便被破解,此密码也早已失效.
            它是Kerberos加密通信使用最多的密钥.

   5. TGT: Ticket组成:【仅做参考】
      Kerberos原理和基础小结-LMLPHP

Kerberos的基本认证过程:

  要看下面的认证过程,必须先了解上面提到的基本概念.
  下面的说明是通过这条命令开始, 此命令是让NFS借助于Kerberos做身份验证.
  注意:下面说明并不一定完全正确,但可以帮助你更快速的理解Kerberos内部复杂的认证逻辑.

    mount -t nfs -o v4.2,sec=krb5p server.group8.example.com:/protected /mnt/nfssec
    #当执行此命令后,我的理解:
      下图为Kerbors服务端日志信息输出:
        Kerberos原理和基础小结-LMLPHP
        注意: 此图是后来截的,system1就是NFS Server, server是Kerberos KDC服务器.
        从Kerberos日志中可以看到:
        客户端第一次去访问nfs server时,客户端实际和Kerberos通信了两次.
        我的理解如下:
          1.Client首先要与kerberos服务取得联系,获得与Kerberos通信的初始随机密钥,但是Kerberos
            要知道你找我做什么事? 是让我帮你生成访问其它服务器的TGT?还是获取密码验证?还是
            要与我建立通信?等 所以 Client首次与Kerberos通信时,Client将自己的Principal明文放在
            与Kerberos通信的包中,并将自己的需求+预认证信息使用自己的principal对应的密钥加密,
            然后发给Kerberos,kerberos收到后,它使用明文的principal找到数据库中对应的密钥,然后
            尝试解密,因为一个principal对应多个加密算法计算的随机密钥,我的理解是这样,(每次通信
            随机使用其中一个加密算法生成的密钥,对需求信息做加密,可增大破解的难度)kerberos会依次
            尝试这些密钥,若成功解密,则继续,否则返回错误. 当Kerberos解密成功后,它看到里面的信息,
            你要与我建立通信,于是kerberos就知道,我应该使用krbtgt这个principal对应的密钥来对Client
            的预认证信息做加密,生成TGT, 并且生成你和我通信使用的随机密码,并使用你的prinicpal中
            随机的一个密钥加密,最终将TGT和加密后的随机密码发给Client.

          Client自己的Principal: Cp
          Client自己的Principal对应的密钥: Ck
          Client----[(Cp) (Ck{预认证数据})]----------->Kerberos

         Kerberos的principal对应的密钥:Kk
         Kerberos---[(Kk{TGT}) (Ck{KC-RandomKey})]------->Client

          说明:
            随机密码: 即Session key.
            上面的过程实际就是Kerberos中的第一个子协议, Authentication Service Exchange认证交换服务。

            Client给kerberos发送到就是AS_REQ(认证服务请求),而Kerberos回应Client的就是AS_REP。

        上面描述过程如下图:

          Kerberos原理和基础小结-LMLPHP

        第一次通信成功完成.
        第二次Client需要访问system1上的nfs服务,于是使用第一次获取的TGT 加
        使用自己和kerberos之间的随机密钥将自己的需求加密,发给Kerberos,kerberos收到后,
        它会先尝试使用自己的Principal对应的密钥解密TGT,以便获取与Client通信的随机密码.
        【注意: Kerberos协议中,为了避免使用kerberos协议的服务软件,自行维护随机密码列表,
        因此它在实现时,将随机密码放到TGT中,TGT中包含了客户端的信息和随机密码,
        这样服务软件只要知道, 我用我的principal中的密钥尝试解密客户端提供的TGT,
        若能解密,就可确定这个是KDC颁发给Client的,然后使用其中我和Client之间专用的
        随机密码,就能解密需求部分.这样就避免了为每个客户端都要缓存和它通信时,使用的随机密码了.】
        当使用自己的Principal尝试解密TGT,解密成功后,kerberos就可以获取于客户端通信的随机密码,
        接着Client的需求信息解密,知道Client想访问Sytem1 这台 NFS服务器,于是,kerberos
        使用Client指定的nfs的主机名,去查询数据库,若找到对应的principal,则使用该principal
        对应的密钥,并生成Client和NFS之间通信的随机密码,然后将C_N_random_key和Client的信息
        使用NFS主机对于的principal的密钥加密,生成TGT,接着使用Kerberos和Client之间的随机密钥
        将C_N_random_key加密,最终一并发给Client.

        过程如下:
          Client---[(Kk{TGT}) (Kck{Client的需求})]------------------------->Kerberos

          NFS Server的principal对应的密钥: Ks
          Kerberos---[(Ks{TGT}) (Kck{Client-NFS-Random_Key})]------->Client

        上面描述的过程就是Kerberos的第二个子协议: TGS(Ticket Granting Service)Exchange
        TGS_REQ: Client给Kerberos发请求. TGS_REP: Kerberos给Client回应.

        最后,如下图描述的一样,Client使用 通过NFS的principal对应的密钥加密的TGT+自己和NFS
        之间通信使用的随机密码加密的认证请求信息发给NFS, NFS使用/etc/krb5.keytab(默认使用此keytab)
        查出自己prinicipal对应的密钥,并尝试解密TGT,若成功解密,将获取到Client和自己通信的随机密码,
        并使用该随机密码解密认证请求,首先检查时间戳是否在合理区间,一般为5分钟之内,若时间戳合理,则
        最后对比认证请求中的信息与TGT中的信息是否一致,若一致则认证通过,允许你访问我共享的资源.
        注意:
          第三个子协议Client/Server Exchange是支持双向认证的, 它的双向认证如下:
          Server从Authenticator(即Client的需求)提取Timestamp,使用Session Key(即C_N_random_key)
          进行加密,并将其发送给Client用于Client验证Server的身份。

        上面描述大概如下图:
        下图描述的就是TGS Exchange 和第三个子协议【Client/Server Exchange】
          Kerberos原理和基础小结-LMLPHP

        上面三个子协议似乎完美的解决的了认证问题.
        但事实上问题还没有解决,因为Client和Server之间通信可能需要很长时间,甚至一直。
        Client只有与Server通信,就必须提供 Server的principal对于的密钥加密的TGT,因为TGT中
        包含了Client和Server通信使用的Session Key(即随机密码),所以这是非常不安全的,
        因为principal对于的密钥就相当于密码,只要时间足够,也不是不可能破解.
        为了解决这个问题,kerberos又引入了第四个子协议: User2User
        过程如下:

        Client自己的Principal: Cp
        Client自己的Principal对应的密钥: Ck
        Client----[(Cp) (Ck{预认证数据})]--------------------------------------->Kerberos

        Kerberos的principal对应的密钥:Kk
        Kerberos---[(Kk{TGT}) (Ck{Kerberos-Client-Random-Key})]------->Client

        #上面交互后,Client得到了KDC的principal密钥加密的TGT
        接着Client需要去Server端获取Server与KDC之间的TGT,以便从此TGT中获取,
        Server与KDC之间通信使用的随机密码(Session-key).

        Client---[(Kk{TGT}) (Kck{Client的需求})]------------------------->Kerberos

        Server的principal对应的密钥: Ks
        Kerberos---[(Ks{TGT}) (Kck{Client-Server-Random_Key})]------->Client

        Kcs: 即Server和Client之间的随机密钥
        Client---[(Ks{TGT}) (Kcs{我需要你和KDC之间的TGT})]--------------->Server

        Server---[Kcs{ (Kk{TGT}) }]---------------------------------------------->Client

        #当获得Server和KDC之间的TGT后,Client将自己与KDC之间的TGT,自己的需求信息,
        通过Client_KDC_random_key加密后,一并发给KDC, KDC收到后,会先解密与Client
        之间的TGT,获取Client_KDC_random_key, 解密需求信息,然后对比其中的信息与TGT
        中Client的信息是否匹配, 若匹配,则继续使用自己的principal对于的密钥解密与Server
        之间的TGT,获取KDC_Server_random_key,接着使用K_S_random_Key对客户端信息
        及Client_Server_random_key一起加密,生成TGT,返回给Client.

        Kck[] : 这表示中括号里面的内容是Client和KDC之间使用的TGT.
        Ksk[]: 这表示中括号里面的内容是Server与KDC之间使用的TGT
        Kck{} : 这表示花括号中的内容是使用Client和KDC之间的随机密钥加密的数据.
        Client--[Kck[(Kk{TGT})] Ksk[(Kk{TGT})] Kck{预认证信息}]------------------------>Kerberos

      #当Kerberos收到Client与自己的TGT,Server与自己的TGT后,会先解密自己的Client
      之间的TGT,获取自己与Client之间通信的随机密钥, 接着解密预认证信息,验证Client的身份,
      当Client身份验证通过后, KDC才会继续解密自己与Server之间的TGT,获取自己与Server之间
      的随机密钥,并使用该随机密钥将Client的信息 + Server与Client之间通信的随机密钥 一起加密
      生成新的TGT,并将该TGT发给Client.

        Ksk: 是Server与KDC之间的随机密钥
        Client---[Ksk{TGT} Kcs{自己的需求}]--------------------------------->Server

      #接着Client就可以使用该TGT,加上自己和Server之间的随机密钥加密后的需求,发给Server.
      Server收到到,使用KDC和自己之间的随机密钥解密TGT,获取其中的随机密钥,并解密Client的需求,
      接着从需求中获取时间戳,客户端信息与TGT中的信息做比对,若匹配,则验证通过,允许Client
      访问我的资源.

        Server---[Kcs{你是合法用户,可以访问我的资源}]---------------------->Client

        Client----[Ksk{TGT} Kcs{请求具体的资源}]---------------------------->Server

        Server---[Kcs{资源数据}]------------------------------------------------>Client

  这里有一篇写Kerberos内部认证原理的文章:
    http://www.cnblogs.com/artech/archive/2007/07/05/807492.html
  下面是redhat官方对Kerberos的说明:
    https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_a_kerberos_5_client

最后,在告诉你一个不幸的消息,这些原理仅仅只是Kerberos的工作机制,但在具体实现中,可能存在
差异,我在RHEL7.0上测试,相同的配置却会出现认证通过 和 认证失败这种结果,而且认证失败后,
几乎很难排错。结果我发现重启几次后,竟然神奇的好了,什么也没有改?这是怎么回事?

NFS与Kerberos结合对我来说,还是有些头疼,希望能有更好解决方案的文章出现。

在RHEL7.0上测试时,nfs-secure是客户端必须开机启动的服务,客户端在进行krb认证时,
是有该服务协助完成的.而且该服务实际是rpc-gssd.service的软连接。
而nfs-secure-server不知道为何,在服务端应该可以启动,但是我无论如何都不能启动它.
nfs-secure-server是rpc-svcgssd.service的软连接.

我始终没有搞明白,nfs-secure 和 nfs-secure-server到底哪个其作用?能够协助NFS实现与Kerberos交互?
为何nfs-secure-server对应的rpc-svcgssd启动不了?

/etc/gssproxy/gssproxy.conf   #此配置文件中的配置对Kerberos认证起什么作用?
              为何它定义的keytab缓存目录中什么东西都没有?而且总是报错
gssproxy[925]: (OID: { 1 2 840 113554 1 2 2 }) Unspecified GSS failure. Minor code may provide more information, No credentials cache found

这些问题都有待继续深入学习Kerberos,希望高手路过,给予指点一二。

=================================================【最近发现下文中存在诸多错误,仅做参考】===================================================

kerberos协议原理:

  Kerberos基础
    Kerberos依赖于单密钥加密技术;
    我们可以把对口令进行散列计算,以便产生单密钥加密算法所需的密钥。
    核心思想:
      天下有一个秘密,只有你和我知道,如果我能向你证明我知道这个秘密,我就是我。

  KDC:票证颁发中心
        单密钥加密技术【又叫:对称加密技术】
  原理:密钥加密算法要求双方共享同一个密钥。密钥就是密码的散列结果(散列可以使56或128位的),
    数据是被密钥加密的,解密也是要通过密码散列得到密钥,在用密钥解密数据。
    三要素:密钥、算法和数据(要加密的数据)

  基本认证过程:
    1. Kerberos中有三种角色:
      CA(认证服务器), 服务器, 客户端, 客户端和服务器要信任CA, 并且CA要存储它们每个人的私有密码。
      2. CA为了便于查询它们每个人的密码, 要求他们必须有一个唯一的名字,称为principal.
        3. 安全个体(principal)
      定义:
      1. 凡是可以与账户和口令联系在一起的任何事物都可以被认为是安全个体;
      2. 每个安全个体都有一个可被认证的身份;
      3. 在认证的过程中,正在被证明的是参与各方的安全个体的身份。

    4. 认证过程:
    假如客户端A, 要访问服务器B, 过程如下:
    首先: A将自己和B的Pricipal发给CA, CA就知道A要访问B, 然后, 查询自己的
      密码数据库,获取A 和 B对应的密码.
      A---[A_Pricipal, B_Pricipal]----->CA

    接着: CA生成了一个认证因子(类似于证书), 其中包含时间戳,我CA的信息,
      A的信息(A的IP,A的主机名,等等), 然后生成一个随机密码(RandomKey),
      并使用A的密码,将 [认证因子 + RandomKey] 加密成"Encryption Client".
      接着使用B的密码, 将[RandomKey] 加密成 "Encryption Server".
      CA--[EC, ES]--------------------->A

     然后: A收到了EC 和 ES, A使用自己的密码将EC解密, 获得了认证因子+RandomKey.
      A使用Randomkey 对 [认证因子] 加密
      A---[ 加密的认证因子 + ES]-------------->B

   最后: B收到了来自A的访问请求, 然后 使用自己的密码将ES解密, 获取RandomKey.
    然后使用RandomKey 解密 加密的认证因子, 获取认证信息, B读取认证信息,
    知道这是我信任的CA,接着比对访问者提供的信息与CA提供的认证信息是否匹配,
    匹配则认证通过, 允许访问.
      B-----------[A需要的数据]----------->A

  认证因子: Ticket组成:【仅做参考】
    

  Kerberos的主配置文件【krb5.conf】:
    从版本1.14开始,可通过KRB5_CONFIG变量来指定krb5.conf的位置
    其中目录名可包含: 字母、数字字符、破折号或下划线

    foo = bar *    #'*':表示foo的最终值是bar, 第二个foo的值,将永不生效.
    foo = baz

    #这必须定义在配置文件首部,用于包含其它配置文件,必须是绝对路径.
    # 文件名: 可包含字母数字、破折号或下划线
      include FILENAME
      includedir DIRNAME    #必须以".conf"结尾.

    #加载模块的方式:
    #模块必须是绝对路径
      module MODULEPATH:RESIDUAL

  主要段:
    [libdefaults] Kerberos V5库使用的设置
    [realms] 特定于realm的联系信息和设置
    [domain_realm] 将服务器主机名映射到Kerberos领域

  以下具体配置参数说明,可参考:
    rpm -ql krb5-workstation krb5-server |grep pdf

      Kerberos原理和基础小结-LMLPHP

  [libdefaults]
    default_realm = ZCZF.COM    #标识客户机的默认Kerberos域; 将其值设置为Kerberos Realm(领域).
                   若无设置此值,那么在调用kinit(1)等程序时,必须使用每个Kerberos principal(主体)指定一个realm(域)。
    forwardable = true        #true:在KDC允许的情况下,初始票证在缺省情况下是可转发的。默认值为false。
    ticket_lifetime = 24h      #设置ticket最大有效期
    renew_lifetime = 1d      #设置默认ticket是否可更新其有效期. 0:不可以.
    clockskew = 1d        #设置ticket(票据)的最大过期时间, 若ticket中标记的过期时间小于它, 则在clockskew的
                  #有效期内, 这个过期的ticket依然有效.
    rdns = false          #true:使用反向解析和正向解析来规范化主机名.false:不使用DNS规范化主机名.
                  #但dns_canonicalize_hostname=True,默认为true,依然会要求主机名必须通过DNS能解析为FQDN.
    dns_lookup_realm = false    #在将主机名映射为Default Realm时, 不通过DNS获取Kerberos的Realm(领域)名称.
    default_ccache_name = KEYRING:persistent:%{uid}     

         #指定默认凭据缓存位置及缓存名, KEYRING:是存储到内核的不可交换内存的密钥环上.
         并以当前有效用户(euser)的UID命名. 【详情查看下文: 缓存类型】
         若不指定,默认使用: FILE:/tmp/krb5cc_%{uid}

    非必要参数,他们都有默认值.
      err_fmt             #定义错误日志格式; %M: 日志消息, %C:错误代码.
      allow_weak_crypto = false   #禁止弱密码,默认值. 默认将不允许使用单向DES加密算法.
                    默认允许使用的加密列表:default_tgs_enctypes,default_tkt_enctypes
                    设置允许使用的加密算法列表:permitted_enctypes
      default_client_keytab_name    #指定用于获取客户端凭据的默认keytab文件名; 默认文件是FILE:/var/kerberos/krb5/user/%{euid}/client.keytab。
      default_keytab_name         #指定应用程序服务器(如sshd)使用的默认keytab名称; 默认是FILE:/etc/krb5.keytab

      dns_canonicalize_hostname=True    #默认, 主机名必须能被DNS解析为完全合格域名.
      rdns=ture                 #使用反向解析和正向解析来规范化主机名.
      dns_lookup_kdc            #从DNS的SRV记录中查询KDC是谁.
      dns_uri_lookup =true          #默认: 若krb5.conf中未指定KDC或其他服务器, 是否使用DNS URI来
                        查询KDC,若DNS中没有KDC的URI记录, 则使用SRV记录中的定义的KDC.
      k5login_authoritative        #true(默认): 必须在本地用户的k5login文件中列出主体,以便授予登录访问权限(如果存在.k5login(5)文件)。
                      false: 即使存在k5login文件但没有列出主体,仍然可以通过其他机制授予主体登录访问权。
      k5login_directory      #设置Kerberos查询k5login文件的路径. 默认找~/.k5login.
      kdc_timesync=1      #默认, CA回应客户端的ticket中,若时间戳与本地系统时间有差距,则kerberos客户端
                  在访问服务器时,会自动使用该时差,调整发送数据包中的时间戳,但不修改本地系统时间.

      realm_try_domains =[-1|0|1|..]    #设置-1:不转换.
                      0:FQDN(server.a.com)将a.com转换为Realm名,
                      1:仅将com转换为Real名. 依次类推.

  [realms]
    admin_server=[IP|Hostname]     #设置主KDC服务器是谁, 建议必须指定, 若不指定它将默认根据[libdefaults] dns_lookup_kdc
                      的值来决定是否向DNS查询KDC, 但自动查询KDC存在缺陷,不建议使用.
      kdc = [IP|Hostname]          #用于指明当前KDC服务器的地址.
    auth_to_local_names          #本小节允许您设置从主体名称到本地用户名称的显式映射。标记是映射名,值是对应的本地用户名。
    default_domain            #将Kerberos4的principals转换为Kerberos5的principals,如:rcmd.hostname => host/hostname.domain.
    http_anchors=[FILE:OpenSSL-Style-CA.pem |DIR:/path/*.pem |ENV:X509_PROXY_CA]
        # 当通过HTTPS代理访问KDCs和kpasswd服务器时,可以使用此标记指定CA证书的位置,
          应该信任CA证书为代理服务器颁发证书。如果未指定,则使用系统范围的缺省CA证书集。

    kdc= [ [Hostname |IP][:Port] | [IPv6][:Port] ]    #设置本realm中运行的KDC主机的IP或主机名. 若为IPv6+端口,IPv6要用中括号括起来.
    master_kdc                 #若realm中有主KDC,从KDC,的环境中,客户端修改了密码,从KDC还没有同步,
                          导致认证失败,这时若设置主KDC,客户端将直接向主KDC认证.
    kpasswd_server        #指向执行所有密码更改的服务器。如果没有这样的条目,将尝试admin_server主机上的端口464。
    auth_to_local        #用于定义将主体名映射为本地用户名的映射规则.【这部分不是很懂】

  示例:
    [realms]
    TEST.COM = {
      kdc = kerberos.test.com
      admin_server = kerberos.test.com
      auth_to_local = RULE:[2:$1](johndoe)s/^. * $/guest/
      auth_to_local = RULE:[2:$1;$2](^. * ;admin$)s/;admin$//
      auth_to_local = RULE:[2:$2](^. * ;root)s/^. * $/root/
      auto_to_local = DEFAULT
      }
    注:
      此标记允许您设置将主体名称映射到本地用户名的一般规则。如果对正在翻译的主体名称没有显式映射,
    则将使用它。可能的值是主体名称将用作本地用户名。如果主体有多个组件或不在默认域中,则此规则
    不适用,转换将失败。
    auth_to_local 表达式的格式:
      [n:string](regexp)s/pattern/replacement/g
      注:
        n:  为整数,指明目标主体应该有几部分组成。
        string:   是引用后面(regexp).. 正则匹配到的内容. 's///g'这是查询替换的语法,g:全局替换.
            如果主体是johndoe/admin,那么[2:$2$1foo]将生成字符串adminjohndoefoo)。
            如果这个字符串匹配regexp,那么将在该字符串上运行s//[g]替换命令。
            可选的g将导致对字符串的替换是全局的,而不是只替换字符串中的第一个匹配项。
            上面三个示例说明: 将导致任何没有root或admin的主体作为第二个使用默认规则进行翻译的组件。
            带有第二个admin组件的主体将成为它的第一个组件。根将用作具有根的第二个组件的任何主体的本地名称。
            这两条规则的例外是任何主体johndoe/*,它总是获取本地名称guest。【还是不懂如何使用!】

  [domain_realm]
    #部分提供了从域名或主机名到Kerberos realm name的转换。注:主机名和域名应该用小写字母。
    crash.mit.edu = TEST.ATHENA.MIT.EDU
    .dev.mit.edu = TEST.ATHENA.MIT.EDU
    mit.edu = ATHENA.MIT.EDU
      #在将域名映射为Kerberos的Realm名时,越精确越优先匹配,此例中若前两个都没有匹配,则属于mit.edu域的所有
      主机名都将被映射为ATHENA.MIT.EDU. 若主机名也不匹配mit.edu,则根据[libdefaults] realm_try_domains
      的设置值,来尝试将完全合格域名的主机名,中的域名部分转换为Kerberos Realm名.
    realm_try_domains=[-1|0|1|..] # -1:不转换. 0:FQDN(server.a.com)将a.com转换为Realm名, 1:将com转换为Real名.
                    依次类推.

  Kerberos Ticket(票证) 缓存类型和密钥文件(keytab)
    ccache type 是定义具体的keytab密钥文件以什么方式缓存在Kerberos客户端, 它支持缓存在进程内存中,
    或缓存在磁盘上,表现为具体的文件,也支持使用KCM这类缓存密钥文件的服务器上.
    而keytab部分主要说明, 它的组成及内部格式.

  ccache type:
    ticket缓存,是为了避免客户端多次访问Web或Mail服务时,每次都向KDC发送验证信息,获取ticket,
  从而提高客户端的访问体验. 但缓存密钥会带来一定的风险, 因为缓存的密钥将允许,登录用户直接
  登录授权主机,而无需密码. 所以需要谨慎使用.
    klist -A 可查看缓存信息.
    它输出的信息包含:服务端principal名,客户端prinicipal名,生存期信息和标志,及ticket本身等.
    ticket的缓存类型有七类:
      1.KEYRING:仅linux可用,它使用内核KEYRING支持将认证数据存储在不可交换的内核内存中,只有当前用户才能访问它。
        它支持:
        • KEYRING:name
        • KEYRING:process:name - process keyring
        • KEYRING:thread:name - thread keyring
        • KEYRING:session:name - session keyring
        • KEYRING:user:name - user keyring
        • KEYRING:persistent:uidnumber     #此类型必须内核支持,否则它将默认使用user keyring.
      2.DIR: 在多Kerberos realm或多KDC环境下比较常用,它用于指定一个目录,来统一缓存这些ticket.
      3.FILE: 默认值.缓存单个ticket.
      4.MEMORY:若ticket仅被一个进程所使用,可使用内存来缓存ticket,这样更安全,而且当进程退出时,
            ticket将被销毁.
      5. MSLSA和API: 仅适用于Windows
      6.KCM: 使用KCM服务器来缓存ticket,但Kerberos5目前还未实现KCM,若要使用有两种途径:
          1.使用Heimdel提供的KCM.

          2.必须是OS X系统,它实现了一个自带的KCM.

  keytab(key table):
    它如其名,它通常是一个标准文件,文件中每行存储一个principal name 对应的密钥版本号、加密类型和加密密钥本身,及时间戳组成.
   它主要用于允许服务器应用程序接受来自客户机的身份验证,但也可用于为客户机应用程序获取初始凭据。

    图片未上传,请自行使用 klist  -k  KeytabFile   -teK  查看.
    它的格式:
      type:value
      type: 有三种值: 【注: 这部说明,和ccache不知道有何区别.】
      FILE:表示一个标准文件,其值必须为绝对路径的文件名.
      MEMORY:表示存储在当前进程内存中的临时keytab.
      SRVTAB:表示不支持Kerberos 4 SRVTAB格式的文件

    klist -k #可查看keytab.
    kadmin:可用它们从KDC数据库中提取密钥.
    ktadd :可以创建或附加Keytabs
    ktutil(1)和k5srvutil(1)命令可操纵Keytabs

  服务器端默认keytab:
    如果应用程序没有请求特定的keytab,则服务器应用程序将使用缺省keytab。默认keytab的名称由以下内容决定,按优先级递减顺序排列:
    1. KRB5_KTNAME:使用此环境变量指定的keytab
    2. 使用配置文件中default_keytab_name所指定的keytab
    3. 按照代码中缺省keytab查找 FILE:/etc/krb5.keytab。

  客户端默认Keytab查找顺序:
    1.The KRB5_CLIENT_KTNAME environment variable.
    2. The default_client_keytab_name profile variable in libdefaults.
    3. 按照代码中缺省keytab查找FILE:/var/kerberos/krb5/user/%{euid}/client.keytab

kdc.conf:

  此配置文件是krb5.conf的补充,它们可合并在一起.此配置文件是给krb5kdc,kadmind守护进程及kdb5_util程序使用的配置文件.
该文件默认位置: /var/kerberos/krb5kdc, KRB5_KDC_PROFILE:此环境变量可用于指定自定义的kdc.conf文件的位置.
另注: 所有对kdc.conf的修改,都需要重启KDC服务,方可生效.

它包含以下部分:
  [kdcdefaults] KDC行为的默认值
  [realms] 特定于realm的数据库配置和设置
  [dbdefaults]数据库默认设置
  [dbmodules] Per-database settings
  [logging] 控制Kerberos守护进程执行日志记录的方式

此配置文件主要配置:
  [kdcdefaults] 和 [realms],kdcdefaults是提供kdc默认值的,即 realms中没有提供的参数值,
  将从该定义中获取该参数值.

[realms]:
  acl_file      #访问控制列表文件的位置,kadmind使用该文件确定允许哪些主体以及
            Kerberos数据库上的哪些权限。
  database_module:    #默认值是域名。若无[dbmodules]段,则默认值将用于所有数据库参数。
  database_name:       #当前realm的Kerberos数据库的位置。默认值是/var/kerberos/krb5kdc/principal.
            【注: 此参数,已标记为废弃】
  default_principal_expiration      #指定在此realm中创建的principals默认过期时间。默认为0:即从不过期
  default_principal_flags:       #指定在此realm中创建principal时的默认属性.
                  可指定多个默认属性字段,每个字段用逗号隔开; +: 表示启用, -:禁用.
                  默认启用的属性: postdateable, forwardable, tgt-based, renewable,
                    proxiable, dup-skey,allow-tickets, 和service
         preauth:如果在客户端主体上启用了此标志,则需要该主体在接收任何票据之前对KDC进行预认证。
            在服务主体上,启用此标志意味着该主体的服务票证将只颁发给具有已设置预验证位的TGT的客户端。

  allow-tickets    #启用给认证客户端生成ticket,不启用,意味着客户端将无法认证.
  dup-skey      #启用此标志允许主体为另一个用户获取会话密钥,从而允许对该主体进行用户对用户的身份验证。

  restrict_anonymous_to_tgt=false    #false:允许匿名principal对服务principal的票证请求.
                    true:拒绝匿名访问,不允许对服务进行匿名身份验证.
  kadmind_listen=[IP|Port|IP:Port|[IPv6][:Port]]    #可指定多个,用逗号隔开.
  kadmind_port=[Port]          #默认kadmind守护进程的监听的端口为749,若设置了kadmind_listen,则该参数
                    设置的端口将覆盖此参数的值.
  kdc_listen=[IP|Port|IP:Port|[IPv6][:Port]]    #指定krb5kdc守护进程的UDP监听地址和/或端口
  kdc_ports :          #krb5kdc守护进程监听UDP请求的端口,默认端口为88
  kdc_tcp_listen=[IP|Port|IP:Port|[IPv6][:Port]]    #指定krb5kdc守护进程的TCP监听地址和/或端口
                        若要禁用TCP,可将该值设置为kdc_tcp_listen=""。
  kdc_tcp_ports:       #krb5kdc守护进程监听TCP请求的端口,默认端口为88
  kpasswd_listen=[IP|Port|IP:Port|[IPv6][:Port]]    #指定kadmind的kpasswd守护进程监听的地址和端口,默认464.
  kpasswd_port       #设置kpasswd的监听端口
  max_life           #指定票证在此域(realm)中可能有效的最大时间段。默认值是24小时。
  max_renewable_life:       #指定有效票证在此领域中可以更新的最长时间。默认值为0:不可更新。
  no_host_referral        #列出要阻止获得基于主机的引用处理的服务,即使客户机将服务器主体标记为基于主机的,
                或者服务也列在host_based_services中。no_host_reference =*将完全禁用引用处理。
  des_crc_session_supported=true    #true:提供对弱加密方式des-cbc-crc的支持,但kbr5.conf[libdefaults]中若
                    定义了allow_weak_crypto=false,即不允许弱加密,则此参数无效.
  key_stash_file           # 指定主键存储的位置(通过kdb5_util stash)。
                    默认/var/kerberos/krb5kdc/.k5.REALM,其中领域是Kerberos领域。
   supported_enctypes    #指定此域中主体的默认key/salt组合。通过kadmin创建的任何主体都将具有这些类型的key。
            这个标签的默认值是:
              aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal
              des3-cbc-sha1:normal arcfour-hmac-md5:normal。

kadm5.acl:
    Kerberos kadmind守护进程使用访问控制列表(ACL)文件管理Kerberos数据库的访问权限。
  对于影响主体(principal)的操作,ACL文件还控制哪些主体(principals)可以操作哪些其他主体。
  若修改了该ACL文件,必须重启kadmind,才能使配置生效.

语法格式:
  #: 注释行

  #ACL文件中的行顺序很重要。第一个匹配条目将控制目标主体上的参与者主体的访问。
  principal permissions [target_principal [restrictions] ]
  注:
    principal: 指定要控制权限的主体名,可使用'*'做通配符
    permissions: 设置主体可执行 和 不可执行的操作.该值可由以下多个字符组成.
          以下字母,小写为允许操作, 大写为不允许操作.
          a 允许添加主体或策略
          c 允许更改主体的密码
          d 允许删除主体或策略
          e 允许提取主键
            注:该特权允许用户从数据库中提取密钥,必须非常小心地处理,以避免泄露重要密钥,
              比如kadmin/*或krbtgt/*主体的密钥。
          i 允许查询主体或策略
          l 允许列出所有主体或策略
          m 允许修改主体或策略
          p 允许传播主体数据库(用于增量数据库传播)
             s 允许为主体显式设置键
          x|* admcilsp的缩写。所有特权(但不包含e)
        注:
          lockdown_keys主体属性可用于防止从特定主体提取密钥,而不管授予的特权是什么。

      target_principal: [可选],指定可应用权限的主体,主体名可使用通配符'*',【不懂和principal的区别】
      restrictions: [可选]
          {+|-}flagname #flagname强制指定值。允许的标志与kdc.conf中的default_principal_flags变量的标志相同。
            -clearpolicy #强制策略为空
          -policy Pol #强制策略为指定的Pol.
          -{expire, pwexpire, maxlife, maxrenewlife} Time #(getdate字符串)关联值将强制使用MIN(时间,请求值)。

  ACL文件配置示例:
    #TEST.EDU这个realm(领域)的所有主体(principal)都将具有管理特权.
    */[email protected]     *
    [email protected]       ADMCIL
    joeadmin/*@TEST.EDU    il          */[email protected]
    以上三条结合起来看:
      joeadmin用户,拥有管理admin实例joeadmin/[email protected]的所有权限
      但他对null实例[email protected]完全没有权限(第2行)
      他对root,非admin和 非null实例(例如extra或dbadmin)具有查询任何具有实例主体的权限(匹配第3行)。

    */[email protected]       ci      *[email protected]
          #TEST.EDU中的任何root主体都可以查询或更改其null实例的密码,
          但不能查询或更改其他任何null实例的密码。
          (这里,*1表示反向引用"*/[email protected]"中'*'所匹配到的内容。)
    */[email protected]      l     *
          #TEST.EDU中的任何根主体都可以生成数据库中的主体列表和数据库中的策略列表。
          这一行与第4行是分开的,因为list权限只能全局授予,而不能授予特定的目标主体。
    [email protected]       x      * -maxlife 9h -postdateabl
          #服务管理系统主体sms@TEST_EDU拥有所有权限,但是它创建或修改的任何主体
          都不能获得可更新的ticket(票据)或生命周期超过9小时的ticket。

      注: 这部分我理解不深,希望有更深入了解的大牛,分享共同学习

Kerberos数据库管理:

    kerberos DB中存储了realm(领域)中所有Kerberos Principal(Kbr主体),他们的密码,及他们的其他管理信息.
  Kerberos5 目前使用的是嵌入式高性能数据库 berkeley DB 1.8版本的.
  该数据库读性能很强,但写一般,大小仅300k左右. 目前已被Oracle收购.

  KbrDB可被三个工具操作:
    管理员:   kdb5_util :来整体管理Kerberos数据库.
        kadmin: 用来修改数据库中的具体条目.
    用户: kpasswd: 来修改自己的密码.

        kadmin.local : 这是网络管理Kerberos数据库的工具,它受到上面提到的ACL文件的访问控制.

  kdb5_util:
    kdb5_util提供了创建、删除、加载或转储Kerberos数据库的方法。它还包含滚转数据库主键的命令,
    以及保存密钥的副本,以便kadmind和krb5kdc守护进程可以使用数据库而不需要手工输入密码.

  kadmin:
    kadmin提供Kerberos主体、密码策略和服务密钥表(keytabs)的维护。
    它通常扮演网络客户机,使用Kerberos身份验证与kadmind通信,来远程维护数据库.
  kadmin.local:
    它可直接访问本地文件系统上的Kerberos数据库(或通过LDAP),要批量操作数据库,必须使用kadmin.local。

  创建kerberos数据库:
    kdb5_util [-r realm] [-d dbname] [-k mkeytype] [-M mkeyname]
    [-kv mkeyVNO] [-sf stashfilename] [-m] command [command_options]
    公共选项说明:
      -r RealmName      #指定Kerberos数据库的领域名.
      -d DBName      #指定存储主体(principal)数据库的名称;
                  默认情况下,数据库是kdc.conf中列出的数据库,密码策略数据库和锁文件也从这个值派生。
      -k MasterKeyType    #指定DB中主键的键类型。默认值由kdc.conf中的master_key_type给出。
      -kv MKVerions     #指定数据库中主键的版本号;默认值是1。注意,0是不允许的。
      -M MKName      #数据库中主键的主体名称。若未指定,则使用kdc.conf中master_key_name的值。
      -sf 隐藏文件名     #若需要创建数据库的隐藏文件,可使用此选项设置该隐藏文件名.
      -m            #要求密码必需从键盘输入
      -P Password      #指定Master DB的数据库密码.

    kdb5_util create [-s]    #-s:创建数据库的隐藏文件,若数据库存在,则会创建失败.
                隐藏文件允许KDC向数据库实用程序(如kadmind、krb5kdc和kdb5_util)进行身份验证。
        destroy [-f] #-f:不提示用户,直接删除数据库.
        示例:
        创建Kerberos数据库:
        [root@ldap krb5kdc]# kdb5_util create -s -P zhang75656
        Loading random data
          Initializing database '/var/kerberos/krb5kdc/principal' for realm 'ZCF.COM',
          master key name 'K/[email protected]'
        
          .k5.ZCF.COM:

            就是创建的数据库, 创建的隐藏文件.

  管理Kerberos数据库的两种方式:
    Kerberos服务器上,本地管理:
    kadmin.local:
      lock      #仅锁定数据库(使用时要特别小心!)
      unlock    #Release exclusive database lock
      purgekeys   #从主体中清除以前保留的旧密钥
      get_strings, getstrs      #在主体上显示字符串属性

  远程管理kerberos的数据库:
    kadmin -r RealmName [ -p 安全主体名 |-k [-t keytab] | -c ] -s KerberosServer[IP|Hostname]
    注:
      -p : 指定Kerberos数据库中以存在,并且在kadm5.acl 中为其配置了足够权限的安全主体(可理解为用户名).
      -k : 若不指定-t Keytab ,则默认使用 /etc/krb5.keytab.中包含的第一个可认证安全主体去连接登录kerberos.
      -c: 使用缓存中的密钥 或 缓存中的keytab密钥来登录kerberos.

另外在官方说明文档中,还有很多高级部分并未深入学习.
如: 密码策略, 数据库管理等.

实验部分:

  1. 通过Kerberos 协议实现无密码SSH登录
  2. 通过Kerberos 协议实现安全的NFS共享

  实验环境:
      hostname: kerberos.zcf.com
      KerberosServer【192.168.10.21】
        NTPServer
        DNSServer
          |
      ------------------------------------------------
      |                 |
    Hosname:server.zcf.com      Hostname:client.zcf.com
    SSHServer               Client【192.168.10.22】
    NFSServer
    【192.168.10.113】

    注意:
      DNS已经配置好了主机名解析, 若无DNS,必须在/etc/hosts中添加解析记录.
      NTP服务器也是配置好的, 并且使用ntpdata都强制同步了时间.

KerberosServer:
  1. 安装Kerberos
    yum install krb5-devel krb5-server krb5-workstation pam_krb5

  2. 修改krb5.conf 和 kdc.conf

    vim /etc/krb5.conf
      # Configuration snippets may be placed in this directory as well
      includedir /etc/krb5.conf.d/

    [logging]
    default = FILE:/var/log/krb5libs.log
    kdc = FILE:/var/log/krb5kdc.log
    admin_server = FILE:/var/log/kadmind.log

    [libdefaults]
    default_realm = ZCF.COM
    dns_lookup_realm = false
    ticket_lifetime = 24h
    renew_lifetime = 1d
    forwardable = true
    rdns = false
    clockskew = 1d
    # default_realm = EXAMPLE.COM
    default_ccache_name = KEYRING:persistent:%{uid}

    [realms]
    ZCF.COM = {
      kdc = kerberos.zcf.com
      admin_server = kerberos.zcf.com
      auth_to_local = RULE:[2:$1](user1)s/^.*$/root/
    }

    [domain_realm]
    .zcf.com = ZCF.COM
    zcf.com = ZCF.COM

  

  vim /var/kerberos/krb5kdc/kdc.conf
    [kdcdefaults]
    kdc_ports = 88
    kdc_tcp_ports = 88

    [realms]
    ZCF.COM = {
      acl_file = /var/kerberos/krb5kdc/kadm5.acl
      dict_file = /usr/share/dict/words
      admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
      max_life = 10h 0m 0s
      max_renewable_life = 7d 0h 0m 0s
      #master_key_name = 'K/[email protected]'
      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
      #database_name = /var/kerberos/krb5kdc/principal
    }

  3. 创建Kerberos数据库
    kdb5_util create -s -P 123456789
      Loading random data
      Initializing database '/var/kerberos/krb5kdc/principal' for realm 'ZCF.COM',
          master key name 'K/[email protected]'      #创建krb5的数据库

  4. 创建安全主体(可简单理解为 创建用户)
    注:
    Principal 是由三个部分组成:
    名字(name),实例(instance),REALM(域)。
    比如一个标准的 Kerberos 的用户是:name/instance@REALM

    kadmin.local
      ?        #列出支持的命令列表
      addprinc     #回车查看帮助

      addprinc zcf
      addprinc user1
      addprinc admin    #创建用户
      listprincs          #查看
      quit            #退出

  5. 配置网络访问Kerberos数据库的权限
    vim /var/kerberos/krb5kdc/kadm5.acl

      #*/[email protected] *   #禁用默认所有admin实例下的安全名具有完全权限.
      [email protected] i         #定义安全主体user1仅可查询.
      [email protected] lae    #定义安全主体admin,可网络登录,并具有列出,添加,导出权限.

  6. 启动Kerberos服务
    systemctl start krb5kdc kadmin
    systemctl status krb5kdc kadmin

  7. 防火墙配置
    firewall-cmd --permanent --add-service=kerberos --add-service=kadmin
    firewall-cmd --reload

  Kerberos实现SSH登录
    1. SSHServer配置:
      vim /etc/ssh/ssh_config
        GSSAPIAuthentication yes
        GSSAPIDelegateCredentials yes
        GSSAPIKeyExchange yes
        GSSAPITrustDNS yes

    2. 重启SSHD服务
      systemctl restart sshd

    3. 配置系统支持Kerberos认证登录
    3.1 安装kerberos客户端工具
      yum install krb5-libs krb5-workstation pam_krb5 authconfig

    3.2 从Kerberos服务器上复制配置文件
      scp kerberos.zcf.com:/etc/krb5.conf /etc/krb5.conf

    3.3 导入主机凭据(Host Credential)
      kadmin -r ZCF.COM -p admin -s kerberos.zcf.com
          #输入admin这个安全主体的密码登录成功后:
      addprinc -randkey host/server.zcf.com      #创建主机凭据,使用自动随机密码.
      ktadd -k /etc/krb5.keytab host/server.zcf.com    #导出主机凭据到/etc/krb5.keytab文件中.
          注: admin必须有权限导出,前面已授权了.

    3.4 查看导出的密钥文件.
      klist -k /etc/krb5.keytab -teK

    3.5 配置系统使用kerberos协议认证
      authconfig --enablekrb5 --krb5kdc=kerberos.zczf.com --krb5realm=ZCZF.COM --update

    4. 配置客户端连接SSH登录时, 使用指定的安全主体
      vim ~/.k5login
        [email protected] #注: zcf这个安全主体在上文已经添加到kerberos数据库中.

客户端配置:
  1. 安装kerberos支持软件
    yum install krb5-libs krb5-workstation pam_krb5
      注:
      ubuntu 需要安装: krb5-user

  2. 修改kerberos主配置文件,可直接从kerberos上复制
    scp kerberos.zcf.com:/etc/krb5.conf /etc/krb5.conf

  3. 创建并导出主机密钥
    kadmin -r ZCF.COM -p admin -s kerberos.zcf.com
      addprinc -randkey   host/client.zcf.com
      ktadd -k    /etc/krb5.keytab    host/client.zcf.com

  4. 查看导出密钥
    klist -k /etc/krb5.keytab -teK

  5. 获取SSH Server端指定允许的安全主体密钥,并使用该安全主体做验证.
    kinit zcf         #输入密码后,获取成功
    klist -l      #查看已经缓存的安全主体zcf的密钥信息.
      注:
      获取zcf安全主体的密钥信息的过程,大致可理解如下:
      #客户端使用直接的主机凭据中的密钥对自己的认证信息做加密,
      #然后在附加上主机凭据名,发给KDC.
  可简单理解:
    主机凭据: host/client.zcf.com: 凭据密钥: Kc
    注意: 主机凭据名,在发给KDC前,它一般组合格式为:
      名字: host 实例名: hostname 域名:KDC的Realm
        在测试中,我自己的理解:
      这个主机凭据是从keytab中获取的, 但keytab中可能有多个
    凭据,到底使用那个? 不同软件搜索Principal(主体)名是不同的,
    如下面要说的NFS,它的搜索方式是 host/主机名@realm,
    或nfs/主机名@realm,等...它定义了多个.
    #Kerberos接收到请求后,通过明文:host/client.zczf.com凭据名.
    找到该凭据对应的密钥, 使用该密钥对预认证信息解密.

      Client--[凭据名{预认证信息}Kc]---------------->Kerberos(KDC)

    #KDC检查客户端的预认证信息,知道该客户端是合法客户端,
      接着给该客户端生成Ticket(TGT:票据),并使用自己的密钥(K)对该Ticket,
      加密,然后使用客户端的密钥(Kc), 对客户端和KDC之间通信的随机密钥加密.

      KDC--[{TGT}K {randkey}Kc]------------------>Client

    #客户端获取TGT和随机密钥后, 接着将 获取安全主体zcf密钥的请求 使用随机密钥
    加密,并附加TGT认证信息,发给KDC; Kck:KDC和Client直接的随机密钥

      Client---[{TGT}K {zcf密钥是什么}Kck]---------->KDC

   #KDC收到请求后,使用自己的密钥解密TGT,知道是Client发来的信息,找到与Client
    之间的随机密钥,解密请求信息. 获知Client需要zcf的密钥,然后,从数据库中获取
    zcf的密钥, 并使用Kck加密,返回给Client.

      KDC--[{zcf的密钥}Kck]---------------------------->Client

  6. 测试登录SSH Server
    ssh [email protected]
      注:
      关于SSH是如何无密码登录成功的,我还不是非常理解内部细节.
      我的理解:
        Client 和 SSHServer之间可通过主机凭据获得互相认证.
        过程大致如下:
        Client---[{TGT}K {我要和SSHServer通信}Kck]---------->KDC

          Ks: SSHServer的密钥
        KDC--[{TGT}Ks {C和S之间的randkey}Kck]--------------->Client

          Kcs: Client和SSHServer之间的随机密钥
        Client--[{TGT}Ks {我的认证信息}Kcs]-------------------->SSHServer

    经过上面的过程,SSHServer认证Client成功,但是SSHServer认证成功,
  并不能让Client登录,因为,系统必须要求登录的人,有帐号信息,而上面
  在认证过程中,并没有涉及任何root帐号的密码信息,因此,无法向系统
  提供root的密码,完成系统登录,因此为了能完成系统登录, 我猜想,
  才需要这个中间帐号 zcf ,Client可能在认证通过后,会向SSHServer
  提交zcf这个安全主体,SSHServer再向系统提交该安全主体,因为系统已经启用了
  Kerberos认证,因此,系统会向Kerberos发起认证,若zcf这个帐号成功认证,
  系统就会允许此次无密码登录.

Kerberos+NFS提供安全的网络共享服务:

  1. 安装NFS服务器软件和kerberos支持软件
    yum install nfs-utils krb5-workstation pam_krb5

  2. 配置NFS导出共享目录,并启用kerberos验证
    mkdir -pv /data/nfs{1,2}

    vim /etc/exports
      /data/nfs1 192.168.10.0/24(rw,sync,sec=krb5p)
      /data/nfs2 192.168.10.0/24(ro,sync)
      注:
      man exports
        sec: sys(默认不加密方式)
        krb5(仅用于身份验证)
        krb5i(完整性保护)
        krb5p(隐私保护)

  3. 配置NFS使用最新版本.
    vim /etc/sysconfig/nfs
      RPCNFSDARGS="--nfs-version 4.2"

  4. 配置Kerberos相关信息
    4.1 复制Kerberos上的主配置文件krb5.conf到本地.
      scp kerberos.zczf.com:/etc/krb5.conf /etc/krb5.conf

    4.2 添加并导入主机密钥
      kadmin -r ZCF.COM -p admin -s kerberos.zcf.com
      addprinc -randkey nfs/server.zcf.com
      ktadd -k /etc/krb5.keytab nfs/server.zcf.com
      注:
        其实SSH节配置时,已经创建主机凭据,这里其实可不创建.
        因为默认NFS从keytab中搜索主机凭据的顺序是:
        <HOSTNAME>$@<REALM>
        root/<hostname>@<REALM>
        nfs/<hostname>@<REALM>
        host/<hostname>@<REALM>
        root/<anyname>@<REALM>
        nfs/<anyname>@<REALM>
        host/<anyname>@<REALM>
        只有找到第一个包含的主机凭据,就不在查询了.

    4.3 验证导出的密钥
      klist -k /etc/krb5.keytab -teK

  5. 启动NFS服务
      systemctl start nfs nfs-secure
      systemctl status nfs nfs-secure

  6. 配置防火墙
    firewall-cmd --permanent --add-service=nfs
    firewall-cmd --reload

  7. SELinux
    NFS服务导出的共享目录不需要添加SELinux的标签. 所以不建议给NFS共享添加写权限.
    从NFSv4.2后exports中多一个security_label,此选项似乎可设置SELinux标签。
    翻译:
      通过设置此选项,使用NFSv4.2或更高版本的客户机将能够设置和检索安全标签(如SELinux使用的那些标签)。
      只有当所有客户端使用一致的安全策略时,这才会有效。注意,早期内核不支持这个导出选项,
      默认情况下启用了安全标签。

      NFS是不支持用户名密码这种方式的身份认证的.
      但可通过kerberos这种共享密码认证协议做验证.

NFS客户端配置:
  1. 安装软件
    yum install nfs-utils krb5-workstation pam_krb5

  2. 配置Kerberos相关信息
    2.1 复制Kerberos上的主配置文件krb5.conf到本地.
      scp kerberos.zcf.com:/etc/krb5.conf /etc/krb5.conf

    2.2 添加并导入主机密钥
      kadmin -r ZCF.COM -p admin -s kerberos.zcf.com
      addprinc -randkey nfs/server.zcf.com
      ktadd -k /etc/krb5.keytab nfs/server.zcf.com

    2.3 验证导出的密钥
      klist -k /etc/krb5.keytab -teK

  3. 创建挂载点
    mkdir -pv /mnt/nfs{1,2}

  4. 启动NFS支持Kerberos的rpc.gssd服务.
    systemctl start nfs-secure
    systemctl status nfs-secure

  5. 测试挂载
    5.1 先测试NFS服务是否可正常提供服务
      mount server.zcf.com:/data/nfs2 /mnt/nfs2

    5.2 若上面成功,说明,NFSServer是正常工作的.
      mount -t nfs -o v4.2,sec=krb5p server.zcf.com:/data/nfs1 /mnt/nfs1

    5.3 最后添加/etc/fstab,实现开机自动挂载
      vim /etc/fstab
        server.zcf.com:/data/nfs1 /mnt/nfs1 nfs defaults,rw,v4.2,sec=krb5p 0 0

  另注:
    其实不用每次都使用 kadmin 远程登录kerberos,来操作数据库, 可以直接在kerberos服务器
    直接将密钥导出来,scp到每个客户端上即可.

遇到的错误:
参考文章:
https://blog.csdn.net/weixin_42442164/article/details/82110859
https://blog.csdn.net/weixin_33832340/article/details/86931220

NFS客户端错误:
Apr 6 07:27:26 rnode6 rpc.gssd[14301]: ERROR: failed to parse nfs/clnt1e/info
Apr 6 07:27:36 rnode6 rpc.gssd[14301]: ERROR: unable to resolve 192.168.10.113 to hostname: Name or service not known
解决:
在DNS上添加对PTR zone.让DNS支持对192.168.10.113的反向解析

Kerberos错误:
Apr 06 09:34:47 ldap.zczf.com krb5kdc[5701](info): TGS_REQ (4 etypes {18 17 16 23}) 192.168.10.22: LOOKING_UP_SERVER: authtime 0, nfs/[email protected] for nfs/[email protected], Server not found in Kerberos database
解决:
提示没有找到nfs/[email protected]的主体记录, 就是因为之前做实验时,没有搞清楚安全主体的构成.
所以添加错误了.只需要在添加一个 nfs/server.zczf.com的安全主体即可.

05-11 19:54