[INFRA] EMR集群安全配置传输中加密和Kerberos认证配置详解

请注意本文部分内容经过AI辅助生成,虽然经过笔者检查但是并不保证内容的正确性,请自行判断准确性,本文对相关后果不承担责任

EMR Security Configuration(安全配置)是 Amazon EMR 提供的可复用安全策略模板,用于集中定义集群的加密、认证和授权设置。

  • 创建后存储在 EMR 服务端(非集群本身),可被多个集群复用
  • 适用于 EMR 4.8.0 及更高版本,并且创建后不可修改,只能删除重建

控制台创建 Security Configuration 时包含四大部分,本文仅涉及In Transit和Kerberos 部分

部分 说明
Encryption 静态数据加密(At Rest)和传输中数据加密(In Transit)
Authentication 认证协议:IAM / Kerberos / LDAP
Authorization 授权模式:Instance Profile / Runtime Role / Lake Formation / Ranger
IMDS EC2 实例元数据服务版本控制

传输中数据加密(In Transit)

启用后,EMR 自动为支持 TLS 的开源组件配置加密通信(Spark、Tez、MapReduce 等)。

证书提供方式

方式 说明
PEM 自行生成 PEM 证书,打包为 zip 上传到 S3
Custom 自定义 Java 类实现 TLSArtifactsProvider 接口,JAR 上传到 S3

PEM 证书 zip 包文件要求

文件名 是否必须 说明
privateKey.pem 必须 私钥文件
certificateChain.pem 必须 证书链文件
trustedCertificates.pem 可选 受信任的 CA 证书(建议提供非 Java 默认信任的 CA 证书)

PEM 文件在 TLS 通信中的角色

EMR 启用 In-transit encryption 后,每个节点都会从 S3 下载同一份证书 zip 包。集群内节点既是 Server 又是 Client(互相通信),所以每个节点同时需要三个文件:

复制代码
每个 EMR 节点:
├── privateKey.pem           ← 当别人连我时,用它签名证明"我确实是证书持有者"
├── certificateChain.pem     ← 当别人连我时,把这个发给对方作为身份证明
└── trustedCertificates.pem  ← 当我连别人时,用它验证对方的证书是否可信

TLS 握手过程(以 Spark Executor 连接 Driver 为例):

复制代码
节点 A (Driver/Server)                     节点 B (Executor/Client)
┌───────────────────────┐                  ┌───────────────────────┐
│                       │  ① TCP 连接       │                       │
│                       │ ◄──────────────── │                       │
│                       │                   │                       │
│ certificateChain.pem  │ ──────────────►  │ trustedCertificates   │
│ (公钥证书=身份证)      │  ② 发送证书       │ .pem 验证证书可信 ✅   │
│                       │                   │                       │
│ privateKey.pem        │                   │                       │
│ (私钥=证明身份证是我的) │ ◄──────────────── │ 用证书中的公钥加密     │
│                       │  ③ 密钥协商        │ 预主密钥发给 A        │
│                       │                   │                       │
│        ④ 双方建立加密通道,开始传输数据      │                       │
└───────────────────────┘                  └───────────────────────┘

各组件使用证书的通信场景

通信场景 Server 端(用 privateKey + certificateChain) Client 端(用 trustedCertificates 验证)
Spark shuffle 数据传输 Executor 的 BlockManager 另一个 Executor
Spark Driver ↔ Executor RPC Driver Executor
HDFS DataNode 之间块复制 源 DataNode 目标 DataNode
HDFS Client 读写数据 DataNode NameNode / Client
YARN NodeManager ↔ ResourceManager ResourceManager NodeManager
Tez Task 间 shuffle Task 所在节点 另一个 Task 节点
MapReduce shuffle Reducer 拉取 Mapper 输出 Mapper 所在节点 ShuffleHandler
HBase RegionServer 间通信 RegionServer 另一个 RegionServer
Presto/Trino Worker ↔ Coordinator Coordinator Worker

