上一篇 下一篇 分享链接 返回 返回顶部

在Debian系统的香港服务器中,我如何用“Samba + ACL”治好了多地办公文件的权限混乱问题

发布人:Minchunlin 发布时间:2025-09-23 10:20 阅读量:669


那天是个潮湿的周一早上,香港电讯机房的空调把我冻得直打哆嗦。深圳、上海和新加坡三个办公室刚刚完成系统整合,大家的文件全堆在一台旧NAS上:谁都能改,谁都能删;市场部抱怨设计稿经常被“覆盖”,财务说年结文件“又少了一个版本”。我站在机柜前,看着那台不断报警的老NAS,心里只有一句话:得上“可审计、可继承、可回滚”的权限体系。

最后落地方案是:Debian 12 + Samba 4 + POSIX ACL + Btrfs 快照(shadow copy)+ 审计 + 回收站。这篇就是我把它一步步搭起来、踩坑、修坑的完整记录。

1. 现场与目标

环境与目标:

  • 机房:香港(HK Equinix)
  • 办公点:深圳(SZ)、上海(SH)、新加坡(SG)
  • 广域链路:专线/MPLS,香港到深圳/上海 RTT 12–24ms,新加坡 35–45ms

主要诉求:

  • 按 部门/项目 控制读写,默认继承权限,能审计谁动过文件
  • Windows / macOS 混用无痛
  • 版本可回滚(用户看到“以前版本”)
  • 异地访问性能尽量靠谱

2. 硬件与网络拓扑(实配)

项目 型号/规格 备注
服务器 Dell PowerEdge R7525 1U,热插拔
CPU 2 × AMD EPYC 7313 16C/32T ×2
内存 256GB DDR4 ECC 足够缓存
系统盘 2 × 960GB SATA SSD (RAID1) /, /boot, /var
数据盘 6 × 4TB NVMe(RAID10) LVM 上 Btrfs 子卷
网卡 2 × 25GbE (bonding, LACP) 上行到核心交换
VLAN 内网 10.20.0.0/16;管理 10.99.0.0/24 与办公网通过防火墙做端口策略
OS Debian 12 (bookworm) Samba 4.17+
时间 chrony 对时,来源 AD DC/NTP Kerberos 靠时间很敏感

为什么选 Btrfs:原生快照 + reflink,能配合 Samba shadow_copy2 给 Windows 用户“以前版本”。XFS/EXT4 也行,但快照回滚要多点工程。

3. 设计思路(核心要点)

Samba 做 AD 成员服务器(不自建域控):

  • 身份/组统一在 AD 管理,Linux 侧用 winbind + idmap rid 映射 UID/GID。
  • POSIX ACL 为根,配合 vfs_acl_xattr,权限继承与 Windows 端一致。
  • Btrfs 子卷 + snapper 定时快照,Samba 用 shadow_copy2 暴露“以前版本”。
  • 回收站 + 审计:vfs_recycle、vfs_full_audit。
  • macOS 兼容:vfs_fruit + catia + streams_xattr,减少乱码与 ._ 资源叉问题。
  • SMB3 + 多通道:广域条件下尽量稳;签名与加密按“安全优先、性能平衡”开关。

4. 基础准备

# 1) 基础包
apt update
apt install -y samba winbind smbclient cifs-utils acl attr \
               krb5-user libpam-winbind libnss-winbind \
               chrony snapper btrfs-progs

# 2) 让 /srv 支持 ACL(ext4/xfs/btrfs 默认 xattr/acl 支持,一般无需特别加 -o acl)
mkdir -p /srv/share

时间与 DNS(很关键):

  • /etc/chrony/chrony.conf 指向 AD/NTP;
  • /etc/resolv.conf 指向 AD DNS(否则 Kerberos/域加入各种玄学故障)。

5. 存储卷与快照(Btrfs + snapper)

