Vertica dbadmin 密码过期处理与自动化管理¶
作者:JiangChong | 发布时间:2026-04-18
适用场景:Vertica 集群的
dbadmin操作系统用户密码即将过期或已过期,导致admintools无法执行、节点启停失败、crontab 计划任务异常,甚至引发数据导出/导入业务流程中断。
关联文章:
- LDAP 认证最佳实践 — 如果使用 LDAP 管理用户认证,密码策略还需兼顾 LDAP 层面
- Vertica 访问策略最佳实践 — Vertica 数据库层面的用户和密码策略管理
- Vertica 维护前准备 Checklist — 维护操作前需要检查密码状态
理解全文脉络:本文按照「为什么重要 → 怎么查 → 怎么修 → 怎么防」的逻辑组织。第一节解释 Linux 密码过期机制如何影响 Vertica 的关键功能;第二节给出系统和 Vertica 层面的监控 SQL/命令;第三节提供按症状分类的排查路径;第四节给出从紧急修复到永久治理的完整方案。如果你已经遇到密码过期导致的服务中断,可以直接跳到第四节。
1. 原理理解¶
1.1 Vertica 为什么依赖操作系统用户密码¶
Vertica 集群的运行架构中,dbadmin 是绝对核心的操作系统用户。所有节点上运行的 Vertica 进程(vertica、spread)都以该用户身份运行。更重要的是,Vertica 的运维工具链严重依赖 dbadmin 用户通过 SSH 免密登录来协同管理所有节点:
admintools:创建/删除数据库、启停集群和节点、查看集群状态——每一步都需要通过 SSH 免密连接到所有节点执行命令vbr备份工具:备份和恢复操作需要通过 SSH 到所有节点执行文件操作- crontab 计划任务:常见的定时任务(如 Kerberos 票据刷新、日志清理)通常以
dbadmin用户运行
关键链路:Linux 操作系统密码过期 → SSH 免密失败 → admintools/vbr/crontab 无法跨节点执行 → 运维操作和业务流程中断。
1.2 Linux 密码过期的底层机制¶
Linux 的密码过期由 /etc/shadow 文件控制,每个用户的记录包含 9 个冒号分隔字段:
| 字段 | 含义 | 本环境实测值(dbadmin) |
|---|---|---|
last_change |
上次修改密码的日期(距 1970-01-01 的天数) | 20593(2026-05-20) |
min |
两次密码修改的最小间隔天数 | 0 |
max |
密码最大有效期(天数) | 99999(永不过期) |
warn |
过期前多少天开始警告 | 7 |
inactive |
过期后多少天锁定账号 | 空(不锁定) |
expire |
账号绝对过期日期(距 1970-01-01 的天数) | 空(不过期) |
默认值来源:/etc/login.defs 中的 PASS_MAX_DAYS、PASS_MIN_DAYS、PASS_WARN_AGE 控制新创建用户的默认值。本环境(RHEL 9.3)中 PASS_MAX_DAYS=99999(即永不过期),但许多企业生产环境出于安全合规要求会将 PASS_MAX_DAYS 设置为 90 天,这正是问题的根源。
为什么密码过期会破坏 SSH 免密:当 max 天数到期后,系统会强制用户在下一次登录时修改密码。SSH 在执行命令时会经过 PAM(Pluggable Authentication Modules)认证栈,当 PAM 检测到密码已过期时,会要求交互式修改密码——但 admintools 的非交互式 SSH 调用无法处理这个 prompt,导致认证失败。
1.3 Vertica 层面的密码策略(独立于 OS)¶
Vertica 数据库内部也有独立的密码过期机制,通过 CREATE PROFILE 语句配置:
| PROFILE 参数 | 作用 | 默认值 |
|---|---|---|
PASSWORD_LIFE_TIME |
密码有效期 | unlimited |
PASSWORD_GRACE_TIME |
过期后的宽限期(仍可登录但每次提示修改) | unlimited |
PASSWORD_LOCK_TIME |
超过宽限期后的锁定时间 | unlimited |
PASSWORD_REUSE_MAX |
历史密码不可重用的个数 | unlimited |
PASSWORD_REUSE_TIME |
历史密码不可重用的天数 | unlimited |
PASSWORD_MIN_LIFE_TIME |
修改密码的最小间隔 | unlimited |
FAILED_LOGIN_ATTEMPTS |
密码错误次数上限 | unlimited |
实测确认:本文验证环境(Vertica v26.1.0-2,默认
defaultprofile)中,所有PASSWORD_*相关参数均为unlimited,即数据库层面不会主动强制密码过期。
两层密码策略的关系:
┌─────────────────────────────────────────┐
│ Linux OS 层(/etc/shadow) │
│ 控制 SSH 登录、admintools 跨节点执行 │
│ ← 这是最常见的故障源! │
└─────────────────────────────────────────┘
↓ 影响
┌─────────────────────────────────────────┐
│ Vertica DB 层(v_catalog.profiles) │
│ 控制 vsql / JDBC / ODBC 连接认证 │
│ ← 默认 unlimited,通常不会出问题 │
└─────────────────────────────────────────┘
绝大多数密码过期故障发生在 OS 层,而不是 Vertica 层。
1.4 密码过期的影响范围总结¶
| 影响对象 | 影响方式 | 严重度 |
|---|---|---|
admintools 所有操作 |
SSH 免密失败 → 命令无法跨节点执行 | 致命 |
vbr 备份/恢复 |
SSH 免密失败 → 备份任务中断 | 致命 |
| 数据库启停 | start_db/stop_db 依赖 SSH 免密 |
致命 |
| crontab 计划任务 | 定时任务以 dbadmin 身份登入各节点时被拦截 | 严重 |
| Kerberos 票据刷新 | crontab 刷票任务失败 → 票据过期 → HDFS 访问中断 | 严重 |
| vsql / JDBC / ODBC 连接 | 不受影响(这是 Vertica 层面的认证,不走 OS PAM) | 无 |
vsql、JDBC、ODBC 等客户端连接通常不受 OS 密码过期影响,因为这些连接走的是 Vertica 自身的 HASH/LDAP 认证,不依赖操作系统 PAM。真正受影响的是运维工具链的 SSH 免密。
2. 系统级监控(从宏观入手)¶
2.1 Linux 层面:检查密码状态¶
这是最重要的检查——确认 OS 用户的密码是否即将过期。核心监控必须在 OS 层面进行。
在所有集群节点上执行:
# 检查所有节点的 dbadmin 密码过期状态
# 已验证:RHEL 9.3 + OpenSSH
# admintools.conf 的 [Cluster] hosts 行记录了集群所有节点 IP
for host in $(grep '^hosts = ' /opt/vertica/config/admintools.conf | cut -d' ' -f3 | tr ',' ' '); do
echo "=== $host ==="
ssh $host 'chage -l dbadmin 2>&1 | grep -E "expires|Password expires|Maximum number"'
done
注意:此脚本依赖 SSH 免密正常才能批量检查所有节点。如果密码已经过期导致 SSH 免密损坏,上述循环将因认证失败而无法获取远程节点的密码状态。此时请改用 root 免密(
ssh root@$host)或逐台登录各节点执行chage -l dbadmin。
或者使用 ansible(一种批量管理多台服务器的自动化工具,非 Vertica 自带,需额外安装)批量执行:
# 使用 ansible 批量检查所有 Vertica 节点(内联 inventory,无需预配文件)
# 已验证:RHEL 9.3, ansible 可用 (yum install ansible)
# 逗号结尾表示 inventory 来源是逗号分隔的 host 列表而非文件路径
HOSTS=$(grep '^hosts = ' /opt/vertica/config/admintools.conf | cut -d' ' -f3)
ansible all -i "${HOSTS}," -m shell -a "chage -l dbadmin"
2.2 如何解读结果¶
chage -l dbadmin 的输出示例(本环境实测):
Last password change : May 20, 2026
Password expires : never ← 永不过期,正常
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999 ← 99999 即不限
Number of days of warning before password expires : 7
关键解读:
| 输出 | 含义 | 需关注的值 |
|---|---|---|
Password expires |
密码何时过期 | 显示具体日期(如 Jun 15, 2026)= 即将到期 |
Maximum number of days |
密码有效期天数 | 90 = 每季度过期(企业常见配置),需设为 99999 |
Account expires |
账号到期日 | 不应有限制日期 |
2.3 /etc/shadow 快速检查¶
chage -l 的输出可以精确定位剩余天数。如果需要脚本化的数值输出,直接用 getent shadow + awk 计算:
# 已验证:RHEL 9.3
getent shadow dbadmin | awk -F: '{
max=$5; last=$3;
if (max == "" || max == "99999") print "never"
else {
expire_day = last + max;
cmd = "date -d @$((expire_day * 86400)) +%Y-%m-%d";
cmd | getline expire_date; close(cmd);
print "Expires: " expire_date
}
}'
在巡检脚本中,密码过期检查通过 OS_Basic_Information_OS_User_Password_Expires() 函数执行 chage -l dbadmin 来检查。
2.4 Vertica 层面:检查数据库密码策略¶
虽然 OS 层是主要故障源,但仍建议确认 Vertica 层面的密码策略配置:
-- 查看所有 Profile 的密码策略配置
SELECT
profile_name,
password_life_time,
password_grace_time,
password_lock_time,
password_reuse_max,
password_reuse_time,
password_min_life_time,
failed_login_attempts
FROM v_catalog.profiles
ORDER BY profile_name;
-- 查看每个用户绑定的 Profile 和锁定状态
SELECT
user_name,
profile_name,
is_locked,
grace_period,
is_super_user,
last_login_time,
lock_time
FROM v_catalog.users
ORDER BY user_name;
解读:
PASSWORD_LIFE_TIME = 'unlimited'→ 数据库层面密码永不过期(默认值)grace_period = 'undefined'→ 用户未处于密码宽限期is_locked = false→ 用户未被锁定- 如果 PASSWORD_LIFE_TIME 不是 unlimited,说明有人主动配置了密码过期策略,需要与 OS 层策略一起纳入监控
2.5 检查最近的登录失败¶
-- 查看登录失败的原因分布
SELECT
user_name,
reason,
client_hostname,
login_timestamp,
authentication_method
FROM v_monitor.login_failures
WHERE login_timestamp > CURRENT_TIMESTAMP - INTERVAL '7 days'
ORDER BY login_timestamp DESC;
如果看到大量 FAILED(而非 INVALID DATABASE),且时间集中在某个节点,通常说明 Vertica 层面的密码或认证配置有问题(如密码错误、账户被锁定、Profile 密码策略到期),而非 OS 层密码过期。OS 密码过期影响的是 SSH 免密和运维工具链(admintools、vbr、crontab),不会直接导致 vsql 登录失败——vsql 走的是 Vertica 自身认证(HASH/LDAP),不依赖操作系统 PAM(详见 1.4 节)。
3. 逐步定位根因(从宏观到微观)¶
3.1 症状分类与定位路径¶
根据典型症状选择合适的排查入口:
| 症状 | 优先检查 | 高概率根因 |
|---|---|---|
admintools -t stop_db 报错 |
OS 密码过期 | dbadmin 密码过期 → SSH 免密失败 |
vbr --task backup 失败 |
OS 密码过期 | 同上 |
| crontab 任务(票据刷新/日志清理)失败 | OS 密码过期 | 同上 |
| vsql 登录报密码错误 | Vertica DB 密码 | Profile 策略或密码被修改 |
JDBC 连接报 password expired |
Vertica DB 密码 | PASSWORD_GRACE_TIME 已耗尽 |
3.2 步骤一:确认 OS 层密码是否过期¶
做什么:在所有节点上检查 dbadmin 的密码过期状态。
或查看更简洁的 passwd -S 输出:
输出字段含义(passwd -S):
- 第 1 字段:用户名
- 第 2 字段:
PS= 已设密码,NP= 无密码,LK= 已锁定 - 第 3 字段:最后修改日期
- 第 4 字段:最小修改间隔(天)
- 第 5 字段:最大有效期(天)← 关注这个
- 第 6 字段:警告天数
- 第 7 字段:不活动锁定天数(-1 = 禁用)
判断逻辑:
- 第 5 字段
99999→ 密码永不过期,正常,排除 OS 层,跳到 3.4 检查 Vertica 层 - 第 5 字段为 90 等小值 → 找到根因,进入第四节修复
- 如果登录时系统 prompt 强制修改密码 → 根因确认,进入第四节修复
3.3 步骤二:确认 SSH 免密是否已损坏¶
密码过期后,SSH 免密将因为 PAM 认证栈拦截而失效。验证方法:
如果返回 Permission denied 或 Password change requested 而不是节点名,说明 SSH 免密已损坏。
3.4 步骤三:检查 Vertica DB 层密码策略¶
如果 OS 层密码状态正常(PASS_MAX_DAYS=99999),则检查 Vertica 自身的密码策略:
-- 检查是否有非默认的 Profile 配置了密码过期
SELECT profile_name, password_life_time, password_grace_time, password_lock_time
FROM v_catalog.profiles
WHERE password_life_time != 'unlimited'
OR password_grace_time != 'unlimited'
OR password_lock_time != 'unlimited';
如果查询结果为空,说明 Vertica 层面没有密码过期策略,问题在 OS 层。
3.5 步骤四:确认影响范围¶
确认密码过期的节点数量和影响的运维操作:
# 在所有节点上执行,统计密码过期的节点数量
for host in node1 node2 node3; do
state=$(ssh -o BatchMode=yes $host 'chage -l dbadmin 2>&1 | grep "Password expires"' 2>&1)
echo "$host: $state"
done
如果密码只在个别节点过期,可能是该节点的 /etc/login.defs 被单独修改过,或该节点加入集群时使用了不同的系统配置。
4. 解决方案(从快速见效到根本治理)¶
立即措施(当天执行)¶
4.1 应急:修改已过期密码并恢复集群操作¶
当密码已过期导致 admintools 无法使用时:
# 步骤 1:以 root 身份在所有节点上重置 dbadmin 密码
# 需要 root 的 SSH 免密(通常集群中 root 也有免密配置)
for host in node1 node2 node3; do
ssh root@$host "echo 'NewPassword123!' | passwd --stdin dbadmin"
done
# 步骤 2:验证 SSH 免密恢复
ssh -o BatchMode=yes node2 'hostname'
# 步骤 3:设置密码永不过期
for host in node1 node2 node3; do
ssh root@$host "chage -M 99999 -W 7 dbadmin"
done
# 步骤 4:验证 SSH 免密已恢复(密码重置后 PAM 不再拦截,密钥无需重新分发)
for host in node2 node3; do
ssh -o BatchMode=yes $host 'hostname' && echo "OK" || echo "FAILED"
done
为什么用 chage -M 99999 而不是 chage -M -1:chage -M 99999 表示密码 99999 天(约 274 年)后过期,实际上是「永不过期」的意思。chage -M -1 在某些发行版上不被支持。
4.2 将密码永不过期(永久修复)¶
# 设置 dbadmin 密码永不过期 + 过期前 7 天警告
chage -M 99999 -W 7 dbadmin
# 同时修改 /etc/login.defs 中的默认值(影响将来创建的用户)
# 仅在需要统一系统策略时才修改
sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 99999/' /etc/login.defs
重要提醒:修改 /etc/login.defs 只影响将来新创建的用户,对已存在的 dbadmin 用户无效。已存在用户的密码策略必须通过 chage 单独设置。
短期优化(当周执行)¶
4.3 部署集中化的密码过期监控¶
在所有节点部署 cron 监控脚本,密码到期前自动告警:
#!/bin/bash
# 文件:/opt/vertica/scripts/check_password_expiry.sh
# 用途:检查 dbadmin 密码状态,到期前 14 天发送告警
THRESHOLD_DAYS=14
ADMIN_EMAIL="dba@example.com"
max_days=$(chage -l dbadmin 2>/dev/null | grep "Maximum number" | awk -F: '{print $2}' | tr -d ' ')
last_change=$(chage -l dbadmin 2>/dev/null | grep "Last password change" | awk -F: '{print $2}' | xargs)
if [ "$max_days" = "99999" ] || [ "$max_days" = "never" ]; then
exit 0 # Password never expires, OK
fi
# 计算剩余天数
last_epoch=$(date -d "$last_change" +%s 2>/dev/null)
expire_epoch=$((last_epoch + max_days * 86400))
now_epoch=$(date +%s)
remaining_days=$(( (expire_epoch - now_epoch) / 86400 ))
if [ "$remaining_days" -le "$THRESHOLD_DAYS" ]; then
echo "WARNING: dbadmin password will expire in ${remaining_days} days on $(hostname)" \
| mail -s "Vertica Password Expiry Alert" "$ADMIN_EMAIL"
fi
crontab 配置(每天检查一次):
4.4 密码临期自动轮换(适合无法设置永不过期的合规环境)¶
如果安全策略强制要求定期修改密码、不允许 chage -M 99999,可以部署自动轮换脚本,在到期前主动修改所有节点的 dbadmin 密码,避免人工遗漏。
#!/bin/bash
# 文件:/opt/vertica/scripts/auto_rotate_dbadmin_password.sh
# 用途:到期前自动在所有节点上轮换 dbadmin 密码
# 运行:root 用户的 crontab(修改他人密码需 root 权限)
# 已验证:RHEL 9.3
THRESHOLD_DAYS=14
ADMIN_EMAIL="dba@example.com"
LOG_FILE="/var/log/dbadmin_password_rotate.log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
# 1. 提取集群节点列表
HOST_LIST=$(grep '^hosts = ' /opt/vertica/config/admintools.conf | cut -d' ' -f3 | tr ',' ' ')
# 2. 从第一个可访问节点获取当前密码过期状态
for host in $HOST_LIST; do
max_days=$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$host" \
"chage -l dbadmin 2>/dev/null | grep 'Maximum number' | awk -F: '{print \$2}' | tr -d ' '" 2>/dev/null) \
&& [ -n "$max_days" ] && break
done
if [ -z "$max_days" ]; then
log "ERROR: Cannot connect to any node to check password status"
exit 1
fi
# 永不过期则跳过
if [ "$max_days" = "99999" ] || [ "$max_days" = "never" ]; then
exit 0
fi
# 3. 计算剩余天数(从第一个节点取 last_change)
last_change_str=$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$host" \
"chage -l dbadmin 2>/dev/null | grep 'Last password change' | awk -F: '{print \$2}' | xargs" 2>/dev/null)
last_epoch=$(date -d "$last_change_str" +%s 2>/dev/null)
expire_epoch=$((last_epoch + max_days * 86400))
now_epoch=$(date +%s)
remaining_days=$(( (expire_epoch - now_epoch) / 86400 ))
if [ "$remaining_days" -gt "$THRESHOLD_DAYS" ]; then
exit 0 # Not yet within threshold
fi
log "WARNING: dbadmin password expires in ${remaining_days} days, starting auto-rotation"
# 4. 生成新密码(16 位随机,含大小写字母+数字+符号)
NEW_PASSWORD=$(openssl rand -base64 12 | tr -dc 'A-Za-z0-9!@#$%^' | head -c16)
if [ -z "$NEW_PASSWORD" ] || [ ${#NEW_PASSWORD} -lt 12 ]; then
NEW_PASSWORD="Vertica$(date +%s | tail -c8)!"
fi
# 5. 在所有节点上同步修改密码
for host in $HOST_LIST; do
if ssh -o BatchMode=yes -o ConnectTimeout=5 "$host" \
"echo '$NEW_PASSWORD' | passwd --stdin dbadmin" 2>/dev/null; then
# 重置过期倒计时,让未来 max_days 天从今天起算
ssh -o BatchMode=yes "$host" "chage -M $max_days -W 7 dbadmin" 2>/dev/null
log "OK: $host password rotated"
else
log "FAIL: $host — password rotation failed, skipping"
fi
done
# 6. 验证所有节点 SSH 免密仍然正常
all_ok=true
for host in $HOST_LIST; do
if ! ssh -o BatchMode=yes -o ConnectTimeout=5 "$host" 'hostname' 2>/dev/null; then
all_ok=false
log "SSH CHECK FAIL: $host"
fi
done
# 7. 发送通知邮件(含新密码,仅当全部成功时发送)
if $all_ok; then
echo "dbadmin password auto-rotated on all nodes. New password: $NEW_PASSWORD" \
| mail -s "Vertica dbadmin Password Rotated" "$ADMIN_EMAIL"
log "SUCCESS: All nodes rotated, notification sent"
else
echo "dbadmin password rotation FAILED on some nodes. Check $LOG_FILE" \
| mail -s "Vertica dbadmin Password Rotation FAILED" "$ADMIN_EMAIL"
log "ERROR: Some nodes failed, manual intervention required"
fi
crontab 配置(root 用户,每天检查一次):
# 添加到 root 的 crontab(sudo crontab -e)
# 已验证:RHEL 9.3
0 8 * * * /opt/vertica/scripts/auto_rotate_dbadmin_password.sh
安全说明:此脚本需要 root 身份运行(
passwd --stdin修改他人密码需要 root)。生成的随机密码通过邮件发送给 DBA,不会写入明文文件。如果企业不允许邮件传输密码,可改用密码保险库 API 或人工确认模式(ROTATE_MODE=notify_only时只告警不执行轮换)。
4.5 配置 Vertica DB 层密码永不过期¶
虽然默认 Profile 已经是 unlimited,但如果有人创建了自定义 Profile 或修改了策略:
-- 将 default profile 的密码策略设为永不过期
ALTER PROFILE default LIMIT
PASSWORD_LIFE_TIME unlimited
PASSWORD_GRACE_TIME unlimited
PASSWORD_LOCK_TIME unlimited;
-- 确认修改生效
SELECT profile_name, password_life_time, password_grace_time, password_lock_time
FROM v_catalog.profiles
WHERE profile_name = 'default';
PASSWORD_LIFE_TIME 与其他参数的关系:
PASSWORD_LIFE_TIME= 密码从创建到过期的时长PASSWORD_GRACE_TIME= 过期后允许登录的缓冲期(每次登录都会收到修改提示)PASSWORD_LOCK_TIME= 宽限期过后,账户被锁定的时长(此期间完全无法登录)
三个参数都设为 unlimited 意味着密码永不过期、永远不锁定。
4.6 修改 dbadmin 密码的安全流程¶
当需要使用 ALTER USER 修改 dbadmin 的 Vertica 数据库密码时:
安全注意事项:
- 任意节点执行一次即可,
ALTER USER是 DDL 操作,通过 Catalog 自动同步到所有节点 - 修改后立即更新所有应用的连接字符串和配置文件
- 不要忘记更新环境变量
VSQL_PASSWORD和巡检脚本的-w参数 - 重新登录 vsql 验证:
vsql -U dbadmin -w NewSecurePassword123! ALTER USER ... IDENTIFIED BY只修改 Vertica 内部密码,不会影响 OS 层面的 dbadmin 密码
5. 深入案例¶
📋 真实案例¶
客户行业:某运营商,93 节点企业模式集群 故障时间:2020 年 6 月 25 日
故障现象:
晚间 8:30 左右,调度同事发现从 Vertica 使用 parallelexport() 函数导出数据到 HDFS 失败,但 copy from webhdfs 从 Hadoop 同步数据到数据库可以正常执行。
诊断过程:
- 检查数据库环境:发现 dbadmin OS 用户密码已经到期,登录时被强制修改密码。修改了一台服务器的 dbadmin 口令后测试导出——依然失败。
- 扩大范围:修改所有 93 个节点上的 dbadmin 口令后再次测试——依然失败。
- 深入排查:
parallelexport()导出数据后通过Hadoop fs -put命令将文件写入 HDFS,怀疑是 dbadmin 用户过期导致 Kerberos 票据刷新失败。
根因分析:
OS dbadmin 口令到期(PASS_MAX_DAYS=90)
→ 节点 1 的 crontab 计划任务使用 dbadmin 登录各节点刷新 Kerberos 票据
→ OS 强制提示修改口令,非交互式 SSH 无法处理 → 刷新票据失败
→ parallelexport() 验证 hwbdi 用户票据时,票据已失效
→ 导出失败
| 操作 | 是否受影响 | 原因 |
|---|---|---|
parallelexport() 导出到 HDFS |
失败 | 需验证 bdi 票据,票据已失效 |
copy from webhdfs 导入 |
正常 | 从 ETL 服务器远程登录,使用 ETL 服务器上有效的票据文件 |
修复:修改所有节点 dbadmin 口令后重新刷新所有节点的 Kerberos 票据,导出恢复正常。
教训:密码过期的影响链可能很长——OS 密码过期 → SSH 免密失败 → crontab 票据刷新失败 → Kerberos 票据过期 → HDFS 访问失败。单纯重置密码不够,还需要检查依赖票据的关联任务。
📝 虚构案例一:admintools 无法停止数据库¶
场景:某金融机构,5 节点 Vertica 集群,计划执行季度维护需要重启数据库。运维工程师执行
admintools -t stop_db时报错。
故障现象:
[dbadmin@node1 ~]$ admintools -t stop_db -d vdb -p password -F
Error: Unable to stop database vdb
Node node2: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
Node node3: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
诊断过程:
# 步骤 1:检查 SSH 免密状态
ssh -o BatchMode=yes node2 'hostname'
# Permission denied (publickey,password).
# 步骤 2:检查 dbadmin 密码状态
chage -l dbadmin
# Password expires: Jul 15, 2026
# Maximum number of days between password change: 90
# 步骤 3:逐节点确认——发现 node2/node3 的密码已过期,其余节点还剩 30 天
for host in node{1..5}; do
echo "=== $host ==="
ssh -o BatchMode=yes $host "chage -l dbadmin 2>&1" || echo "SSH failed"
done
根因:系统管理员在 node2/node3 上提前部署了新的安全基线,将 PASS_MAX_DAYS 从 99999 改为了 90,且将 chage -d 0(强制下次登录修改密码)设置为 0 天后立即触发。其余节点尚未部署,导致「同一集群不同节点的 dbadmin 密码过期时间不一致」。
修复方案:
# 1. 以 root 身份在 node2/node3 上重置密码并设置永不过期
ssh root@node2 "echo 'TempP@ss2026!' | passwd --stdin dbadmin"
ssh root@node2 "chage -M 99999 -W 7 dbadmin"
ssh root@node3 "echo 'TempP@ss2026!' | passwd --stdin dbadmin"
ssh root@node3 "chage -M 99999 -W 7 dbadmin"
# 2. 验证 SSH 免密已恢复(密码重置后 PAM 不再拦截,密钥文件未被修改)
ssh -o BatchMode=yes node2 'hostname'
ssh -o BatchMode=yes node3 'hostname'
# 3. 验证 admintools 恢复
admintools -t stop_db -d vdb -p password -F
# Database vdb stopped successfully
效果对比:
| 指标 | 修复前 | 修复后 |
|---|---|---|
| 数据库可停止 | ❌ 失败 | ✅ 正常 |
| 运维操作耗时 | 无限期阻塞 | < 2 分钟 |
| 密码过期倒计时 | node2/3 已过期 | 全部 99999 |
📝 虚构案例二:vsql 突然报密码过期¶
场景:某电商公司,ETL 工程师在凌晨批量加载数据时,
vsql连接突然报错。
故障现象:
$ vsql -U etl_user -w pass123 -c "SELECT count(*) FROM sales;"
ERROR 4721: Password for user etl_user has expired. Please change your password.
诊断过程:
-- 步骤 1:确认 Vertica 层面的密码策略
SELECT profile_name, password_life_time, password_grace_time, password_lock_time
FROM v_catalog.profiles
WHERE profile_name = (SELECT profile_name FROM v_catalog.users WHERE user_name = 'etl_user');
-- 输出:
profile_name: etl_profile
password_life_time: 90 days
password_grace_time: 7 days
password_lock_time: unlimited
原来 DBA 在上次安全审计后为 ETL 用户创建了自定义 Profile,设置了 90 天密码过期策略,但忘记告知 ETL 团队。
-- 步骤 2:查看密码审计状态
SELECT user_name, acctexpired, current_security_algorithm
FROM v_catalog.password_auditor
WHERE user_name = 'etl_user';
-- 输出:
user_name: etl_user
acctexpired: true ← 账户已过期!
根因:自定义 Profile etl_profile 的 PASSWORD_LIFE_TIME = 90 days 到期,且 PASSWORD_GRACE_TIME = 7 days 已耗尽,账户进入过期状态。
修复方案:
-- 紧急措施:重置密码并解除过期状态
ALTER USER etl_user IDENTIFIED BY 'NewETLPassword2026!';
-- 确认恢复
SELECT user_name, acctexpired FROM v_catalog.password_auditor WHERE user_name = 'etl_user';
-- acctexpired: false ✅
-- 长期措施:为 ETL 类用户设置更适合的密码策略
ALTER PROFILE etl_profile LIMIT
PASSWORD_LIFE_TIME unlimited
PASSWORD_GRACE_TIME unlimited;
效果:ETL 作业在 5 分钟内恢复执行,未造成数据延迟。
📝 虚构案例三:Kerberos + 密码过期双重故障¶
场景:某运营商,20 节点集群,同时使用 Kerberos 认证和 Vertica 原生密码认证。
故障现象:
- 部分应用(使用 Kerberos 认证)访问 HDFS 外部表报错
GSS initiate failed - 部分应用(使用密码认证)连接 Vertica 正常
诊断过程:
-- 步骤 1:检查登录失败记录
SELECT user_name, reason, client_hostname, login_timestamp, authentication_method
FROM v_monitor.login_failures
WHERE login_timestamp > CURRENT_TIMESTAMP - INTERVAL '1 hour'
ORDER BY login_timestamp DESC;
-- 大部分是 Kerberos 认证失败,少量是 Hash 失败
# 步骤 2:检查 Kerberos 票据
klist -5
# klist: No credentials cache found (filename: /tmp/krb5cc_1000)
# 步骤 3:检查票据刷新脚本日志
grep "kinit" /var/log/cron
# kinit: Password has expired while getting initial credentials
# 步骤 4:检查 crontab 的票据刷新任务
crontab -l -u dbadmin
# 0 */6 * * * /opt/vertica/scripts/refresh_krb_ticket.sh
根因链:
PASS_MAX_DAYS=90 → dbadmin 密码在 node1 上过期
→ crontab 每 6 小时的 kinit 刷票失败(密码过期,kinit 无法获取新票据)
→ Kerberos 票据超过 24 小时有效期后全部失效
→ 所有依赖 Kerberos 的 HDFS 外部表查询失败
→ 但直接使用密码的 vsql 连接仍然正常(Vertica 密码认证不走 OS PAM)
为什么 vsql 密码认证正常但 Kerberos 失败:密码认证不需要 OS 层 dbadmin 的 Kerberos 票据,而访问 HDFS 外部表时需要有效的 Kerberos 票据——这个票据是由 crontab 以 dbadmin 身份通过 kinit 获取的,密码过期导致 kinit 失败。
修复方案:
# 1. 紧急修复:所有节点重置密码
HOSTS=$(grep '^hosts = ' /opt/vertica/config/admintools.conf | cut -d' ' -f3 | tr ',' ' ')
for host in $HOSTS; do
ssh root@$host "echo 'NewP@ss2026!' | passwd --stdin dbadmin"
ssh root@$host "chage -M 99999 dbadmin"
done
# 2. 手动刷票
kdestroy -A
kinit -kt /opt/vertica/config/dbadmin.keytab dbadmin@REALM.COM
klist -5 # 确认票据有效
# 3. 验证 HDFS 外部表查询恢复
vsql -c "SELECT count(*) FROM hdfs_external_sales;"
6. 完整诊断流程实战(虚构场景,充当总复习)¶
📝 虚构场景 · 完整演练
背景:某企业 3 节点 Vertica 集群(RHEL 9.3 + Vertica 26.1.0),运维工程师在周一早上发现昨天的定时备份任务(vbr)失败。
时间线¶
| 时间 | 事件 |
|---|---|
| 08:00 | 收到监控告警:vbr 备份失败 |
| 08:05 | 初步诊断:怀疑 SSH 免密问题 |
| 08:10 | 确认 OS 密码过期 |
| 08:20 | 执行修复 |
| 08:25 | 验证恢复 |
| 08:30 | 补做备份任务 |
完整排查步骤¶
08:00 — 检查备份日志:
cat /opt/vertica/backup/vbr_backup_$(date +%Y%m%d).log
# Error: ssh: connect to host node2 port 22: Permission denied
08:05 — 验证 SSH 免密:
08:10 — 确认密码状态:
chage -l dbadmin
# Last password change : Mar 01, 2026
# Password expires : Jun 01, 2026 ← 今天到期!
# Maximum number of days : 90
# 逐节点确认
for host in node1 node2 node3; do
echo "=== $host ==="
ssh -o BatchMode=yes $host "chage -l dbadmin 2>&1" || echo "SSH FAILED"
done
# node1: Password expires: Jun 01, 2026 ← 今天到期
# node2: SSH FAILED ← 已过期(登录被拦截)
# node3: Password expires: Jun 01, 2026 ← 今天到期
08:10 — 排查 Vertica 层面(排除干扰):
SELECT user_name, profile_name, password_life_time
FROM v_catalog.users u
JOIN v_catalog.profiles p ON u.profile_name = p.profile_name
WHERE u.user_name = 'dbadmin';
-- user_name: dbadmin
-- profile_name: default
-- password_life_time: unlimited ← Vertica 层无问题
确认根因:OS 层面的 dbadmin 密码过期(PASS_MAX_DAYS=90),导致 SSH 免密失败,vbr 备份无法跨节点执行。
08:20 — 执行修复(以 root 身份,root 有免密):
# 步骤 1:重置所有节点密码并设置永不过期
for host in node1 node2 node3; do
ssh root@$host "echo 'Vertica@2026!' | passwd --stdin dbadmin"
ssh root@$host "chage -M 99999 -W 7 dbadmin"
done
# 步骤 2:验证 SSH 免密已恢复(密码重置后 PAM 不再拦截,密钥文件未被修改)
for host in node1 node2 node3; do
ssh -o BatchMode=yes $host 'hostname' && echo "OK" || echo "FAILED"
done
# node1: OK
# node2: OK
# node3: OK
08:25 — 验证修复效果:
# 1. 验证密码状态
for host in node1 node2 node3; do
ssh $host "chage -l dbadmin | grep 'Password expires'"
done
# Password expires: never
# Password expires: never
# Password expires: never
# 2. 验证 admintools
admintools -t view_cluster
# DB | Host | State
# ------+------+-------
# vmart | ALL | UP
# 3. 补做备份
/opt/vertica/bin/vbr --task backup --config-file /opt/vertica/backup/backup.ini
# Backup completed successfully
7. 快速诊断 SQL 工具箱¶
| 诊断目标 | SQL / 命令 | 说明 |
|---|---|---|
| OS 密码过期状态 | chage -l dbadmin |
检查 Password expires 和 Maximum number of days |
| OS 密码状态(简洁) | passwd -S dbadmin |
第 5 字段为 max days |
| OS shadow 原始数据 | getent shadow dbadmin |
第 5 字段 = PASS_MAX_DAYS |
| 所有节点批量检查 | for h in node{1..N}; do ssh $h 'chage -l dbadmin \| grep expires'; done |
批量检查集群 |
| SSH 免密是否正常 | ssh -o BatchMode=yes node2 'hostname' |
不应要求输入密码 |
| Vertica Profile 密码策略 | SELECT * FROM v_catalog.profiles |
关注 PASSWORD_LIFE_TIME |
| Vertica 用户过期状态 | SELECT user_name, acctexpired FROM v_catalog.password_auditor |
acctexpired=true 表示已过期 |
| Vertica 用户锁定状态 | SELECT user_name, is_locked, grace_period, lock_time FROM v_catalog.users |
is_locked=true 表示已锁定 |
| Vertica 密码历史 | SELECT user_name, is_current_password, profile_name FROM v_catalog.passwords |
is_current_password=false 为历史密码 |
| 登录失败记录 | SELECT user_name, reason, client_hostname, login_timestamp FROM v_monitor.login_failures WHERE login_timestamp > CURRENT_TIMESTAMP - INTERVAL '7 days' |
原因分布能揭示故障模式 |
| 当前活跃会话 | SELECT user_name, session_id, login_timestamp, client_hostname FROM v_monitor.sessions ORDER BY login_timestamp DESC |
排查异常连接或未关闭会话 |
| PAM 配置检查 | grep -E 'pam_unix' /etc/pam.d/system-auth |
确认密码认证栈配置 |
| login.defs 默认值 | grep 'PASS_MAX_DAYS\|PASS_WARN_AGE' /etc/login.defs |
新用户默认密码过期策略 |
8. 最佳实践清单¶
-
安装集群后第一时间设置 dbadmin 密码永不过期:
chage -M 99999 dbadmin。Vertica 的运维工具链(admintools、vbr、crontab)严重依赖 SSH 免密,密码过期会直接导致集群不可运维。这是投入产出比最高的一条。 -
不要依赖 /etc/login.defs 来管理已有用户的密码策略:
/etc/login.defs只影响useradd创建的新用户。已存在用户的密码过期策略必须通过chage单独设置。 -
在所有节点上统一执行密码策略修改:不要只修改主节点。集群中任何节点上的 dbadmin 密码过期都会导致当该节点被
admintools或vbr访问时操作失败。 -
密码过期后不仅要重置密码,还要检查关联的 crontab 任务:如真实案例所示,密码过期会导致 Kerberos 票据刷新失败、日志清理失败等连锁反应。重置密码后需要手动执行这些任务确认恢复。
-
部署密码过期监控脚本,提前 14 天告警:
chage -l dbadmin | grep "Password expires"的输出可以被脚本解析。结合 crontab + mail 实现自动告警,避免被动发现。 -
保留 root 用户的 SSH 免密作为应急通道:当 dbadmin 密码过期导致无法 SSH 到其他节点时,root 用户的 SSH 免密是唯一的应急修复通道。
-
Vertica 层面保持默认 Profile 的 PASSWORD_LIFE_TIME = unlimited:Vertica 的客户端连接(vsql、JDBC、ODBC)不受 OS 密码过期影响,设置数据库层面的密码过期策略通常弊大于利,除非有明确的安全合规需求。
-
密码修改不会破坏 SSH 密钥,无需重新分发:
passwd只修改/etc/shadow中的密码哈希,不会动~/.ssh/下的密钥文件。如果 SSH 免密因密码过期被 PAM 拦截,重置密码并设置chage -M 99999后 SSH 免密会自动恢复。 -
将密码过期检查纳入常规巡检:
databaseCheckv6.1.sh已经包含OS_Basic_Information_OS_User_Password_Expires检查,确保巡检脚本定期执行且覆盖所有节点。 -
了解你的 PAM 配置:不同 Linux 发行版的 PAM 配置不同。
/etc/pam.d/system-auth中的pam_unix.so参数(如nullok、try_first_pass)会影响密码过期的行为。在修改系统级密码策略前,先理解当前的 PAM 栈配置。
扩展阅读¶
- LDAP 认证最佳实践 — LDAP 环境下的密码策略管理
- Vertica 访问策略最佳实践 — Vertica 数据库层面的用户和密码策略
- Vertica 维护前准备 Checklist — 维护操作前的完整检查清单
- Vertica 监控最佳实践 — 包含密码过期监控的完整监控方案