自签名证书与 trustedCertificates.pem

TLS 连接时,Client 需要验证 Server 的证书是否由受信任的 CA 签发。Java 有默认的受信任 CA 列表(cacerts),包含 DigiCert、Let's Encrypt 等公共 CA。自签名证书不在这个列表里,验证会失败。trustedCertificates.pem 告诉 EMR "除了 Java 默认信任的 CA,也信任这个证书"。自签名证书既是证书本身也是签发者,所以直接复制即可。

复制代码
自签名时:certificateChain.pem == trustedCertificates.pem(自己签自己,自己信任自己)
CA 签发时:trustedCertificates.pem = CA 根证书(如果不在 Java 默认信任列表中才需要提供)

主机名验证(hadoop.ssl.hostname.verifier)

TLS 握手时 Hadoop 默认验证对方证书 CN 是否与实际主机名匹配。使用通配符证书(如 CN=*.cn-north-1.compute.internal)时,节点主机名 ip-10-0-1-23.cn-north-1.compute.internal 能匹配通配符,验证通过。如果证书 CN 是具体主机名,其他节点连接时主机名不匹配,TLS 握手失败。

行为
DEFAULT(默认) 严格验证 CN/SAN 与主机名匹配
ALLOW_ALL 跳过主机名验证,只验证证书本身是否可信

设置方式(创建集群时通过 classification 传入):

json 复制代码
[{"Classification": "core-site", "Properties": {"hadoop.ssl.hostname.verifier": "ALLOW_ALL"}}]

集群内所有节点共用同一份证书,通配符确保无论哪个节点出示证书,主机名验证都能通过。如果要用具体主机名的证书(每个节点不同),PEM zip 方式无法实现,需要用 Custom 证书提供者(Java TLSArtifactsProvider 实现),在运行时根据节点主机名动态生成/获取对应证书。

