103 lines
3.9 KiB
Markdown
103 lines
3.9 KiB
Markdown
# Sudo 密码传递模式
|
||
|
||
> 常见陷阱:heredoc 消耗密码导致 sudo 认证失败
|
||
|
||
## 模式对比
|
||
|
||
### ❌ 错误:heredoc 中使用 `echo | sudo -S`
|
||
```bash
|
||
# 失败:密码在第一个命令后被消耗,sudo 第二次读取时得到空行
|
||
echo 'z1020' | sudo -S bash -c 'cat > /etc/file << EOF
|
||
some content
|
||
EOF
|
||
another command' # 这里 sudo 读不到密码
|
||
```
|
||
|
||
### ✅ 正确:单条命令直接 pipe
|
||
```bash
|
||
echo 'z1020' | sudo -S sysctl -w vm.swappiness=10
|
||
```
|
||
|
||
### ✅ 正确:多条命令用 bash -c(内容不在 heredoc)
|
||
```bash
|
||
# bash -c 的参数是单行字符串,不是 heredoc,密码可重复使用
|
||
echo 'z1020' | sudo -S bash -c 'sysctl -w vm.swappiness=10 && sysctl -w net.core.default_qdisc=fq'
|
||
```
|
||
|
||
### ✅ 正确:分开执行(最可靠)
|
||
```bash
|
||
# 每条命令独立 pipe,密码各用一次
|
||
echo 'z1020' | sudo -S sysctl -w vm.swappiness=10
|
||
echo 'z1020' | sudo -S sysctl -w net.core.default_qdisc=fq
|
||
echo 'z1020' | sudo -S sysctl -w net.ipv4.tcp_congestion_control=bbr
|
||
```
|
||
|
||
### ✅ 正确:用 tee 写入文件(替代 heredoc)
|
||
```bash
|
||
# heredoc 需要交互式 shell,用 tee 代替
|
||
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
|
||
```
|
||
|
||
## 根本原因
|
||
|
||
`echo 'password' | sudo -S` 中,密码通过 stdin 传递,但:
|
||
- **Heredoc `<<EOF`** 也会从 stdin 读取内容,把密码吃掉了
|
||
- **`sudo -S`** 第一次 read 成功,后续命令重试时 stdin 已耗尽
|
||
|
||
## 验证方法
|
||
```bash
|
||
# 检查上条 sudo 命令是否成功
|
||
sudo -n true && echo "sudo OK" || echo "sudo failed"
|
||
```
|
||
|
||
---
|
||
|
||
## 坑 #6:sudo flag 顺序打错(2026-06-28 实测)
|
||
|
||
**症状**:单独跑 `echo 'pw' | sudo -S -v` 接受密码,但换 `echo 'pw' | sudo -S <args>` 写法立即 `[3 incorrect password attempts]`。
|
||
|
||
**根因**:flag 顺序/组合打错(比如 `sudo -S -p '' gpg ...`)时 sudo wrapper 抛 usage error,但 sudo 内部认证层把 stdin 已消耗算成"密码不匹配",导致 3 次 fail 锁。
|
||
|
||
**正确(-S 必须独立)**:
|
||
```bash
|
||
echo 'z1020' | sudo -S gpg --dearmor -o /usr/share/keyrings/microsoft-edge.gpg /tmp/msedge.asc
|
||
```
|
||
|
||
**教训**:先在最小可工作命令验证 sudo 接受密码(`echo 'pw' | sudo -S whoami`),再叠加业务参数。Flag 顺序/组合改一次验证一次。
|
||
|
||
---
|
||
|
||
## 坑 #7:提议"额外步骤"前没先做 preflight(浪费 3-4 步)
|
||
|
||
**反例**(2026-06-28 Edge):
|
||
1. 用户问要不要加 apt 自动更新源 → 直接跑到加 GPG key 那里,失败 2 次
|
||
2. 真相:`.deb` 安装时 post-install hook 早已写好 `/usr/share/keyrings/microsoft-edge.gpg` 和 `/etc/apt/sources.list.d/microsoft-edge.sources`,只是我没先看一眼。
|
||
|
||
**正确流程**:提议任何"额外配置"前先 fs 探测现状:
|
||
```bash
|
||
ls /etc/apt/sources.list.d/ | grep -i -E 'edge|micros|teams|vscode|...'
|
||
ls /usr/share/keyrings/ | grep -i -E 'edge|micros|microsoft|...'
|
||
cat /etc/apt/sources.list.d/<name>.list /etc/apt/sources.list.d/<name>.sources 2>/dev/null
|
||
```
|
||
|
||
**规则**:先 `ls`/`cat` 看现状,再告诉用户"剩什么没做",不要上来就说"我没做 X,要不要我加"。
|
||
|
||
⚠️ **这条规律适用于大部分 `.deb` 包**:Microsoft 系(Edge 已验证;VS Code/Teams/PowerToys 推测同模式)通常自带 post-install 写源。其他发行包(Chrome / Slack / Discord beta)通常**不**自带,需要手动加。
|
||
|
||
---
|
||
|
||
## 坑 #8:用 `sudo -v` 单独 stamp,回避管道 sudo 反复认证
|
||
|
||
**观察**:`echo 'pw' | sudo -S <业务命令>` 容易踩 sudo flag 顺序/组合边界问题,反复解锁浪费时间。
|
||
|
||
**解决**:先 stamp sudo 缓存(默认 5min),之后业务命令直接 `sudo <cmd>`:
|
||
```bash
|
||
# 一次性输密码
|
||
echo 'z1020' | sudo -S -v
|
||
# 5 分钟内免密(不指定命令)
|
||
sudo dpkg -i /tmp/edge.deb
|
||
sudo apt update
|
||
```
|
||
|
||
**前提**:5 分钟窗口期内能列出所有 sudo 操作。如果密集 sudo 命令散落在整个 session 里,就只能在每次登录态新发命令时分别 `echo | sudo -S`。
|