Hadoop集群取证

当我们成功仿真出 Hadoop 集群的各个节点(NameNode、DataNode、ResourceManager、NodeManager)后,往往需要恢复 HDFS 与 YARN 服务,才能提取集群元数据、业务数据和作业日志。Hadoop 集群对主机名解析和时钟同步非常敏感,仿真后第一步通常是修通网络与时间。

Hadoop 基础知识

什么是 Hadoop

Hadoop 是开源的分布式存储与计算平台,核心由两部分组成:

  • HDFS(分布式文件系统):NameNode(NN)保存全部元数据(目录树、文件→块映射、权限),元数据以 fsimage(全量快照)+ edits(增量编辑日志)形式持久化在磁盘;DataNode(DN)保存实际数据块(block),默认副本数 3,定期向 NN 发送心跳与块报告。
  • YARN(资源调度框架):ResourceManager(RM)统一分配集群资源;NodeManager(NM)运行在每个数据节点上,负责启动容器(Container)执行 MapReduce/Spark 等任务。
  • 可选组件:SecondaryNameNode(定期合并 fsimage+edits,并非热备)、JournalNode(HA 模式下共享 edits)、ZKFC(HA 自动故障切换)、JobHistoryServer(MapReduce 历史作业)、TimelineServer(YARN 应用历史)。

生产环境常见发行版:Apache 原生(配置在 $HADOOP_HOME/etc/hadoop/)、CDH/CDP(/etc/hadoop/conf/)、HDP/Ambari。

取证要点速览

类别关键位置
配置文件目录$HADOOP_HOME/etc/hadoop/(原生)或 /etc/hadoop/conf/(CDH/CDP,软链到 conf.<版本>/)
核心配置core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml、workers(旧版 slaves)
NameNode 元数据dfs.namenode.name.dir 指定目录下的 current/fsimage_* 与 edits_*,默认 file://${hadoop.tmp.dir}/dfs/name
DataNode 数据块dfs.datanode.data.dir 下的 current/BP-*/current/finalized/subdir*/blk_*,默认 ${hadoop.tmp.dir}/dfs/data
JournalNode(HA)dfs.journalnode.edits.dir,默认 /tmp/hadoop/dfs/journalnode
服务日志$HADOOP_LOG_DIR(默认 $HADOOP_HOME/logs):hadoop-*-namenode-*.log、hadoop-*-datanode-*.log、yarn-*-resourcemanager-*.log、yarn-*-nodemanager-*.log
HDFS 审计日志$HADOOP_LOG_DIR/hdfs-audit.log(每次文件读写的用户/IP/操作记录,重点)
YARN 容器日志(本地)yarn.nodemanager.log-dirs,默认 ${hadoop.tmp.dir}/logs/userlogs/application_*/container_*
YARN 聚合日志(HDFS)yarn.log-aggregation-enable=true 时在 HDFS /tmp/logs/<用户>/logs/<appid>/ 或 /app-logs/
Web 界面NN :9870(3.x)/:50070(2.x),RM :8088,DN :9864,NM :8042,JobHistory :19888
RPC 端口NN :8020(fs.defaultFS,部分老环境 :9000),RM :8032
Kerberoscore-site.xml 中 hadoop.security.authentication=kerberos,keytab 常在 /etc/security/keytabs/ 或配置内指定路径

离线取证技巧:服务起不来也能拿到元数据

即使集群完全无法启动,NameNode 磁盘上的 fsimage/edits 就是全部元数据,可直接离线解析(详见”工作负载取证”一节)。先定位元数据目录:

# 从配置文件读出真实目录
grep -A1 'dfs.namenode.name.dir' /etc/hadoop/conf/hdfs-site.xml
grep -A1 'hadoop.tmp.dir'        /etc/hadoop/conf/core-site.xml
find / -name 'fsimage_*' -o -name 'edits_inprogress*' 2>/dev/null   # 兜底全盘搜索

仿真环境网络配置

启动网卡

仿真出的节点默认网卡可能未启用,逐台拉起并获取 IP:

ip link set ens33 up
dhclient ens33

修复主机名解析(关键)

Hadoop 各进程通过主机名互相寻址,配置里写死的都是原集群的主机名。仿真后 IP 变了,必须把 /etc/hosts 改成新 IP 映射:

hostnamectl                                  # 确认本机主机名
cat /etc/hosts
# 每台节点都写入全集群的映射,例如:
# 192.168.170.10  master
# 192.168.170.11  slave1
# 192.168.170.12  slave2

若不确定集群有哪些节点,从 workers(旧版 slaves)文件和 hdfs-site.xml 的 HA 配置中获取:

