群晖 DSM SSH 免密登录与短密码:多机互信及 Ansible 批量管理
群晖这东西用了几年之后基本上都会从点界面过渡到敲命令行。原因很简单备份脚本、跨设备同步、批量改文件、跑 Docker 容器、定时任务这些活儿用 DSM 的图形界面点起来太累SSH 上去两行命令就搞定。但真到配 SSH 的时候三个问题几乎人人都会撞上一是 DSM 那套密码策略又臭又长8 位起步还要大小写加数字平时手动输一次两次还行脚本里写死一个这种密码简直是自找麻烦二是辛辛苦苦配了密钥登录还是要密码翻遍教程也找不到原因三是手里有三四台群晖互相之间传个文件、跑个同步任务每次都得输密码脚本根本没法自动化。这篇就把这三件事从头到尾讲清楚短密码怎么设、DSM 的密码策略卡在哪一层、免密登录为什么配了不生效、多台群晖之间怎么搭一张互相免密的信任网。文章里的命令我在 DSM 6 和 DSM 7 上都实测过中间踩的坑会原样写出来包括排查链路你照着做基本能一次跑通。1. 群晖的 Linux 底子先把你要面对的环境摸清楚很多人把群晖当成一个黑盒 NAS其实它就是一台跑着 Linux 的 x86 或 ARM 小主机DSM 只是套在上面的管理界面。你在 SSH 里敲的每一条命令最终都落到 Linux 上。所以配 SSH 之前先把几个基础事实确认清楚后面所有操作都建立在这上面环境没搞明白后面每一步都是猜。1.1 SSH 服务的开启与端口调整DSM 默认是把 SSH 关掉的需要手动开。路径在控制面板 → 终端机和 SNMP → 终端机勾上启动 SSH 功能端口默认 22。我一般会把端口改掉比如改成 2222 或某个五位数端口理由不用多说22 端口每天被扫描的次数多到离谱日志里全是爆破记录烦人。改端口还有一个容易忽略的点改完记得在控制面板 → 安全性 → 防火墙里放行新端口同时把 22 关掉。很多人改完端口发现连不上第一反应是 SSH 服务坏了其实是防火墙没放行这个坑我至少踩过两回。开启之后用你 DSM 的管理员账号登录就行ssh -p 2222 你的用户名群晖IP第一次登录会问你要不要接受指纹输 yes。到这里如果一切正常你应该能看到一个$或#提示符。DSM 7 里管理员组用户登录后默认是普通用户权限需要sudo -i才能拿到 root这点和 DSM 6 还不太一样DSM 6 里管理员组用户登录后权限更宽一些。1.2 群晖用户家目录的真实路径与权限陷阱这是后面免密登录能不能成的最关键因素必须先讲。群晖的用户家目录不在常规的/home/用户名而是在数据卷上。以 volume1 为例真实路径是/volume1/homes/用户名同时系统会给一个软链接/var/services/homes/用户名指过去。你在 SSH 里cd ~落到的是哪条路径取决于登录方式有时候是软链接路径有时候是真实路径这个细节会直接影响后面 authorized_keys 的读取。更坑的是这个家目录的权限。群晖默认给 homes 目录的权限经常是711甚至更松而且某些版本下/volume1/homes本身就允许组或其他用户写。SSH 的 sshd 有一个StrictModes机制默认开启它会检查你的家目录、.ssh目录、authorized_keys文件的权限只要家目录被组或其他用户可写sshd 就会直接忽略你的密钥转回密码认证。这就是密钥配了跟没配一样的头号原因。你要做的第一件事是先确认家目录权限ls -ld /volume1/homes/你的用户名期望看到的是drwxr-xr-x也就是 755owner 是你自己组和其他用户没有写权限。如果是drwxrwxrwx或者组可写就得收紧。1.3 为什么登录后不是 bash以及该不该管群晖默认给用户配置的登录 shell 是/bin/sh。DSM 里其实是有 bash 的路径就是/bin/bash但用户默认不用它。这带来的直接后果是你从别的地方抄来的脚本里面用了[[ ]]、数组、${var//a/b}这类 bash 特性直接报语法错误一些习惯了 bash 补全和快捷键的人用 sh 会非常别扭。查看当前 shellecho $SHELL grep 你的用户名 /etc/passwd想改成 bash编辑/etc/passwd里对应用户那一行的最后一个字段从/bin/sh改成/bin/bash。但这里有个必须提醒的点群晖的用户信息是由 DSM 的用户管理模块维护的你在/etc/passwd里的手改有可能会在你通过 DSM 界面改动该用户比如改密码、改所属组之后被系统重新覆盖回去。所以我的做法是要么不折腾需要 bash 时直接bash起一个子 shell 或者sudo -i要么改完之后用一个开机任务定期校正。图省事的就选前者。2. 短密码DSM 的密码策略到底卡在哪一层短密码这事得先把动机说清楚不然容易被当成不安全操作。我的使用场景是这样的内网环境只有我一个人用密码只用于本地 SSH 和偶尔的界面登录不需要扛外网爆破但脚本里、Ansible 的 inventory 里、cron 的配置里天天要写这个密码。这种情况下一个 6 位纯数字或者简单字符串带来的便利远远大于它带来的风险。反过来如果你的群晖是直接暴露在公网、开了 QuickConnect 或者做了端口转发那短密码就是给自己挖坑这种情况下请老老实实上 16 位随机密码加密钥登录别省这一步。2.1 控制面板里能改到什么程度DSM 的密码复杂度是在控制面板 → 用户与群组 → 高级 → 密码设置里控制的。这里有几个可调项最小密码长度、是否必须包含大小写字母、是否必须包含数字、是否必须包含特殊字符。默认情况下最小长度是 8且通常要求至少包含字母和数字。你可以把最小长度往下拉。不同 DSM 版本界面能给到的下限不太一样有的版本能一路拉到 0有的版本卡在某个值上。我实测的 DSM 7 上最小长度是可以设到比较低的配合把必须包含那几项全部取消勾选就能设置纯数字或者很短的密码了。设置完之后修改某个用户的密码在用户与群组里选中该用户点编辑重新输入密码即可。这时候你会发现之前设置 6 位密码被拒绝的用户现在能改成功了。2.2 系统账号和 PAM 层界面改不动时怎么办有一类账号在 DSM 界面里根本看不到比如root、还有各种服务账号。这些账号的密码不受界面策略约束但也不意味着能随便设。root账号在群晖里默认是被禁用的密码是随机生成的你需要主动设置才能用sudo synouser --setpw root 你的新密码synouser是群晖提供的用户管理工具用它改密码的好处是绕开了一部分界面的策略校验而且改完立即生效。同样的命令也能改普通用户sudo synouser --setpw 用户名 新密码如果连synouser都被策略挡住那说明限制在更底层的 PAM 模块上。群晖的密码质量检查通常挂在pam_pwquality或pam_cracklib上相关配置在/etc/security/目录下不同 DSM 版本文件名和路径有差异可能是pwquality.conf也可能是别的名字。你可以先在这个目录里找找ls /etc/security/ grep -r minlen /etc/security/ 2/dev/null找到对应配置后把minlen、minclass、dcredit、ucredit这些参数调松。不过我得说实话直接改 PAM 配置文件是有点风险的DSM 升级时会把这些文件重置而且改错了可能导致整个认证体系出问题连界面都登录不进去。所以我的建议是能用界面加synouser解决的就别动 PAM。只有在确实绕不过去的时候才碰改之前先备份原文件。2.3 短密码的适用边界与几个现实提醒关于短密码有几条经验值得分享。第一条DSM 界面的登录和 SSH 登录是两套认证流程但共用同一套密码。你把密码设短了界面的登录也变短了。如果你担心别人碰到你的键盘那就别把界面登录也一起放松可以考虑给界面单独开一个复杂密码的管理员账号短密码只给 SSH 用的普通账号。第二条短密码配合免密登录其实是最佳组合。真正日常操作你根本不输密码密钥搞定短密码只是作为密钥失效时的兜底或者给某些不支持密钥的老工具用。所以短密码 密钥登录这套组合比长密码 每次手输要安全得多也舒服得多这个逻辑很多人一开始想反了。第三条如果你有多个账号别都用同一个短密码。群晖的 sudo 日志/var/log/messages或auth.log会记录认证失败一旦某个短密码被爆破成功横向移动到其他账号就是一瞬间的事。3. 免密登录密钥认证要过的三道权限关卡免密登录的原理大家都懂本地生成一对密钥公钥放到服务器上私钥留在本地登录时服务器用公钥验证你手上的私钥。逻辑很清晰但在群晖上90% 的失败都发生在公钥放上去了但还是让输密码这一步。原因基本都集中在三个地方家目录权限、.ssh目录及authorized_keys的权限、sshd 配置。这一节把这三道关卡逐个拆开。3.1 生成密钥与把公钥送到群晖的两种方式先在本地机器上生成密钥。现在推荐用 ed25519比 RSA 短、快、安全性也够ssh-keygen -t ed25519 -C synology-key一路回车生成的私钥在~/.ssh/id_ed25519公钥在~/.ssh/id_ed25519.pub。私钥的权限会被自动设成 600如果哪天你手动改过导致权限变松ssh 会直接拒绝使用这个私钥这个也是常见报错来源。送公钥上去有两种方式。第一种是用ssh-copy-idssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 用户名群晖IP但这招在群晖上不一定能用因为群晖的 shell 环境比较精简有些版本没有ssh-copy-id或者它执行过程中的一些命令在 busybox 环境下跑不通会报奇怪的错。这时候就用第二种手动一条管道命令搞定cat ~/.ssh/id_ed25519.pub | ssh -p 2222 用户名群晖IP \ mkdir -p ~/.ssh chmod 700 ~/.ssh \ cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这条命令一次性把目录建好、权限设好、公钥追加进去、再把文件权限设好是我最常用的方式比ssh-copy-id可控得多尤其是mkdir -p和两个chmod一定要带上不然就是给自己后面埋坑。3.2 权限三件套家目录、.ssh、authorized_keys公钥放上去之后先别急着测试把这三个权限确认一遍能省掉大量返工。对象路径期望权限说明家目录/volume1/homes/用户名755关键组和其他用户不能有写权限.ssh 目录~/.ssh700只有自己能进公钥文件~/.ssh/authorized_keys600只有自己能读写私钥本地~/.ssh/id_ed25519600权限过松 ssh 会拒绝使用一条命令搞定服务器侧chmod 755 ~ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys注意chmod 755 ~这一句是群晖上最容易被忽略的一步。很多教程只提醒你改.ssh和authorized_keys但群晖的 homes 目录权限天生就偏松不改的话 sshd 的StrictModes直接把你的密钥判死刑。还有一个隐藏点如果你用sudo -i切换到了 root然后以 root 身份去操作普通用户的家目录务必确认 owner 没被改掉。chown一旦写错家目录归属变了密钥同样会失效。3.3 sshd 配置里的几个关键项权限都对了还不行的就该看sshd_config了。文件在/etc/ssh/sshd_config用 root 打开sudo vi /etc/ssh/sshd_config重点确认这几项PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys StrictModes yes PermitRootLogin noPubkeyAuthentication必须是 yes这个默认就是但有的精简系统或者被改过的配置会是 no。AuthorizedKeysFile默认指向.ssh/authorized_keys如果被改成了别的路径你得把公钥放到那个路径去。StrictModes我建议保持 yes靠权限管理而不是靠关掉检查来解决问题关掉它是治标不治本。PermitRootLogin建议保持 no需要 root 权限的时候用sudo -i提权不要直接放开 root 登录。改完配置要重启 sshd 服务。这里群晖和普通 Linux 不一样用的是群晖自己的服务管理命令# DSM 7 sudo synosystemctl restart sshd # DSM 6 sudo synoservice --restart sshd如果你不确定是哪个版本两条都试一下报 command not found 的那条就是版本不对。重启之后新配置才生效。3.4 配好了还让输密码完整排查链路这一段是我踩坑最多的地方把排查顺序完整写出来你按顺序走一遍基本能定位到问题。第一步先看详细日志。本地用-v参数登录ssh -v -p 2222 用户名群晖IP输出里会明确告诉你有没有尝试公钥认证、公钥有没有被服务器接受。如果看到Offering public key之后紧接着Server accepts key那就说明密钥被接受了这时候如果还要密码问题可能出在别的地方比如多因素。如果看到Authentication refused: bad ownership or modes那百分之百是权限问题回到 3.2 重新检查。第二步在服务器侧看 sshd 日志sudo tail -f /var/log/auth.log # 或者 sudo cat /var/log/messages | grep sshd日志里会写明拒绝的具体原因比本地-v更直接。第三步确认公钥真的写进去了。有时候管道命令写到一个错误的位置或者写进了软链接指向的另一个文件cat ~/.ssh/authorized_keys ls -la ~/.ssh/第四步确认家目录没被加密或者没挂载。群晖有个家目录加密功能如果开启了且当前没挂载比如卷被卸载、或者刚重启还没挂载你的~/.ssh/authorized_keys实际上是读不到的表现就是密钥无效、退回密码。这种情况用界面登录一次让家目录挂载起来问题就消失了。第五步检查是否有多个 authorized_keys 路径。有些群晖版本因为用户被 DSM 重建过家目录路径变了旧密钥在新路径下自然不生效。把这些走一遍剩下的基本都是配置没重启或者改错了文件这种低级错误。4. 多台群晖互相免密从 ssh config 到批量分发单机免密搞定之后真正的效率提升来自多台设备之间的免密。典型场景A 群晖定时把备份推到 B 群晖C 群晖跑一个脚本从 A 拉数据B 又要把日志同步到 C。如果每台都要手输密码这些任务根本没法自动化。这一节讲怎么把这几台机器连成一张互相免密的网。4.1 用 ssh config 管理多台设备不要每次都在命令行里手写 IP、端口、用户名用~/.ssh/config把它们固化下来。在每台需要发起连接的群晖上编辑~/.ssh/configHost nas-a HostName 192.168.1.10 Port 2222 User admin IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 Host nas-b HostName 192.168.1.11 Port 2222 User admin IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 Host nas-c HostName 192.168.1.12 Port 2222 User admin IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60配好之后直接ssh nas-b scp backup.tar.gz nas-c:/volume1/backup/ rsync -avz /volume1/data/ nas-a:/volume1/data/ServerAliveInterval 60这个参数是我强烈建议加的它每 60 秒发一个心跳包防止长时间传输时连接被中间设备掐断。跨网段、走路由器的场景特别容易断加了这个参数稳定很多。注意这个 config 文件其实是发起方的配置所以哪台机器要主动连别人就得在它的~/.ssh/config里配好对方。要做双向互连A 连 B、B 也连 A那两台都要各自配一份 config并且各自把自己的公钥放到对方机器上。4.2 写个脚本批量把公钥分发到多台群晖手上有 N 台群晖的时候一台台ssh-copy-id太累写个循环一把梭。假设你在发起机器上把目标机器的信息写进一个列表#!/bin/bash # batch-copy-key.sh KEY_FILE$HOME/.ssh/id_ed25519.pub TARGETS( admin192.168.1.10:2222 admin192.168.1.11:2222 admin192.168.1.12:2222 ) for target in ${TARGETS[]}; do USER_HOST${target%%:*} PORT${target##*:} echo 处理 $USER_HOST (端口 $PORT) cat $KEY_FILE | ssh -p $PORT $USER_HOST \ mkdir -p ~/.ssh chmod 700 ~/.ssh \ cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys \ chmod 755 ~ \ grep -c ssh-ed25519 ~/.ssh/authorized_keys echo done这个脚本做了两件事分发公钥同时输出该机器上现在有多少个 ed25519 公钥方便你确认每次是否写入成功。第一次跑的时候每台机器还是要输一次密码来完成分发但从第二台开始如果你用了ssh-agent把私钥加载进来连这一次都能省。配合ssh-agent的用法eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519加载之后同一会话内的所有 ssh 操作都不再问密码批量分发效率高很多。不过要注意群晖上默认可能没有ssh-agent如果报 command not found就别折腾了老老实实每台输一次密码。4.3 Ansible 场景下的免密开发与批量管理热词里出现了 Ansible 免密登录这个场景其实很适合群晖集群。当你有五六台以上群晖需要统一改配置、统一部署脚本、统一检查状态的时候一台台手敲已经不合理了用 Ansible 把整个集群管起来是对的思路。Ansible 的前提就是控制节点能免密 SSH 到所有被管节点。所以你在 4.2 里分发的这套密钥正好就是 Ansible 需要的。控制节点上装好 Ansible 之后编辑 inventory[nas] nas-a ansible_host192.168.1.10 ansible_port2222 ansible_useradmin nas-b ansible_host192.168.1.11 ansible_port2222 ansible_useradmin nas-c ansible_host192.168.1.12 ansible_port2222 ansible_useradmin [nas:vars] ansible_ssh_private_key_file~/.ssh/id_ed25519 ansible_python_interpreter/usr/local/bin/python3这里有个群晖特有的坑ansible_python_interpreter。群晖的 Python 路径和普通 Linux 不一样通常是/usr/local/bin/python3而且有些 DSM 版本默认没装 PythonAnsible 会报 python not found。要么在套件中心装 Python3要么用裸 ssh 模块ansible.builtin.raw绕过 Python 直接执行命令。用 raw 模块虽然笨但在群晖上是最稳的兜底方案。跑一条测试命令ansible nas -i inventory.ini -m raw -a uptime如果三台都返回了运行时间说明免密链路整体通了后面就能用 Ansible 做批量备份、批量清理、批量同步这些事了。4.4 多机信任链的边界与安全考量多台互相免密之后安全边界就变成了一把私钥等于一圈机器的访问权。这里有几个我认为必须守住的底线。第一私钥只放在真正需要发起连接的机器上不要为了省事把私钥拷到每一台群晖。A 只需要连 B那就把 A 的公钥放到 B 上而不是把私钥也拷过去。私钥散落越多泄露面越大。第二用不同的密钥对区分用途。管理用的密钥、备份任务用的密钥、临时脚本用的密钥分开生成各自分发。这样某个密钥泄露时你只需要吊销对应的公钥从authorized_keys里删掉那一行即可不用全盘重来。第三限制哪些账号可以被密钥登录。如果某台群晖上有多个用户不想让某些服务账号也能被密钥访问可以在对应的authorized_keys里加限制项比如command/volume1/scripts/backup.sh,no-port-forwarding,no-pty ssh-ed25519 AAAA...这样即使这个公钥被人拿到也只能执行指定脚本不能拿到一个交互式 shell。第四定期检查authorized_keys。时间长了之后你可能自己都不记得哪些公钥还有用。定期把每台群晖的authorized_keys拉出来看一眼把不认识的、过期的删掉。5. 长期维护那些配好之后才慢慢冒出来的坑免密登录不是配完就一劳永逸它有几个时间炸弹可能过几周、几个月或者在你升级 DSM 之后突然失效。这一节讲讲这些坑都是我自己和身边人真实遇到的。5.1 DSM 升级后 sshd_config 被重置最典型的一个。DSM 大版本升级比如从 7.0 升到 7.1、7.2的时候/etc/ssh/sshd_config有可能被重置回默认值。你之前改的那些参数Port、PubkeyAuthentication、AuthorizedKeysFile全都没了。表现就是升级完之后SSH 端口变回 22密钥登录失效一头雾水。应对办法很简单改完 sshd_config 之后立刻备份一份sudo cp /etc/ssh/sshd_config /volume1/homes/你的用户名/sshd_config.bak每次升级完对比一下当前配置和备份不一样就恢复回去然后重启 sshd。养成这个习惯能省很多排查时间。同样要备份的还有~/.ssh/整个目录以及本地的密钥对私钥备份到加密的存储上别明文放着。5.2 家目录加密与未挂载导致的密钥假失效群晖的家目录加密功能控制面板里可以开启在安全上是好事但和免密登录配合起来会有个迷惑现象卷没挂载的时候~/.ssh/authorized_keys实际上是空的或者读不到sshd 找不到你的公钥于是退回密码认证。你会觉得密钥明明配好了怎么又让我输密码。判断方法登进去ls -la ~/.ssh/如果目录不存在或者文件是空的那就是家目录没挂载。解决办法是先用界面登录一次或者手动挂载对应的加密卷让家目录就位。要跑自动化的机器我建议不要在家目录上开加密把密钥和脚本放到一个普通共享文件夹路径下避免这种不确定性。5.3 端口、防火墙与自动封禁的连锁反应最后一个坑比较隐蔽。你改了 SSH 端口防火墙放行了一切正常。过几天突然连不上一查发现是群晖的自动封禁功能把你这台发起连接的机器拉黑了。群晖的安全性设置里有个自动封锁默认开启当某个 IP 短时间内多次登录失败就会被封一段时间。批量分发密钥、Ansible 扫描的时候很容易触发这个机制尤其是密码输错几次的时候。处理办法在控制面板 → 安全性 → 自动封锁里把你自己内网的网段加入白名单或者临时调高允许的失败次数。做批量操作之前先确认白名单里有你的发起机器 IP能省掉一大堆莫名其妙连不上的问题。另外提醒一个容易忽略的点fail2ban这类工具在群晖上不一定有但如果你自己装了记得它的日志和封禁规则也要一起看否则排查方向会被带偏。还有一个和 NFS 相关的边界顺便提一句SSH 免密和 NFS 挂载的权限是两套体系。SSH 免密靠的是密钥认证不看 UID而 NFS 挂载是看 UID/GID 的。所以如果你有多台群晖又想通过 NFS 互相挂载目录比如跨设备看视频、共享大文件那还得保证各台机器上同名用户的 UID 一致否则会出现能挂上但没权限读写的情况。这两个问题经常被混在一起其实根源完全不同排查的时候要分开看。我自己在实际使用中的体会是群晖的 SSH 免密这套东西难点从来不在技术本身而在群晖给 Linux 做的那一层魔改家目录路径、权限默认值、服务管理命令、配置文件被重置的时机这些和标准 Linux 都不一样。把这篇里提到的几个关键路径和命令记下来第一次配置可能要多花半小时排查但配好之后看着定时任务安安静静跑完、多台设备之间数据自动流转那种终于不用管了的踏实感是值得的。最后再分享一个小习惯把所有群晖的 SSH 相关配置config 文件、sshd_config 备份、密钥分发脚本集中放在一个共享文件夹里换机器或者重装的时候五分钟就能恢复整套环境。