在我们的生产环境有多套 Hadoop 集群,这些集群都配置了 Kerberos 安全鉴权,有次的需求是需要将其中一个集群(D)上的 hdfs 数据同步到另一个集群(C),需要做信任关系。因为 D 集群比较重要,我们想尽量让 C 集群重启而不让 D 重启,所以考虑只做单向信任,在 C 集群增加 D 的访问,这样只用重启 C 集群。

D –> C

C 集群主体 OSS2.COM
D 集群主体 OSS3.COM

现将过程记录如下

准备工作

  1. C 集群,D 集群所有的节点上 /etc/hosts 加上互相的 集群主机

  2. hdfs 客户端机器上的 /etc/krb5.conf 加上两边集群的主体(realm)配置。

开始配置

添加 krbtgt 的跨域信任

ssh 连到 D 集群的 ipa 主机

1
kadmin.local -q 'addprinc -pw 12345678 krbtgt/[email protected]' -x ipa-setup-override-restrictions

@ 后面是当前域,当前是 D 集群的域

理解: 在 D 集群中加上 C 的凭据主体

配置 auth_to_local 规则

Ambari 页面上

HDFS - ADVANCED core-site - hadoop.security.auth_to_local

对应的是 core-site.xml

Ambari 上修改后,重启,这个配置会推送到所有的 hdfs 节点(datanode)上

在 DEFAULT 后面加上

1
2
3
4
5
6
RULE:[1:[email protected]$0](.*@OSS3.COM)s/@.*//
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/

当时看着专家组这么配置,具体什么含义专家也不会给你解释

这个 RULE 配置乍一看确实有点费解,Ambari 页面上的配置描述是这么写的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
The mapping from kerberos principal names to local OS mapreduce.job.user.names.
So the default rule is just "DEFAULT" which takes all principals in your default domain to their first component.
"[email protected]" and "omalley/[email protected]" to "omalley", if your default domain is APACHE.ORG.
The translations rules have 3 sections:
base filter substitution
The base consists of a number that represents the number of components in the principal name excluding the realm and the pattern for building the name from the sections of the principal name. The base uses $0 to mean the realm, $1 to mean the first component and $2 to mean the second component.

[1:[email protected]$0] translates "[email protected]" to "[email protected]"
[2:$1] translates "omalley/[email protected]" to "omalley"
[2:$1%$2] translates "omalley/[email protected]" to "omalley%admin"

The filter is a regex in parens that must the generated string for the rule to apply.

"(.*%admin)" will take any string that ends in "%admin"
"(.*@ACME.COM)" will take any string that ends in "@ACME.COM"

Finally, the substitution is a sed rule to translate a regex into a fixed string.

"s/@ACME\.COM//" removes the first instance of "@ACME.COM".
"s/@[A-Z]*\.COM//" removes the first instance of "@" followed by a name followed by ".COM".
"s/X/Y/g" replaces all of the "X" in the name with "Y"

So, if your default realm was APACHE.ORG, but you also wanted to take all principals from ACME.COM that had a single component "[email protected]", you'd do:

RULE:[1:[email protected]$0]([email protected])s/@.//
DEFAULT

To also translate the names with a second component, you'd make the rules:

RULE:[1:[email protected]$0]([email protected])s/@.//
RULE:[2:[email protected]$0]([email protected])s/@.//
DEFAULT

If you want to treat all principals from APACHE.ORG with /admin as "admin", your rules would look like:

RULE[2:$1%[email protected]$0](.%[email protected])s/./admin/
DEFAULT

翻译一下

这个配置的作用是将 kerberos principal 名称映射为本地操作系统的 mapreduce.job.user.names 用户
所以默认的规则只是一个 “DEFAULT”,如果域是你的默认域(/etc/krb5.conf 中配置的 default_realm),这条规则会取 principals 名称的第一部分作为系统用户名。

如果你的默认域是 APACHE.ORG,那么 “[email protected]“ 和 “omalley/[email protected]“ 将被映射为 “omalley”.
映射规则由三部分组成:

base filter substitution

base 部分,由一个数字和一个匹配规则组成。数字代表 principal name (不包含域名)由几个部分构成,匹配规则是用于从服务主体名称构建用户名. $0 表示域名(realm) , $1 代表第一个部分,$2 第二个部分.

格式是这样的

1
[<number>:<string>]

数字为 1 ,就是 @ 前面只有 1 个字符串
数字为 2 ,就是 @ 前面有 2 个字符串,字符串间隔为 /

[1:[email protected]$0] 将 “[email protected]“ 转化为 “[email protected]
[2:$1] 将 “omalley/[email protected]“ 转化为 “omalley”
[2:$1%$2] 将 “omalley/[email protected]“ 转化为 “omalley%admin”

filter 部分是一个正则表达式。 用来匹配生成的字符串。

“(.%admin)” 将匹配以 “%admin” 为结尾的字符串
“(.
@ACME.COM)” 将匹配以 “@ACME.COM” 为结尾的字符串

