文章目录
- 背景
- 一、先摸清楚现有的用户和组关系
-
- [1. 看当前用户自己的组](#1. 看当前用户自己的组)
- [2. 看指定用户的组](#2. 看指定用户的组)
- [3. 看某个文件/文件夹当前的属主和属组](#3. 看某个文件/文件夹当前的属主和属组)
- [4. 看系统里所有的组、以及某个组的成员](#4. 看系统里所有的组、以及某个组的成员)
- 二、创建一个专属用户组,只放一个用户
- 三、创建一个"只拥有文件、不能真正登录"的账户
-
- [怎么"扮演"一个 nologin 账户去测试权限](#怎么"扮演"一个 nologin 账户去测试权限)
- 四、创建目标目录并设置基础权限
- [五、让整个 test 组都能读写(不只是属主一个人)](#五、让整个 test 组都能读写(不只是属主一个人))
- 六、用默认ACL堵住最后一个漏洞
-
- [实测:故意换一个"苛刻"的 umask,验证规则不受影响](#实测:故意换一个"苛刻"的 umask,验证规则不受影响)
- [七、Windows 那边 SMB 映射死活"拒绝访问"](#七、Windows 那边 SMB 映射死活"拒绝访问")
-
- [第一步排查:Samba 用户和 Linux 用户是两套账户体系](#第一步排查:Samba 用户和 Linux 用户是两套账户体系)
- 第二步排查:路径链上每一层的执行权限有没有断掉
- [第三步排查:smb.conf 里的访问控制配置](#第三步排查:smb.conf 里的访问控制配置)
- [还是不行?直接看 Samba 日志](#还是不行?直接看 Samba 日志)
- 总结
背景
最近团队里要新开一个数据集目录,只想让固定几个人能往里写东西,其他同事只能拷贝、只读,不能瞎改。本来以为 chmod 三下五除二就能搞定,结果一路踩了好几个坑------从"这个组有哪些人都搞不清",到"nologin 账户怎么切换",再到最后 Windows 那边 SMB 死活拒绝访问。整个过程记录下来,给同样场景的朋友省点排查时间。
环境说明:
| 配置项 | 详情 |
|---|---|
| 系统 | Ubuntu(Dell PowerEdge R740xd 服务器) |
| 共享服务 | Samba |
| 涉及目录 | /hqdata/shares/algo-test |
| 目标账户 | AAAA(新建,只用来"拥有"文件,不需要真正登录) |
一、先摸清楚现有的用户和组关系
在动手改权限之前,一定要先弄清楚"谁在哪个组里",不然容易改错。
1. 看当前用户自己的组
bash
groups # 只列组名
id # uid/gid/所有附加组,信息最全
id 的输出长这样:
uid=1000(myaccount) gid=1000(myaccount) groups=1000(myaccount),27(sudo)
2. 看指定用户的组
bash
id 用户名
groups 用户名
3. 看某个文件/文件夹当前的属主和属组
这一步特别关键,很多权限问题一上来就该先看这个:
bash
ls -ld /path/to/folder
输出类似:
drwxr-xr-x 2 BBBB developers 4096 Sep 18 10:00 /path/to/folder
第三列是属主,第四列是属组。
4. 看系统里所有的组、以及某个组的成员
bash
cat /etc/group # 系统所有组
getent group 组名 # 查某个组的成员
⚠️ 避坑提示 :/etc/group 每一行结尾的成员列表,只包含把这个组当附加组 的用户,某个用户如果是这个组的主组(primary group) ,不会出现在这个列表里,得用 id 用户名 看 gid= 那部分才准确。
二、创建一个专属用户组,只放一个用户
假设我要新建一个 test 组,只让 AAAA 这一个人在里面。第一步别急着建组,先确认一下这个组名有没有被占用:
bash
getent group test
如果没有任何输出,说明组名可用,可以放心建:
bash
sudo groupadd test
⚠️ 避坑提示 :如果 getent group test 已经有输出(比如显示了别的成员),说明这个组名已经被占用了,直接往里加人会导致原来那些人也拿到你接下来要设置的目录权限。这种情况建议换个不会撞车的组名,比如 algo-test-group。
三、创建一个"只拥有文件、不能真正登录"的账户
团队里已经有一个类似的账户 BBBB,专门用来当文件属主,平时不需要真人拿它登录服务器。我想让新账户 AAAA 也照这个模式建。
先看一下 BBBB 现有的配置长什么样:
bash
getent passwd BBBB
BBBB:x:1012:1012::/home/BBBB:/usr/sbin/nologin
拆开看,最后一段 /usr/sbin/nologin 就是关键------这个账户的登录 shell 被设成了 nologin,意味着它从设计上就不允许交互式登录,不管密码对不对,尝试登录都会被拒绝。
照着这个模式建 AAAA:
bash
sudo useradd -m -s /usr/sbin/nologin AAAA
sudo passwd AAAA
-m:自动创建家目录,避免出现"配置里写着有家目录,实际却没建"的尴尬情况;-s /usr/sbin/nologin:直接禁用交互式登录,和BBBB保持一致。
建完验证一下:
bash
getent passwd AAAA
AAAA:x:1013:1013::/home/AAAA:/usr/sbin/nologin
再把它加进 test 组:
bash
sudo usermod -aG test AAAA
⚠️ 避坑提示 :这里的 -a(append)千万别漏!如果只写 -G test,会把这个用户原来所有的附加组全部清空 ,只留下 test 一个,是个很容易踩的坑。
验证一下组关系:
bash
id AAAA
uid=1013(AAAA) gid=1013(AAAA) groups=1013(AAAA),1014(test)
怎么"扮演"一个 nologin 账户去测试权限
因为 shell 被设成了 nologin,正常的 su AAAA 会直接报错:
This account is currently not available.
正确的绕过方式是用 sudo -u 显式指定一个可用的 shell:
bash
sudo -u AAAA /bin/bash
这样能拿到一个真正以 AAAA 身份运行的 bash 会话,可以正常测试她对文件的读写权限,操作完 exit 退出就行,不会对账户本身的登录配置做任何永久改动。
四、创建目标目录并设置基础权限
因为 AAAA 对共享目录的上层(比如 /hqdata/shares)本来就没有写权限,新目录得先由有权限的账户(比如管理员)建出来,再把属主转交给 AAAA:
bash
sudo mkdir /hqdata/shares/algo-test
sudo chown AAAA:test /hqdata/shares/algo-test
sudo chmod 755 /hqdata/shares/algo-test
755 展开是 rwxr-xr-x:属主读写执行,属组和其他人都只能读、进目录、拷贝,不能改。
到这一步,如果只是想让 AAAA 一个人拥有完整权限、其他人(包括 test 组里未来加进来的其他人)都只读,配置已经够了。
五、让整个 test 组都能读写(不只是属主一个人)
后来发现需求变了------不只是 AAAA 一个人能写,而是希望以后往 test 组里加的所有人,都能自动对这个目录树拥有完整权限。这时候思路要从"锁定属主"切换成"锁定属组"。
关键是两个机制配合:
- setgid 位 :保证以后在这棵目录树下新建的子目录 ,自动继承属组为
test,而不是继承创建者自己的主组; - 属组权限设为 rwx :让
test组的所有成员都能读写执行,不只是属主。
bash
sudo chgrp -R test /hqdata/shares/algo-test
sudo chmod -R 2775 /hqdata/shares/algo-test
2775 拆开:
- 开头的
2是 setgid 位; - 属主
rwx; - 属组(
test)rwx✅; - 其他人
r-x。
验证一下:
bash
ls -ld /hqdata/shares/algo-test
drwxrwsr-x 2 AAAA test 4096 Sep 29 17:48 algo-test
第4位是小写的 s,说明 setgid 生效了。这时候如果用 AAAA 身份在里面建一个子目录,子目录会自动带上 test 属组和 setgid 位,不需要每层手动重复设置。
六、用默认ACL堵住最后一个漏洞
setgid 只保证了"属组是谁"会被继承,但属组具体有没有写权限,还是取决于创建者当时的 umask 。如果哪天有个组成员的 umask 恰好是比较严格的 022,他新建出来的子目录属组权限就会变成只读,达不到"组内所有人都能写"的效果。
更稳妥的做法是给目录设置默认ACL ------目录专属的一种规则,效果是:目录下新建的任何文件/子目录,自动套用这个规则,而且这个规则会一路传给子目录的子目录,不受创建者 umask 影响。
bash
sudo setfacl -R -d -m u::rwx /hqdata/shares/algo-test
sudo setfacl -R -d -m g::rwx /hqdata/shares/algo-test
sudo setfacl -R -d -m o::rx /hqdata/shares/algo-test
-d:default ACL,只对目录有意义,表示"这个目录下新建的东西自动套用这条规则";-R:递归应用到已存在的所有子目录。
验证:
bash
getfacl /hqdata/shares/algo-test
# file: hqdata/shares/algo-test
# owner: AAAA
# group: test
# flags: -s-
user::rwx
group::rwx
other::r-x
default:user::rwx
default:group::rwx
default:other::r-x
看到 default: 开头的几行就说明配置已经生效了。
实测:故意换一个"苛刻"的 umask,验证规则不受影响
bash
sudo -u AAAA bash -c "umask 022; mkdir /hqdata/shares/algo-test/test-umask022"
getfacl /hqdata/shares/algo-test/test-umask022
就算故意把 umask 设成 022,新建目录的 group:: 那一行也应该依然是 rwx,而不是 r-x------这才说明真正摆脱了对 umask 的依赖,不再靠运气。
⚠️ 避坑提示 :默认ACL只保证"新建时"套用规则,如果以后有人手动 chmod 把某个子目录改坏了(比如误操作设成 777),ACL 不会主动纠正已存在的错误权限。如果目录用得比较频繁,建议定期跑一下巡检:
bash
find /hqdata/shares/algo-test ! -group test # 找属组异常的项
find /hqdata/shares/algo-test -type d ! -perm -g+w # 找属组没有写权限的项
七、Windows 那边 SMB 映射死活"拒绝访问"
目录权限配好了,以为大功告成,结果 Windows 上用 AAAA 账户登录 SMB 共享,一直提示"拒绝访问"。
第一步排查:Samba 用户和 Linux 用户是两套账户体系
这是最容易被忽略的一点------Linux 系统账户和 Samba 账户是分开存储的,即便 Linux 那边账户、密码、组全配好了,Samba 服务照样不认识这个用户,除非专门给它建了 Samba 账户。
bash
sudo pdbedit -L | grep AAAA
如果这条命令没有任何输出,说明这个用户压根没有 Samba 账户,这就是拒绝访问的直接原因。解决方法:
bash
sudo smbpasswd -a AAAA
执行后会让你单独设一次 Samba 密码(可以和 Linux 密码一样,也可以不同,是两套独立体系)。
再确认一下账户状态是不是启用的:
bash
sudo pdbedit -Lv AAAA
留意 Account Flags 那一行,正常是 [U ];如果看到 D 字样说明被禁用了,需要:
bash
sudo smbpasswd -e AAAA # -e 表示enable,启用账户
第二步排查:路径链上每一层的执行权限有没有断掉
即使目标目录本身权限没问题,如果上级目录没给执行权限,Samba 也没法"穿过"上级目录访问到深层目录,同样会报拒绝访问。用这条命令把路径上每一层的权限都列出来:
bash
namei -l /hqdata/shares/algo-test
f: /hqdata/shares/algo-test
drwxr-xr-x root root /
drwxr-xr-x root root hqdata
drwxr-xr-x root root shares
drwxrwsr-x AAAA test algo-test
留意每一层最后的执行位(x),只要中间某一层对目标用户来说缺 x,就会导致"看得到共享名字,但进不去"。
第三步排查:smb.conf 里的访问控制配置
bash
cat /etc/samba/smb.conf
重点检查对应共享段里的这几项:
valid users:如果写了这一项,只有列在里面的用户/组才能访问,常见写法是valid users = AAAA, @test(@前缀代表按 Linux 组授权,组内所有人自动被允许,不用每次单独加用户名);invalid users:如果目标用户被明确写在这里,同样会被拒绝;read only:如果设成yes,即便文件系统权限允许写,Samba 层面也会先把写操作拦掉。
改完配置记得重启服务:
bash
sudo systemctl restart smbd
还是不行?直接看 Samba 日志
日志里通常会给出确切原因:
bash
sudo tail -50 /var/log/samba/log.smbd
重新在 Windows 上映射一次,让报错"新鲜出炉",再看日志最后几行,一般能看到类似 NT_STATUS_ACCESS_DENIED 的字样,并提示具体是哪条规则拒绝的。
总结
这次踩坑最大的感悟是:普通的 user/group/other 三段式权限,搞不定"给某个组的所有成员开放写权限,同时保证以后新建的子目录也自动生效"这种需求 ,必须靠 setgid 位 + 默认ACL 两个机制配合才能做到"以后不用手动干预,规则自动传递到任意深度"。另外 SMB 共享这块也提醒了我一句话:Linux 系统账户和 Samba 账户是两套完全独立的体系,配置权限时容易只顾着 Linux 这边,却忘了 Samba 那边也要单独建账户,这个坑排查起来最费时间。