精华内容
下载资源
问答
  • HDFS配置Kerberos认证

    万次阅读 2016-04-22 10:03:13
    HDFS配置Kerberos认证

    Hadoop Kerberos安全机制介绍



    HDFS配置Kerberos认证

    2014.11.04

    本文主要记录 CDH Hadoop 集群上配置 HDFS 集成 Kerberos 的过程,包括 Kerberos 的安装和 Hadoop 相关配置修改说明。

    注意:

    下面第一、二部分内容,摘抄自《Hadoop的kerberos的实践部署》,主要是为了对 Hadoop 的认证机制和 Kerberos 认证协议做个简单介绍。在此,对原作者表示感谢。

    1. Hadoop 的认证机制

    简单来说,没有做 kerberos 认证的 Hadoop,只要有 client 端就能够连接上。而且,通过一个有 root 的权限的内网机器,通过创建对应的 linux 用户,就能够得到 Hadoop 集群上对应的权限。

    而实行 Kerberos 后,任意机器的任意用户都必须现在 Kerberos 的 KDC 中有记录,才允许和集群中其它的模块进行通信。

    详细介绍请参考 Hadoop安全机制研究

    2. Kerberos 认证协议

    Kerberos 是一种网络认证协议,其设计目标是通过密钥系统为客户机/服务器应用程序提供强大的认证服务。

    使用 Kerberos 时,一个客户端需要经过三个步骤来获取服务:

    • 认证:客户端向认证服务器发送一条报文,并获取一个含时间戳的 Ticket-Granting Ticket(TGT)。
    • 授权:客户端使用 TGT 向 Ticket-Granting Server(TGS)请求一个服务 Ticket。
    • 服务请求:客户端向服务器出示服务 Ticket ,以证实自己的合法性。

    为此,Kerberos 需要 The Key Distribution Centers(KDC)来进行认证。KDC 只有一个 Master,可以带多个 slaves 机器。slaves 机器仅进行普通验证。Mater 上做的修改需要自动同步到 slaves。

    另外,KDC 需要一个 admin,来进行日常的管理操作。这个 admin 可以通过远程或者本地方式登录。

    3. 搭建 Kerberos

    3.1 环境

    我们在三个节点的服务器上安装 Kerberos,这三个节点上安装了 hadoop 集群,安装 hadoop 过程见:使用yum安装CDH Hadoop集群。这三个节点机器分布为:cdh1、cdh2、cdh3。

    • 操作系统:CentOs 6.6
    • 运行用户:root

    3.2 安装过程

    3.2.1 准备工作

    确认添加主机名解析到 /etc/hosts 文件中。

    $ cat /etc/hosts
    127.0.0.1       localhost
    
    192.168.56.121 cdh1
    192.168.56.122 cdh2
    192.168.56.123 cdh3
    

    注意:hostname 请使用小写,要不然在集成 kerberos 时会出现一些错误。

    3.2.2 安装 kdc server

    在 KDC (这里是 cdh1 ) 上安装包 krb5、krb5-server 和 krb5-client。

    $ yum install krb5-server krb5-libs krb5-auth-dialog krb5-workstation  -y
    

    在其他节点(cdh1、cdh2、cdh3)安装 krb5-devel、krb5-workstation :

    $ ssh cdh1 "yum install krb5-devel krb5-workstation -y"
    $ ssh cdh2 "yum install krb5-devel krb5-workstation -y"
    $ ssh cdh3 "yum install krb5-devel krb5-workstation -y"
    

    3.2.3 修改配置文件

    kdc 服务器涉及到三个配置文件:

    /etc/krb5.conf
    /var/kerberos/krb5kdc/kdc.conf
    /var/kerberos/krb5kdc/kadm5.acl
    

    配置 Kerberos 的一种方法是编辑配置文件 /etc/krb5.conf。默认安装的文件中包含多个示例项。

    $ cat /etc/krb5.conf
      [logging]
       default = FILE:/var/log/krb5libs.log
       kdc = FILE:/var/log/krb5kdc.log
       admin_server = FILE:/var/log/kadmind.log
    
      [libdefaults]
       default_realm = JAVACHEN.COM
       dns_lookup_realm = false
       dns_lookup_kdc = false
       clockskew = 120
       ticket_lifetime = 24h
       renew_lifetime = 7d
       forwardable = true
       renewable = true
       udp_preference_limit = 1
       default_tgs_enctypes = arcfour-hmac
       default_tkt_enctypes = arcfour-hmac
    
      [realms]
       JAVACHEN.COM = {
        kdc = cdh1:88
        admin_server = cdh1:749
       }
    
      [domain_realm]
        .javachen.com = JAVACHEN.COM
        www.javachen.com = JAVACHEN.COM
    
      [kdc]
      profile=/var/kerberos/krb5kdc/kdc.conf
    

    说明:

    • [logging]:表示 server 端的日志的打印位置
    • [libdefaults]:每种连接的默认配置,需要注意以下几个关键的小配置
      • default_realm = JAVACHEN.COM:设置 Kerberos 应用程序的默认领域。如果您有多个领域,只需向 [realms] 节添加其他的语句。
      • udp_preference_limit= 1:禁止使用 udp 可以防止一个Hadoop中的错误
      • clockskew:时钟偏差是不完全符合主机系统时钟的票据时戳的容差,超过此容差将不接受此票据。通常,将时钟扭斜设置为 300 秒(5 分钟)。这意味着从服务器的角度看,票证的时间戳与它的偏差可以是在前后 5 分钟内。
      • ticket_lifetime: 表明凭证生效的时限,一般为24小时。
      • renew_lifetime: 表明凭证最长可以被延期的时限,一般为一个礼拜。当凭证过期之后,对安全认证的服务的后续访问则会失败。
    • [realms]:列举使用的 realm。
      • kdc:代表要 kdc 的位置。格式是 机器:端口
      • admin_server:代表 admin 的位置。格式是 机器:端口
      • default_domain:代表默认的域名
    • [appdefaults]:可以设定一些针对特定应用的配置,覆盖默认配置。

    修改 /var/kerberos/krb5kdc/kdc.conf ,该文件包含 Kerberos 的配置信息。例如,KDC 的位置,Kerbero 的 admin 的realms 等。需要所有使用的 Kerberos 的机器上的配置文件都同步。这里仅列举需要的基本配置。详细介绍参考:krb5conf

    $ cat /var/kerberos/krb5kdc/kdc.conf
    [kdcdefaults]
     v4_mode = nopreauth
     kdc_ports = 88
     kdc_tcp_ports = 88
    
    [realms]
     JAVACHEN.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 =  des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal des-cbc-crc:v4 des-cbc-crc:afs3
      max_life = 24h
      max_renewable_life = 10d
      default_principal_flags = +renewable, +forwardable
     }
    

    说明:

    • JAVACHEN.COM: 是设定的 realms。名字随意。Kerberos 可以支持多个 realms,会增加复杂度。大小写敏感,一般为了识别使用全部大写。这个 realms 跟机器的 host 没有大关系。
    • master_key_type:和 supported_enctypes 默认使用 aes256-cts。由于,JAVA 使用 aes256-cts 验证方式需要安装额外的 jar 包(后面再做说明)。推荐不使用,并且删除 aes256-cts。
    • acl_file:标注了 admin 的用户权限,需要用户自己创建。文件格式是:Kerberos_principal permissions [target_principal] [restrictions]
    • supported_enctypes:支持的校验方式。
    • admin_keytab:KDC 进行校验的 keytab。

    关于AES-256加密

    对于使用 centos5. 6及以上的系统,默认使用 AES-256 来加密的。这就需要集群中的所有节点上安装 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy File

    下载的文件是一个 zip 包,解开后,将里面的两个文件放到下面的目录中:$JAVA_HOME/jre/lib/security

    为了能够不直接访问 KDC 控制台而从 Kerberos 数据库添加和删除主体,请对 Kerberos 管理服务器指示允许哪些主体执行哪些操作。通过编辑文件 /var/lib/kerberos/krb5kdc/kadm5.acl 完成此操作。ACL(访问控制列表)允许您精确指定特权。

    $ cat /var/kerberos/krb5kdc/kadm5.acl
      */admin@JAVACHEN.COM *
    

    3.2.4 同步配置文件

    将 kdc 中的 /etc/krb5.conf 拷贝到集群中其他服务器即可。

    $ scp /etc/krb5.conf cdh2:/etc/krb5.conf
    $ scp /etc/krb5.conf cdh3:/etc/krb5.conf
    

    请确认集群如果关闭了 selinux。

    3.2.5 创建数据库

    在 cdh1 上运行初始化数据库命令。其中 -r 指定对应 realm。

    $ kdb5_util create -r JAVACHEN.COM -s
    

    出现 Loading random data 的时候另开个终端执行点消耗CPU的命令如 cat /dev/sda > /dev/urandom 可以加快随机数采集。

    该命令会在 /var/kerberos/krb5kdc/ 目录下创建 principal 数据库。

    如果遇到数据库已经存在的提示,可以把 /var/kerberos/krb5kdc/ 目录下的 principal 的相关文件都删除掉。默认的数据库名字都是 principal。可以使用 -d 指定数据库名字。

    3.2.6 启动服务

    在 cdh1 节点上运行:

    $ chkconfig --level 35 krb5kdc on
    $ chkconfig --level 35 kadmin on
    $ service krb5kdc start
    $ service kadmin start
    

    3.2.7 创建 kerberos 管理员

    关于 kerberos 的管理,可以使用 kadmin.local 或 kadmin,至于使用哪个,取决于账户和访问权限:

    • 如果有访问 kdc 服务器的 root 权限,但是没有 kerberos admin 账户,使用 kadmin.local
    • 如果没有访问 kdc 服务器的 root 权限,但是用 kerberos admin 账户,使用 kadmin

    在 cdh1 上创建远程管理的管理员:

    #手动输入两次密码,这里密码为 root
    $ kadmin.local -q "addprinc root/admin"
    
    # 也可以不用手动输入密码
    $ echo -e "root\nroot" | kadmin.local -q "addprinc root/admin"
    

    系统会提示输入密码,密码不能为空,且需妥善保存。

    3.2.8 测试 kerberos

    以下内容仅仅是为了测试,你可以直接跳到下部分内容。

    查看当前的认证用户:

    # 查看principals
    $ kadmin: list_principals
    
      # 添加一个新的 principal
      kadmin:  addprinc user1
        WARNING: no policy specified for user1@JAVACHEN.COM; defaulting to no policy
        Enter password for principal "user1@JAVACHEN.COM":
        Re-enter password for principal "user1@JAVACHEN.COM":
        Principal "user1@JAVACHEN.COM" created.
    
      # 删除 principal
      kadmin:  delprinc user1
        Are you sure you want to delete the principal "user1@JAVACHEN.COM"? (yes/no): yes
        Principal "user1@JAVACHEN.COM" deleted.
        Make sure that you have removed this principal from all ACLs before reusing.
    
      kadmin: exit
    

    也可以直接通过下面的命令来执行:

    # 提示需要输入密码
    $ kadmin -p root/admin -q "list_principals"
    $ kadmin -p root/admin -q "addprinc user2"
    $ kadmin -p root/admin -q "delprinc user2"
    
    # 不用输入密码
    $ kadmin.local -q "list_principals"
    $ kadmin.local -q "addprinc user2"
    $ kadmin.local -q "delprinc user2"
    

    创建一个测试用户 test,密码设置为 test:

    $ echo -e "test\ntest" | kadmin.local -q "addprinc test"
    

    获取 test 用户的 ticket:

    # 通过用户名和密码进行登录
    $ kinit test
    Password for test@JAVACHEN.COM:
    
    $ klist  -e
    Ticket cache: FILE:/tmp/krb5cc_0
    Default principal: test@JAVACHEN.COM
    
    Valid starting     Expires            Service principal
    11/07/14 15:29:02  11/08/14 15:29:02  krbtgt/JAVACHEN.COM@JAVACHEN.COM
      renew until 11/17/14 15:29:02, Etype (skey, tkt): AES-128 CTS mode with 96-bit SHA-1 HMAC, AES-128 CTS mode with 96-bit SHA-1 HMAC
    
    
    Kerberos 4 ticket cache: /tmp/tkt0
    klist: You have no tickets cached
    

    销毁该 test 用户的 ticket:

    $ kdestroy
    
    $ klist
    klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_0)
    
    
    Kerberos 4 ticket cache: /tmp/tkt0
    klist: You have no tickets cached
    

    更新 ticket:

    $ kinit root/admin
      Password for root/admin@JAVACHEN.COM:
    
    $  klist
      Ticket cache: FILE:/tmp/krb5cc_0
      Default principal: root/admin@JAVACHEN.COM
    
      Valid starting     Expires            Service principal
      11/07/14 15:33:57  11/08/14 15:33:57  krbtgt/JAVACHEN.COM@JAVACHEN.COM
        renew until 11/17/14 15:33:57
    
      Kerberos 4 ticket cache: /tmp/tkt0
      klist: You have no tickets cached
    
    $ kinit -R
    
    $ klist
      Ticket cache: FILE:/tmp/krb5cc_0
      Default principal: root/admin@JAVACHEN.COM
    
      Valid starting     Expires            Service principal
      11/07/14 15:34:05  11/08/14 15:34:05  krbtgt/JAVACHEN.COM@JAVACHEN.COM
        renew until 11/17/14 15:33:57
    
      Kerberos 4 ticket cache: /tmp/tkt0
      klist: You have no tickets cached
    

    抽取密钥并将其储存在本地 keytab 文件 /etc/krb5.keytab 中。这个文件由超级用户拥有,所以您必须是 root 用户才能在 kadmin shell 中执行以下命令:

    $ kadmin.local -q "ktadd kadmin/admin"
    
    $ klist -k /etc/krb5.keytab
      Keytab name: FILE:/etc/krb5.keytab
      KVNO Principal
      ---- --------------------------------------------------------------------------
         3 kadmin/admin@LASHOU-INC.COM
         3 kadmin/admin@LASHOU-INC.COM
         3 kadmin/admin@LASHOU-INC.COM
         3 kadmin/admin@LASHOU-INC.COM
         3 kadmin/admin@LASHOU-INC.COM
    

    4. HDFS 上配置 kerberos

    4.1 创建认证规则

    在 Kerberos 安全机制里,一个 principal 就是 realm 里的一个对象,一个 principal 总是和一个密钥(secret key)成对出现的。

    这个 principal 的对应物可以是 service,可以是 host,也可以是 user,对于 Kerberos 来说,都没有区别。

    Kdc(Key distribute center) 知道所有 principal 的 secret key,但每个 principal 对应的对象只知道自己的那个 secret key 。这也是“共享密钥“的由来。

    对于 hadoop,principals 的格式为 username/fully.qualified.domain.name@YOUR-REALM.COM

    通过 yum 源安装的 cdh 集群中,NameNode 和 DataNode 是通过 hdfs 启动的,故为集群中每个服务器节点添加两个principals:hdfs、HTTP。

    在 KCD server 上(这里是 cdh1)创建 hdfs principal:

    kadmin.local -q "addprinc -randkey hdfs/cdh1@JAVACHEN.COM"
    kadmin.local -q "addprinc -randkey hdfs/cdh2@JAVACHEN.COM"
    kadmin.local -q "addprinc -randkey hdfs/cdh3@JAVACHEN.COM"
    

    -randkey 标志没有为新 principal 设置密码,而是指示 kadmin 生成一个随机密钥。之所以在这里使用这个标志,是因为此 principal 不需要用户交互。它是计算机的一个服务器帐户。

    创建 HTTP principal:

    kadmin.local -q "addprinc -randkey HTTP/cdh1@JAVACHEN.COM"
    kadmin.local -q "addprinc -randkey HTTP/cdh2@JAVACHEN.COM"
    kadmin.local -q "addprinc -randkey HTTP/cdh3@JAVACHEN.COM"
    

    创建完成后,查看:

    $ kadmin.local -q "listprincs"
    

    4.2 创建keytab文件

    keytab 是包含 principals 和加密 principal key 的文件。

    keytab 文件对于每个 host 是唯一的,因为 key 中包含 hostname。keytab 文件用于不需要人工交互和保存纯文本密码,实现到 kerberos 上验证一个主机上的 principal。

    因为服务器上可以访问 keytab 文件即可以以 principal 的身份通过 kerberos 的认证,所以,keytab 文件应该被妥善保存,应该只有少数的用户可以访问

    创建包含 hdfs principal 和 host principal 的 hdfs keytab:

    xst -norandkey -k hdfs.keytab hdfs/fully.qualified.domain.name host/fully.qualified.domain.name
    

    创建包含 mapred principal 和 host principal 的 mapred keytab:

    xst -norandkey -k mapred.keytab mapred/fully.qualified.domain.name host/fully.qualified.domain.name
    

    注意
    上面的方法使用了xst的norandkey参数,有些kerberos不支持该参数。
    当不支持该参数时有这样的提示:Principal -norandkey does not exist.,需要使用下面的方法来生成keytab文件。

    在 cdh1 节点,即 KDC server 节点上执行下面命令:

    $ cd /var/kerberos/krb5kdc/
    
    $ kadmin.local -q "xst  -k hdfs-unmerged.keytab  hdfs/cdh1@JAVACHEN.COM"
    $ kadmin.local -q "xst  -k hdfs-unmerged.keytab  hdfs/cdh2@JAVACHEN.COM"
    $ kadmin.local -q "xst  -k hdfs-unmerged.keytab  hdfs/cdh3@JAVACHEN.COM"
    
    $ kadmin.local -q "xst  -k HTTP.keytab  HTTP/cdh1@JAVACHEN.COM"
    $ kadmin.local -q "xst  -k HTTP.keytab  HTTP/cdh2@JAVACHEN.COM"
    $ kadmin.local -q "xst  -k HTTP.keytab  HTTP/cdh3@JAVACHEN.COM"
    

    这样,就会在 /var/kerberos/krb5kdc/ 目录下生成 hdfs-unmerged.keytab 和 HTTP.keytab 两个文件,接下来使用 ktutil 合并者两个文件为 hdfs.keytab

    $ cd /var/kerberos/krb5kdc/
    
    $ ktutil
    ktutil: rkt hdfs-unmerged.keytab
    ktutil: rkt HTTP.keytab
    ktutil: wkt hdfs.keytab
    

    使用 klist 显示 hdfs.keytab 文件列表:

    $ klist -ket  hdfs.keytab
    Keytab name: FILE:hdfs.keytab
    KVNO Timestamp         Principal
    ---- ----------------- --------------------------------------------------------
       2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des3-cbc-sha1)
       2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (arcfour-hmac)
       2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des-hmac-sha1)
       2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des-cbc-md5)
       4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des3-cbc-sha1)
       4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (arcfour-hmac)
       4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des-hmac-sha1)
       4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des-cbc-md5)
       4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des3-cbc-sha1)
       4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (arcfour-hmac)
       4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des-hmac-sha1)
       4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des-cbc-md5)
       3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des3-cbc-sha1)
       3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (arcfour-hmac)
       3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des-hmac-sha1)
       3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des-cbc-md5)
       3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des3-cbc-sha1)
       3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (arcfour-hmac)
       3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des-hmac-sha1)
       3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des-cbc-md5)
       3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des3-cbc-sha1)
       3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (arcfour-hmac)
       3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des-hmac-sha1)
       3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des-cbc-md5)
    

    验证是否正确合并了key,使用合并后的keytab,分别使用hdfs和host principals来获取证书。

    $ kinit -k -t hdfs.keytab hdfs/cdh1@JAVACHEN.COM
    $ kinit -k -t hdfs.keytab HTTP/cdh1@JAVACHEN.COM
    

    如果出现错误:kinit: Key table entry not found while getting initial credentials
    则上面的合并有问题,重新执行前面的操作。

    4.3 部署kerberos keytab文件

    拷贝 hdfs.keytab 文件到其他节点的 /etc/hadoop/conf 目录

    $ cd /var/kerberos/krb5kdc/
    
    $ scp hdfs.keytab cdh1:/etc/hadoop/conf
    $ scp hdfs.keytab cdh2:/etc/hadoop/conf
    $ scp hdfs.keytab cdh3:/etc/hadoop/conf
    

    并设置权限,分别在 cdh1、cdh2、cdh3 上执行:

    $ ssh cdh1 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"
    $ ssh cdh2 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"
    $ ssh cdh3 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"
    

    由于 keytab 相当于有了永久凭证,不需要提供密码(如果修改kdc中的principal的密码,则该keytab就会失效),所以其他用户如果对该文件有读权限,就可以冒充 keytab 中指定的用户身份访问 hadoop,所以 keytab 文件需要确保只对 owner 有读权限(0400)

    4.4 修改 hdfs 配置文件

    先停止集群:

    $ for x in `cd /etc/init.d ; ls hive-*` ; do sudo service $x stop ; done
    $ for x in `cd /etc/init.d ; ls impala-*` ; do sudo service $x stop ; done
    $ for x in `cd /etc/init.d ; ls hadoop-*` ; do sudo service $x stop ; done
    $ for x in `cd /etc/init.d ; ls zookeeper-*` ; do sudo service $x stop ; done
    

    在集群中所有节点的 core-site.xml 文件中添加下面的配置:

    <property>
      <name>hadoop.security.authentication</name>
      <value>kerberos</value>
    </property>
    
    <property>
      <name>hadoop.security.authorization</name>
      <value>true</value>
    </property>
    

    在集群中所有节点的 hdfs-site.xml 文件中添加下面的配置:

    <property>
      <name>dfs.block.access.token.enable</name>
      <value>true</value>
    </property>
    <property>  
      <name>dfs.datanode.data.dir.perm</name>  
      <value>700</value>  
    </property>
    <property>
      <name>dfs.namenode.keytab.file</name>
      <value>/etc/hadoop/conf/hdfs.keytab</value>
    </property>
    <property>
      <name>dfs.namenode.kerberos.principal</name>
      <value>hdfs/_HOST@JAVACHEN.COM</value>
    </property>
    <property>
      <name>dfs.namenode.kerberos.https.principal</name>
      <value>HTTP/_HOST@JAVACHEN.COM</value>
    </property>
    <property>
      <name>dfs.datanode.address</name>
      <value>0.0.0.0:1004</value>
    </property>
    <property>
      <name>dfs.datanode.http.address</name>
      <value>0.0.0.0:1006</value>
    </property>
    <property>
      <name>dfs.datanode.keytab.file</name>
      <value>/etc/hadoop/conf/hdfs.keytab</value>
    </property>
    <property>
      <name>dfs.datanode.kerberos.principal</name>
      <value>hdfs/_HOST@JAVACHEN.COM</value>
    </property>
    <property>
      <name>dfs.datanode.kerberos.https.principal</name>
      <value>HTTP/_HOST@JAVACHEN.COM</value>
    </property>
    

    如果想开启 SSL,请添加(本文不对这部分做说明):

    <property>
      <name>dfs.http.policy</name>
      <value>HTTPS_ONLY</value>
    </property>
    

    如果 HDFS 配置了 QJM HA,则需要添加(另外,你还要在 zookeeper 上配置 kerberos):

    <property>
      <name>dfs.journalnode.keytab.file</name>
      <value>/etc/hadoop/conf/hdfs.keytab</value>
    </property>
    <property>
      <name>dfs.journalnode.kerberos.principal</name>
      <value>hdfs/_HOST@JAVACHEN.COM</value>
    </property>
    <property>
      <name>dfs.journalnode.kerberos.internal.spnego.principal</name>
      <value>HTTP/_HOST@JAVACHEN.COM</value>
    </property>
    

    如果配置了 WebHDFS,则添加:

    <property>
      <name>dfs.webhdfs.enabled</name>
      <value>true</value>
    </property>
    
    <property>
      <name>dfs.web.authentication.kerberos.principal</name>
      <value>HTTP/_HOST@JAVACHEN.COM</value>
    </property>
    
    <property>
      <name>dfs.web.authentication.kerberos.keytab</name>
      <value>/etc/hadoop/conf/hdfs.keytab</value>
    </property>
    

    配置中有几点要注意的:

    • 1. dfs.datanode.address表示 data transceiver RPC server 所绑定的 hostname 或 IP 地址,如果开启 security,端口号必须小于 1024(privileged port),否则的话启动 datanode 时候会报 Cannot start secure cluster without privileged resources 错误
    • 2. principal 中的 instance 部分可以使用 _HOST 标记,系统会自动替换它为全称域名
    • 3. 如果开启了 security, hadoop 会对 hdfs block data(由 dfs.data.dir 指定)做 permission check,方式用户的代码不是调用hdfs api而是直接本地读block data,这样就绕过了kerberos和文件权限验证,管理员可以通过设置 dfs.datanode.data.dir.perm 来修改 datanode 文件权限,这里我们设置为700

    4.5 检查集群上的 HDFS 和本地文件的权限

    请参考 Verify User Accounts and Groups in CDH 5 Due to Security 或者 Hadoop in Secure Mode

    4.6 启动 NameNode

    启动之前,请确认 JCE jar 已经替换,请参考前面的说明。

    在每个节点上获取 root 用户的 ticket,这里 root 为之前创建的 root/admin 的密码。

    $ ssh cdh1 "echo root|kinit root/admin"
    $ ssh cdh1 "echo root|kinit root/admin"
    $ ssh cdh1 "echo root|kinit root/admin"
    

    获取 cdh1的 ticket:

    $ kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh1@JAVACHEN.COM
    

    如果出现下面异常 kinit: Password incorrect while getting initial credentials
    ,则重新导出 keytab 再试试。

    然后启动服务,观察日志:

    $ /etc/init.d/hadoop-hdfs-namenode start
    

    验证 NameNode 是否启动,一是打开 web 界面查看启动状态,一是运行下面命令查看 hdfs:

    $ hadoop fs -ls /
    Found 4 items
    drwxrwxrwx   - yarn hadoop          0 2014-06-26 15:24 /logroot
    drwxrwxrwt   - hdfs hadoop          0 2014-11-04 10:44 /tmp
    drwxr-xr-x   - hdfs hadoop          0 2014-08-10 10:53 /user
    drwxr-xr-x   - hdfs hadoop          0 2013-05-20 22:52 /var
    

    如果在你的凭据缓存中没有有效的 kerberos ticket,执行上面命令将会失败,将会出现下面的错误:

    14/11/04 12:08:12 WARN ipc.Client: Exception encountered while connecting to the server : javax.security.sasl.SaslException:
    GSS initiate failed [Caused by GS***ception: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
    Bad connection to FS. command aborted. exception: Call to cdh1/192.168.56.121:8020 failed on local exception: java.io.IOException:
    javax.security.sasl.SaslException: GSS initiate failed [Caused by GS***ception: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
    

    4.6 启动DataNode

    DataNode 需要通过 JSVC 启动。首先检查是否安装了 JSVC 命令,然后配置环境变量。

    在 cdh1 节点查看是否安装了 JSVC:

    $ ls /usr/lib/bigtop-utils/
    bigtop-detect-classpath  bigtop-detect-javahome  bigtop-detect-javalibs  jsvc
    

    然后编辑 /etc/default/hadoop-hdfs-datanode,取消对下面的注释并添加一行设置 JSVC_HOME,修改如下:

    export HADOOP_SECURE_DN_USER=hdfs
    export HADOOP_SECURE_DN_PID_DIR=/var/run/hadoop-hdfs
    export HADOOP_SECURE_DN_LOG_DIR=/var/log/hadoop-hdfs
    
    export JSVC_HOME=/usr/lib/bigtop-utils
    

    将该文件同步到其他节点:

    $ scp /etc/default/hadoop-hdfs-datanode cdh2:/etc/default/hadoop-hdfs-datanode
    $ scp /etc/default/hadoop-hdfs-datanode cdh3:/etc/default/hadoop-hdfs-datanode
    

    分别在 cdh2、cdh3 获取 ticket 然后启动服务:

    #root 为 root/admin 的密码
    $ ssh cdh1 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh1@JAVACHEN.COM; service hadoop-hdfs-datanode start"
    $ ssh cdh2 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh2@JAVACHEN.COM; service hadoop-hdfs-datanode start"
    $ ssh cdh3 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh3@JAVACHEN.COM; service hadoop-hdfs-datanode start"
    

    观看 cdh1 上 NameNode 日志,出现下面日志表示 DataNode 启动成功:

    14/11/04 17:21:41 INFO security.UserGroupInformation:
    Login successful for user hdfs/cdh2@JAVACHEN.COM using keytab file /etc/hadoop/conf/hdfs.keytab
    

    5. 其他

    5.1 批量生成 keytab

    为了方便批量生成 keytab,写了一个脚本,如下:

    #!/bin/bash
    
    DNS=LASHOU.COM
    hostname=`hostname -i`
    
    yum install krb5-server krb5-libs krb5-auth-dialog krb5-workstation  -y
    rm -rf /var/kerberos/krb5kdc/*.keytab /var/kerberos/krb5kdc/prin*
    
    kdb5_util create -r LASHOU.COM -s
    
    chkconfig --level 35 krb5kdc on
    chkconfig --level 35 kadmin on
    service krb5kdc restart
    service kadmin restart
    
    echo -e "root\nroot" | kadmin.local -q "addprinc root/admin"
    
    for host in  `cat /etc/hosts|grep 10|grep -v $hostname|awk '{print $2}'` ;do
      for user in hdfs hive; do
        kadmin.local -q "addprinc -randkey $user/$host@$DNS"
        kadmin.local -q "xst -k /var/kerberos/krb5kdc/$user-un.keytab $user/$host@$DNS"
      done
      for user in HTTP lashou yarn mapred impala zookeeper sentry llama zkcli ; do
        kadmin.local -q "addprinc -randkey $user/$host@$DNS"
        kadmin.local -q "xst -k /var/kerberos/krb5kdc/$user.keytab $user/$host@$DNS"
      done
    done
    
    cd /var/kerberos/krb5kdc/
    echo -e "rkt lashou.keytab\nrkt hdfs-un.keytab\nrkt HTTP.keytab\nwkt hdfs.keytab" | ktutil
    echo -e "rkt lashou.keytab\nrkt hive-un.keytab\nwkt hive.keytab" | ktutil
    
    #kerberos 重新初始化之后,还需要添加下面代码用于集成 ldap
    
    kadmin.local -q "addprinc ldapadmin@JAVACHEN.COM"
    kadmin.local -q "addprinc -randkey ldap/cdh1@JAVACHEN.COM"
    kadmin.local -q "ktadd -k /etc/openldap/ldap.keytab ldap/cdh1@JAVACHEN.COM"
    
    #如果安装了 openldap ,重启 slapd
    /etc/init.d/slapd restart
    
    #测试 ldap 是否可以正常使用
    ldapsearch -x -b 'dc=javachen,dc=com'
    

    以下脚本用于在每个客户端上获得 root/admin 的 ticket,其密码为 root:

    #!/bin/sh
    
    for node in 56.121 56.122 56.123 ;do
      echo "========10.168.$node========"
      ssh 192.168.$node 'echo root|kinit root/admin'
    done
    

    5.2 管理集群脚本

    另外,为了方便管理集群,在 cdh1 上创建一个 shell 脚本用于批量管理集群,脚本如下(保存为 manager_cluster.sh):

    #!/bin/bash
    
    role=$1
    command=$2
    
    dir=$role
    
    if [ X"$role" == X"hdfs" ];then
      dir=hadoop
    fi
    
    if [ X"$role" == X"yarn" ];then
            dir=hadoop
    fi
    
    if [ X"$role" == X"mapred" ];then
            dir=hadoop
    fi
    
    for node in 56.121 56.122 56.123 ;do
      echo "========192.168.$node========"
      ssh 192.168.$node '
        #先获取 root/admin 的凭证
        echo root|kinit root/admin
        host=`hostname -f| tr "[:upper:]" "[:lower:]"`
        path="'$role'/$host"
        #echo $path
        principal=`klist -k /etc/'$dir'/conf/'$role'.keytab | grep $path | head -n1 | cut -d " " -f5`
        #echo $principal
        if [ X"$principal" == X ]; then
          principal=`klist -k /etc/'$dir'/conf/'$role'.keytab | grep $path | head -n1 | cut -d " " -f4`
          if [ X"$principal" == X ]; then
                echo "Failed to get hdfs Kerberos principal"
                exit 1
          fi
        fi
        kinit -r 24l -kt /etc/'$dir'/conf/'$role'.keytab $principal
        if [ $? -ne 0 ]; then
            echo "Failed to login as hdfs by kinit command"
            exit 1
        fi
        kinit -R
        for src in `ls /etc/init.d|grep '$role'`;do service $src '$command'; done
      '
    done
    

    使用方法为:

    $ sh manager_cluster.sh hdfs start #启动 hdfs 用户管理的服务
    $ sh manager_cluster.sh yarn start #启动 yarn 用户管理的服务
    $ sh manager_cluster.sh mapred start #启动 mapred 用户管理的服务
    
    $ sh manager_cluster.sh hdfs status # 在每个节点上获取 hdfs 的 ticket,然后可以执行其他操作,如批量启动 datanode 等等
    

    5.3 使用 java 代码测试 kerberos

    在 hdfs 中集成 kerberos 之前,可以先使用下面代码(Krb.java)进行测试:

    import com.sun.security.auth.module.Krb5LoginModule;
    
    import javax.security.auth.Subject;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    public class Krb {
        private void loginImpl(final String propertiesFileName) throws Exception {
            System.out.println("NB: system property to specify the krb5 config: [java.security.krb5.conf]");
            //System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
    
            System.out.println(System.getProperty("java.version"));
    
            System.setProperty("sun.security.krb5.debug", "true");
    
            final Subject subject = new Subject();
    
            final Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
            final Map<String,String> optionMap = new HashMap<String,String>();
    
            if (propertiesFileName == null) {
                //optionMap.put("ticketCache", "/tmp/krb5cc_1000");
                optionMap.put("keyTab", "/etc/krb5.keytab");
                optionMap.put("principal", "foo"); // default realm
    
                optionMap.put("doNotPrompt", "true");
                optionMap.put("refreshKrb5Config", "true");
                optionMap.put("useTicketCache", "true");
                optionMap.put("renewTGT", "true");
                optionMap.put("useKeyTab", "true");
                optionMap.put("storeKey", "true");
                optionMap.put("isInitiator", "true");
            } else {
                File f = new File(propertiesFileName);
                System.out.println("======= loading property file ["+f.getAbsolutePath()+"]");
                Properties p = new Properties();
                InputStream is = new FileInputStream(f);
                try {
                    p.load(is);
                } finally {
                    is.close();
                }
                optionMap.putAll((Map)p);
            }
            optionMap.put("debug", "true"); // switch on debug of the Java implementation
    
            krb5LoginModule.initialize(subject, null, new HashMap<String,String>(), optionMap);
    
            boolean loginOk = krb5LoginModule.login();
            System.out.println("======= login:  " + loginOk);
    
            boolean commitOk = krb5LoginModule.commit();
            System.out.println("======= commit: " + commitOk);
            System.out.println("======= Subject: " + subject);
        }
    
        public static void main(String[] args) throws Exception {
            System.out.println("A property file with the login context can be specified as the 1st and the only paramater.");
            final Krb krb = new Krb();
            krb.loginImpl(args.length == 0 ? null : args[0]);
        }
    }
    

    创建一个配置文件krb5.properties:

    keyTab=/etc/hadoop/conf/hdfs.keytab
    principal=hdfs/cdh1@JAVACHEN.COM
    
    doNotPrompt=true
    refreshKrb5Config=true
    useTicketCache=true
    renewTGT=true
    useKeyTab=true
    storeKey=true
    isInitiator=true
    

    编译 java 代码并运行:

    # 先销毁当前 ticket
    
    $ kdestroy
    
    $ javac Krb.java
    
    $ java -cp . Krb ./krb5.properties
    

    6. 总结

    本文介绍了 CDH Hadoop 集成 kerberos 认证的过程,其中主要需要注意以下几点:

    • 1. 配置 hosts,hostname 请使用小写。
    • 2. 确保 kerberos 客户端和服务端连通
    • 3. 替换 JRE 自带的 JCE jar 包
    • 4. 为 DataNode 设置运行用户并配置 JSVC_HOME
    • 5. 启动服务前,先获取 ticket 再运行相关命令

    接下来就是配置 Hadoop 集群中其他服务以集成 kerberos 认证,由于篇幅原因,后面再做说明。

    7. 参考文章



    通常在远程客户端上登录kerbros都需要密码,在学习hadoop的时候提到了ktutil这个工具,这里将使用方法贴出来。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    运行命令
    ktutil
    add_entry -password -p hadoop /admin @psy.com -k 3 -e aes256-cts-hmac-sha1-96
    解释:-k 指编号 -e指加密方式 -password 指使用密码的方式
    例子:
    add_entry -password -p host /admin @psy.com -k 1 -e aes256-cts-hmac-sha1-96
     
    write_kt 文件名.keytab
    作用将密码记录到“文件名.keytab”中
    例子:
    write_kt /hadoop-data/etc/hadoop/hadoop .keytab
     
    使用无密码的方式登录
    kinit -kt username.keytab username
    例子:
      kinit -kt /hadoop-data/etc/hadoop/hadoop .keytab hadoop /admin
      区别于
    kinit -t username.keytab username(这种方式登录的时候还是提示输入密码)

    展开全文
  • HDFS 集成 Kerberos

    2018-06-30 12:59:16
    本文主要记录 CDH Hadoop 集群上配置 HDFS 集成 Kerberos 的过程,包括 Kerberos 的安装和 Hadoop 相关配置修改说明。注意:下面第一、二部分内容,摘抄自《Hadoop的kerberos的实践部署》,主要是为了对 Hadoop 的...

    本文主要记录 CDH Hadoop 集群上配置 HDFS 集成 Kerberos 的过程,包括 Kerberos 的安装和 Hadoop 相关配置修改说明。

    注意:

    下面第一、二部分内容,摘抄自《Hadoop的kerberos的实践部署》,主要是为了对 Hadoop 的认证机制和 Kerberos 认证协议做个简单介绍。在此,对原作者表示感谢。

    1. Hadoop 的认证机制

    简单来说,没有做 kerberos 认证的 Hadoop,只要有 client 端就能够连接上。而且,通过一个有 root 的权限的内网机器,通过创建对应的 linux 用户,就能够得到 Hadoop 集群上对应的权限。

    而实行 Kerberos 后,任意机器的任意用户都必须现在 Kerberos 的 KDC 中有记录,才允许和集群中其它的模块进行通信。

    详细介绍请参考 Hadoop安全机制研究

    2. Kerberos 认证协议

    Kerberos 是一种网络认证协议,其设计目标是通过密钥系统为客户机/服务器应用程序提供强大的认证服务。

    使用 Kerberos 时,一个客户端需要经过三个步骤来获取服务:

    • 认证:客户端向认证服务器发送一条报文,并获取一个含时间戳的 Ticket-Granting Ticket(TGT)。
    • 授权:客户端使用 TGT 向 Ticket-Granting Server(TGS)请求一个服务 Ticket。
    • 服务请求:客户端向服务器出示服务 Ticket ,以证实自己的合法性。

    为此,Kerberos 需要 The Key Distribution Centers(KDC)来进行认证。KDC 只有一个 Master,可以带多个 slaves 机器。slaves 机器仅进行普通验证。Mater 上做的修改需要自动同步到 slaves。

    另外,KDC 需要一个 admin,来进行日常的管理操作。这个 admin 可以通过远程或者本地方式登录。

    3. 搭建 Kerberos

    3.1 环境

    我们在三个节点的服务器上安装 Kerberos,这三个节点上安装了 hadoop 集群,安装 hadoop 过程见:使用yum安装CDH Hadoop集群。这三个节点机器分布为:cdh1、cdh2、cdh3。

    • 操作系统:CentOs 6.6
    • 运行用户:root

    3.2 安装过程

    3.2.1 准备工作

    确认添加主机名解析到 /etc/hosts 文件中。

    1. $ cat /etc/hosts
    2. 127.0.0.1 localhost
    3. 192.168.56.121 cdh1
    4. 192.168.56.122 cdh2
    5. 192.168.56.123 cdh3

    注意:hostname 请使用小写,要不然在集成 kerberos 时会出现一些错误。

    3.2.2 安装 kdc server

    在 KDC (这里是 cdh1 ) 上安装包 krb5、krb5-server 和 krb5-client。

    $ yum install krb5-server krb5-libs krb5-auth-dialog krb5-workstation  -y
    

    在其他节点(cdh1、cdh2、cdh3)安装 krb5-devel、krb5-workstation :

    1. $ ssh cdh1 "yum install krb5-devel krb5-workstation -y"
    2. $ ssh cdh2 "yum install krb5-devel krb5-workstation -y"
    3. $ ssh cdh3 "yum install krb5-devel krb5-workstation -y"

    3.2.3 修改配置文件

    kdc 服务器涉及到三个配置文件:

    /etc/krb5.conf
    /var/kerberos/krb5kdc/kdc.conf
    /var/kerberos/krb5kdc/kadm5.acl
    

    配置 Kerberos 的一种方法是编辑配置文件 /etc/krb5.conf。默认安装的文件中包含多个示例项。

    $ cat /etc/krb5.conf
      [logging]
       default = FILE:/var/log/krb5libs.log
       kdc = FILE:/var/log/krb5kdc.log
       admin_server = FILE:/var/log/kadmind.log
    
      [libdefaults]
       default_realm = JAVACHEN.COM
       dns_lookup_realm = false
       dns_lookup_kdc = false
       clockskew = 120
       ticket_lifetime = 24h
       renew_lifetime = 7d
       forwardable = true
       renewable = true
       udp_preference_limit = 1
       default_tgs_enctypes = arcfour-hmac
       default_tkt_enctypes = arcfour-hmac
    
      [realms]
       JAVACHEN.COM = {
        kdc = cdh1:88
        admin_server = cdh1:749
       }
    
      [domain_realm]
        .javachen.com = JAVACHEN.COM
        www.javachen.com = JAVACHEN.COM
    
      [kdc]
      profile=/var/kerberos/krb5kdc/kdc.conf
    

    说明:

    • [logging]:表示 server 端的日志的打印位置
    • [libdefaults]:每种连接的默认配置,需要注意以下几个关键的小配置
      • default_realm = JAVACHEN.COM:设置 Kerberos 应用程序的默认领域。如果您有多个领域,只需向 [realms] 节添加其他的语句。
      • udp_preference_limit= 1:禁止使用 udp 可以防止一个Hadoop中的错误
      • clockskew:时钟偏差是不完全符合主机系统时钟的票据时戳的容差,超过此容差将不接受此票据。通常,将时钟扭斜设置为 300 秒(5 分钟)。这意味着从服务器的角度看,票证的时间戳与它的偏差可以是在前后 5 分钟内。
      • ticket_lifetime: 表明凭证生效的时限,一般为24小时。
      • renew_lifetime: 表明凭证最长可以被延期的时限,一般为一个礼拜。当凭证过期之后,对安全认证的服务的后续访问则会失败。
    • [realms]:列举使用的 realm。
      • kdc:代表要 kdc 的位置。格式是 机器:端口
      • admin_server:代表 admin 的位置。格式是 机器:端口
      • default_domain:代表默认的域名
    • [appdefaults]:可以设定一些针对特定应用的配置,覆盖默认配置。

    修改 /var/kerberos/krb5kdc/kdc.conf ,该文件包含 Kerberos 的配置信息。例如,KDC 的位置,Kerbero 的 admin 的realms 等。需要所有使用的 Kerberos 的机器上的配置文件都同步。这里仅列举需要的基本配置。详细介绍参考:krb5conf

    1. $ cat /var/kerberos/krb5kdc/kdc.conf
    2. [kdcdefaults ]
    3. v4_mode = nopreauth
    4. kdc_ports = 88
    5. kdc_tcp_ports = 88
    6. [realms ]
    7. JAVACHEN.COM = {
    8. #master_key_type = aes256-cts
    9. acl_file = /var/kerberos/krb5kdc/kadm5.acl
    10. dict_file = /usr/share/dict/words
    11. admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
    12. supported_enctypes = des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal des-cbc-crc:v4 des-cbc-crc:afs3
    13. max_life = 24h
    14. max_renewable_life = 10d
    15. default_principal_flags = +renewable, +forwardable
    16. }

    说明:

    • JAVACHEN.COM: 是设定的 realms。名字随意。Kerberos 可以支持多个 realms,会增加复杂度。大小写敏感,一般为了识别使用全部大写。这个 realms 跟机器的 host 没有大关系。
    • master_key_type:和 supported_enctypes 默认使用 aes256-cts。由于,JAVA 使用 aes256-cts 验证方式需要安装额外的 jar 包(后面再做说明)。推荐不使用,并且删除 aes256-cts。
    • acl_file:标注了 admin 的用户权限,需要用户自己创建。文件格式是:Kerberos_principal permissions [target_principal] [restrictions]
    • supported_enctypes:支持的校验方式。
    • admin_keytab:KDC 进行校验的 keytab。

    关于AES-256加密

    对于使用 centos5. 6及以上的系统,默认使用 AES-256 来加密的。这就需要集群中的所有节点上安装 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy File

    下载的文件是一个 zip 包,解开后,将里面的两个文件放到下面的目录中:$JAVA_HOME/jre/lib/security

    为了能够不直接访问 KDC 控制台而从 Kerberos 数据库添加和删除主体,请对 Kerberos 管理服务器指示允许哪些主体执行哪些操作。通过编辑文件 /var/lib/kerberos/krb5kdc/kadm5.acl 完成此操作。ACL(访问控制列表)允许您精确指定特权。

    1. $ cat /var/kerberos/krb5kdc/kadm5.acl
    2. */admin@JAVACHEN.COM *

    3.2.4 同步配置文件

    将 kdc 中的 /etc/krb5.conf 拷贝到集群中其他服务器即可。

    1. $ scp /etc/krb5.conf cdh2:/etc/krb5.conf
    2. $ scp /etc/krb5.conf cdh3:/etc/krb5.conf

    请确认集群如果关闭了 selinux。

    3.2.5 创建数据库

    在 cdh1 上运行初始化数据库命令。其中 -r 指定对应 realm。

    $ kdb5_util create -r JAVACHEN.COM -s
    

    出现 Loading random data 的时候另开个终端执行点消耗CPU的命令如 cat /dev/sda > /dev/urandom 可以加快随机数采集。

    该命令会在 /var/kerberos/krb5kdc/ 目录下创建 principal 数据库。

    如果遇到数据库已经存在的提示,可以把 /var/kerberos/krb5kdc/ 目录下的 principal 的相关文件都删除掉。默认的数据库名字都是 principal。可以使用 -d 指定数据库名字。

    3.2.6 启动服务

    在 cdh1 节点上运行:

    1. $ chkconfig --level 35 krb5kdc on
    2. $ chkconfig --level 35 kadmin on
    3. $ service krb5kdc start
    4. $ service kadmin start

    3.2.7 创建 kerberos 管理员

    关于 kerberos 的管理,可以使用 kadmin.local 或 kadmin,至于使用哪个,取决于账户和访问权限:

    • 如果有访问 kdc 服务器的 root 权限,但是没有 kerberos admin 账户,使用 kadmin.local
    • 如果没有访问 kdc 服务器的 root 权限,但是用 kerberos admin 账户,使用 kadmin

    在 cdh1 上创建远程管理的管理员:

    1. #手动输入两次密码,这里密码为 root
    2. $ kadmin.local -q "addprinc root/admin"
    3. # 也可以不用手动输入密码
    4. $ echo -e "root\nroot" | kadmin.local -q "addprinc root/admin"

    系统会提示输入密码,密码不能为空,且需妥善保存。

    3.2.8 测试 kerberos

    以下内容仅仅是为了测试,你可以直接跳到下部分内容。

    查看当前的认证用户:

    1. # 查看principals
    2. $ kadmin: list_principals
    3. # 添加一个新的 principal
    4. kadmin: addprinc user1
    5. WARNING: no policy specified for user1@JAVACHEN.COM ; defaulting to no policy
    6. Enter password for principal "user1@JAVACHEN.COM":
    7. Re-enter password for principal "user1@JAVACHEN.COM":
    8. Principal "user1@JAVACHEN.COM" created.
    9. # 删除 principal
    10. kadmin: delprinc user1
    11. Are you sure you want to delete the principal "user1@JAVACHEN.COM"? (yes/no ): yes
    12. Principal "user1@JAVACHEN.COM" deleted.
    13. Make sure that you have removed this principal from all ACLs before reusing.
    14. kadmin: exit

    也可以直接通过下面的命令来执行:

    1. # 提示需要输入密码
    2. $ kadmin -p root/admin -q "list_principals"
    3. $ kadmin -p root/admin -q "addprinc user2"
    4. $ kadmin -p root/admin -q "delprinc user2"
    5. # 不用输入密码
    6. $ kadmin.local -q "list_principals"
    7. $ kadmin.local -q "addprinc user2"
    8. $ kadmin.local -q "delprinc user2"

    创建一个测试用户 test,密码设置为 test:

    $ echo -e "test\ntest" | kadmin.local -q "addprinc test"
    

    获取 test 用户的 ticket:

    1. # 通过用户名和密码进行登录
    2. $ kinit test
    3. Password for test@JAVACHEN.COM:
    4. $ klist -e
    5. Ticket cache: FILE:/tmp/krb5cc_0
    6. Default principal: test@JAVACHEN.COM
    7. Valid starting Expires Service principal
    8. 11/07/14 15:29:02 11/08/14 15:29:02 krbtgt/JAVACHEN.COM@JAVACHEN.COM
    9. renew until 11/17/14 15:29:02, Etype (skey, tkt ): AES-128 CTS mode with 96-bit SHA-1 HMAC, AES-128 CTS mode with 96-bit SHA-1 HMAC
    10. Kerberos 4 ticket cache: /tmp/tkt0
    11. klist: You have no tickets cached

    销毁该 test 用户的 ticket:

    1. $ kdestroy
    2. $ klist
    3. klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_0 )
    4. Kerberos 4 ticket cache: /tmp/tkt0
    5. klist: You have no tickets cached

    更新 ticket:

    1. $ kinit root/admin
    2. Password for root/admin@JAVACHEN.COM:
    3. $ klist
    4. Ticket cache: FILE:/tmp/krb5cc_0
    5. Default principal: root/admin@JAVACHEN.COM
    6. Valid starting Expires Service principal
    7. 11/07/14 15:33:57 11/08/14 15:33:57 krbtgt/JAVACHEN.COM@JAVACHEN.COM
    8. renew until 11/17/14 15:33:57
    9. Kerberos 4 ticket cache: /tmp/tkt0
    10. klist: You have no tickets cached
    11. $ kinit -R
    12. $ klist
    13. Ticket cache: FILE:/tmp/krb5cc_0
    14. Default principal: root/admin@JAVACHEN.COM
    15. Valid starting Expires Service principal
    16. 11/07/14 15:34:05 11/08/14 15:34:05 krbtgt/JAVACHEN.COM@JAVACHEN.COM
    17. renew until 11/17/14 15:33:57
    18. Kerberos 4 ticket cache: /tmp/tkt0
    19. klist: You have no tickets cached

    抽取密钥并将其储存在本地 keytab 文件 /etc/krb5.keytab 中。这个文件由超级用户拥有,所以您必须是 root 用户才能在 kadmin shell 中执行以下命令:

    1. $ kadmin.local -q "ktadd kadmin/admin"
    2. $ klist -k /etc/krb5.keytab
    3. Keytab name: FILE:/etc/krb5.keytab
    4. KVNO Principal
    5. ---- --------------------------------------------------------------------------
    6. 3 kadmin/admin@LASHOU-INC.COM
    7. 3 kadmin/admin@LASHOU-INC.COM
    8. 3 kadmin/admin@LASHOU-INC.COM
    9. 3 kadmin/admin@LASHOU-INC.COM
    10. 3 kadmin/admin@LASHOU-INC.COM

    4. HDFS 上配置 kerberos

    4.1 创建认证规则

    在 Kerberos 安全机制里,一个 principal 就是 realm 里的一个对象,一个 principal 总是和一个密钥(secret key)成对出现的。

    这个 principal 的对应物可以是 service,可以是 host,也可以是 user,对于 Kerberos 来说,都没有区别。

    Kdc(Key distribute center) 知道所有 principal 的 secret key,但每个 principal 对应的对象只知道自己的那个 secret key 。这也是“共享密钥“的由来。

    对于 hadoop,principals 的格式为 username/fully.qualified.domain.name@YOUR-REALM.COM

    通过 yum 源安装的 cdh 集群中,NameNode 和 DataNode 是通过 hdfs 启动的,故为集群中每个服务器节点添加两个principals:hdfs、HTTP。

    在 KCD server 上(这里是 cdh1)创建 hdfs principal:

    1. kadmin.local -q "addprinc -randkey hdfs/cdh1@JAVACHEN.COM"
    2. kadmin.local -q "addprinc -randkey hdfs/cdh2@JAVACHEN.COM"
    3. kadmin.local -q "addprinc -randkey hdfs/cdh3@JAVACHEN.COM"

    -randkey 标志没有为新 principal 设置密码,而是指示 kadmin 生成一个随机密钥。之所以在这里使用这个标志,是因为此 principal 不需要用户交互。它是计算机的一个服务器帐户。

    创建 HTTP principal:

    1. kadmin.local -q "addprinc -randkey HTTP/cdh1@JAVACHEN.COM"
    2. kadmin.local -q "addprinc -randkey HTTP/cdh2@JAVACHEN.COM"
    3. kadmin.local -q "addprinc -randkey HTTP/cdh3@JAVACHEN.COM"

    创建完成后,查看:

    $ kadmin.local -q "listprincs"
    

    4.2 创建keytab文件

    keytab 是包含 principals 和加密 principal key 的文件。

    keytab 文件对于每个 host 是唯一的,因为 key 中包含 hostname。keytab 文件用于不需要人工交互和保存纯文本密码,实现到 kerberos 上验证一个主机上的 principal。

    因为服务器上可以访问 keytab 文件即可以以 principal 的身份通过 kerberos 的认证,所以,keytab 文件应该被妥善保存,应该只有少数的用户可以访问

    创建包含 hdfs principal 和 host principal 的 hdfs keytab:

    xst -norandkey -k hdfs.keytab hdfs/fully.qualified.domain.name host/fully.qualified.domain.name
    

    创建包含 mapred principal 和 host principal 的 mapred keytab:

    xst -norandkey -k mapred.keytab mapred/fully.qualified.domain.name host/fully.qualified.domain.name
    

    注意
    上面的方法使用了xst的norandkey参数,有些kerberos不支持该参数。
    当不支持该参数时有这样的提示:Principal -norandkey does not exist.,需要使用下面的方法来生成keytab文件。

    在 cdh1 节点,即 KDC server 节点上执行下面命令:

    1. $ cd /var/kerberos/krb5kdc/
    2. $ kadmin.local -q "xst -k hdfs-unmerged.keytab hdfs/cdh1@JAVACHEN.COM"
    3. $ kadmin.local -q "xst -k hdfs-unmerged.keytab hdfs/cdh2@JAVACHEN.COM"
    4. $ kadmin.local -q "xst -k hdfs-unmerged.keytab hdfs/cdh3@JAVACHEN.COM"
    5. $ kadmin.local -q "xst -k HTTP.keytab HTTP/cdh1@JAVACHEN.COM"
    6. $ kadmin.local -q "xst -k HTTP.keytab HTTP/cdh2@JAVACHEN.COM"
    7. $ kadmin.local -q "xst -k HTTP.keytab HTTP/cdh3@JAVACHEN.COM"

    这样,就会在 /var/kerberos/krb5kdc/ 目录下生成 hdfs-unmerged.keytab 和 HTTP.keytab 两个文件,接下来使用 ktutil 合并者两个文件为 hdfs.keytab

    1. $ cd /var/kerberos/krb5kdc/
    2. $ ktutil
    3. ktutil: rkt hdfs-unmerged.keytab
    4. ktutil: rkt HTTP.keytab
    5. ktutil: wkt hdfs.keytab

    使用 klist 显示 hdfs.keytab 文件列表:

    1. $ klist -ket hdfs.keytab
    2. Keytab name: FILE:hdfs.keytab
    3. KVNO Timestamp Principal
    4. ---- ----------------- --------------------------------------------------------
    5. 2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des3-cbc-sha1 )
    6. 2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (arcfour-hmac )
    7. 2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des-hmac-sha1 )
    8. 2 11/13/14 10:40:18 hdfs/cdh1@JAVACHEN.COM (des-cbc-md5 )
    9. 4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des3-cbc-sha1 )
    10. 4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (arcfour-hmac )
    11. 4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des-hmac-sha1 )
    12. 4 11/13/14 10:40:18 hdfs/cdh2@JAVACHEN.COM (des-cbc-md5 )
    13. 4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des3-cbc-sha1 )
    14. 4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (arcfour-hmac )
    15. 4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des-hmac-sha1 )
    16. 4 11/13/14 10:40:18 hdfs/cdh3@JAVACHEN.COM (des-cbc-md5 )
    17. 3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des3-cbc-sha1 )
    18. 3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (arcfour-hmac )
    19. 3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des-hmac-sha1 )
    20. 3 11/13/14 10:40:18 HTTP/cdh1@JAVACHEN.COM (des-cbc-md5 )
    21. 3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des3-cbc-sha1 )
    22. 3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (arcfour-hmac )
    23. 3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des-hmac-sha1 )
    24. 3 11/13/14 10:40:18 HTTP/cdh2@JAVACHEN.COM (des-cbc-md5 )
    25. 3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des3-cbc-sha1 )
    26. 3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (arcfour-hmac )
    27. 3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des-hmac-sha1 )
    28. 3 11/13/14 10:40:18 HTTP/cdh3@JAVACHEN.COM (des-cbc-md5 )

    验证是否正确合并了key,使用合并后的keytab,分别使用hdfs和host principals来获取证书。

    1. $ kinit -k -t hdfs.keytab hdfs/cdh1@JAVACHEN.COM
    2. $ kinit -k -t hdfs.keytab HTTP/cdh1@JAVACHEN.COM

    如果出现错误:kinit: Key table entry not found while getting initial credentials
    则上面的合并有问题,重新执行前面的操作。

    4.3 部署kerberos keytab文件

    拷贝 hdfs.keytab 文件到其他节点的 /etc/hadoop/conf 目录

    1. $ cd /var/kerberos/krb5kdc/
    2. $ scp hdfs.keytab cdh1:/etc/hadoop/conf
    3. $ scp hdfs.keytab cdh2:/etc/hadoop/conf
    4. $ scp hdfs.keytab cdh3:/etc/hadoop/conf

    并设置权限,分别在 cdh1、cdh2、cdh3 上执行:

    1. $ ssh cdh1 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"
    2. $ ssh cdh2 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"
    3. $ ssh cdh3 "chown hdfs:hadoop /etc/hadoop/conf/hdfs.keytab ;chmod 400 /etc/hadoop/conf/hdfs.keytab"

    由于 keytab 相当于有了永久凭证,不需要提供密码(如果修改kdc中的principal的密码,则该keytab就会失效),所以其他用户如果对该文件有读权限,就可以冒充 keytab 中指定的用户身份访问 hadoop,所以 keytab 文件需要确保只对 owner 有读权限(0400)

    4.4 修改 hdfs 配置文件

    先停止集群:

    1. $ for x in ` cd /etc/init.d ; ls hive-* ` ; do sudo service $x stop ; done
    2. $ for x in ` cd /etc/init.d ; ls impala-* ` ; do sudo service $x stop ; done
    3. $ for x in ` cd /etc/init.d ; ls hadoop-* ` ; do sudo service $x stop ; done
    4. $ for x in ` cd /etc/init.d ; ls zookeeper-* ` ; do sudo service $x stop ; done

    在集群中所有节点的 core-site.xml 文件中添加下面的配置:

    1. <property>
    2. <name>hadoop.security.authentication </name>
    3. <value>kerberos </value>
    4. </property>
    5. <property>
    6. <name>hadoop.security.authorization </name>
    7. <value>true </value>
    8. </property>

    在集群中所有节点的 hdfs-site.xml 文件中添加下面的配置:

    1. <property>
    2. <name>dfs.block.access.token.enable </name>
    3. <value>true </value>
    4. </property>
    5. <property>
    6. <name>dfs.datanode.data.dir.perm </name>
    7. <value>700 </value>
    8. </property>
    9. <property>
    10. <name>dfs.namenode.keytab.file </name>
    11. <value>/etc/hadoop/conf/hdfs.keytab </value>
    12. </property>
    13. <property>
    14. <name>dfs.namenode.kerberos.principal </name>
    15. <value>hdfs/_HOST@JAVACHEN.COM </value>
    16. </property>
    17. <property>
    18. <name>dfs.namenode.kerberos.https.principal </name>
    19. <value>HTTP/_HOST@JAVACHEN.COM </value>
    20. </property>
    21. <property>
    22. <name>dfs.datanode.address </name>
    23. <value>0.0.0.0:1004 </value>
    24. </property>
    25. <property>
    26. <name>dfs.datanode.http.address </name>
    27. <value>0.0.0.0:1006 </value>
    28. </property>
    29. <property>
    30. <name>dfs.datanode.keytab.file </name>
    31. <value>/etc/hadoop/conf/hdfs.keytab </value>
    32. </property>
    33. <property>
    34. <name>dfs.datanode.kerberos.principal </name>
    35. <value>hdfs/_HOST@JAVACHEN.COM </value>
    36. </property>
    37. <property>
    38. <name>dfs.datanode.kerberos.https.principal </name>
    39. <value>HTTP/_HOST@JAVACHEN.COM </value>
    40. </property>

    如果想开启 SSL,请添加(本文不对这部分做说明):

    1. <property>
    2. <name>dfs.http.policy </name>
    3. <value>HTTPS_ONLY </value>
    4. </property>

    如果 HDFS 配置了 QJM HA,则需要添加(另外,你还要在 zookeeper 上配置 kerberos):

    1. <property>
    2. <name>dfs.journalnode.keytab.file </name>
    3. <value>/etc/hadoop/conf/hdfs.keytab </value>
    4. </property>
    5. <property>
    6. <name>dfs.journalnode.kerberos.principal </name>
    7. <value>hdfs/_HOST@JAVACHEN.COM </value>
    8. </property>
    9. <property>
    10. <name>dfs.journalnode.kerberos.internal.spnego.principal </name>
    11. <value>HTTP/_HOST@JAVACHEN.COM </value>
    12. </property>

    如果配置了 WebHDFS,则添加:

    1. <property>
    2. <name>dfs.webhdfs.enabled </name>
    3. <value>true </value>
    4. </property>
    5. <property>
    6. <name>dfs.web.authentication.kerberos.principal </name>
    7. <value>HTTP/_HOST@JAVACHEN.COM </value>
    8. </property>
    9. <property>
    10. <name>dfs.web.authentication.kerberos.keytab </name>
    11. <value>/etc/hadoop/conf/hdfs.keytab </value>
    12. </property>

    配置中有几点要注意的:

    • 1. dfs.datanode.address表示 data transceiver RPC server 所绑定的 hostname 或 IP 地址,如果开启 security,端口号必须小于 1024(privileged port),否则的话启动 datanode 时候会报 Cannot start secure cluster without privileged resources 错误
    • 2. principal 中的 instance 部分可以使用 _HOST 标记,系统会自动替换它为全称域名
    • 3. 如果开启了 security, hadoop 会对 hdfs block data(由 dfs.data.dir 指定)做 permission check,方式用户的代码不是调用hdfs api而是直接本地读block data,这样就绕过了kerberos和文件权限验证,管理员可以通过设置 dfs.datanode.data.dir.perm 来修改 datanode 文件权限,这里我们设置为700

    4.5 检查集群上的 HDFS 和本地文件的权限

    请参考 Verify User Accounts and Groups in CDH 5 Due to Security 或者 Hadoop in Secure Mode

    4.6 启动 NameNode

    启动之前,请确认 JCE jar 已经替换,请参考前面的说明。

    在每个节点上获取 root 用户的 ticket,这里 root 为之前创建的 root/admin 的密码。

    1. $ ssh cdh1 "echo root|kinit root/admin"
    2. $ ssh cdh1 "echo root|kinit root/admin"
    3. $ ssh cdh1 "echo root|kinit root/admin"

    获取 cdh1的 ticket:

    $ kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh1@JAVACHEN.COM
    

    如果出现下面异常 kinit: Password incorrect while getting initial credentials
    ,则重新导出 keytab 再试试。

    然后启动服务,观察日志:

    $ /etc/init.d/hadoop-hdfs-namenode start
    

    验证 NameNode 是否启动,一是打开 web 界面查看启动状态,一是运行下面命令查看 hdfs:

    1. $ hadoop fs -ls /
    2. Found 4 items
    3. drwxrwxrwx - yarn hadoop 0 2014-06-26 15:24 /logroot
    4. drwxrwxrwt - hdfs hadoop 0 2014-11-04 10:44 /tmp
    5. drwxr-xr-x - hdfs hadoop 0 2014-08-10 10:53 /user
    6. drwxr-xr-x - hdfs hadoop 0 2013-05-20 22:52 /var

    如果在你的凭据缓存中没有有效的 kerberos ticket,执行上面命令将会失败,将会出现下面的错误:

    14/11/04 12:08:12 WARN ipc.Client: Exception encountered while connecting to the server : javax.security.sasl.SaslException:
    GSS initiate failed [Caused by GS***ception: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
    Bad connection to FS. command aborted. exception: Call to cdh1/192.168.56.121:8020 failed on local exception: java.io.IOException:
    javax.security.sasl.SaslException: GSS initiate failed [Caused by GS***ception: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
    

    4.6 启动DataNode

    DataNode 需要通过 JSVC 启动。首先检查是否安装了 JSVC 命令,然后配置环境变量。

    在 cdh1 节点查看是否安装了 JSVC:

    1. $ ls /usr/lib/bigtop-utils/
    2. bigtop-detect-classpath bigtop-detect-javahome bigtop-detect-javalibs jsvc

    然后编辑 /etc/default/hadoop-hdfs-datanode,取消对下面的注释并添加一行设置 JSVC_HOME,修改如下:

    1. export HADOOP_SECURE_DN_USER =hdfs
    2. export HADOOP_SECURE_DN_PID_DIR =/var/run/hadoop-hdfs
    3. export HADOOP_SECURE_DN_LOG_DIR =/var/ log/hadoop-hdfs
    4. export JSVC_HOME =/usr/lib/bigtop-utils

    将该文件同步到其他节点:

    1. $ scp /etc/default/hadoop-hdfs-datanode cdh2:/etc/default/hadoop-hdfs-datanode
    2. $ scp /etc/default/hadoop-hdfs-datanode cdh3:/etc/default/hadoop-hdfs-datanode

    分别在 cdh2、cdh3 获取 ticket 然后启动服务:

    1. #root 为 root/admin 的密码
    2. $ ssh cdh1 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh1@JAVACHEN.COM; service hadoop-hdfs-datanode start"
    3. $ ssh cdh2 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh2@JAVACHEN.COM; service hadoop-hdfs-datanode start"
    4. $ ssh cdh3 "kinit -k -t /etc/hadoop/conf/hdfs.keytab hdfs/cdh3@JAVACHEN.COM; service hadoop-hdfs-datanode start"

    观看 cdh1 上 NameNode 日志,出现下面日志表示 DataNode 启动成功:

    14/11/04 17:21:41 INFO security.UserGroupInformation:
    Login successful for user hdfs/cdh2@JAVACHEN.COM using keytab file /etc/hadoop/conf/hdfs.keytab
    

    5. 其他

    5.1 批量生成 keytab

    为了方便批量生成 keytab,写了一个脚本,如下:

    1. #!/bin/bash
    2. DNS =LASHOU.COM
    3. hostname = `hostname -i `
    4. yum install krb5-server krb5-libs krb5-auth-dialog krb5-workstation -y
    5. rm -rf /var/kerberos/krb5kdc/*.keytab /var/kerberos/krb5kdc/prin*
    6. kdb5_util create -r LASHOU.COM -s
    7. chkconfig --level 35 krb5kdc on
    8. chkconfig --level 35 kadmin on
    9. service krb5kdc restart
    10. service kadmin restart
    11. echo -e "root\nroot" | kadmin.local -q "addprinc root/admin"
    12. for host in `cat /etc/hosts |grep 10 |grep -v $hostname |awk '{print $2}' ` ; do
    13. for user in hdfs hive ; do
    14. kadmin.local -q "addprinc -randkey $user/$host@$DNS"
    15. kadmin.local -q "xst -k /var/kerberos/krb5kdc/$user-un.keytab $user/$host@$DNS"
    16. done
    17. for user in HTTP lashou yarn mapred impala zookeeper sentry llama zkcli ; do
    18. kadmin.local -q "addprinc -randkey $user/$host@$DNS"
    19. kadmin.local -q "xst -k /var/kerberos/krb5kdc/$user.keytab $user/$host@$DNS"
    20. done
    21. done
    22. cd /var/kerberos/krb5kdc/
    23. echo -e "rkt lashou.keytab\nrkt hdfs-un.keytab\nrkt HTTP.keytab\nwkt hdfs.keytab" | ktutil
    24. echo -e "rkt lashou.keytab\nrkt hive-un.keytab\nwkt hive.keytab" | ktutil
    25. #kerberos 重新初始化之后,还需要添加下面代码用于集成 ldap
    26. kadmin.local -q "addprinc ldapadmin@JAVACHEN.COM"
    27. kadmin.local -q "addprinc -randkey ldap/cdh1@JAVACHEN.COM"
    28. kadmin.local -q "ktadd -k /etc/openldap/ldap.keytab ldap/cdh1@JAVACHEN.COM"
    29. #如果安装了 openldap ,重启 slapd
    30. /etc/init.d/slapd restart
    31. #测试 ldap 是否可以正常使用
    32. ldapsearch -x -b 'dc=javachen,dc=com'

    以下脚本用于在每个客户端上获得 root/admin 的 ticket,其密码为 root:

    1. #!/bin/sh
    2. for node in 56.121 56.122 56.123 ; do
    3. echo "========10.168.$node========"
    4. ssh 192.168. $node 'echo root|kinit root/admin'
    5. done

    5.2 管理集群脚本

    另外,为了方便管理集群,在 cdh1 上创建一个 shell 脚本用于批量管理集群,脚本如下(保存为 manager_cluster.sh):

    1. #!/bin/bash
    2. role = $1
    3. command = $2
    4. dir = $role
    5. if [ X "$role" == X "hdfs" ] ; then
    6. dir =hadoop
    7. fi
    8. if [ X "$role" == X "yarn" ] ; then
    9. dir =hadoop
    10. fi
    11. if [ X "$role" == X "mapred" ] ; then
    12. dir =hadoop
    13. fi
    14. for node in 56.121 56.122 56.123 ; do
    15. echo "========192.168.$node========"
    16. ssh 192.168. $node '
    17. #先获取 root/admin 的凭证
    18. echo root|kinit root/admin
    19. host=`hostname -f| tr "[:upper:]" "[:lower:]"`
    20. path="' $role '/$host"
    21. #echo $path
    22. principal=`klist -k /etc/' $dir '/conf/' $role '.keytab | grep $path | head -n1 | cut -d " " -f5`
    23. #echo $principal
    24. if [ X"$principal" == X ]; then
    25. principal=`klist -k /etc/' $dir '/conf/' $role '.keytab | grep $path | head -n1 | cut -d " " -f4`
    26. if [ X"$principal" == X ]; then
    27. echo "Failed to get hdfs Kerberos principal"
    28. exit 1
    29. fi
    30. fi
    31. kinit -r 24l -kt /etc/' $dir '/conf/' $role '.keytab $principal
    32. if [ $? -ne 0 ]; then
    33. echo "Failed to login as hdfs by kinit command"
    34. exit 1
    35. fi
    36. kinit -R
    37. for src in `ls /etc/init.d|grep ' $role '`;do service $src ' $command '; done
    38. '
    39. done

    使用方法为:

    1. $ sh manager_cluster.sh hdfs start #启动 hdfs 用户管理的服务
    2. $ sh manager_cluster.sh yarn start #启动 yarn 用户管理的服务
    3. $ sh manager_cluster.sh mapred start #启动 mapred 用户管理的服务
    4. $ sh manager_cluster.sh hdfs status # 在每个节点上获取 hdfs 的 ticket,然后可以执行其他操作,如批量启动 datanode 等等

    5.3 使用 java 代码测试 kerberos

    在 hdfs 中集成 kerberos 之前,可以先使用下面代码(Krb.java)进行测试:

    1. import com.sun.security.auth.module.Krb5LoginModule ;
    2. import javax.security.auth.Subject ;
    3. import java.io.File ;
    4. import java.io.FileInputStream ;
    5. import java.io.InputStream ;
    6. import java.util.HashMap ;
    7. import java.util.Map ;
    8. import java.util.Properties ;
    9. public class Krb {
    10. private void loginImpl ( final String propertiesFileName ) throws Exception {
    11. System . out . println ( "NB: system property to specify the krb5 config: [java.security.krb5.conf]" );
    12. //System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
    13. System . out . println ( System . getProperty ( "java.version" ));
    14. System . setProperty ( "sun.security.krb5.debug" , "true" );
    15. final Subject subject = new Subject ();
    16. final Krb5LoginModule krb5LoginModule = new Krb5LoginModule ();
    17. final Map < String , String > optionMap = new HashMap < String , String >();
    18. if ( propertiesFileName == null ) {
    19. //optionMap.put("ticketCache", "/tmp/krb5cc_1000");
    20. optionMap . put ( "keyTab" , "/etc/krb5.keytab" );
    21. optionMap . put ( "principal" , "foo" ); // default realm
    22. optionMap . put ( "doNotPrompt" , "true" );
    23. optionMap . put ( "refreshKrb5Config" , "true" );
    24. optionMap . put ( "useTicketCache" , "true" );
    25. optionMap . put ( "renewTGT" , "true" );
    26. optionMap . put ( "useKeyTab" , "true" );
    27. optionMap . put ( "storeKey" , "true" );
    28. optionMap . put ( "isInitiator" , "true" );
    29. } else {
    30. File f = new File ( propertiesFileName );
    31. System . out . println ( "======= loading property file [" + f . getAbsolutePath ()+ "]" );
    32. Properties p = new Properties ();
    33. InputStream is = new FileInputStream ( f );
    34. try {
    35. p . load ( is );
    36. } finally {
    37. is . close ();
    38. }
    39. optionMap . putAll (( Map ) p );
    40. }
    41. optionMap . put ( "debug" , "true" ); // switch on debug of the Java implementation
    42. krb5LoginModule . initialize ( subject , null , new HashMap < String , String >(), optionMap );
    43. boolean loginOk = krb5LoginModule . login ();
    44. System . out . println ( "======= login: " + loginOk );
    45. boolean commitOk = krb5LoginModule . commit ();
    46. System . out . println ( "======= commit: " + commitOk );
    47. System . out . println ( "======= Subject: " + subject );
    48. }
    49. public static void main ( String [] args ) throws Exception {
    50. System . out . println ( "A property file with the login context can be specified as the 1st and the only paramater." );
    51. final Krb krb = new Krb ();
    52. krb . loginImpl ( args . length == 0 ? null : args [ 0 ]);
    53. }
    54. }

    创建一个配置文件krb5.properties:

    keyTab=/etc/hadoop/conf/hdfs.keytab
    principal=hdfs/cdh1@JAVACHEN.COM
    
    doNotPrompt=true
    refreshKrb5Config=true
    useTicketCache=true
    renewTGT=true
    useKeyTab=true
    storeKey=true
    isInitiator=true
    

    编译 java 代码并运行:

    1. # 先销毁当前 ticket
    2. $ kdestroy
    3. $ javac Krb.java
    4. $ java -cp . Krb ./krb5.properties

    6. 总结

    本文介绍了 CDH Hadoop 集成 kerberos 认证的过程,其中主要需要注意以下几点:

    • 1. 配置 hosts,hostname 请使用小写。
    • 2. 确保 kerberos 客户端和服务端连通
    • 3. 替换 JRE 自带的 JCE jar 包
    • 4. 为 DataNode 设置运行用户并配置 JSVC_HOME
    • 5. 启动服务前,先获取 ticket 再运行相关命令

    接下来就是配置 Hadoop 集群中其他服务以集成 kerberos 认证,由于篇幅原因,后面再做说明。

    7. 参考文章

    展开全文
  • HDFS使用Kerberos

    万次阅读 2017-02-17 15:12:01
    转载自:...本文尝试记录HDFS各服务配置使用kerberos的过程,配置的东西比较多,一定会有疏漏。 我的环境: 三台服务器,分别命名为zelda1、zelda2、zelda3ubuntu 14.04hadoop 2.7.2spark 2.0/1.6.1

    转载自:http://www.datastart.cn/tech/2016/06/07/kerberos-1.html


    本文尝试记录HDFS各服务配置使用kerberos的过程,配置的东西比较多,一定会有疏漏

    我的环境:

    • 三台服务器,分别命名为zelda1、zelda2、zelda3
    • ubuntu 14.04
    • hadoop 2.7.2
    • spark 2.0/1.6.1

    原理

    默认Hadoop各个组件间无任何认证,因此可以恶意伪装某一组件(比如NameNode)接入到集群中搞破坏。而通过kerberos,可以将密钥事先放到可靠的节点上并只允许有限制的访问,该节点的服务启动时读取密钥,并与kerberos交互以做认证,从而接入到hadoop集群中。注意,我们这里主要是针对服务与服务之间的安全认证,没有涉及user。

    有很多文章讲解Kerberos的原理,或是过于简单或是过于复杂,下面盗用网上翻译的官方示例,可以很清晰的理解其过程:

    用户要去游乐场,首先要在门口检查用户的身份(即 CHECK 用户的 ID 和 PASS), 如果用户通过验证,游乐场的门卫 (AS) 即提供给用户一张门卡 (TGT)。

    这张卡片的用处就是告诉游乐场的各个场所,用户是通过正门进来,而不是后门偷爬进来的,并且也是获取进入场所一把钥匙。

    现在用户有张卡,但是这对用户来不重要,因为用户来游乐场不是为了拿这张卡的而是为了游览游乐项目,这时用户摩天楼,并想游玩。

    这时摩天轮的服务员 (client) 拦下用户,向用户要求摩天轮的 (ST) 票据,用户说用户只有一个门卡 (TGT), 那用户只要把 TGT 放在一旁的票据授权机 (TGS) 上刷一下。 票据授权机 (TGS) 就根据用户现在所在的摩天轮,给用户一张摩天轮的票据 (ST), 这样用户有了摩天轮的票据,现在用户可以畅通无阻的进入摩天轮里游玩了。

    当然如果用户玩完摩天轮后,想去游乐园的咖啡厅休息下,那用户一样只要带着那张门卡 (TGT). 到相应的咖啡厅的票据授权机 (TGS) 刷一下,得到咖啡厅的票据 (ST) 就可以进入咖啡厅。

    当用户离开游乐场后,想用这张 TGT 去刷打的回家的费用,对不起,用户的 TGT 已经过期了,在用户离开游乐场那刻开始,用户的 TGT 就已经销毁了。

    下面还有张图来说明这个过程。

    原理图

    Kerberos有如下几个概念:

    Term Description
    Key Distribution Center, or KDC 可信任的认证来源,密钥分发中心
    Kerberos KDC Server KDS服务提供者
    Kerberos Client 集群中准备去做kerberos认证的机器
    Principal The unique name of a user or service that authenticates against the KDC
    Keytab A file that includes one or more principals and their keys.当不方便使用密码的时候
    Realm 我简单理解为域
    KDC Admin Account 管理员账户,用来添加其他principal

    Principal可以理解为用户或服务的名字,全集群唯一,由三部分组成:username(or servicename)/instance@realm,例如:nn/zelda1@ZELDA.COM,zelda1为集群中的一台机器;或admin/admin@ZELDA.COM,管理员账户。

    • username or servicename:在本文里为服务,HDFS的2个服务分别取名为nn和dn,即namenode和datanode
    • instance:在本文里为具体的FQDN机器名,用来保证全局唯一(比如多个datanode节点,各节点需要各自独立认证)
    • realm:域,我这里为ZELDA.COM(全大写哟)

    对于HDFS的各个服务来说,keytab更合适:生成一个keytab文件,其包含一个或多个principal+key对,例如在HDFS配置文件里为nn指定的keytab文件:

    <property>
      <name>dfs.namenode.keytab.file</name>
      <value>/etc/security/nn.service.keytab</value>
    </property>
    <property>
    
    

    配置

    配置DNS服务

    如上所述,Principal中的instance为各主机的FQDN名,所以集群中需要有DNS,这里我们用的是dnsmasq,相对比较简单。 简单说明下DNS:DNS是一个递归服务,以查询zh.wikipedia.org为例:

    客户端发送查询报文”query zh.wikipedia.org”至DNS服务器,DNS服务器首先检查自身缓存,如果存在记录则直接返回结果。 如果记录老化或不存在,则

    1. DNS服务器向根域名服务器发送查询报文”query zh.wikipedia.org”,根域名服务器返回.org域的权威域名服务器地址,这一级首先会返回的是顶级域名的权威域名服务器。
    2. DNS服务器向.org域的权威域名服务器发送查询报文”query zh.wikipedia.org”,得到.wikipedia.org域的权威域名服务器地址。
    3. DNS服务器向.wikipedia.org域的权威域名服务器发送查询报文”query zh.wikipedia.org”,得到主机zh的A记录,存入自身缓存并返回给客户端。

    我们平时上网配置的杭州电信DNS地址(202.101.172.35),对于PC来说只要有DNS解析的需求,都会丢给这个地址的服务器(即为hzdns1)上,那么全球这么多国家这么多地址,显然不可能都存在杭州电信的hzdns1上,所以它会继续向上一直到根服务器请求解析。

    所以,在我们这里其实可以自己架设了一个dns缓存服务器,集群内所有的DNS请求都先走这个服务器,如果查询失败,再由这台DNS缓存服务器向上查询;同时,我们也可以将集群内各个主机的主机名加到DNS缓存服务器里,这样集群内的FQDN解析就可以通过这个DNS缓存服务器来完成了(当然,需要将各个机器的DNS nameserver配置为集群内的DNS缓存服务器)。多说一句,对于企业内已有自建DNS的情况,加个接入级的DNS服务器对已有拓扑无任何影响。

    我的操作系统是ubuntu 14.04,安装比较简单,sudo apt-get install dnsmasq即可。不过我人品比较好,遇到了网易163的ubuntu源错乱的情况,怎么也get不了,总是提示xx包被依赖但不会被安装,换用aliyun的源正常了。如果你在杭州,建议更换,服务器在杭州电信,速度特别好:

    deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
    

    dnsmasq安装后需要做配置,可以参考我的:

    no-resolv
    no-poll
    server=202.101.172.35
    domain=zelda.com
    

    值得注意的是,配置upstream DNS有两个办法:

    1. 从resolv.conf(or compatible)文件中获取。但我在配置resolv-file=的时候遇到了些障碍,如果用这种方式,发现dnsmasq总是会请求一个61.x.x.x的DNS地址(温州电信的DNS)作为其upstream DNS,但其实这个DNS已经故障不能访问了,即使不用resolv.conf新增一个文件也不能解决。
    2. 指定no-resolv,直接在dnsmasq的配置文件中指定upstream server,对我来说更方便。

    检查DNS服务:各机器的/etc/resolv.conf修改为dnsmasq服务所在机器的地址(zelda2),ping集群内各机器的FQDN,如ping zelda1、ping zelda1.zelda.com、ping www.googlebaidu.com。

    配置NTP

    Kerberos集群对时间同步敏感度较高,默认时间相差超过5分钟就会出现问题,所以最好是在集群中增加NTP服务器。不过我的集群机器比较少,先跳过NTP吧。

    创建MIT KDC

    Kerberos有不同的实现,如MIT KDC、Microsoft Active Directory等。我这里采用的是MIT KDC。安装过程可以参考ubuntu官网

    这段是根据history写的回忆录,可能有错误,下次安装的时候记得修正

    (一)krb5 MDC机器上:

    1、安装KDC服务和管理员服务

    apt-get install krb5-kdc krb5-admin-server
    

    kdc是服务提供者,admin-server是admin登录上去做配置的服务提供者。

    跟centos、Suse不一样,UBUNTU的Kr5安装时会提示要求用户输入KDC的realm(如ZELDA.COM)、提供服务的机器名(如zelda2),直接生成krb5的配置文件和realm(/etc/krb5.conf和/var/lib/krb5/principal等),如下:

    [libdefaults]
            default_realm = ZELDA.COM
    ..
    [realms]
            ZELDA.COM = {
                    kdc = zelda2
                    admin_server = zelda2
            }
    [domain_realm]
    ..
            .zelda.com = ZELDA.COM
            zelda.com = ZELDA.COM
    

    注意domain_realm这里,默认生成的文件里没有这两行,你可以试试不加是否也没问题。

    2、创建新的realm

    !!在ubuntu版本里,不需要做这步,因为上面包安装的时候已经做了。如果装包的时候跳过了config阶段,才需要再来一把。

    krb5_newrealm
    

    3、创建一个管理员账户

    建议使用一个跟平时用的账户不同的名字。在KDC的机器上:

    $ kadmin.local
    kadmin.local: addprinc steve/admin
    

    记住自己的密码。kadmin.local是在KDC所在的机器上使用的,而kadmin是任意机器都可以,方便远程管理不过我没用功。

    4、修改ACL给新的管理员账户权限

    修改/etc/krb5kdc/kadm5.acl:

    steve/admin@ZELDA.COM *
    

    当然也可以把steve改为*,这样任意admin这个instance里的用户都有管理员权限了。由于后面配置Hadoop各组件的时候我参考了Hortonwork的文档,所以我还增加了一个admin/admin的用户:

    kadmin.local -q "addprinc $username/admin
    

    5、重启服务

    /etc/init.d/krb5-kdc restart
    /etc/init.d/krb5-admin-server restart
    

    6、使用kinit测试

    $ kinit steve/admin
    passwd:
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_0
    Default principal: steve/admin@ZELDA.COM
    
    Valid starting       Expires              Service principal
    06/06/2016 17:29:07  06/07/2016 03:29:07  krbtgt/ZELDA.COM@ZELDA.COM
    	renew until 06/07/2016 17:29:03
    

    (二)在各Krb Client机器上

    所有机器上安装krb5的client:

    apt-get install krb5-user krb5-config
    

    为HDFS等组件生成keytab

    具体参考hortonworks官网

    使用admin账户进入kadmin控制台,对于每个服务来说,命令有2条:

    addprinc -randkey nn/zelda1@ZELDA.COM
    xst -k nn.service.keytab nn/zelda1
    

    第一条是向KDC增加一个principal,之后使用lisprincs可以看到,注意名字按照HDP的要求来; 第二条是导出keytab文件,生成的文件在/var/lib/krb5kdc中。由于拿到了keytab实际也就拿到了Kerberos认证,所以需要将keytab文件放到一个比较隐秘的目录(例如/etc/security/),并且小心其读写权限,只要给最终用户授权就好了。

    HDFS的datanode一般有多个,我的做法是为每台机器单独生成keytab,各个机器的keytab只包含自己的principal。也有人为所有datanode生成一个keytab文件,然后扔到各个机器上混用,更方便一点,不过我没用过。

    可以使用klist检查keytab是不是自己想要的:

    klist –k -t /etc/security/nn.service.keytab
    

    配置HDFS

    Hadoop的配置分为2步:

    1. 创建Principal和*unix用户的映射关系。

    例如我们上面datanode服务的Principal是dn/zelda1@ZELDA.COM,默认的hadoop.security.auth_to_local规则是将instance和realm去掉,只保留dn,但实际上hdfs的用户并不是dn(我这里操作hdfs的用户是dtdream,如果你用包安装的话可能是叫hdfs,具体可以看hdfs上默认文件的用户是谁),dn这个用户在linux机器里也不存在,那么dn连接nn的时候,会提示错误找不到这个用户的组:

    2016-06-07 19:06:58,329 INFO SecurityLogger.org.apache.hadoop.ipc.Server: Auth successful for dn/zelda2@ZELDA.COM (auth:KERBEROS)
    2016-06-07 19:06:58,393 WARN org.apache.hadoop.security.UserGroupInformation: No groups available for user dn
    2016-06-07 19:06:58,393 INFO org.apache.hadoop.ipc.Server: IPC Server handler 2 on 8020, call org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol.versionRequest from 192.168.103.224:55035 Call#0 Retry#0: org.apache.hadoop.security.AccessControlException: Access denied for user dn. Superuser privilege is required
    

    map配置方法:修改core-site.xml,增加这段:

    <property>
      <name>hadoop.security.auth_to_local</name>
      <value>
    RULE:[2:$1@$0]([nd]n@ZELDA.COM)s/.*/dtdream/
    DEFAULT
    </value>
    </property>
    
    

    RULE的写法可以参考这儿,跟Kerberos的规则一样。具体到hadoop,这篇文章更直接一点。

    上面的RULE表示会将nn和dn都替换为dtdream。

    2、配置HDFS

    2.1 总的配置

    详细各参数的说明请见hortonworks官网,下面直接贴出来我的配置,略长。

    <property>
      <name>dfs.block.access.token.enable</name>
      <value>true</value>
    </property>
    
    <!-- NameNode security config -->
    <property>
      <name>dfs.namenode.kerberos.principal</name>
      <value>nn/_HOST@ZELDA.COM</value>
    </property>
    <property>
      <name>dfs.namenode.keytab.file</name>
      <value>/etc/security/nn.service.keytab</value> <!-- path to the HDFS keytab -->
    </property>
    <property>
      <name>dfs.https.port</name>
      <value>50470</value>
    </property>
    <property>
      <name>dfs.https.address</name>
      <value>zelda1.zelda.com:50470</value>
    </property>
    
    <!-- DataNode security config -->
    <property>
      <name>dfs.datanode.kerberos.principal</name>
      <value>dn/_HOST@ZELDA.COM</value>
    </property>
    <property>
      <name>dfs.datanode.keytab.file</name>
      <value>/etc/security/dn.service.keytab</value> <!-- path to the HDFS keytab -->
    </property>
    <property>
      <name>dfs.datanode.data.dir.perm</name>
      <value>700</value>
    </property>
    
    <!-- datanode SASL配置 -->
    <property>
      <name>dfs.datanode.address</name>
      <value>0.0.0.0:61004</value>
    </property>
    <property>
      <name>dfs.datanode.http.address</name>
      <value>0.0.0.0:61006</value>
    </property>
    <property>
      <name>dfs.http.policy</name>
      <value>HTTPS_ONLY</value>
    </property>
    <property>
      <name>dfs.data.transfer.protection</name>
      <value>integrity</value>
    </property>
    
    <property>
         <name>dfs.permissions.supergroup</name>
         <value>supergroup</value>
         <description>The name of the group of
         super-users.</description>
    </property>
    
    <property>
         <name>dfs.web.authentication.kerberos.principal</name>
         <value>HTTP/_HOST@ZELDA.COM</value>
    </property>
    <property>
         <name>dfs.web.authentication.kerberos.keytab</name>
         <value>/etc/security/spnego.service.keytab</value>
    </property>
    

    简要说明:

    • _HOST是变量,表示所在机器的FQDN名,这样所有节点可以共用一份hdfs-site.xml
    • namenode的webUI改为了https,端口号这里为50470
    • 需要保证各个keytab文件对当前的dtdream可以访问

    2.2 特别说明下datanode的SASL配置。

    如果不加中间SASL这部分配置,启动时datanode会报错并退出:

    2016-06-07 14:02:03,509 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Exception in secureMain
    java.lang.RuntimeException: Cannot start secure DataNode without configuring either privileged resources or SASL RPC data transfer protection and SSL for HTTP.  Using privileged resources in combination with SASL RPC data transfer protection is not supported.
            at org.apache.hadoop.hdfs.server.datanode.DataNode.checkSecureConfig(DataNode.java:1173)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.startDataNode(DataNode.java:1073)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.<init>(DataNode.java:428)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.makeInstance(DataNode.java:2370)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.instantiateDataNode(DataNode.java:2257)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.createDataNode(DataNode.java:2304)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.secureMain(DataNode.java:2481)
            at org.apache.hadoop.hdfs.server.datanode.DataNode.main(DataNode.java:2505)
    2016-06-07 14:02:03,513 INFO org.apache.hadoop.util.ExitUtil: Exiting with status 1
    2016-06-07 14:02:03,516 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: SHUTDOWN_MSG:
    

    Kerberos要求datanode以secure mode启动,在2.6之前的版本,hadoop只能使用jsvc,先以root用户来启动datanode,然后再切到普通用户;由于我们只对普通用户做了免密码打通,以root用户启动start-dfs.sh脚本会报错,而且jsvc看上去比较复杂。下面说的很清楚:

    As of version 2.6.0, SASL can be used to authenticate the data transfer protocol. In this configuration, it is no longer required for secured clusters to start the DataNode as root using jsvc and bind to privileged ports. To enable SASL on data transfer protocol, set dfs.data.transfer.protection in hdfs-site.xml, set a non-privileged port for dfs.datanode.address, set dfs.http.policy to HTTPS_ONLY and make sure the HADOOP_SECURE_DN_USER environment variable is not defined. Note that it is not possible to use SASL on data transfer protocol if dfs.datanode.address is set to a privileged port. This is required for backwards-compatibility reasons.

    配置上有这么几点:

    • 设置dfs.data.transfer.protection为integrity
    • 设置dfs.datanode.address为非特权端口,即大于1024的端口,我这用的是61004
    • 设置dfs.http.policy为HTTPS_ONLY
    • 确保HADOOP_SECURE_DN_USER变量为空

    不过故事到这里还没结束,按上面的配置同步各节点后启动hdfs,会发现namenode报错后退出:

    2016-06-07 14:12:37,273 INFO org.apache.hadoop.http.HttpServer2: HttpServer.start() threw a non Bind IOException
    java.io.FileNotFoundException: /home/dtdream/.keystore (No such file or directory)
            at java.io.FileInputStream.open(Native Method)
            at java.io.FileInputStream.<init>(FileInputStream.java:146)
            at org.mortbay.resource.FileResource.getInputStream(FileResource.java:275)
            at org.mortbay.jetty.security.SslSocketConnector.createFactory(SslSocketConnector.java:242)
            at org.mortbay.jetty.security.SslSocketConnector.newServerSocket(SslSocketConnector.java:476)
            at org.apache.hadoop.security.ssl.SslSocketConnectorSecure.newServerSocket(SslSocketConnectorSecure.java:46)
            at org.mortbay.jetty.bio.SocketConnector.open(SocketConnector.java:73)
            at org.apache.hadoop.http.HttpServer2.openListeners(HttpServer2.java:914)
            at org.apache.hadoop.http.HttpServer2.start(HttpServer2.java:856)
            at org.apache.hadoop.hdfs.server.namenode.NameNodeHttpServer.start(NameNodeHttpServer.java:142)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.startHttpServer(NameNode.java:752)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:638)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:811)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:795)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1488)
            at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1554)
    2016-06-07 14:12:37,275 INFO org.apache.hadoop.metrics2.impl.MetricsSystemImpl: Stopping NameNode metrics system...
    

    2.3 没有keystore文件呀

    其实到这跟hadoop,Kerberos就没什么关系了,纯粹是https的配置了。简单说明下原理:https要求集群中有一个CA,它会生成ca_key和ca_cert,想要加入这个集群的节点,需要拿到这2个文件,然后经过一连串的动作生成keystore,并在hadoop的ssl-server.xml和ssl-client.xml中指定这个keystore的路径和密码,这样各个节点间就可以使用https进行通信了(可能大概是这么回事吧)。更详细的可以参考SASL配置

    下面直接贴命令。

    CA机器上:

    openssl req -new -x509 -keyout test_ca_key -out test_ca_cert -days 9999 -subj '/C=CN/ST=zhejiang/L=hangzhou/O=dtdream/OU=security/CN=zelda.com'
    

    将上面生成的test_ca_key和test_ca_cert丢到所有机器上,在各个机器上继续:

    keytool -keystore keystore -alias localhost -validity 9999 -genkey -keyalg RSA -keysize 2048 -dname "CN=zelda.com, OU=test, O=test, L=hangzhou, ST=zhejiang, C=cn"
    keytool -keystore truststore -alias CARoot -import -file test_ca_cert
    keytool -certreq -alias localhost -keystore keystore -file cert
    openssl x509 -req -CA test_ca_cert -CAkey test_ca_key -in cert -out cert_signed -days 9999 -CAcreateserial -passin pass:changeit
    keytool -keystore keystore -alias CARoot -import -file test_ca_cert
    keytool -keystore keystore -alias localhost -import -file cert_signed
    

    最终在当前目录下会生成keystore、trustkeystore文件。

    2.4 配置ssl-server.xml和ssl-client.xml

    从{target}.xml.example文件拷贝一份出来,并制定keystore、trustkeystore两个文件的路径、password,然后同步到所有节点。

    2.5 启动HDFS

    从namenode的日志可以看到服务已经正常启动,DN都连接上来了,使用https://{namenode_ip}:50470上可以看到各个datanode。但是使用hadoop命令行 fs -ls时会报错:

    ./hadoop fs -ls /
    16/06/08 13:24:35 WARN ipc.Client: Exception encountered while connecting to the server : javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
    ls: Failed on local exception: java.io.IOException: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]; Host Details : local host is: "zelda1/192.168.103.237"; destination host is: "zelda1":8020;
    

    提示没有credentials,也就是说没有凭据。一方面说明Kerberos的确是保护了hdfs,另一方面也说明我们还需要给本地加一个Principal来访问hdfs。

    2.6 增加用户Principal

    KDC上:

    kadmin.local:  addprinc dtdream@ZELDA.COM
    WARNING: no policy specified for dtdream@ZELDA.COM; defaulting to no policy
    Enter password for principal "dtdream@ZELDA.COM":
    Re-enter password for principal "dtdream@ZELDA.COM":
    Principal "dtdream@ZELDA.COM" created.
    

    再在hdfs客户端的机器上使用kinit初始化credentials,再去访问hdfs就正常了。

    $ kinit dtdream@ZELDA.COM
    Password for dtdream@ZELDA.COM: 
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_1000
    Default principal: dtdream@ZELDA.COM
    
    Valid starting       Expires              Service principal
    2016-06-08T13:37:21  2016-06-08T23:37:21  krbtgt/ZELDA.COM@ZELDA.COM
    	renew until 2016-06-09T13:37:19
    $ ./hadoop fs -ls /
    Found 3 items
    drwxr-xr-x   - dtdream supergroup          0 2016-05-27 09:45 /home
    drwxrwxr-x   - dtdream supergroup          0 2016-05-25 16:01 /tmp
    drwxr-xr-x   - dtdream supergroup          0 2016-05-25 16:11 /user
    

    2.7 配置chrome以访问被Kerberos保护的hdfs webUI

    配置FIREFOX、chrome、IE支持Kerberos HTTP SPNEGO,参考这里

    以firefox为例,需要将zelda.com作为可信uri,设置到network.negotiate-auth.trusted-uris里去。

    but,还是有问题,我不知道怎么把认证传过去,先放一下。

    http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.4.0/bk_Security_Guide/content/_optional_install_a_new_mit_kdc.html

    Kerberos安装参考

    主要参考hortonworks官网


    传送门:

    Kerberos从入门到放弃(一):HDFS使用kerberos

    Kerberos从入门到放弃(二):YARN、Spark、Hive使用kerberos

    Kerberos从入门到放弃(三):kerberos+LDAP各司其职


    展开全文
  • HDFS用户权限管理

    2019-01-25 14:43:07
    HDFS用户权限管理
                   

    1 hdfs权限

    1.1 超级用户

    启动namenode服务的用户就是超级用户, 该用户的组是supergroup

    具体配置参考之前我的博客

    Ubuntu上使用Hadoop 2.x 一 hdfs超级用户创建和设置

    CentOS6.6安装 HDFS 2.7.1

    1.2 文件权限管理

    1.2.1 创建时的owner和group

    文件或者目录被创建之时,服从BSD规则,owner是客户端进程的用户,group是父目录的group

    1.2.2 访问权限说明

    objectrwxstick bit(restricted deletion flag)
    file读文件写或者追加写文件 无效
    directory列出目录的内容创建或者删除子文件或子目录访问子文件或者子目录阻止移动或者删除该目录内的文件或目录(超级用户,owner和group不会被stick bit阻止)
         

    由于和POSIX类似较多,可以参考以下两篇Linux用户的博客

    Linux用户管理命令

    Linux文件权限

    1.2.3 应用示例

    1. 创建/input目录,用于接收外部写入的数据
      • input目录的group也是input,owner是lisa(超级用户),
      • 创建/input/dean目录,用于接收dean用户写入的数据, owner是dean用户,group用户允许写入数据
    2. 创建目录
      $ hdfs dfs -mkdir -p /input/dean  $ hdfs dfs -ls /Found 3 itemsdrwxr-xr-x   - lisa supergroup          0 2015-11-08 17:26 /inputdrwxr-xr-x   - lisa supergroup          0 2015-09-28 15:21 /testdrwxr-xr-x   - lisa supergroup          0 2015-11-08 17:09 /tmp$ hdfs dfs -ls /inputFound 1 itemsdrwxr-xr-x   - lisa supergroup          0 2015-11-08 17:26 /input/dean
      • 修改input目录的owner为lisa,group从supergroup改为input
      $ hdfs dfs -chown lisa:input /input$ hdfs dfs -ls /Found 3 itemsdrwxr-xr-x   - lisa input               0 2015-11-08 17:26 /inputdrwxr-xr-x   - lisa supergroup          0 2015-09-28 15:21 /testdrwxr-xr-x   - lisa supergroup          0 2015-11-08 17:09 /tmp
      • 修改/input/dean目录的ower和group都为dean
      $ hdfs dfs -ls /inputFound 1 itemdrwxrwxr-x   - dean dean           0 2015-11-21 16:24 /input/dean

      注意,客户机上创建Linux 用户dean,无需在namenode节点上创建该用户

    3. 允许input group用户写入/input/qoros目录
      1. 先要设置目录权限,让input组用户都能读,写,执行该目录
        $ hdfs dfs -chmod -R g+w /input/qoros
      2. 然后在客户机上
        • 创建guoqiang帐号和组input
        useradd guoqianggroupadd input
        • 改guoqiang用户组为input
        usermod -g input guoqiang

        在namenode所在的服务器上添加相同的用户和组,这点很奇怪,如果不这么干写操作会被拒绝,这会造成麻烦,因为两个namenode节点都要这么干

        useradd guoqiangusermod -g input guoqiang
    4. 取消其他用户的所有权限
      $ hdfs dfs -chmod -R o-r /input/dean$ hdfs dfs -ls /inputFound 1 itemsdrwxrwx--x   - lisa supergroup          0 2015-11-08 17:26 /input/dean$ hdfs dfs -chmod -R o-x /input/dean$ hdfs dfs -ls /inputFound 1 itemsdrwxrwx---   - lisa supergroup          0 2015-11-08 17:26 /input/dean

    1.2.4 不支持setuid 和 setgid bits

    1.3 POSIX ACLs(目前尚未使用)

    为特定的用户和组提供细致粒度的权限管理, 而不只是owner,group。该功能默认关闭, 需要如下设置打开

    dfs.namenode.acls.enabled true

    具体配置实在hdfs-site.xml中

    <property> <name>dfs.permissions.enabled</name> <value>true</value> </property><property> <name>dfs.namenode.acls.enabled</name> <value>true</value> </property>

    在core-site.xml设置用户组默认权限.

    <property><name>fs.permissions.umask-mode</name><value>002</value></property>

    1.3.1 hadoop支持两种用户认证模式

    simple or kerberos

    1.4 参考文档

    Author: dean

    Created: 2015-11-21 六 16:44

    Validate


               

    再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

    展开全文
  • Hadoop的安全特性包括身份验证、服务级授权、Web控制台身份验证和数据保密。 认证 终端用户账户 当启用服务级别身份验证时,在安全模式下使用Hadoop的最终用户需要使用Kerberos身份验证。进行身份验证的最简单方法是...
  • HDFS配置kerberos

    2019-05-11 23:38:20
    1:在hadoop01机器上...t添加对hdfs的认证: kadmin.local -q "addprinc -randkey hdfs/hadoop01@DYLAN.COM" kadmin.local -q "addprinc -randkey hdfs/hadoop02@DYLAN.COM" kadmin.local -q "addprinc -randkey...
  • hdfs关闭kerberos

    2019-06-04 11:44:41
    hadoop.security.authentication: Kerberos -> Simple hadoop.security.authorization: true -> false dfs.datanode.address: -> from 1004 (for Kerberos) to 50010 (default) dfs.datanode....
  • 一篇文章搞懂 HDFSKerberos 认证

    万次阅读 2021-06-10 09:02:35
    Kerberos 是一种网络认证协议,它使用加密来提供高度安全的认证机制。 这种认证机制由于具备以下功能而大受欢迎。 相互认证:在进行会话之前,客户端和服务器可以进行相互认证。 单点登录:一旦登录,令牌(token)的...
  • hdfs配置kerberos

    2014-10-26 22:57:00
    显然本文的目的是为hadoop的hdfs服务配置kerberos,作者同时打开了webhdfs权限开关,这就出现一个问题了。namenode启动失败, 原因是http/admin@psy.com 登录失败, 但是nn/admin@psy.com 却能够成功登录。...
  • HDFS权限管理

    2021-04-22 11:39:12
    HDFS权限管理 一、概述 HDFS实现了一种权限模型。每一个文件或者文件夹,都有属主和属组。文件或文件夹对其他的用户(非属组和属主的用户)也是有单独的权限可以设定。 对于文件来讲,r 代表着可读权限,w 代表着可...
  • ambari test kerberos client时日志文件权限问题:  1.Couldn't open log file /var/log/kadmind.log: 权限不够  修改权限:  chmod 777 /var/log/kadmind.log  如果不慎把keytab 删除(删除了 /etc/...
  • 访问Kerberos环境下的HBase代码 Spark2Streaming应用实时读取Kafka代码 写入数据到kafka代码 SparkStreaming读kafka写入HDFS 本教程基于CDH5.8.0其它组件版本为:spark2.1.0、kafka0.10.2、HDFS2.6.0 ...
  • 二、HDFS配置Kerberos认证 1.创建认证规则 在 Kerberos 安全机制里,一个 principal 就是 realm 里的一个对象,一个 principal 总是和一个密钥(secret key)成对出现的。 这个 principal 的对应物可以是...
  • HDFS集群整合Kerberos配置步骤

    千次阅读 2018-05-25 16:44:44
    1 概述本文档用于HDFS整合Kerberos配置的详细步骤说明,版本分别为2.7.3和1.16。2 前提条件假设已有安装配置好的HDFS集群和YARN,本文使用4台服务器,角色分别为:192.168.1.10:NameNode、SecondaryNameNode、...
  • 1.修改hdfs配置 在两个集群的hdfs-site.xml中添加以下内容: <property> <name>dfs.namenode.rpc-bind-host</name> <value>0.0.0.0</value> <description></...
  • HDFS上配置kerberos(十一)

    千次阅读 2017-04-01 16:36:31
    三、部署Kerberos Keytab文件 四、修改HDFS配置文件,包括 1)core-site.xml 2)hdfs-site.xml 五、启动namenode 六、启动datanode 步骤实施 1、创建认证规则  [root@cdh1 training]# kadmin.local -q ...
  • 前提条件:迁移数据时的用户,需要在clusterA和clusterB集群都有对应的权限。 hadoop distcp \ -Dmapreduce.job.hdfs-servers.token-renewal.exclude=clusterA \ # 失败IP或者修改为hostname -Dmapred.job.queue....
  • Java访问kerberos认证的HDFS文件

    千次阅读 2020-01-15 15:12:06
    Kerberos是一种计算机网络授权协议,用来在非安全网络中,对个人通信以安全的手段进行身份认证。 具体HADOOP的访问HDFS使用Kerberos的作用和原理请自己查阅相关文档。 之前做项目时第一次使用Kbs访问HDFS,当时不...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,797
精华内容 1,518
关键字:

hdfskerberos权限管理