自签名 PEM 证书的要求

  1. 通配符域名(CN) :证书的 Common Name 必须使用通配符匹配集群所在 VPC 的内部域名
    • cn-north-1(北京):CN=*.cn-north-1.compute.internal
    • cn-northwest-1(宁夏):CN=*.cn-northwest-1.compute.internal
    • 其他区域:CN=*.<region>.compute.internal
  2. 密钥算法:推荐 RSA 2048 位或更高
  3. 有效期:根据需要设置,示例中使用 365 天
  4. 如果不使用通配符 :必须设置 hadoop.ssl.hostname.verifier=ALLOW_ALL(EMR 7.3.0+ 通过 core-site classification 配置,低版本直接修改 core-site.xml
  5. 自签名证书仅适合测试,生产环境建议使用内部 CA 签发或自定义证书提供者

生成自签名证书示例

bash 复制代码
# 生成自签名证书和私钥(以北京区域为例)
openssl req -x509 -newkey rsa:2048 \
  -keyout privateKey.pem \
  -out certificateChain.pem \
  -days 365 -nodes \
  -subj '/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=MyDept/CN=*.cn-north-1.compute.internal'

# 自签名证书需要复制为 trustedCertificates.pem
cp certificateChain.pem trustedCertificates.pem

# 打包为 zip(文件名必须严格匹配)
zip -r -X my-certs.zip certificateChain.pem privateKey.pem trustedCertificates.pem

# 上传到 S3
aws s3 cp my-certs.zip s3://my-bucket/emr-certs/my-certs.zip

Kerberos 认证

控制台提供三种认证协议:IAM、Kerberos、LDAP。

IAM(AWS Identity and Access Management)是默认方式,使用 IAM 身份联合或临时安全凭证管理用户访问,无需额外配置。

Kerberos 是一个网络认证协议,通过可信第三方 KDC(Key Distribution Center)验证身份,解决"在不安全网络中证明你是谁"的问题。没有 Kerberos 时,任何人可以通过 HADOOP_USER_NAME=hdfs 伪装成超级用户,HDFS 权限形同虚设。启用 Kerberos 后,每个用户/服务必须先通过 KDC 认证获取 Ticket,才能访问集群资源。

概念 说明
KDC 可信第三方,负责验证身份、签发票据
Principal 身份标识,格式 name/instance@REALM,如 hdfs/ip-10-0-1-1@EC2.INTERNAL
TGT (Ticket) KDC 签发的临时通行证,有时效性(默认 24h),用来向各服务证明身份
Keytab 存储 Principal 密钥的文件(等同于密码文件),服务进程用它自动获取和续期 TGT
Service Ticket 用 TGT 向 KDC 换取的针对具体服务的票据,访问 HDFS/Hive/YARN 时出示

TGT vs Keytab 的区别:

  • Keytab = 密码文件(长期有效,存在磁盘上,服务进程用它自动认证)
  • TGT = 临时通行证(有时效,过期作废,用 Keytab 或密码换取)

Kerberos 保护了哪些组件

组件 没有 Kerberos 有 Kerberos
HDFS 任何人可伪装成任何用户读写文件 必须持有有效 Ticket,按 Principal 身份做权限检查
YARN 任何人可提交/杀死作业 只能管理自己的作业
Hive/HiveServer2 匿名连接,无身份验证 必须 Kerberos 认证后才能连接和查询
Spark 无身份区分 Driver/Executor 之间通过 Kerberos 互相认证
HBase 任何人可读写任何表 按 Principal 做 ACL 控制
Presto/Trino 无认证 通过 Kerberos 认证用户身份

注意:Kerberos 只负责认证(你是谁),授权(你能干什么)由各组件自己的权限系统负责(如 HDFS 文件权限/ACL、Hive 权限、Ranger 策略等)。

两种模式

模式一:Cluster-dedicated KDC

  • Master 节点同时运行 KDC + NameNode + HiveServer2 等
  • 适用:单集群、测试环境
  • 优点:简单,EMR 自动安装配置
  • 缺点:主节点挂了 KDC 也没了

模式二:External KDC

  • 独立 KDC 服务器,多个 EMR 集群共用
  • 适用:多集群共享、生产环境、企业 AD 集成
  • 优点:统一身份管理,集群销毁不影响 KDC
  • 缺点:需自己维护 KDC,网络需可达

配置分两个地方

Security Configuration(可复用模板)中配置:

  • Provider:ClusterDedicatedKdc / ExternalKdc
  • Ticket lifetime:默认 24 小时,最大 596523 小时。集群应用和服务会自动续期,SSH 用户需手动执行 kinit 续期
  • Cross-realm trust(可选):对方的 Realm、Domain、Admin server(端口 749)、KDC server(端口 88)

创建集群时通过 --kerberos-attributes 配置(每个集群不同):

  • Realm:Kerberos realm 名称,惯例全大写
  • KdcAdminPassword:KDC 管理员密码
bash 复制代码
aws emr create-cluster \
  --security-configuration "MyKerberosSecConfig" \
  --kerberos-attributes '{
    "Realm": "EC2.INTERNAL",
    "KdcAdminPassword": "MyKdcP@ss123"
  }' \
  ...

Realm 命名规则

场景 能随便写吗 建议
Cluster-dedicated KDC,独立使用 随便写 EC2.INTERNAL,简单省事
Cluster-dedicated KDC,其他集群要引用 随便写,但定了别改 取有意义的名字,如 EMR.PROD
External KDC 必须和外部 KDC 一致 问 KDC 管理员
Cross-realm trust 对接 AD 对方 Realm 必须和 AD 一致 自己的 Realm 可以随便取

集群创建后,所有 Principal 自动带上 Realm 后缀:

复制代码
hdfs/ip-10-0-1-1.cn-north-1.compute.internal@EC2.INTERNAL
yarn/ip-10-0-1-1.cn-north-1.compute.internal@EC2.INTERNAL
hive/ip-10-0-1-1.cn-north-1.compute.internal@EC2.INTERNAL

