本文主要记录 cdh hadoop 集群上配置 hdfs 集成 kerberos 的过程,包括 kerberos 的安装和 hadoop 相关配置修改说明。
系统环境:
操作系统:centos 6.6
hadoop版本:<code>cdh5.4</code>
jdk版本:<code>1.7.0_71</code>
运行用户:root
集群各节点角色规划为:
cdh1作为master节点,其他节点作为slave节点,我们在cdh1节点安装kerberos server,在其他节点安装kerberos client。
确认添加主机名解析到 <code>/etc/hosts</code> 文件中。
注意:hostname 请使用小写,要不然在集成 kerberos 时会出现一些错误。
在 cdh1 上安装包 krb5、krb5-server 和 krb5-client。
在其他节点(cdh1、cdh2、cdh3)安装 krb5-devel、krb5-workstation :
kdc 服务器涉及到三个配置文件:
配置 kerberos 的一种方法是编辑配置文件 /etc/krb5.conf。默认安装的文件中包含多个示例项。
说明:
<code>[logging]</code>:表示 server 端的日志的打印位置
<code>[libdefaults]</code>:每种连接的默认配置,需要注意以下几个关键的小配置
<code>default_realm = javachen.com</code>:设置 kerberos 应用程序的默认领域。如果您有多个领域,只需向 [realms] 节添加其他的语句。
<code>ticket_lifetime</code>: 表明凭证生效的时限,一般为24小时。
<code>renew_lifetime</code>: 表明凭证最长可以被延期的时限,一般为一个礼拜。当凭证过期之后,对安全认证的服务的后续访问则会失败。
<code>clockskew</code>:时钟偏差是不完全符合主机系统时钟的票据时戳的容差,超过此容差将不接受此票据。通常,将时钟扭斜设置为 300 秒(5 分钟)。这意味着从服务器的角度看,票证的时间戳与它的偏差可以是在前后 5 分钟内。
<code>udp_preference_limit= 1</code>:禁止使用 udp 可以防止一个 hadoop 中的错误
<code>[realms]</code>:列举使用的 realm。
<code>kdc</code>:代表要 kdc 的位置。格式是 <code>机器:端口</code>
<code>admin_server</code>:代表 admin 的位置。格式是 <code>机器:端口</code>
<code>default_domain</code>:代表默认的域名
<code>[appdefaults]</code>:可以设定一些针对特定应用的配置,覆盖默认配置。
<code>javachen.com</code>: 是设定的 realms。名字随意。kerberos 可以支持多个 realms,会增加复杂度。大小写敏感,一般为了识别使用全部大写。这个 realms 跟机器的 host 没有大关系。
<code>master_key_type</code>:和 <code>supported_enctypes</code> 默认使用 <code>aes256-cts</code>。java 使用 <code>aes256-cts</code> 验证方式需要安装 jce 包,见下面的说明。为了简便,你可以不使用<code>aes256-cts</code> 算法,这样就不需要安装 jce 。
<code>acl_file</code>:标注了 admin 的用户权限,需要用户自己创建。文件格式是:<code>kerberos_principal permissions [target_principal] [restrictions]</code>
<code>supported_enctypes</code>:支持的校验方式。
<code>admin_keytab</code>:kdc 进行校验的 keytab。
关于aes-256加密: 下载的文件是一个 zip 包,解开后,将里面的两个文件放到下面的目录中:<code>$java_home/jre/lib/security</code>
为了能够不直接访问 kdc 控制台而从 kerberos 数据库添加和删除主体,请对 kerberos 管理服务器指示允许哪些主体执行哪些操作。通过编辑文件 /var/lib/kerberos/krb5kdc/kadm5.acl 完成此操作。acl(访问控制列表)允许您精确指定特权。
将 kdc 中的 <code>/etc/krb5.conf</code> 拷贝到集群中其他服务器即可。
请确认集群如果关闭了 selinux。
在 cdh1 上运行初始化数据库命令。其中 <code>-r</code> 指定对应 realm。
出现 <code>loading random data</code> 的时候另开个终端执行点消耗cpu的命令如 <code>cat /dev/sda > /dev/urandom</code> 可以加快随机数采集。该命令会在 <code>/var/kerberos/krb5kdc/</code> 目录下创建 principal 数据库。
如果遇到数据库已经存在的提示,可以把 <code>/var/kerberos/krb5kdc/</code> 目录下的 principal 的相关文件都删除掉。默认的数据库名字都是 principal。可以使用 <code>-d</code> 指定数据库名字。
在 cdh1 节点上运行:
关于 kerberos 的管理,可以使用 <code>kadmin.local</code> 或 <code>kadmin</code>,至于使用哪个,取决于账户和访问权限:
如果有访问 kdc 服务器的 root 权限,但是没有 kerberos admin 账户,使用 <code>kadmin.local</code>
如果没有访问 kdc 服务器的 root 权限,但是用 kerberos admin 账户,使用 <code>kadmin</code>
在 cdh1 上创建远程管理的管理员:
系统会提示输入密码,密码不能为空,且需妥善保存。
查看当前的认证用户:
也可以直接通过下面的命令来执行:
创建一个测试用户 test,密码设置为 test:
获取 test 用户的 ticket:
销毁该 test 用户的 ticket:
更新 ticket:
抽取密钥并将其储存在本地 keytab 文件 /etc/krb5.keytab 中。这个文件由超级用户拥有,所以您必须是 root 用户才能在 kadmin shell 中执行以下命令:
在 kerberos 安全机制里,一个 principal 就是 realm 里的一个对象,一个 principal 总是和一个密钥(secret key)成对出现的。
这个 principal 的对应物可以是 service,可以是 host,也可以是 user,对于 kerberos 来说,都没有区别。
kdc(key distribute center) 知道所有 principal 的 secret key,但每个 principal 对应的对象只知道自己的那个 secret key 。这也是“共享密钥“的由来。
对于 hadoop,principals 的格式为 <code>username/[email protected]</code>。
通过 yum 源安装的 cdh 集群中,namenode 和 datanode 是通过 hdfs 启动的,故为集群中每个服务器节点添加两个principals:hdfs、http。
在 kcd server 上(这里是 cdh1)创建 hdfs principal:
<code>-randkey</code> 标志没有为新 principal 设置密码,而是指示 kadmin 生成一个随机密钥。之所以在这里使用这个标志,是因为此 principal 不需要用户交互。它是计算机的一个服务器帐户。
创建 http principal:
创建完成后,查看:
keytab 是包含 principals 和加密 principal key 的文件。keytab 文件对于每个 host 是唯一的,因为 key 中包含 hostname。keytab 文件用于不需要人工交互和保存纯文本密码,实现到 kerberos 上验证一个主机上的 principal。因为服务器上可以访问 keytab 文件即可以以 principal 的身份通过 kerberos 的认证,所以,keytab 文件应该被妥善保存,应该只有少数的用户可以访问。
创建包含 hdfs principal 和 host principal 的 hdfs keytab:
创建包含 mapred principal 和 host principal 的 mapred keytab:
注意: 上面的方法使用了xst的norandkey参数,有些kerberos不支持该参数。 当不支持该参数时有这样的提示:<code>principal -norandkey does not exist.</code>,需要使用下面的方法来生成keytab文件。
在 cdh1 节点,即 kdc server 节点上执行下面命令:
这样,就会在 <code>/var/kerberos/krb5kdc/</code> 目录下生成 <code>hdfs-unmerged.keytab</code> 和 <code>http.keytab</code> 两个文件,接下来使用 <code>ktutil</code> 合并者两个文件为 <code>hdfs.keytab</code>。
使用 klist 显示 hdfs.keytab 文件列表:
验证是否正确合并了key,使用合并后的keytab,分别使用hdfs和host principals来获取证书。
如果出现错误:<code>kinit: key table entry not found while getting initial credentials</code>, 则上面的合并有问题,重新执行前面的操作。
拷贝 hdfs.keytab 文件到其他节点的 /etc/hadoop/conf 目录
并设置权限,分别在 cdh1、cdh2、cdh3 上执行:
由于 keytab 相当于有了永久凭证,不需要提供密码(如果修改kdc中的principal的密码,则该keytab就会失效),所以其他用户如果对该文件有读权限,就可以冒充 keytab 中指定的用户身份访问 hadoop,所以 keytab 文件需要确保只对 owner 有读权限(0400)
先停止集群:
在集群中所有节点的 core-site.xml 文件中添加下面的配置:
在集群中所有节点的 hdfs-site.xml 文件中添加下面的配置:
如果想开启 ssl,请添加(本文不对这部分做说明):
如果 hdfs 配置了 qjm ha,则需要添加(另外,你还要在 zookeeper 上配置 kerberos):
如果配置了 webhdfs,则添加:
配置中有几点要注意的:
<code>dfs.datanode.address</code>表示 data transceiver rpc server 所绑定的 hostname 或 ip 地址,如果开启 security,端口号必须小于 <code>1024</code>(privileged port),否则的话启动 datanode 时候会报 <code>cannot start secure cluster without privileged resources</code> 错误
principal 中的 instance 部分可以使用 <code>_host</code> 标记,系统会自动替换它为全称域名
如果开启了 security, hadoop 会对 hdfs block data(由 <code>dfs.data.dir</code> 指定)做 permission check,方式用户的代码不是调用hdfs api而是直接本地读block data,这样就绕过了kerberos和文件权限验证,管理员可以通过设置 <code>dfs.datanode.data.dir.perm</code> 来修改 datanode 文件权限,这里我们设置为700
启动之前,请确认 jce jar 已经替换,请参考前面的说明。
在每个节点上获取 root 用户的 ticket,这里 root 为之前创建的 root/admin 的密码。
获取 cdh1的 ticket:
如果出现下面异常 <code>kinit: password incorrect while getting initial credentials</code>,则重新导出 keytab 再试试。
然后启动服务,观察日志:
验证 namenode 是否启动,一是打开 web 界面查看启动状态,一是运行下面命令查看 hdfs:
如果在你的凭据缓存中没有有效的 kerberos ticket,执行上面命令将会失败,将会出现下面的错误:
datanode 需要通过 jsvc 启动。首先检查是否安装了 jsvc 命令,然后配置环境变量。
在 cdh1 节点查看是否安装了 jsvc:
然后编辑 <code>/etc/default/hadoop-hdfs-datanode</code>,取消对下面的注释并添加一行设置 <code>jsvc_home</code>,修改如下:
将该文件同步到其他节点:
分别在 cdh2、cdh3 获取 ticket 然后启动服务:
观看 cdh1 上 namenode 日志,出现下面日志表示 datanode 启动成功:
本文介绍了 cdh hadoop 集成 kerberos 认证的过程,其中主要需要注意以下几点:
配置 hosts,<code>hostname</code> 请使用小写
确保 kerberos 客户端和服务端连通
替换 jre 自带的 jce jar 包
为 datanode 设置运行用户并配置 <code>jsvc_home</code>
启动服务前,先获取 ticket 再运行相关命令