Files
juwan-backend/docs/redis-username-discovery.md
T

1069 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Redis 用户名查找和认证配置指南
**问题日期:** 2026年2月22日
**环境:** juwan namespace
**Redis 版本:** 7.0.12
**部署模式:** RedisReplication (OpsTree Operator)
---
## 📋 目录
1. [问题背景](#问题背景)
2. [Redis 认证机制演进](#redis-认证机制演进)
3. [诊断过程](#诊断过程)
4. [用户名发现结果](#用户名发现结果)
5. [各语言连接配置](#各语言连接配置)
6. [常见问题解答](#常见问题解答)
7. [安全建议](#安全建议)
---
## 🎯 问题背景
### 问题描述
在配置应用连接 Redis 时,发现只有密码信息(存储在 Kubernetes Secret `user-redis` 中),但不清楚:
- Redis 是否需要用户名?
- 如果需要,用户名是什么?
- 如何查找 Redis 的用户名配置?
### 初始已知信息
```yaml
Secret: user-redis
Namespace: juwan
Key: password
Value: (base64 编码的密码)
```
### 疑问
- 使用 RedisInsight 等管理工具时,Username 字段应该填什么?
- 应用代码中是否需要配置 Username?
- 不同 Redis 版本的认证方式是否有差异?
---
## 📚 Redis 认证机制演进
### Redis 6.0 之前:传统密码认证
**特点:**
- ❌ 不支持多用户
- ✅ 只需配置一个全局密码
- 🔧 配置项:`requirepass`
- 👤 隐式用户名:`default`(客户端不需要指定)
**配置示例:**
```conf
# redis.conf
requirepass mypassword
```
**连接方式:**
```bash
# 只需要密码
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 容器的正确名称,以便执行命令
**命令:**
```bash
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` 容器**
**关键信息:**
```yaml
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 中提取密码,用于认证
**命令:**
```bash
kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d
```
**输出:**
```
<密码内容> # 实际密码已隐藏
```
**说明:**
- Secret 中的数据以 base64 编码存储
- 需要解码才能得到明文密码
- `base64 -d` 在 Linux/Mac 上;Windows PowerShell 需要用其他方法
**Windows PowerShell 解码方法:**
```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 以及有哪些用户
**命令:**
```bash
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
```
**命令解析:**
```bash
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:使用密码(不指定用户名)**
```bash
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:显式指定用户名**
```bash
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli --user default --pass <password> PING
```
**预期输出:**
```
PONG
```
**说明:显式指定 default 用户也可以正常连接**
---
**方法 3:测试错误的用户名**
```bash
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` 用户的详细权限配置
**命令:**
```bash
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 配置
```yaml
认证模式: 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 客户端的默认行为
1. **向后兼容**
```
Redis 6.0+ 保持了与旧版本的兼容性
当客户端只提供密码时,自动使用 'default' 用户
```
2. **客户端实现**
```go
// go-redis 内部逻辑(伪代码)
if password != "" && username == "" {
username = "default" // 自动补全
}
```
3. **AUTH 命令演进**
```bash
# Redis 5.x 及之前
AUTH password # 只有密码
# Redis 6.0+(向后兼容)
AUTH password # 等价于 AUTH default password
AUTH username password # 新格式
```
#### 何时需要显式指定用户名?
| 场景 | 是否需要 | 原因 |
|-----|---------|------|
| 使用 `default` 用户 | ❌ 不需要 | 客户端自动使用 |
| 创建了自定义用户 | ✅ 需要 | 必须明确指定 |
| 多应用共享 Redis | ✅ 推荐 | 权限隔离 |
| 审计需求 | ✅ 推荐 | 区分访问来源 |
| 管理工具连接 | ⚠️ 可选 | 有些工具要求填写 |
---
## 💻 各语言连接配置
### Go (go-redis)
#### 方式 1:只用密码(推荐)
```go
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:显式指定用户名
```go
// 显式指定 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 模式(生产推荐)
```go
// 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 框架
#### 配置文件
```yaml
# app/users/rpc/etc/pb.yaml
Redis:
Type: sentinel
MasterName: mymaster
SentinelAddrs:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Pass: ${REDIS_PASSWORD} # 只需密码,不需要用户名
```
#### 如果需要自定义用户
```yaml
Redis:
Type: sentinel
MasterName: mymaster
SentinelAddrs:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Username: default # 可选:显式指定
Pass: ${REDIS_PASSWORD}
```
---
### Python (redis-py)
#### 只用密码
```python
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+
```python
# 显式指定 username
r = redis.Redis(
host='user-redis-master.juwan.svc.cluster.local',
port=6379,
username='default', # 明确指定
password=os.getenv('REDIS_PASSWORD'),
db=0
)
```
#### Sentinel 模式
```python
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(只用密码)
```yaml
spring:
redis:
password: ${REDIS_PASSWORD} # 只需密码
sentinel:
master: mymaster
nodes:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
```
#### 显式指定用户名(Spring Boot 2.6+
```yaml
spring:
redis:
username: default # 可选
password: ${REDIS_PASSWORD}
sentinel:
master: mymaster
nodes:
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
```
#### Java 代码(Jedis
```java
// 只用密码
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)
#### 只用密码
```javascript
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+
```javascript
// 显式指定 username
const redis = new Redis({
host: 'user-redis-master.juwan.svc.cluster.local',
port: 6379,
username: 'default', // 明确指定
password: process.env.REDIS_PASSWORD,
});
```
#### Sentinel 模式
```javascript
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 命令行
#### 只用密码
```bash
# 方式 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
```
#### 显式指定用户名
```bash
# 方式 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 运行:**
```bash
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
**连接配置:**
```json
{
"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 是哪个版本?
**查看方法:**
```bash
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: 如何创建自定义用户?
**场景:** 为不同应用创建独立的用户账号
#### 创建只读用户
```bash
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SETUSER readonly on \
'>readonly_password' \
~* \
+@read -@write -@dangerous
```
**验证:**
```bash
# 使用新用户登录
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
```
#### 创建应用专用用户
```bash
# 只能访问 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 配置
```bash
# 持久化到配置文件
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL SAVE
```
⚠️ **注意:** 在 Kubernetes 环境中,Pod 重启可能丢失 ACL 配置。建议:
1. 使用 ConfigMap 存储 ACL 配置
2. 在 StatefulSet 启动脚本中加载配置
3. 或使用 Redis Operator 的 ACL 管理功能
### Q4: 如何查看所有用户?
```bash
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <password> ACL LIST
```
### Q5: 如何重置用户密码?
#### 重置 default 用户密码
```bash
# 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"
**可能原因:**
1. **密码错误**
```bash
# 验证密码
kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d
```
2. **用户名错误**
```bash
# 检查用户是否存在
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <admin_password> ACL LIST
```
3. **用户被禁用**
```bash
# 启用用户
kubectl exec -it user-redis-0 -n juwan -c user-redis -- \
redis-cli -a <admin_password> ACL SETUSER default on
```
4. **网络连接到了错误的 Redis 实例**
```bash
# 确认连接的主机
kubectl get svc -n juwan | grep redis
```
### Q7: 在 Kubernetes 中如何安全地传递密码?
**推荐方案:环境变量 + Secret**
```yaml
# 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
```
**应用代码:**
```go
// 从环境变量读取
password := os.Getenv("REDIS_PASSWORD")
rdb := redis.NewClient(&redis.Options{
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
Password: password,
})
```
**❌ 不推荐:**
```yaml
# 不要在配置文件中硬编码密码
Redis:
Password: "hardcoded_password" # ❌ 不安全
```
---
## 🔒 安全建议
### 1. 密码强度
**检查当前密码强度:**
```bash
PASSWORD=$(kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d)
echo "密码长度: ${#PASSWORD}"
```
**推荐:**
- ✅ 至少 32 字符
- ✅ 包含大小写字母、数字、特殊字符
- ✅ 使用密码生成器:`openssl rand -base64 32`
### 2. 权限最小化
**不要所有应用都用 default 超级用户!**
```bash
# 为不同应用创建独立用户
# 用户 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 用户,也应该限制危险命令:**
```bash
# 禁止 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 日志记录:**
```bash
# 查看最近的 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 天轮换一次**
```bash
#!/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 限制访问:**
```yaml
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) |
### 最佳实践
1. **开发/测试环境**
```yaml
# 简单配置即可
Password: <from_secret>
# Username 省略
```
2. **生产环境(推荐)**
```yaml
# 为每个应用创建独立用户
Username: app_user
Password: <dedicated_password>
# 限制权限和 key 范围
```
3. **连接方式**
```
⭐⭐⭐ Sentinel 模式(推荐)
- 自动故障转移
- 高可用
- 只需密码(username 可省略)
```
---
**文档版本:** 1.0
**创建日期:** 2026年2月22日
**维护者:** DevOps Team
**下次审查:** 2026年3月22日