kadmin.local vs kadmin

kadmin.local kadmin
连接方式 直接读 KDC 本地数据库文件 通过网络连接 kadmin 服务(端口 749)
需要认证吗 不需要,但需要 root 权限(sudo) 需要,用 xxx/admin@REALM Principal + 密码
在哪能用 只能在 KDC 所在机器上(即 Master 节点) 任何能访问 KDC 的机器上
KDC 服务挂了能用吗 能用(不依赖服务进程) 不能

EMR 默认不创建 admin Principal ,ACL 规则 */admin *e 允许任何 xxx/admin 格式的 Principal 做管理操作,但需要先用 kadmin.local 手动创建:

bash 复制代码
# 在 Master 节点上创建管理员 Principal(只需做一次)
sudo kadmin.local -q 'addprinc -pw <你的密码> root/admin@EC2.INTERNAL'

# 之后就可以用 kadmin 了(任何能访问 Master 749 端口的机器上)
kadmin -p root/admin@EC2.INTERNAL -w <你的密码> -q 'listprincs'

# sudo kadmin 会自动推断为 root/admin,不需要 -p
sudo kadmin -w <你的密码> -q 'listprincs'

常用管理命令:

bash 复制代码
# 以下均可用 kadmin.local(Master 节点)或 kadmin(远程)执行
addprinc -pw user1pass user1@EC2.INTERNAL    # 创建用户
cpw -pw newpass user1@EC2.INTERNAL           # 修改密码
delprinc user1@EC2.INTERNAL                  # 删除用户
listprincs                                   # 列出所有 Principal

用户实际使用

  • kinit user1 之后,不管你的 Linux 用户是 hadoop、root 还是 ec2-user,HDFS 都认你是 user1。
bash 复制代码
# 获取 Ticket
kinit user1
Password for user1@EC2.INTERNAL: ****

# 查看 Ticket
klist
Ticket cache: FILE:/tmp/krb5cc_990
Default principal: user1@EC2.INTERNAL

Valid starting     Expires            Service principal
03/24/26 09:52:43  03/24/26 19:52:43  krbtgt/EC2.INTERNAL@EC2.INTERNAL
        renew until 03/25/26 09:52:43
# 以 user1 身份操作 HDFS
hdfs dfs -ls /user/user1    # 有权限
hdfs dfs -ls /user/user2    # Permission denied(取决于 HDFS 权限设置)

# HADOOP_USER_NAME 伪装在 Kerberos 环境下无效。Kerberos 以 Ticket 中的 Principal 为准,忽略环境变量
HADOOP_USER_NAME=hdfs hdfs dfs -touchz /tmp/test.txt
hdfs dfs -ls /tmp/test.txt
# owner 仍然是 user1,不是 hdfs
相关推荐
zhojiew2 小时前
[INFRA] EMR集群启用HA高可用架构和配置分析
aws·emr·bigdata
moton20172 小时前
TLS协议原理全解析:从SSL到TLS1.3的安全演进
网络协议·安全·ssl
亚马逊云开发者2 小时前
S3 桶名不用再抢了:Account Regional Namespaces 来了
aws
聚铭网络2 小时前
【一周安全资讯0321】工信部启动工业数据筑基行动,建设面向AI赋能的高质量行业数据集;360回应“安全龙虾”私钥泄露事件
人工智能·安全
CDN3602 小时前
中小团队安全方案:360CDN 高防服务器基础配置
运维·服务器·安全
码农小白AI2 小时前
AI审核加持的IACheck:临电配电箱安全检测报告如何确保用电安全
安全
算法-大模型备案 多米3 小时前
算法备案算法安全自评估报告模板(精简版)
大数据·人工智能·安全·语音识别·文心一言
IT观测3 小时前
深析倍思充电宝其技术优势与安全标准
安全
亚远景aspice3 小时前
亚远景-ISO 21434:汽车网络安全全生命周期风险管理的技术框架
运维·网络·安全