我把数据盘做了 RAID10 → LVM VG → 在 LV 上格式化 Btrfs(你也可以直接 Btrfs 直上阵列层)。挂载参数偏稳健:

UUID=xxxx /srv btrfs defaults,ssd,compress=zstd:3,autodefrag,noatime 0 0

子卷结构:

btrfs subvolume create /srv/share/projects
btrfs subvolume create /srv/share/finance
btrfs subvolume create /srv/share/public

# 为每个子卷启用 snapper(会在子卷下创建 .snapshots)
snapper -c projects create-config /srv/share/projects
snapper -c finance  create-config /srv/share/finance

# 调整清理与频率(示例:保留7天小时快照、4周每日、6个月每月)
sed -i 's/TIMELINE_CREATE="no"/TIMELINE_CREATE="yes"/' /etc/snapper/configs/projects
sed -i 's/TIMELINE_CREATE="no"/TIMELINE_CREATE="yes"/' /etc/snapper/configs/finance
sed -i 's/TIMELINE_LIMIT_HOURLY="10"/TIMELINE_LIMIT_HOURLY="168"/' /etc/snapper/configs/projects
# ...根据容量政策微调

systemctl enable --now snapper-timeline.timer snapper-cleanup.timer

6. 加入 AD 域(域成员服务器)

假设域是 CORP.EXAMPLE.COM,NetBIOS 名 CORP,并且已经把 DNS 指向 AD。

# 交互时填 realm:CORP.EXAMPLE.COM
dpkg-reconfigure krb5-user

kinit Administrator
# 成功会拿到 TGT,不成功先查时间/DNS

net ads join -U Administrator
# 看到 "Joined 'HOSTNAME' to realm 'CORP.EXAMPLE.COM'" 就对了

systemctl enable --now winbind

把 NSS/PAM 接上(登录/查人可用):

/etc/nsswitch.conf 中 passwd: files systemd winbind、group: files systemd winbind

测试:

getent passwd 'CORP\\alice'
getent group  'CORP\\Design'

7. Samba 全局配置(/etc/samba/smb.conf)

以下配置在 Debian 12 + Samba 4.17 实测可用;不同版本语法可能略有差异。

[global]
   workgroup = CORP
   security = ADS
   realm = CORP.EXAMPLE.COM

   # ID 映射(RID 后端简单稳定)
   idmap config * : backend = tdb
   idmap config * : range   = 3000-7999
   idmap config CORP : backend = rid
   idmap config CORP : range   = 10000-999999

   # Winbind 行为
   winbind use default domain = yes
   winbind refresh tickets = yes
   winbind enum users  = no
   winbind enum groups = no

   # VFS 与 ACL/扩展属性
   vfs objects = acl_xattr catia fruit streams_xattr
   inherit permissions = yes
   inherit acls = yes
   map acl inherit = yes
   store dos attributes = yes
   ea support = yes

   # 协议与安全:SMB3、多通道、签名/加密按需
   server min protocol = SMB2_10
   server max protocol = SMB3
   server signing      = if_required
   smb encrypt         = desired
   server multi channel support = yes

   # I/O(广域/混合文件类型取平衡)
   aio read size  = 1
   aio write size = 1
   use sendfile   = yes
   strict locking = no
   deadtime = 15

   # Mac 兼容(资源叉/非法字符)
   fruit:metadata = stream
   fruit:resource = stream
   fruit:locking  = none
   fruit:encoding = native

   # 日志
   log level = 1
   logging = syslog@1 /var/log/samba/log.%m

8. 共享定义与“以前版本”、回收站、审计

8.1 项目共享(Projects)

