Apache Hadoop — 在一个 Pod 里搭起并运维 HDFS 与 YARN
简单认证对你报出的名字照单全收
一句话总结
HDFS 的权限检查与 POSIX 几乎相同,还具备 ACL,但是HDFS 并不负责回答“你是谁”这个问题。在默认设置的简单认证(simple)下,客户端自称的名字会被原样采信,所以权限只是防止失误的装置,而不是防御攻击的装置。
为什么需要区分这两件事
权限里包含两个问题。你是谁(认证)与这个人是否被允许做这件事(授权)。HDFS 对后一个问题回答得很细致,问题出在前一个。
HDFS 权限指南说明,用户的识别方式由 hadoop.security.authentication 选择。在 core-default.xml 中,这个值默认为 simple,说明里在括号中写着“无认证”。simple 模式下,客户端进程的身份由主机操作系统决定,类 Unix 系统上就是 whoami 的值。指南还进一步写道:无论哪种模式,确定用户身份的机制都在 HDFS 之外,HDFS 内部没有创建用户或处理凭据的功能。
所以在这个实验中,只要设置一个环境变量 HADOOP_USER_NAME=alice,那个 shell 就成了 alice,连密码都不需要。安全模式文档明确说明,这不是 bug 而是设计。默认配置下,阻止一切网络访问、不让攻击者接触到集群,是你自己的责任;如果想限制谁能访问数据,就必须用 Kerberos 启用认证。
工作原理
权限位。每个文件和目录都有所有者、组,以及针对所有者、组成员和其他用户这三类的权限。对文件而言,r 是读取,w 是写入和追加。对目录而言,r 是列出内容,w 是在其中创建或删除,x 是访问子项。由于没有可执行文件的概念,所以没有 setuid、setgid 位。新建文件的所有者是客户端的身份,组则沿用父目录的组(BSD 规则)。这里经常出错:并不像 Linux 那样附带用户的主组。
检查顺序。用户名与所有者相同,就只看所有者权限。否则,如果组列表中有该文件的组,就只看组权限。两者都不是,就看其他用户的权限。在上面命中,下面就不再看。另外,所有操作都要求能够穿过整条路径。要访问 /foo/bar/baz,/、/foo、/foo/bar 都必须有 x。
删除是父目录的事。在指南按操作列出的表中,delete 要求的不是文件本身,而是父目录的 w。也就是说,即使文件是只读的,只要目录可写就能删除。要在所有人都能写的共享目录中防止别人删除自己的文件,就要设置粘滞位。设置了粘滞位的目录中,只有超级用户、目录所有者和文件所有者才能删除或移动其中的文件。
组由 NameNode 决定。用户名由客户端自称,但这个用户属于哪些组则不同。组映射文档指出,HDFS 中把用户映射到组的过程发生在 NameNode 上,因此 NameNode 主机的系统配置决定组成员关系。默认实现直接使用操作系统的组查询。另外,HDFS 以字符串而不是数字 ID 保存文件的用户和组。所以,如果 NameNode 所在的机器上没有 finance 组,无论在客户端一侧创建多少个组,HDFS 都不认识。查询结果默认缓存 300 秒,因此刚把人加入组之后,可能仍按旧的成员关系检查。
超级用户。与 NameNode 进程相同的身份就是超级用户,对超级用户,权限检查不会失败。hdfs-default.xml 中 dfs.permissions.superusergroup(默认 supergroup)的成员也是超级用户。在以 root 启动 NameNode 的本实验中,root 就是超级用户。
ACL——表达与组织结构不同的例外
权限位只能表达“一个所有者、一个组”。如果想把财务文件夹开放给 finance 组,同时只额外给负责审计的 bob 一个人读取权限,用权限位就做不到。ACL 正是为此而生。dfs.namenode.acls.enabled 在 3.5.0 中默认为 true。
hdfs dfs -chown alice:finance /proj/finance
hdfs dfs -chmod 750 /proj/finance
hdfs dfs -setfacl -m user:bob:r-x /proj/finance # bob 에게 목록과 통과
hdfs dfs -setfacl -m default:user:bob:r-x /proj/finance # 앞으로 만들 자식에게 상속
hdfs dfs -getfacl /proj/finance
ACL 一旦附加,检查顺序中会插入两个位置。所有者之后要看命名用户条目,组之后要看命名组条目。这两者和未命名的组条目还要再经过一次 mask 过滤。mask 是扩展条目所能给出的权限上限。陷阱在于:对带 ACL 的文件执行 chmod,改变的不是组位,而是 mask。一次 chmod 700 就会悄悄挡住 bob 的读取。
默认(default)ACL 只存在于目录上,新的子项创建时会复制它。指南写道,复制只发生在创建的瞬间,之后即使修改父目录的默认 ACL,已有的子项也不会变。所以要给已有文件授权,就得另外用 setfacl -R 再跑一遍。一个文件能附加的条目也受限:访问 ACL 32 个、默认 ACL 32 个,而且带 ACL 的文件会占用更多 NameNode 内存。指南推荐的做法是:大部分情况用权限位解决,只用 ACL 叠加少数例外。
在现场相遇的样子
第一,明明限制了权限,却有人读到了文件。在简单认证的集群中,任何人都可以自称是 alice。如果安全处于关闭状态,WebHDFS 也会把 user.name 查询参数的值直接当作用户。权限只能防住同事的失误。真正的边界需要 Kerberos,在此之前,网络访问控制是唯一的围墙。
第二,新文件的组与预期不同。这是因为它沿用父目录的组。先把团队文件夹的组调整好,其下的新文件就会自动跟随。
第三,已经加入组,却仍被拒绝。组成员关系由 NameNode 一侧查询并缓存,而不是由客户端。要检查 NameNode 所在的机器上是否有该组和该成员,以及缓存是否还保留着旧值。
第四,设置了默认 ACL,旧文件却仍然读不了。继承是创建瞬间的复制。已有的文件要另行设置。
第五,关闭权限检查不是解决办法。把 dfs.permissions.enabled 设为 false,只是关闭检查,模式、所有者和组依然保留。指南写道,无论这个值如何,chmod、chgrp、chown、setfacl 始终会检查权限。
实际工作中真正重要的事
- HDFS 只做授权,认证交给外部。默认值 simple 会采信对方自称的名字。
- 能否删除由父目录的 w 决定。共享文件夹要设置粘滞位。
- 新文件的组来自父目录。先把团队文件夹的组调整好。
- 对带 ACL 的文件执行 chmod 会改变 mask。扩展条目可能一下子全部收窄。
- 默认 ACL 只在创建的瞬间复制。已有文件要另行修改。
下一项实验要做什么
把财务文件夹设为 alice 所有、finance 组、750,并以 alice 的身份上传文件。用一个环境变量切换用户,看到 bob 被拒绝之后,再用 ACL 只向 bob 一个人开放读取,确认他真的能读到。设置默认 ACL,看新建的文件是否继承了这项权限,再确认在设置了粘滞位的共享文件夹中,试图删除别人的文件会被拒绝。最后在报告中写下:简单认证防不住什么,以及为什么需要 Kerberos。