25 KiB
Redis 用户名查找和认证配置指南
问题日期: 2026年2月22日
环境: juwan namespace
Redis 版本: 7.0.12
部署模式: RedisReplication (OpsTree Operator)
📋 目录
🎯 问题背景
问题描述
在配置应用连接 Redis 时,发现只有密码信息(存储在 Kubernetes Secret user-redis 中),但不清楚:
- Redis 是否需要用户名?
- 如果需要,用户名是什么?
- 如何查找 Redis 的用户名配置?
初始已知信息
Secret: user-redis
Namespace: juwan
Key: password
Value: (base64 编码的密码)
疑问
- 使用 RedisInsight 等管理工具时,Username 字段应该填什么?
- 应用代码中是否需要配置 Username?
- 不同 Redis 版本的认证方式是否有差异?
📚 Redis 认证机制演进
Redis 6.0 之前:传统密码认证
特点:
- ❌ 不支持多用户
- ✅ 只需配置一个全局密码
- 🔧 配置项:
requirepass - 👤 隐式用户名:
default(客户端不需要指定)
配置示例:
# redis.conf
requirepass mypassword
连接方式:
# 只需要密码
redis-cli -h host -p 6379 -a mypassword
# 或使用 AUTH 命令
redis-cli -h host -p 6379
> AUTH mypassword
优点:
- ✅ 配置简单
- ✅ 向后兼容
缺点:
- ❌ 所有客户端共享同一密码
- ❌ 无法区分不同应用的访问权限
- ❌ 无法限制特定命令
- ❌ 审计困难
Redis 6.0+:ACL(访问控制列表)
引入时间: Redis 6.0 (2020年5月)
新特性:
- ✅ 支持多用户
- ✅ 每个用户有独立的密码
- ✅ 细粒度权限控制(命令、key、channel)
- ✅ 默认用户
default兼容旧版本 - ✅ 支持运行时动态修改
架构对比:
传统模式:
┌─────────────┐
│ 所有客户端 │
└──────┬──────┘
│ (一个密码)
↓
┌─────────────┐
│ Redis │
│ (全权限) │
└─────────────┘
ACL 模式:
┌────────┐ ┌────────┐ ┌────────┐
│ App A │ │ App B │ │ Admin │
└───┬────┘ └───┬────┘ └───┬────┘
│ user1 │ user2 │ admin
│ (读写) │ (只读) │ (全部)
↓ ↓ ↓
┌───────────────────────────────┐
│ Redis ACL │
│ user1: +@write +@read │
│ user2: +@read ~cache:* │
│ admin: +@all ~* │
└───────────────────────────────┘
ACL 规则语法:
user <username> on <password> ~<keypattern> +<command>
示例:
user alice on >secret123 ~* +@all # 全部权限
user bob on >pass456 ~cache:* +get +set # 只能操作 cache:* 的 key
user readonly on >readonly ~* +@read -@write # 只读权限
🔍 诊断过程
步骤 1:确认 Pod 容器名称
目的: 找到 Redis 容器的正确名称,以便执行命令
命令:
kubectl get pod user-redis-0 -n juwan -o jsonpath='{.spec.containers[*].name}'
输出:
user-redis redis-exporter
分析:
- ✅ Pod 中有 2 个容器
- 📦
user-redis:Redis 主容器 - 📊
redis-exporter:Prometheus 监控容器 - 🎯 需要连接到
user-redis容器
关键信息:
Pod: user-redis-0
Containers:
- name: user-redis # ← Redis 服务容器
image: quay.io/opstree/redis:v7.0.12
port: 6379
- name: redis-exporter # ← 监控容器
image: quay.io/opstree/redis-exporter
port: 9121
步骤 2:获取 Redis 密码
目的: 从 Kubernetes Secret 中提取密码,用于认证
命令:
kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d
输出:
<密码内容> # 实际密码已隐藏
说明:
- Secret 中的数据以 base64 编码存储
- 需要解码才能得到明文密码
base64 -d在 Linux/Mac 上;Windows PowerShell 需要用其他方法
Windows PowerShell 解码方法:
$encoded = kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}'
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encoded))
步骤 3:检查 ACL 配置(关键步骤)
目的: 查询 Redis 的用户配置,确认是否启用 ACL 以及有哪些用户
命令:
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a $(kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d) \
ACL LIST
命令解析:
kubectl exec -it user-redis-0 \ # 在 user-redis-0 Pod 中执行命令
-n juwan \ # 命名空间
-c user-redis \ # 指定容器
-- \ # 分隔符
redis-cli \ # Redis 命令行工具
-a $(kubectl get secret ...) \ # 使用密码认证
ACL LIST # 列出所有 ACL 用户
输出:
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1) "user default on #e3e7d4b9413497efc274c747b2ee88023e00e6416080db92c7bdd49a73f32d3d ~* &* +@all"
输出分析:
警告信息
Warning: Using a password with '-a' option on the command line interface may not be safe.
- ⚠️ 安全提醒:命令行中的密码可能被历史记录或进程列表泄露
- 💡 生产环境建议:使用配置文件或环境变量传递密码
ACL 规则详解
user default on #e3e7d4b...73f32d3d ~* &* +@all
| | | | | | |
| | | | | | └─ 权限:所有命令
| | | | | └──── 所有 Pub/Sub channel
| | | | └─────── 所有 key pattern
| | | └──────────────────────────── 密码哈希(SHA256)
| | └─────────────────────────────── 状态:已启用
| └─────────────────────────────────────── 用户名
└──────────────────────────────────────────── 类型:用户
权限标识含义:
| 标识 | 含义 | 说明 |
|---|---|---|
on |
用户已启用 | 可以登录 |
off |
用户已禁用 | 无法登录 |
~* |
Key Pattern | * = 所有 key;~cache:* = 只能访问 cache 开头的 key |
&* |
Pub/Sub Pattern | * = 所有 channel |
+@all |
命令权限 | @all = 所有命令;+get +set = 只能用 GET/SET |
-@dangerous |
禁止命令组 | 禁止危险命令(FLUSHDB, KEYS 等) |
#hash |
密码哈希 | SHA256 哈希值,不存储明文 |
命令组示例:
@read:只读命令(GET, HGET, LRANGE 等)@write:写入命令(SET, HSET, LPUSH 等)@admin:管理命令(CONFIG, SHUTDOWN 等)@dangerous:危险命令(FLUSHALL, KEYS 等)@all:所有命令
结论:
- ✅ Redis 启用了 ACL 模式
- 👤 用户名是:
default - 🔑 密码已配置(存储为 SHA256 哈希)
- 🔓 权限:完全访问(所有命令、所有 key、所有 channel)
步骤 4:验证用户名配置
目的: 确认 default 用户可以正常工作
方法 1:使用密码(不指定用户名)
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> PING
预期输出:
Warning: Using a password with '-a' option on the command line interface may not be safe.
PONG
✅ 说明:只提供密码可以正常连接(默认使用 default 用户)
方法 2:显式指定用户名
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli --user default --pass <password> PING
预期输出:
PONG
✅ 说明:显式指定 default 用户也可以正常连接
方法 3:测试错误的用户名
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli --user wronguser --pass <password> PING
预期输出:
(error) WRONGPASS invalid username-password pair or user is disabled.
❌ 说明:不存在的用户名会认证失败
步骤 5:查看完整的 ACL 信息
目的: 了解 default 用户的详细权限配置
命令:
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL GETUSER default
输出:
1) "flags"
2) 1) "on"
2) "allkeys"
3) "allchannels"
4) "allcommands"
3) "passwords"
4) 1) "e3e7d4b9413497efc274c747b2ee88023e00e6416080db92c7bdd49a73f32d3d"
5) "commands"
6) "+@all"
7) "keys"
8) 1) "*"
9) "channels"
10) 1) "*"
11) "selectors"
12) (empty array)
详细分析:
| 字段 | 值 | 含义 |
|---|---|---|
flags |
on, allkeys, allchannels, allcommands |
用户已启用,可访问所有资源 |
passwords |
e3e7d4b... (SHA256) |
密码哈希 |
commands |
+@all |
允许所有命令组 |
keys |
* |
可访问所有 key |
channels |
* |
可访问所有 Pub/Sub channel |
权限总结:
- ✅ 用户状态:启用(on)
- ✅ 命令权限:所有命令(+@all)
- ✅ Key 权限:所有 key(~*)
- ✅ Channel 权限:所有 channel(&*)
- 🔒 密码:已设置且加密存储
🎯 用户名发现结果
最终结论
✅ 当前 Redis 配置
认证模式: ACL (Redis 6.0+)
用户名: default
密码: (存储在 Secret user-redis 中)
权限: 完全访问(超级用户)
状态: 已启用
📝 连接参数汇总
| 参数 | 值 | 备注 |
|---|---|---|
| 用户名 | default |
可省略,客户端默认使用 |
| 密码 | kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d |
必需 |
| Host (集群内) | user-redis-master.juwan.svc.cluster.local |
写操作 |
| Host (集群内) | user-redis-replica.juwan.svc.cluster.local |
读操作 |
| Host (Sentinel) | user-redis-sentinel-sentinel.juwan.svc.cluster.local |
推荐 |
| Port | 6379 |
Redis 数据端口 |
| Sentinel Port | 26379 |
Sentinel 端口 |
为什么大多数情况不需要指定用户名?
Redis 客户端的默认行为
-
向后兼容
Redis 6.0+ 保持了与旧版本的兼容性 当客户端只提供密码时,自动使用 'default' 用户 -
客户端实现
// go-redis 内部逻辑(伪代码) if password != "" && username == "" { username = "default" // 自动补全 } -
AUTH 命令演进
# Redis 5.x 及之前 AUTH password # 只有密码 # Redis 6.0+(向后兼容) AUTH password # 等价于 AUTH default password AUTH username password # 新格式
何时需要显式指定用户名?
| 场景 | 是否需要 | 原因 |
|---|---|---|
使用 default 用户 |
❌ 不需要 | 客户端自动使用 |
| 创建了自定义用户 | ✅ 需要 | 必须明确指定 |
| 多应用共享 Redis | ✅ 推荐 | 权限隔离 |
| 审计需求 | ✅ 推荐 | 区分访问来源 |
| 管理工具连接 | ⚠️ 可选 | 有些工具要求填写 |
💻 各语言连接配置
Go (go-redis)
方式 1:只用密码(推荐)
import "github.com/redis/go-redis/v9"
// 不指定 Username,自动使用 default
rdb := redis.NewClient(&redis.Options{
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
Password: os.Getenv("REDIS_PASSWORD"), // 只需密码
DB: 0,
})
方式 2:显式指定用户名
// 显式指定 Username(效果相同)
rdb := redis.NewClient(&redis.Options{
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
Username: "default", // 明确指定
Password: os.Getenv("REDIS_PASSWORD"),
DB: 0,
})
Sentinel 模式(生产推荐)
// Sentinel 模式也支持用户名
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{
"user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379",
},
// Username 可省略(默认 default)
Password: os.Getenv("REDIS_PASSWORD"),
DB: 0,
})
Go-Zero 框架
配置文件
# app/users/rpc/etc/pb.yaml
Redis:
Type: sentinel
MasterName: mymaster
SentinelAddrs:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Pass: ${REDIS_PASSWORD} # 只需密码,不需要用户名
如果需要自定义用户
Redis:
Type: sentinel
MasterName: mymaster
SentinelAddrs:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Username: default # 可选:显式指定
Pass: ${REDIS_PASSWORD}
Python (redis-py)
只用密码
import redis
# 不指定 username
r = redis.Redis(
host='user-redis-master.juwan.svc.cluster.local',
port=6379,
password=os.getenv('REDIS_PASSWORD'), # 只需密码
db=0
)
显式指定用户名(redis-py 4.3+)
# 显式指定 username
r = redis.Redis(
host='user-redis-master.juwan.svc.cluster.local',
port=6379,
username='default', # 明确指定
password=os.getenv('REDIS_PASSWORD'),
db=0
)
Sentinel 模式
from redis.sentinel import Sentinel
sentinel = Sentinel([
('user-redis-sentinel-sentinel.juwan.svc.cluster.local', 26379)
])
# 获取主节点(不指定 username)
master = sentinel.master_for(
'mymaster',
password=os.getenv('REDIS_PASSWORD')
)
# 或显式指定
master = sentinel.master_for(
'mymaster',
username='default',
password=os.getenv('REDIS_PASSWORD')
)
Java (Spring Data Redis)
application.yml(只用密码)
spring:
redis:
password: ${REDIS_PASSWORD} # 只需密码
sentinel:
master: mymaster
nodes:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
显式指定用户名(Spring Boot 2.6+)
spring:
redis:
username: default # 可选
password: ${REDIS_PASSWORD}
sentinel:
master: mymaster
nodes:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Java 代码(Jedis)
// 只用密码
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool pool = new JedisPool(
poolConfig,
"user-redis-master.juwan.svc.cluster.local",
6379,
2000,
"password" // 只需密码
);
// 显式指定用户名(Jedis 4.0+)
JedisPool pool = new JedisPool(
poolConfig,
"user-redis-master.juwan.svc.cluster.local",
6379,
2000,
"default", // 用户名
"password" // 密码
);
Node.js (ioredis)
只用密码
const Redis = require('ioredis');
// 不指定 username
const redis = new Redis({
host: 'user-redis-master.juwan.svc.cluster.local',
port: 6379,
password: process.env.REDIS_PASSWORD, // 只需密码
});
显式指定用户名(ioredis 4.0+)
// 显式指定 username
const redis = new Redis({
host: 'user-redis-master.juwan.svc.cluster.local',
port: 6379,
username: 'default', // 明确指定
password: process.env.REDIS_PASSWORD,
});
Sentinel 模式
const redis = new Redis({
sentinels: [
{
host: 'user-redis-sentinel-sentinel.juwan.svc.cluster.local',
port: 26379
}
],
name: 'mymaster',
password: process.env.REDIS_PASSWORD, // username 可省略
});
redis-cli 命令行
只用密码
# 方式 1:命令行参数
redis-cli -h user-redis-master.juwan.svc.cluster.local -p 6379 -a <password>
# 方式 2:交互式登录
redis-cli -h user-redis-master.juwan.svc.cluster.local -p 6379
> AUTH <password>
OK
显式指定用户名
# 方式 1:命令行参数
redis-cli -h host -p 6379 --user default --pass <password>
# 方式 2:交互式登录
redis-cli -h host -p 6379
> AUTH default <password>
OK
🛠️ 管理工具配置
RedisInsight
配置示例:
Name: juwan-user-redis
Host: localhost (使用 kubectl port-forward)
Port: 6379
Username: default ← 填这个(或留空)
Password: <从 Secret 获取>
说明:
- ✅ Username 可以填
default - ✅ Username 也可以留空(某些版本支持)
- 🔧 建议先 port-forward:
kubectl port-forward -n juwan svc/user-redis-master 6379:6379
Redis Commander
Docker 运行:
docker run -d \
-e REDIS_HOSTS=juwan:user-redis-master.juwan.svc.cluster.local:6379:0:password \
-p 8081:8081 \
rediscommander/redis-commander
URL 格式:
# 不带用户名
redis://:<password>@host:6379
# 带用户名
redis://default:<password>@host:6379
Another Redis Desktop Manager
连接配置:
{
"name": "juwan-redis",
"host": "localhost",
"port": 6379,
"auth": "password", // 只需密码
"username": "" // 留空(或填 "default")
}
❓ 常见问题解答
Q1: 为什么有些地方说 Redis 不需要用户名?
A: 这取决于 Redis 版本:
Redis 5.x 及之前:
└─ ❌ 不支持用户名,只有全局密码
└─ 配置:requirepass password
Redis 6.0+:
└─ ✅ 支持 ACL 多用户
└─ 但保持向后兼容
└─ 如果只提供密码,自动使用 'default' 用户
Q2: 我的 Redis 是哪个版本?
查看方法:
kubectl exec -it user-redis-0 -n juwan -c user-redis -- redis-cli -v
# 或
kubectl exec -it user-redis-0 -n juwan -c user-redis -- redis-server --version
你的环境:
Redis 7.0.12 (quay.io/opstree/redis:v7.0.12)
✅ 支持 ACL
✅ 用户名: default
Q3: 如何创建自定义用户?
场景: 为不同应用创建独立的用户账号
创建只读用户
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER readonly on \
'>readonly_password' \
~* \
+@read -@write -@dangerous
验证:
# 使用新用户登录
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli --user readonly --pass readonly_password GET somekey
# 尝试写操作(应该失败)
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli --user readonly --pass readonly_password SET somekey value
# (error) NOPERM User has no permissions to run the 'set' command
创建应用专用用户
# 只能访问 app:* 开头的 key
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER app_user on \
'>app_password' \
~app:* \
+@all
保存 ACL 配置
# 持久化到配置文件
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SAVE
⚠️ 注意: 在 Kubernetes 环境中,Pod 重启可能丢失 ACL 配置。建议:
- 使用 ConfigMap 存储 ACL 配置
- 在 StatefulSet 启动脚本中加载配置
- 或使用 Redis Operator 的 ACL 管理功能
Q4: 如何查看所有用户?
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL LIST
Q5: 如何重置用户密码?
重置 default 用户密码
# 1. 生成新密码
NEW_PASSWORD=$(openssl rand -base64 32)
# 2. 在 Redis 中更新
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <old_password> ACL SETUSER default ">$NEW_PASSWORD"
# 3. 更新 Kubernetes Secret
kubectl create secret generic user-redis \
--from-literal=password=$NEW_PASSWORD \
--dry-run=client -o yaml | kubectl apply -f -
# 4. 重启应用 Pods(使新密码生效)
kubectl rollout restart deployment/user-rpc -n juwan
Q6: 客户端报错 "WRONGPASS invalid username-password pair"
可能原因:
-
密码错误
# 验证密码 kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d -
用户名错误
# 检查用户是否存在 kubectl exec -it user-redis-0 -n juwan -c user-redis -- \ redis-cli -a <admin_password> ACL LIST -
用户被禁用
# 启用用户 kubectl exec -it user-redis-0 -n juwan -c user-redis -- \ redis-cli -a <admin_password> ACL SETUSER default on -
网络连接到了错误的 Redis 实例
# 确认连接的主机 kubectl get svc -n juwan | grep redis
Q7: 在 Kubernetes 中如何安全地传递密码?
推荐方案:环境变量 + Secret
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-rpc
spec:
template:
spec:
containers:
- name: user-rpc
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: user-redis
key: password
应用代码:
// 从环境变量读取
password := os.Getenv("REDIS_PASSWORD")
rdb := redis.NewClient(&redis.Options{
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
Password: password,
})
❌ 不推荐:
# 不要在配置文件中硬编码密码
Redis:
Password: "hardcoded_password" # ❌ 不安全
🔒 安全建议
1. 密码强度
检查当前密码强度:
PASSWORD=$(kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d)
echo "密码长度: ${#PASSWORD}"
推荐:
- ✅ 至少 32 字符
- ✅ 包含大小写字母、数字、特殊字符
- ✅ 使用密码生成器:
openssl rand -base64 32
2. 权限最小化
不要所有应用都用 default 超级用户!
# 为不同应用创建独立用户
# 用户 A:只能读写自己的 key
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER app_a on \
'>password_a' ~app_a:* +@all
# 用户 B:只读
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER app_b on \
'>password_b' ~* +@read
3. 禁止危险命令
即使是 default 用户,也应该限制危险命令:
# 禁止 FLUSHALL, FLUSHDB, KEYS 等命令
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER default -flushall -flushdb -keys
# 查看限制后的权限
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL GETUSER default
4. 审计日志
启用 ACL 日志记录:
# 查看最近的 ACL 事件
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL LOG 10
# 输出示例:
# 1) reason: auth
# username: default
# timestamp: 1234567890
5. 定期轮换密码
建议:每 90 天轮换一次
#!/bin/bash
# rotate-redis-password.sh
# 1. 生成新密码
NEW_PWD=$(openssl rand -base64 32)
# 2. 更新 Redis
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a "$OLD_PWD" ACL SETUSER default ">$NEW_PWD"
# 3. 更新 Secret
kubectl create secret generic user-redis \
--from-literal=password="$NEW_PWD" \
-n juwan --dry-run=client -o yaml | kubectl apply -f -
# 4. 滚动重启应用
kubectl rollout restart deployment/user-rpc -n juwan
echo "密码已轮换,新密码: $NEW_PWD"
6. 网络隔离
NetworkPolicy 限制访问:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: redis-access-policy
namespace: juwan
spec:
podSelector:
matchLabels:
app: user-redis
policyTypes:
- Ingress
ingress:
# 只允许 user-rpc 访问
- from:
- podSelector:
matchLabels:
app: user-rpc
ports:
- protocol: TCP
port: 6379
📝 总结
核心发现
| 项目 | 值 |
|---|---|
| 认证模式 | ✅ ACL (Redis 6.0+) |
| 用户名 | default |
| 密码位置 | Secret user-redis in namespace juwan |
| 权限级别 | 超级用户(+@all ~* &*) |
| 是否必须指定用户名 | ❌ 不必须(客户端默认使用 default) |
最佳实践
-
开发/测试环境
# 简单配置即可 Password: <from_secret> # Username 省略 -
生产环境(推荐)
# 为每个应用创建独立用户 Username: app_user Password: <dedicated_password> # 限制权限和 key 范围 -
连接方式
⭐⭐⭐ Sentinel 模式(推荐) - 自动故障转移 - 高可用 - 只需密码(username 可省略)
文档版本: 1.0
创建日期: 2026年2月22日
维护者: DevOps Team
下次审查: 2026年3月22日