[Projects]
   path = /srv/share/projects
   read only  = no
   browseable = yes

   # 授权策略
   create mask    = 0660
   directory mask = 0770
   force group    = "CORP\\ProjectUsers"

   # 版本与回收
   vfs objects = acl_xattr recycle full_audit shadow_copy2 catia fruit streams_xattr

   # 回收站
   recycle:repository = .recycle/%U
   recycle:keeptree  = yes
   recycle:versions  = yes
   recycle:exclude   = *.tmp,*.bak,~$*

   # 以前版本 (shadow copy)
   shadow: snapdir    = /srv/share/projects/.snapshots
   shadow: sort       = desc
   shadow: format     = @GMT-%Y.%m.%d-%H.%M.%S
   shadow: localtime  = yes
   shadow: snapprefix = ''

   # 审计(写操作)
   full_audit:prefix   = %u|%I|%S
   full_audit:success  = mkdir rmdir write pwrite unlink rename write_data
   full_audit:failure  = connect
   full_audit:facility = LOCAL7
   full_audit:priority = NOTICE

8.2 财务共享(Finance)

[Finance]
   path = /srv/share/finance
   read only  = no
   browseable = no

   create mask    = 0660
   directory mask = 0770
   force group    = "CORP\\Finance"

   vfs objects = acl_xattr recycle full_audit shadow_copy2 catia fruit streams_xattr
   recycle:repository = .recycle/%U
   recycle:keeptree  = yes
   recycle:versions  = yes

   shadow: snapdir    = /srv/share/finance/.snapshots
   shadow: format     = @GMT-%Y.%m.%d-%H.%M.%S
   shadow: sort       = desc
   shadow: localtime  = yes

重启服务:

testparm
systemctl restart smbd nmbd winbind

9. 用 POSIX ACL 固化“谁能做什么”

组设计(在 AD 里建组):

组名(AD) 作用 备注
CORP\ProjectUsers 项目区默认工作组 新人入职加进来
CORP\Design 设计子区写  
CORP\PM PM 子区写  
CORP\Finance 财务区读/写 仅财务共享可见

目录与继承(示例):

# 目录属主/组,便于“force group”一致
chown -R root:"CORP\\ProjectUsers" /srv/share/projects
chown -R root:"CORP\\Finance"      /srv/share/finance

# 清理遗留 ACL(谨慎执行,确保目标目录正确)
setfacl -R -b /srv/share/projects
setfacl -R -b /srv/share/finance

# 项目区:默认 ProjectUsers 可读写,并继承到新建文件/目录
setfacl -m g:"CORP\\ProjectUsers":rwx /srv/share/projects
setfacl -m d:g:"CORP\\ProjectUsers":rwx /srv/share/projects
setfacl -m m::rwx /srv/share/projects   # 调整有效权限掩码(mask)

# 设计子目录更严格
mkdir -p /srv/share/projects/Design
setfacl -m g:"CORP\\Design":rwx /srv/share/projects/Design
setfacl -m d:g:"CORP\\Design":rwx /srv/share/projects/Design

# 财务区:仅 Finance 组
setfacl -m g:"CORP\\Finance":rwx /srv/share/finance
setfacl -m d:g:"CORP\\Finance":rwx /srv/share/finance

# 查看
getfacl /srv/share/projects | sed -n '1,40p'

小贴士:shell 中域名反斜杠要转义:"CORP\\Design"。

关键是 d:(default)条目,保证新建文件/目录自动继承。

10. 客户端体验与校验

Windows:映射 \\files.corp.example.com\Projects,右键 → “以前的版本” 就能看到 Btrfs 快照;权限页能看到 AD 组。

macOS:smb://files.corp.example.com/Projects,fruit+catia 基本消灭了 ._ 和非法字符报错。

Linux:测试:

smbclient //files/Projects -U alice

11. 广域性能与参数取舍(我们的真实数值)

场景 RTT 带宽 大文件(4GB) 小文件(3万×8KB)
深圳 ↔ 香港 14ms 1Gbps 110–125 MB/s 15–25 MB/s
上海 ↔ 香港 22ms 1Gbps 95–110 MB/s 12–18 MB/s
新加坡 ↔ 香港 38ms 1Gbps 70–85 MB/s 8–12 MB/s