cat /etc/hadoop/conf/workers
grep -E 'dfs.ha.namenodes|dfs.namenode.rpc-address' -A1 /etc/hadoop/conf/hdfs-site.xml

启动集群服务

原生 Apache 集群用自带脚本(需在配置了免密 SSH 的启动节点执行,否则逐台手动起):

$HADOOP_HOME/sbin/start-dfs.sh      # 启动 NN + 所有 DN(读 workers 文件)
$HADOOP_HOME/sbin/start-yarn.sh     # 启动 RM + 所有 NM
mapred --daemon start historyserver # 启动 MapReduce 历史服务器(可选)

逐台手动启动(免密 SSH 失效时):

hdfs --daemon start namenode
hdfs --daemon start datanode
yarn --daemon start resourcemanager
yarn --daemon start nodemanager

CDH/CDP 环境:

systemctl status hadoop-hdfs-namenode hadoop-hdfs-datanode hadoop-yarn-resourcemanager hadoop-yarn-nodemanager
systemctl restart hadoop-hdfs-namenode hadoop-hdfs-datanode

访问 Web 界面

http://<NN节点IP>:9870     # HDFS 概览、DataNode 列表、文件浏览器(Utilities → Browse the file system)
http://<RM节点IP>:8088     # YARN 应用列表与资源使用

若 NameNode 卡在安全模式(Safe Mode)无法写入,确认块报告收齐后强制退出:

hdfs dfsadmin -safemode get      # 查看当前是否处于安全模式
hdfs dfsadmin -safemode leave    # 强制离开安全模式(仿真恢复常用)

时钟偏差

仿真出来的几台节点之间有时钟偏差时,Kerberos 票据校验会失败(C\lock skew too great),YARN 心跳与块报告也可能异常,需要统一时间:

#1. 关闭自动同步(防止 chrony/NTP 与手动设置打架)
timedatectl set-ntp false
systemctl stop chrony && systemctl disable chrony

#2.手动统一时间(在每台节点上执行,时间保持一致)
timedatectl set-timezone Asia/Shanghai
timedatectl set-time "2024-01-01 12:00:00"
hwclock --systohc        # 同步写入硬件时钟 RTC

#3.确认时间一致(逐台执行比对)
date
timedatectl

#4.重启 Hadoop 服务(Kerberos 对时钟最敏感,统一后重启恢复)
$HADOOP_HOME/sbin/stop-dfs.sh && $HADOOP_HOME/sbin/start-dfs.sh
$HADOOP_HOME/sbin/stop-yarn.sh && $HADOOP_HOME/sbin/start-yarn.sh

系统取证

基本系统信息

Hadoop 版本

hdfs version             # Hadoop 版本、编译时间、源码校验和(最重要)
yarn version
dpkg -l | grep -i hadoop      # Debian 系安装的组件包版本
rpm -qa | grep -i hadoop      # RHEL/CentOS(CDH/HDP)组件版本
cat /etc/os-release           # 底层操作系统版本

主机内核版本

uname -a
uname -r

主机名与节点列表

hostnamectl
cat /etc/hostname
cat /etc/hosts               # 集群各节点 IP/主机名映射常记录在此
cat $HADOOP_HOME/etc/hadoop/workers   # 全部 DataNode/NodeManager 节点名

时间服务器地址

cat /etc/chrony/chrony.conf    # server/pool 行即时间源
chronyc sources                # 在线状态查看
timedatectl                    # 时区与时间同步状态
cat /etc/ntp.conf              # 老版本可能用 ntpd

配置文件取证

配置文件是还原集群架构的第一手资料,先整体打包带走再逐条分析:

tar -czf hadoop-conf.tar.gz -C /etc/hadoop conf 2>/dev/null
tar -czf hadoop-conf-home.tar.gz -C $HADOOP_HOME etc/hadoop