. 匹配任意的单个字符(any single character)
* 匹配前一个字符出现 0 次或者 多次

substitution 部分是一个 sed 替换规则。使用固定字符串替换被匹配的正则表达式。

“s/@ACME.COM//“ 删除 第一个匹配到的 “@ACME.COM”.
“s/@[A-Z]*.COM//“ 删除第一个匹配到的 “@” 后面跟着一个大写的名字,后面跟着 “.COM”.
“s/X/Y/g” 替换所有的 “X” 为 “Y”

如果你的默认域是 APACHE.ORG, 但是你想匹配从 ACME.COM 域来的所有只含一个部分的 principals “[email protected]“, 你可以这么写 rule:

RULE:1:[email protected]$0s/@.//
DEFAULT

如果还要映射有第二个部分的 principal 名称, 你要加上第二条 rule:

RULE:1:[email protected]$0s/@.//
RULE:2:[email protected]$0s/@.//
DEFAULT

如果你想将来自 APACHE.ORG 域的所有带有 /admin 的 principal 作为 “admin”, 你的 rule 要这么写:

RULE2:$1%[email protected]$0s/./admin/
DEFAULT

这个配置讲的有些不清楚,可以再看看 https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html#realms 这里讲的要清楚些

总的来说,格式是这样的:

1
[n:string](regexp)s/pattern/replacement/g

n 确定 principal name 有几个部分
string 转化原文到指定的输出格式
regexp 正则表达式过滤
s/pattern/replacement/g 替换输出

可以编写多个规则,一旦主体与规则匹配,则会跳过其余规则。

再来看看我们的配置,因为 DEFAULT 是转化默认域(OSS2.COM)的,所以跨域部分的配置要在 DEFAULT 之后配置

1
2
3
4
5
6
RULE:[1:[email protected]$0](.*@OSS3.COM)s/@.*//
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/

详细理解下:

第一行

1
RULE:[1:[email protected]$0](.*@OSS3.COM)s/@.*//

表示将 [email protected] 映射为 aaa

我们可以使用hadoop org.apache.hadoop.security.HadoopKerberosName 进行测试

1
2
$ hadoop org.apache.hadoop.security.HadoopKerberosName [email protected]
Name: [email protected] to aaa

第二行

1
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/

principal 包含两个部分时,且第一部分@主体的结果是 [email protected],映射到 hdfs
测试如下:

1
2
$ hadoop org.apache.hadoop.security.HadoopKerberosName dn/[email protected]
Name: dn/[email protected] to hdfs

这种 rule 主要是映射 服务类的 principal

1
Service/[email protected]

服务名为 dn 的是 datanode ,需要被映射到 hdfs 用户

后面几行依次是

  • nm, nodemanager, 映射到 yarn 用户
  • nn, namenode,映射到 hdfs 用户
  • rm, resourcemanager,映射到 yarn 用户
  • yarn, 映射到 yarn 用户

鉴于我们的需求只涉及 hdfs 文件跨集群拷贝,所以以上组件的规则已经足够。

注意:这些都是将 OSS3.COM 域的 principal 进行转换。