影响因素与调优经验:

  • SMB3 多通道对大文件很有帮助(多网卡/多队列);
  • 小文件延时占主导,开启 AIO、确保 DC/DNS/时间稳定,收益有限但能拉齐抖动;
  • 签名/加密:我们采用 signing=if_required, encrypt=desired,专线内网 + 边界 IPsec。强制加密会明显掉速,按安全策略取舍;
  • 禁止防火墙/UTM 对 445 做“文件防护/反病毒重扫”,不然 R/W 抖到怀疑人生。

12. 审计与回收:谁动了我的文件

我们把 full_audit 送到 LOCAL7,再由 rsyslog 写入独立文件并配一条简单的规则进 Elasticsearch。

  • /etc/rsyslog.d/30-samba-audit.conf:
  • local7.notice    /var/log/samba/audit.log

回收站:用户误删先在 .recycle/<用户名> 找;找不到再去“以前版本”。

13. 常见坑与我当时怎么填的

加入域失败(KDC unreachable)

原因:DNS 没指向 AD,或 UDP 88 被墙。

解法:把 /etc/resolv.conf 指向 AD DNS;临时 dig _kerberos._udp.CORP.EXAMPLE.COM SRV 验证。

Kerberos 票据过期 / 时间漂移

症状:随机认证失败。

解法:chrony 对时,winbind refresh tickets = yes,并监控 klist。

文件权限看着对,实际写不进去

原因:POSIX ACL 的 mask 把有效权限削了。

解法:setfacl -m m::rwx <dir>,再核对 getfacl 里 mask 行。

默认继承没生效

原因:只设了 g:xxx:rwx,没设 d:g:xxx:rwx。

解法:对目录同时设置 default ACL(d:)。

macOS 复制报错 / 名称含 : 等字符

解法:启用 catia;fruit 选项按上面配置。

“以前版本”里空空如也

原因:snapper 未开定时器,或 shadow: snapdir 路径不对。

解法:systemctl status snapper-timeline.timer;确认 .snapshots 在共享根目录下。

性能忽上忽下

原因:安全设备对 445 做 L7 检查。

解法:和网安团队沟通,转策略到边界加密/白名单,不要深度扫描 SMB。

14. 变更与回滚流程(SOP 摘要)

步骤 操作 验证
变更前 snapper -c projects create -d "pre-change" snapper -c projects list
修改 ACL setfacl ... getfacl、Windows 新建文件继承测试
用户回报异常 snapper -c projects status <id1>..<id2> 评估差异
回滚文件 Windows “以前版本”或 cp --reflink=auto 从快照拷回 二次确认
审计 /var/log/samba/audit.log 归档

15. 维护脚本(节选)

批量设置某些子目录只给设计组写:

#!/usr/bin/env bash
set -euo pipefail

BASE=/srv/share/projects
TARGETS=(BrandA BrandB Campaign2025)

for t in "${TARGETS[@]}"; do
  d="$BASE/$t/Design"
  mkdir -p "$d"
  setfacl -m g:"CORP\\Design":rwx "$d"
  setfacl -m d:g:"CORP\\Design":rwx "$d"
  setfacl -m m::rwx "$d"
done

上线那天,我让三地的代表各自演示:新建、修改、回滚、从回收站找文件。财务的小伙伴点开“以前的版本”,找回了一个月前的表格,笑得很真;设计那边终于不用再在群里问“谁把我图改了”。
机柜里新服务器的风扇还是那么吵,但我心里安静了下来。权限清晰、继承稳定、可审计可回滚,这不是某个“黑科技”,只是把 Samba、ACL 和快照认真地拼起来,按规则运行。
后来有人问我:这套是不是有点“重”?我说,是,但稳定和可追溯,在多地协同里,永远是最轻的成本。

目录结构
全文