Sudo密码的存储和自动调用

简介

keysudo.sh是一个用于安全存储和调用 sudo 密码的 Bash 脚本工具,通过 GNOME Keyring 实现敏感信息的加密存储。脚本设计目标是通过密钥环系统减少密码的明文暴露,同时解决 sudo 验证失败导致的账户锁定问题。

主要功能

  • 🔐 自动将 sudo 密码存储至 GNOME Keyring
  • 🔄 支持 3 次验证尝试(可配置)
  • ⚠️ 智能检测系统环境(支持 Arch/RHEL 系)
  • 🔒 密码输入支持 systemd-ask-password 工具
  • 🛡️ 密码错误时自动重置 sudo 失败计数
  • 🚫 杜绝密码明文存储和传输

快速使用

基础用法

1
2
3
4
5
6
# 获取密码(自动触发存储流程)
syndns_password=$(./keysudo.sh)

# 使用示例(建议立即清理变量)
echo $syndns_password | sudo -S your_command
unset syndns_password

安装依赖

1
2
3
4
5
# Arch 系系统
sudo pacman -S pambase libsecret

# RHEL/CentOS 系系统
sudo yum install pam libsecret-tools

卸载密码

1
secret-tool clear syndns_password_key syndns_password

常见问题

Q1: 密码无法存储到密钥环

1
2
3
4
# 检查密钥环服务状态
gnome-keyring-daemon --start
# 验证存储功能
echo "test" | secret-tool store --label="Test" test_key test_value

Q2: sudo 被锁定后如何处理

1
2
3
4
5
# 显示当前失败计数(RHEL系)
sudo pam_tally2 --user $USER

# 强制解锁所有用户(Arch系)
sudo faillock --reset

程序源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#! /bin/bash
#
# Program : keysudo.sh
# Author : Zhen-Hua Feng(冯振华)
# Email : fengzhenhua@outlook.com
# Date : 2025-01-10 20:41
# CopyRight: Copyright (C) 2025--
# License : Distributed under terms of the MIT license.
#
# 定义标识符
SYN_KEY="syndns_password" # 密钥环中的唯一标识符
SYN_SUDO_NUM_MAX="3" # 确保这个数值与您系统中sudo验证次数一致,以免进入死循环
# 检测依赖,确保secret-tool正确安装
if ! command -v secret-tool &>/dev/null; then
echo "错误:需要安装 secret-tool(包名:libsecret-tools)" >&2
exit 1
fi
# 探测系统sud解锁程序
SYN_RES_CMD=""
if command -v faillock &>/dev/null; then
SYN_RES_CMD="faillock --user $USER --reset"
elif command -v pam_tally2 &>/dev/null; then
SYN_RES_CMD="pam_tally2 --user $USER --reset"
else
echo "错误:未找到可用SUDO解锁工具 !" >&2
echo "请安装:Arch系安装pambase,RHEL系安装pam" >&2
exit 1 # 正确终止脚本
fi
# 存储密码到 GNOME Keyring
# 测试密码过程中存在sudo次数限制,如果sudo被锁定了,那本脚本在首次没有完成密码保存的工作后将处于锁定状态
SYN_KEY_GET(){
local SYN_AMT="$SYN_SUDO_NUM_MAX"
while [[ "$SYN_AMT" -gt 0 ]]; do
SYN_KEY_X=$(secret-tool lookup syndns_password_key "$SYN_KEY")
if [[ -z "$SYN_KEY_X" ]]; then
unset SYN_KEY_DATA
# 使用专业密码输入工具
if command -v systemd-ask-password &>/dev/null; then
SYN_KEY_DATA=$(systemd-ask-password --timeout=30 "请求sudo密码:")
else
printf "$0 请求输入sudo密码(30秒超时):" >&2
# 增加超时后的清理逻辑
if ! read -rs -t 30 SYN_KEY_DATA; then
printf "\n输入超时,操作取消。\n" >&2
unset SYN_KEY_DATA
exit 1
fi
fi
if [[ -z "$SYN_KEY_DATA" ]]; then
printf "\n密码不能为空,请重新输入。\n" >&2
else
if printf "%s" "$SYN_KEY_DATA" | secret-tool store --label="Syndns Password" syndns_password_key "$SYN_KEY"; then
sudo -k
if printf "%s" "$SYN_KEY_DATA" | sudo -S -v 2>/dev/null; then
# 存储成功后立即清理
unset SYN_KEY_DATA
printf "\n密码已成功存储到 GNOME Keyring 中。\n" >&2
return 0
else
SYN_AMT=$((SYN_AMT - 1))
SYN_FAIL_RES "警告:当前系统可能需要手动重置失败计数!"
fi
else
printf "\n无法存储密码,请检查 GNOME Keyring 是否可用。\n" >&2
exit 1
fi
fi
else
sudo -k
if ! printf "%s" "$SYN_KEY_X" | sudo -S -v 2>/dev/null; then
SYN_AMT=$((SYN_AMT - 1))
secret-tool clear syndns_password_key "$SYN_KEY" # 清空密码,重新循环才能进入设置
SYN_FAIL_RES "警告:当前系统可能需要手动重置失败计数!"
else
return 0
fi
fi
done
printf "尝试次数已达上限,操作终止。\n" >&2
SYN_FAIL_RES "请切换至ROOT权限解除锁定: $SYN_RES_CMD"
exit 1
}
SYN_FAIL_RES(){
if grep -qi 'arch' /etc/os-release 2>/dev/null; then
faillock --user $USER --reset
else
# 优先显示传入的定制化提示
printf "$1 \n" >&2
# 补充建议命令(带sudo前缀)
[ -n "$SYN_RES_CMD" ] && echo "可尝试执行: sudo $SYN_RES_CMD" >&2
fi
}
sudo -k # 清除sudo缓存
SYN_KEY_GET
echo $SYN_KEY_X