关键字段速查:

  • core-site.xml
    • fs.defaultFS —— NameNode RPC 地址(hdfs://master:8020),HA 模式下为 nameservice 名
    • hadoop.tmp.dir —— 所有默认数据目录的根,元数据/数据块默认都在其下
    • hadoop.security.authentication —— simple(用户名直传,无认证)或 kerberos
    • hadoop.proxyuser.<用户>.hosts/groups —— 允许冒充其他用户的代理配置,权限滥用高发点
  • hdfs-site.xml
    • dfs.namenode.name.dir / dfs.datanode.data.dir —— 元数据与数据块的真实落盘位置
    • dfs.replication —— 副本数
    • dfs.permissions.enabled、dfs.permissions.superusergroup —— 权限开关与超级组
    • dfs.nameservices、dfs.ha.namenodes.<NS> —— HA 模式下的 NameNode 列表
    • dfs.namenode.keytab.file、dfs.namenode.kerberos.principal —— Kerberos 凭据位置
    • dfs.namenode.audit.log.async 等 —— 审计日志开关
  • yarn-site.xml
    • yarn.resourcemanager.hostname —— RM 所在节点
    • yarn.log-aggregation-enable / yarn.nodemanager.remote-app-log-dir —— 日志聚合去向
    • yarn.nodemanager.local-dirs / yarn.nodemanager.log-dirs —— 容器工作目录与本地日志目录
    • yarn.acl.enable、yarn.admin.acl —— YARN 管理员名单
  • mapred-site.xml
    • mapreduce.jobhistory.address、mapreduce.jobhistory.done-dir —— 历史作业数据位置
  • hadoop-env.sh / yarn-env.sh
    • HADOOP_LOG_DIR、JAVA_HOME、各进程的 JVM 参数

集群信息

HDFS 集群状态

hdfs dfsadmin -report      # 集群总容量、各 DataNode 的 IP/主机名/容量/存活状态(核心命令)
hdfs dfsadmin -safemode get
hdfs dfsadmin -printTopology   # 机架感知拓扑:节点在哪个机架

-report 输出中可提取:Configured Capacity、DFS Used、各节点 Last contact 时间(判断节点掉线时间点)、Decommission 状态。

HDFS 文件系统健康检查

hdfs fsck / -files -blocks -locations > fsck.txt   # 每个文件的块分布、缺失/损坏块、副本不足块
hdfs fsck / -list-corruptfileblocks                # 仅列出损坏文件(入侵删库痕迹)

YARN 集群状态

yarn node -list -all            # 全部 NodeManager 及其状态(RUNNING/LOST/DECOMMISSIONED)
yarn application -list -appStates ALL   # 全部应用(含已完成):AppID、用户、队列、类型、最终状态
yarn queue -status root         # 队列资源分配

MapReduce 历史作业

mapred job -list all            # 全部历史作业(需 JobHistoryServer 运行)
mapred job -status <job_id>     # 单个作业详情:提交用户、起止时间、输入输出路径

历史作业数据同时落盘在 mapreduce.jobhistory.done-dir(默认 HDFS /tmp/hadoop-yarn/staging/history/done/),.jhist 文件可离线解析。

高可用(HA)状态

hdfs haadmin -getServiceState nn1     # 当前哪个 NN 是 Active
hdfs haadmin -getAllServiceState

HA 集群的共享 edits 在 JournalNode 的 dfs.journalnode.edits.dir(默认 /tmp/hadoop/dfs/journalnode/<NS名>/current/)下,是元数据取证的另一处来源。

工作负载与数据取证

HDFS 目录树与文件清单

hdfs dfs -ls -R / > hdfs_tree.txt              # 全量目录树:权限、属主、大小、时间戳
hdfs dfs -count -q /                           # 各目录配额、文件数、总大小
hdfs dfs -du -h /                              # 各目录实际占用(快速定位大数据目录)
hdfs dfs -ls /snapshottable 2>/dev/null; hdfs lsSnapshottableDir   # 快照目录

重点关注目录:/user/(用户数据)、/tmp/logs/(YARN 聚合日志)、/apps/、/hbase/、/hive/ 或 /user/hive/warehouse/(Hive 数仓)、/tmp/hadoop-yarn/staging/(作业暂存)。

导出 HDFS 文件

hdfs dfs -get /user/alice/data /导出目录/        # 递归下载整个目录到本地
hdfs dfs -get /user/alice/secret.txt /导出目录/  # 单文件
hdfs dfs -cat /user/alice/secret.txt > secret.txt  # 直接输出到本地文件

大量小文件可先归档再导出:

hadoop archive -archiveName data.har -p /user/alice /archive   # HAR 归档(集群上执行)
hdfs dfs -get /archive/data.har /导出目录/
hdfs dfs -cat /user/alice/bigfile | zstd -T0 > bigfile.zst     # 边下边压缩

导出后做完整性校验:

hdfs dfs -checksum hdfs:///user/alice/secret.txt   # HDFS 端校验和(MD5-of-CRC 组合)
sha256sum /导出目录/secret.txt | tee secret.sha256

NameNode 元数据取证(fsimage / edits,核心)

fsimage 记录某一时刻的完整命名空间,edits 记录其后的每次变更。即使不启动集群也能离线解析:

# fsimage 转可读格式(XML 或 Delimited,含全路径、属主、权限、时间戳、块列表)
hdfs oiv -i fsimage_0000000000000123456 -o fsimage.xml -p XML
hdfs oiv -i fsimage_0000000000000123456 -o fsimage.csv -p Delimited
hdfs oiv -i fsimage_... -o fsimage_rev.txt -p FileDistribution   # 块大小分布统计

# edits 转 XML:每一次创建/删除/重命名/权限变更的操作序列(时间线取证关键)
hdfs oev -i edits_0000000000000123457-0000000000000234567 -o edits.xml -p XML

edits 解析出的 <RECORD> 中 OP_DELETE、OP_RENAME、OP_SET_PERMISSIONS、OP_SET_OWNER 等操作可还原文件删除与篡改的时间线。注意 edits_inprogress_* 是当前未滚动的编辑日志,也必须一并提取。

DataNode 数据块离线取证

NN 不可用、或怀疑有未登记的残留数据时,直接翻 DataNode 磁盘:

ls <dfs.datanode.data.dir>/current/BP-*/current/finalized/subdir*/
# blk_<块ID>        数据本体
# blk_<块ID>_<时间戳>.meta   块校验和元数据

块文件名本身不含原始路径,需用 fsimage/-report/块报告建立 块ID → 文件路径 映射后再还原内容。dfs.datanode.data.dir 支持逗号分隔多磁盘,逐盘检查。删除文件后的残留块可能仍在 finalized/ 中,是数据恢复的重点区域。

YARN 应用日志

yarn logs -applicationId application_1700000000000_0001          # 导出该应用全部容器日志(重点)
yarn logs -applicationId <appid> -containerId <cid> -nodeAddress <node:8041>  # 精确到容器
yarn logs -applicationId <appid> -log_files stderr               # 只看某类日志

yarn logs 要求日志聚合开启且聚合文件还在 HDFS 上(默认 /tmp/logs/<提交用户>/logs/<appid>/)。聚合日志被清理时,退而取 NodeManager 本地目录:

ls ${hadoop.tmp.dir}/logs/userlogs/application_*/container_*/
# 每个容器目录下:stdout、stderr、syslog、launch_container.sh(启动命令,含完整 classpath 与环境变量)

launch_container.sh 能还原作业实际执行的命令,是恶意作业分析的直接证据。

存储取证

NameNode 存储目录

ls <dfs.namenode.name.dir>/current/
# fsimage_* / fsimage_*.md5   命名空间镜像及其校验和
# edits_*                     编辑日志段
# edits_inprogress_*          当前编辑日志
# seen_txid                   已应用的最新事务 ID
# VERSION                     集群 ID(clusterID)、命名空间 ID、创建时间、存储类型
# in_use.lock                 进程锁

VERSION 文件中的 clusterID 必须与 DataNode 上 BP-*(块池 ID 内嵌 clusterID)一致,可用于确认多块磁盘是否属于同一集群;cTime/layoutVersion 记录集群初始化时间与版本。

DataNode 存储目录

ls <dfs.datanode.data.dir>/current/
# BP-<随机数>-<NN地址>-<时间戳>/   块池目录(每集群一个)
#   current/finalized/subdir*/blk_*   已完成的数据块
#   current/rbw/                        正在写入的块(replica being written)
# VERSION                               storageID、cTime、clusterID

YARN 本地工作目录

ls ${hadoop.tmp.dir}/nm-local-dir/     # yarn.nodemanager.local-dirs:作业 jar、依赖、分布式缓存的本地副本

作业提交的可执行文件(jar/python 脚本)会以分布式缓存形式分发到每个 NM 的 nm-local-dir/usercache/<用户>/filecache/ 下,是提取恶意代码样本的直接位置。

Hive/HBase 等组件数据(若存在)

  • Hive 表数据:HDFS /user/hive/warehouse/,元数据在外部 RDBMS(MySQL/PostgreSQL,连接串在 hive-site.xml 的 javax.jdo.option.ConnectionURL)
  • HBase:HDFS /hbase/,元数据在 HBase 自身系统表

用户与权限取证

认证体系

grep -A1 'hadoop.security.authentication' /etc/hadoop/conf/core-site.xml
  • simple:无真正认证,客户端自报用户名(HADOOP_USER_NAME 环境变量即可冒充),此时属主信息只能作为参考
  • kerberos:强认证,继续按下节提取 Kerberos 信息

HDFS 权限与超级用户

grep -A1 'dfs.permissions' /etc/hadoop/conf/hdfs-site.xml    # 权限开关与超级用户组(默认 supergroup)
hdfs dfs -ls /                                               # 各路径属主/属组/权限位
hdfs dfs -getfacl /user                                      # ACL 明细
hdfs groups <用户名>                                          # 该用户在集群侧的属组解析结果

超级用户 = 启动 NameNode 的操作系统用户(通常 hdfs)+ dfs.permissions.superusergroup 组内成员,检查 /etc/passwd、/etc/group 中这些账号与组成员,以及 hdfs、yarn、mapred 等服务账号的 sudo 权限。

Kerberos 集成

cat /etc/krb5.conf                        # KDC 地址、默认 Realm
cat /var/kerberos/krb5kdc/kdc.conf        # KDC 配置(若本机是 KDC)
klist -kt /etc/security/keytabs/hdfs.headless.keytab   # 列出 keytab 中的 principal(不需密码)
ls /etc/security/keytabs/                 # CDH/HDP 标准 keytab 目录

keytab 文件可直接用于以该服务身份认证(kinit -kt <keytab> <principal>),仿真恢复 Kerberized 集群时经常需要。同步确认所有节点时钟(见”时钟偏差”),否则票据校验失败。KDC 数据库(MIT KDC 默认 /var/kerberos/krb5kdc/principal)包含全部 principal,可用 kadmin.local 列出:kadmin.local -q "listprincs"。

代理用户与授权

grep -B1 -A1 'hadoop.proxyuser' /etc/hadoop/conf/core-site.xml   # 允许 Hue/Oozie 等冒充用户的白名单
grep -B1 -A1 'yarn.admin.acl\|yarn.acl.enable' /etc/hadoop/conf/yarn-site.xml
grep -B1 -A1 'hadoop.security.authorization' /etc/hadoop/conf/core-site.xml
cat /etc/hadoop/conf/hadoop-policy.xml                            # 服务级授权:哪些用户/组可调哪些 RPC 协议

hadoop.proxyuser.*.hosts=* + groups=* 是最危险的配置,意味着该服务账号可冒充任意用户从任意机器接入。

日志取证

HDFS 审计日志(重点)

cat $HADOOP_LOG_DIR/hdfs-audit.log

每个文件级操作一行,格式形如:

2024-01-01 12:00:00,123 INFO FSNamesystem.audit: allowed=true ugi=alice (auth:SIMPLE) ip=/192.168.1.100 cmd=open src=/user/bob/secret.txt dst=null perm=null proto=rpc

可提取的关键信息:ugi(操作用户与认证方式)、ip(来源客户端)、cmd(open/create/delete/rename/setPermission/setOwner 等)、src/dst(路径)。据此可还原:谁读了什么数据(数据窃取溯源)、谁删除/改权限了哪些文件(破坏痕迹)。若服务起不来,直接到日志目录翻历史文件与滚动归档(hdfs-audit.log.*)。

NameNode / DataNode 服务日志

ls $HADOOP_LOG_DIR/
cat $HADOOP_LOG_DIR/hadoop-*-namenode-*.log     # NN 启动、安全模式进出、块分配、节点上下线
cat $HADOOP_LOG_DIR/hadoop-*-datanode-*.log     # DN 块接收/删除、心跳异常
grep -i 'decommission\|shutdown\|corrupt' $HADOOP_LOG_DIR/hadoop-*-namenode-*.log

NN 日志中的 BLOCK* NameSystem.delete、节点 join/leave 记录可补充审计日志之外的基础设施级事件。

YARN 服务日志

cat $HADOOP_LOG_DIR/yarn-*-resourcemanager-*.log   # 应用提交/完成/杀死、队列调度、节点注册与失联
cat $HADOOP_LOG_DIR/yarn-*-nodemanager-*.log       # 容器启动/停止、本地化下载记录
grep -E 'Submitted application|application_.*to RUNNING|Killing application' $HADOOP_LOG_DIR/yarn-*-resourcemanager-*.log

RM 日志可还原每个应用的提交用户、提交来源 IP 与执行时间线,与 yarn logs 提取的容器日志互相印证。

系统层日志

journalctl -u hadoop-hdfs-namenode -u hadoop-hdfs-datanode -u hadoop-yarn-resourcemanager --no-pager   # CDH/CDP
cat /var/log/auth.log /var/log/secure        # SSH/PAM 登录记录(看谁登过集群节点)
last -f /var/log/wtmp                        # 登录历史
cat /var/log/cron /var/log/crontab 2>/dev/null   # 定时任务(自动化作业/后门)
history; cat ~/.bash_history                 # 各账号执行过的 hdfs/yarn 命令(重点找 dfsadmin、rm -r、kinit)