再看看除了这些,一般还会配置什么 rule,这里我贴出 DEFAULT 以上的 rule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
RULE:[1:[email protected]$0]([email protected])s/.*/ambari-qa/
RULE:[1:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[1:[email protected]$0]([email protected])s/.*/spark/
RULE:[1:[email protected]$0](.*@OSS3.COM)s/@.*//
RULE:[2:[email protected]$0]([email protected])s/.*/ams/
RULE:[2:[email protected]$0]([email protected])s/.*/ams/
RULE:[2:[email protected]$0]([email protected])s/.*/beacon/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/hive/
RULE:[2:[email protected]$0]([email protected])s/.*/mapred/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/knox/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/ranger/
RULE:[2:[email protected]$0]([email protected])s/.*/rangertagsync/
RULE:[2:[email protected]$0]([email protected])s/.*/rangerusersync/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[1:[email protected]$0]([email protected])s/.*/ambari-qa/
RULE:[1:[email protected]$0]([email protected])s/.*/hbase/
RULE:[1:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[1:[email protected]$0]([email protected])s/.*/spark/
RULE:[1:[email protected]$0](.*@OSS.COM)s/@.*//
RULE:[2:[email protected]$0]([email protected])s/.*/ams/
RULE:[2:[email protected]$0]([email protected])s/.*/ams/
RULE:[2:[email protected]$0]([email protected])s/.*/beacon/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/hbase/
RULE:[2:[email protected]$0]([email protected])s/.*/hive/
RULE:[2:[email protected]$0]([email protected])s/.*/mapred/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/knox/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/hdfs/
RULE:[2:[email protected]$0]([email protected])s/.*/ranger/
RULE:[2:[email protected]$0]([email protected])s/.*/rangerusersync/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
RULE:[2:[email protected]$0]([email protected])s/.*/yarn/
DEFAULT

好吧,为什么他又把这些 OSS3 OSS 的添加到 DEFAULT 上面了,看来是没有和顺序相关,那就不 care 了

可以看到组件还是很多的

配置 /etc/krb5.conf 文件的 [capaths]

这是配置信任域的映射关系

需要注意的是,这个是修改 客户端机器上的 /etc/krb5.conf, 集群节点上的 /etc/krb5.conf 是没有修改的。

/etc/krb5.conf 末尾加上

1
2
3
4
5
[capaths]

OSS3.COM = {
OSS2.COM = .
}

最后配置出来的 krb5.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#File modified by ipa-client-install

includedir /etc/krb5.conf.d/
includedir /var/lib/sss/pubconf/krb5.include.d/

[libdefaults]
default_realm = OSS3.COM
dns_lookup_realm = false
dns_lookup_kdc = false
rdns = false
dns_canonicalize_hostname = false
ticket_lifetime = 365d
renew_lifetime = 3650d
forwardable = true
udp_preference_limit = 0
default_ccache_name = /tmp/krb5cc_%{uid}


[realms]
OSS3.COM = {
kdc = ipa010.oss3.com
kdc = ipa011.oss3.com
kdc = ipa012.oss3.com
master_kdc = ipa010.oss3.com
master_kdc = ipa011.oss3.com
master_kdc = ipa012.oss3.com
admin_server = ipa010.oss3.com
admin_server = ipa011.oss3.com
admin_server = ipa012.oss3.com
kpasswd_server = ipa010.oss3.com
kpasswd_server = ipa011.oss3.com
kpasswd_server = ipa012.oss3.com
default_domain = oss3.com
pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem
pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem

}

OSS2.COM = {
kdc = ipa006.oss2.com:88
master_kdc = ipa006.oss2.com:88
admin_server = ipa006.oss2.com:749
kpasswd_server = ipa006.oss2.com:464
kdc = ipa005.oss2.com:88
master_kdc = ipa005.oss2.com:88
admin_server = ipa005.oss2.com:749
kpasswd_server = ipa005.oss2.com:464
default_domain = oss2.com
pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem
pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem

}



[domain_realm]
.oss3.com = OSS3.COM
oss3.com = OSS3.COM


.oss2.com = OSS2.COM
oss2.com = OSS2.COM

[capaths]

OSS3.COM = {
OSS2.COM = .
}

hdfs-site.xml 中的 ‘dfs.namenode.kerberos.principal.pattern’

我印象中我们是没有专门配置这个的,但是看到 cloudera community 的帖子说了这个,我就去看了下,我们配置的是 *

1
2
3
grep -rn -1 'dfs.namenode.kerberos.principal.pattern' hdfs-site.xml

value *

Ambari 上重启 C 集群的 hdfs 组件。

这个不要点错了鸭,只需要重启 hdfs 组件就可以了,我上次把所有的组件重启了,吓得我一身冷汗

验证

如何检查是不是已经通了呢

在 C 和 D 上创建一个同名的 ipa 用户,密码/加密方式都一样,加密方式一般没有专门去指定,那就不用管

在使用 D 集群凭证的客户端机器上,使用 ip 方式,hdfs dfs -ls ,查看 C 集群文件

ip 使用 C 集群的 active namenode 的 ip

如果能查看就代表通了

我们之前的 跨集群拷贝脚本中涉及到的集群版本比较老,所以脚本中通过这样的方式获取 active nn 的 ip

1
2
3
4
5
6
7
8
9
10
getActiveNameNode(){
namenodes='10.110.123.1 10.110.123.2'
for namenode in ${namenodes}
do
curl -s "http://${namenode}:50070/jmx?qry=Hadoop:service=NameNode,name=NameNodeStatus" | grep 'active' > /dev/null
if [ $? -eq 0 ]; then
active_namenode=${namenode}
fi
done
}

C 集群是 HDP 3.x 的版本,访问 50070 都需要 kerberos 认证,我也没找到别的办法可以认证,于是采用了绕路的方式(骚方法),hdfs dfs -ls 能看的,自然就是 active nn ip 了(呲牙)

1
2
3
4
5
6
7
8
9
10
getActiveNameNode(){
namenodes='10.110.123.1 10.110.123.2'
for namenode in ${namenodes}
do
hdfs dfs -ls hdfs://${namenode}:8020/ > /dev/null
if [ $? -eq 0 ]; then
active_namenode=${namenode}
fi
done
}

参考:
https://www.cnblogs.com/xiaodf/p/10689092.html

https://community.cloudera.com/t5/Community-Articles/Kerberos-cross-realm-trust-for-distcp/ta-p/245590

https://medium.com/remotehero-co/how-to-configure-distcp-on-2-kerberized-clusters-22a24658a7e1

https://www.cnblogs.com/yinzhengjie2020/p/13655547.html

http://t.zoukankan.com/devos-p-5448938.html