ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Redis 密码设置全攻略:requirepass、Docker 与主从联动避坑指南

Redis 密码设置全攻略:requirepass、Docker 与主从联动避坑指南

Redis 默认启动就是裸奔,无密码、无认证,绑在公网上基本等于把数据直接送给别人扫端口的脚本。但很多人觉得“我这是内网环境,没事”,结果内网横向渗透一来,首当其冲遭殃的就是这类无防护 Redis 实例。关于 Redis 设置密码,最常见的是配置文件、docker 容器、命令行这 3 种场景,覆盖了从传统部署到容器化的主流落地方式。这篇文章不打算只贴几个命令,我会把 requirepass 的机制、为什么有的改法重启就失效、主从和哨兵怎么联动,以及实战里踩过的坑全部分享出来。适合维护 Redis 的运维、做后端开发的人,也包括刚接触 Docker 部署、对客户端认证报错一头雾水的同学。

1. Redis 密码机制与原理解析

1.1 requirepass 到底做了什么

Redis 的密码认证,本质是启动时或运行中设置一个requirepass配置项,客户端每次连接后必须先执行AUTH <密码>,认证通过才能继续发命令。没有认证的会话执行任何读写命令,Redis 都会直接返回NOAUTH Authentication required.的错误。设计上很简单,没有用户概念,只要密码对,进来就是超级管理员,能执行FLUSHALL、CONFIG SET、DEBUG这些危险命令。

这里要提一个容易混淆的点:requirepass是 Redis 5.x 及以前主推的密码方案,到了 Redis 6.0 之后引入了 ACL(Access Control List),可以创建多个用户、分配不同命令权限和 key 权限。但从底层实现看,requirepass本质上是给默认用户default设置密码。也就是说,你配置了requirepass,就相当于给 ACL 里的 default 用户启用了密码认证。理解了这层关系,后面看 Redis 6.0+ 的报错信息就不会懵了。

很多人误以为设置密码就能保证数据安全,这个认知有偏差。requirepass是身份认证,不是传输加密。客户端和 Redis 之间的交互如果走裸 TCP,密码和数据一样是明文在网络里跑的。抓包工具一抓,密码就暴露了。所以在能上 TLS 的环境尽量上 TLS,或者至少保证 Redis 只监听内网、不直接暴露公网,这是后话,但意识要先建立起来。

1.2 三个总结:认证流程、密码存储和生效时机

认证流程可以用一句话概括:连接 Redis 后,未认证状态下只能执行AUTH、HELLO、QUIT这类有限命令,其余命令全部被拒;认证成功后,当前连接一直保持有效,直到连接断开或管理员通过CONFIG SET requirepass ""清空密码。

密码在 Redis 配置文件和内存中并不是明文裸存,配置文件里你写的是明文,但 Redis 在内部会以哈希形式记录。所以CONFIG GET requirepass返回的其实是配置值本身,特殊情况会看到空字符串,但不要指望这个命令能看到哈希。这个特性在排查问题时很有用:能查到值,说明配置生效了,但注意不要在公共场合打印它。

生效时机有两个关键差别:改配置文件叫“永久生效但需要重启”,用CONFIG SET改叫“立即生效但可能重启丢失”。很多人一开始没搞明白这两者的关系,导致出现“明明改了密码,重启后连不上了”或者“重启后密码又没了”这两种极端。第 2、3、4 部分我会把每种场景怎么规避都说清楚。

2. 场景一:配置文件设置密码,最适合生产环境

2.1 redis.conf 里怎么改才不出错

生产环境用配置文件管理 Redis 参数是推荐做法,好处是变更留痕、可回滚、可以配合配置管理工具下发。第一步是找到 redis.conf。Linux 上用包管理器安装的 Redis,配置文件通常在这几个位置:

  • /etc/redis/redis.conf:RedHat/CentOS 系、Debian/Ubuntu 系的包管理器常用路径
  • /opt/redis/redis.conf:源码编译安装常见路径
  • /usr/local/etc/redis.conf:macOS 或源码编译另一种常见路径

不确定的话,用redis-cli CONFIG GET dir看工作目录,再配合ps -ef | grep redis看启动命令里是否带了具体配置文件路径。很多细节问题都出在“我改了文件,但 Redis 根本没加载它”。

找到文件后先备份:

cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date +%Y%m%d)

然后用编辑器打开,搜requirepass。默认情况你会看到这一行是被注释掉的:

# requirepass foobared

改成下面这样:

requirepass "MyRedis@2024#Secure"

三个容易出问题的地方要重点说明:

密码里如果包含特殊字符,比如$、"、#、空格,要么用双引号包起来,要么用单引号,但配置文件里更推荐双引号。不要图省事直接写裸字符串,否则遇到#时 Redis 可能把后面内容当成注释,遇到空格时配置解析直接报错。

缩进不是问题,Redis 配置解析不要求顶格,但不要用 Tab,有些编辑器混用了会影响其他工具读取。

如果 Redis 配置文件中同时存在多个requirepass行,Redis 默认采用最后一个配置值,但这种情况很容易给自己埋坑,改完务必用CONFIG GET requirepass确认当前实际值。

2.2 重启服务与连接验证

配置文件改完必须重启 Redis 进程才生效。不同安装方式的重启命令不一样,用 systemd 管理的常见方式:

systemctl restart redis

如果重启后客户端连不上,先检查启动日志有没有配置解析错误。Redis 配置出错通常会在日志里直接打出Bad directive or wrong number of arguments。不要无脑反复重启,排查了日志再动手。

验证密码是否生效,最直接的方式是走一遍交互流程:

redis-cli 127.0.0.1:6379> PING (error) NOAUTH Authentication required. 127.0.0.1:6379> AUTH MyRedis@2024#Secure OK 127.0.0.1:6379> PING PONG

你看到NOAUTH就说明密码已经生效了。生产环境也常用一行命令验证:

redis-cli -a 'MyRedis@2024#Secure' --no-auth-warning PING

-a是密码参数,--no-auth-warning是去掉“Using a password with '-a' is insecure”的警告提示。但我必须提醒你:-a方式会在 shell 历史记录里留下明文密码,如果这台机器有多个开发共管,很容易通过.bash_history泄露。我的习惯是生产环境用交互模式输入AUTH,或者在脚本里通过环境变量读取密码,而不是直接写命令参数。

配置文件方式是三种场景里最稳的,也是主从、哨兵、集群方案的基础,因为在进程重启、机器重启后配置依然有效,不需要额外干预。

3. 场景二:Docker 容器设置密码,镜像参数和配置挂载别混用

3.1 docker run 直接传参,最快速但不建议用于生产

如果你只是本地跑个测试容器,或者临时起一个 Redis 给联调用,最省事的方式是直接用官方镜像启动时传 Redis 参数。官方redis镜像的默认入口是redis-server,所以docker run里镜像名之后的内容都会追加给redis-server进程。命令类似:

docker run -d \ --name redis-server \ -p 6379:6379 \ -v redis-data:/data \ redis:7 \ redis-server --requirepass "MyRedis@2024#Secure"

使用-v redis-data:/data是为了数据持久化,不带的话容器一删数据就全没了。启动后验证:

docker exec -it redis-server redis-cli -a 'MyRedis@2024#Secure' --no-auth-warning PING

这里有个细节:进入容器执行redis-cli时,不要省略-a或AUTH,因为容器内的redis-cli连接的是本机 6379 端口,同样受密码保护。很多第一次用 Docker 跑 Redis 的人在这里被卡住,报NOAUTH后第一反应是“我明明设置了密码”,实际上只是还没认证。

这种方式简单,但有两个明显的坑:一是启动命令里包含明文密码,docker inspect这个容器能看到完整 command;二是容器重建时如果忘了带同样的--requirepass参数,密码会静默消失。所以我的结论是:临时环境可以用,生产环境最好往下看挂载配置文件的方案。

3.2 docker-compose 挂载配置文件,推荐的生产用法

生产环境用 Docker 部署 Redis,我更倾向于把 redis.conf 作为配置唯一来源,用 docker-compose 或 Kubernetes 的方式挂载进去。这样可以复用前面场景一里的配置文件管理流程,也可以配合 Git 做版本化。

先准备一份 redis.conf,红框里至少要包含:

requirepass "MyRedis@2024#Secure"

如果有主从需求,还要把masterauth也写上,这个后面第 5 部分会讲。然后用 docker-compose 启动:

services: redis: image: redis:7 container_name: redis-server ports: - "6379:6379" volumes: - redis-data:/data - ./redis.conf:/etc/redis/redis.conf:ro command: redis-server /etc/redis/redis.conf volumes: redis-data:

关键点在于最后一行command: redis-server /etc/redis/redis.conf。官方镜像默认启动命令是redis-server,不会自动读取挂载到/etc/redis/redis.conf的文件。如果你只写volumes挂载了配置文件,但没指定command,那这份配置文件根本不会生效,密码自然也不会设置。

启动后同样验证:

docker compose ps docker exec -it redis-server redis-cli -a 'MyRedis@2024#Secure' --no-auth-warning PING

在 compose 文件里用环境变量代替明文密码,怎么做?官方镜像本身不直接读取REDIS_PASSWORD环境变量,它只认 redis-server 的参数。常见的做法是把启动命令做成 shell 形式,或者用一个自定义 entrypoint 去读环境变量生成配置。简单一点的方案是不要写在 compose 里,而是把 redis.conf 放到一个只有部署账号可读的路径,通过权限保护配置。这个思路在 Kubernetes 里对应 Secret,在裸机部署里对应文件权限。

Docker 容器里设置密码还有一个经常被问的问题:修改已有容器怎么改密码?答案是不要试图去改运行中容器的启动参数,容器是一次性的。正确操作:要么进入容器用CONFIG SET临时改,但重建容器会丢;要么把 redis.conf 改好后重建容器挂载进去。容器这种不可变基础设施的设计,决定了“修改配置”通常等于“用新配置起新容器”。

4. 场景三:命令行动态设置密码,调试和应急必会

4.1 CONFIG SET 实时生效,验证与立即使用

运维排查问题时,经常需要在不重启进程的前提下临时设置密码。比如 Redis 已经跑在公网上,扫描器已经开始爆破了,这时候最快的处置方式是直接趁攻击间隙设置密码。命令行方式就是为此准备的。

先连上 Redis:

redis-cli 127.0.0.1:6379> CONFIG SET requirepass "MyRedis@2024#Secure" OK

设置成功后,当前会话会立刻处于“待认证”状态。很多人紧接着直接发命令,先收到NOAUTH报错,然后慌了,以为设置失败。这是误解:CONFIG SET本身执行成功了,只是后面的所有命令都需要先认证。所以你要做的是立刻认证:

127.0.0.1:6379> AUTH MyRedis@2024#Secure OK 127.0.0.1:6379> PING PONG

当前这个会话认证完就能继续操作了。其他已连接的客户端不会自动断开,但它们下一条命令会被 Redis 拒绝并要求认证。如果连接池里的连接没有重新认证,应用层会报认证错误,这种状况在客户端侧通常表现为“突然所有请求都失败了”,其实是还没有处理新密码。

命令行方式还有一个使用场景:清空密码。比如你想临时取消认证,或者脚本在自动化编排里需要先去掉密码再改配置,执行:

CONFIG SET requirepass ""

这样 Redis 又回到无密码状态。注意这个操作一旦执行,任何新连接都不需要认证,一定要确认当前是受控环境再做。

4.2 CONFIG REWRITE 能持久化,但不是所有环境都行

命令行方式最大的问题就是“重启即失”。Redis 把运行中的配置项用CONFIG SET改掉后,如果不做持久化,进程一重启配置就回到配置文件里的初始值。那如何把运行中配置写回文件?

127.0.0.1:6379> CONFIG REWRITE OK

CONFIG REWRITE会把当前运行配置中与 redis.conf 不一致的项,自动重写到配置文件。但要注意几个前提:

  • Redis 启动时必须指定了配置文件路径,如果启动时用redis-server不带路径,Redis 会认为没有可重写的配置源,REWRITE 会报错。
  • 配置文件所在目录和文件必须有写权限。用 systemd 启动、配置文件在/etc/redis/时,如果 Redis 以 redis 用户运行,但目录权限是 root 所有,REWRITE 会提示Permission denied。
  • CONFIG REWRITE不会删除文件里原有的注释,它只是把运行值和文件内容合并,这一点对日常看配置的人来说反而是好事,保留了注释方便阅读。

基于这些特点,我建议的用法是:命令行设置密码适合应急和调试,最终落地还是要把密码同步更新到配置文件里。如果你是在 Docker 容器里用命令行动态设置的密码,容器销毁后配置必然丢失,除非你把容器文件系统做成了持久卷,但即便如此,改成配置文件挂载仍然是更明确的方案。

5. 密码设置后的影响范围与联动配置

5.1 主从复制、哨兵和客户端的连带修改

设置密码从来不是“Redis 自己设置完成”这么简单。它会产生一系列连锁影响,最常见的就是正在运行的主从复制突然中断。

主从架构下,如果 master 配置了requirepass,replica 实例连接 master 时必须提供密码。replica 侧并不是通过AUTH命令手动输入,而是在配置文件里写masterauth参数:

masterauth "MyRedis@2024#Secure"

如果你只给 master 设置了 requirepass,却忘了在下级 replica 和哨兵节点上配置 masterauth,复制链路会立刻断开,日志里反复出现MASTER <-> REPLICA sync started和Unable to AUTH master之类的错误。很多人查了半天,最后发现是同步节点缺一个 masterauth。

哨兵模式同理,Sentinel 需要连接 master 和 replica 来做故障转移。如果 Redis 实例设置了 requirepass,Sentinel 配置文件里必须加上:

sentinel auth-pass mymaster MyRedis@2024#Secure

mymaster是你在 Sentinel 配置里给主节点起的名字。这个如果不配,Sentinel 能发现 master,但无法执行AUTH,后面的故障转移操作就会失败。

客户端侧的影响更直接。原来不需要认证的客户端连接,现在必须支持密码。不同语言的客户端配置方式不一样,但思路一致:在连接参数里加上 password。比如常见的连接字符串:

redis://:MyRedis@2024#Secure@127.0.0.1:6379/0

注意连接字符串里的密码放在:和@之间,密码里如果有特殊字符,需要做 URL 编码。很多应用升级密码后连不上,排查半天发现是连接串里的特殊字符没转义。

5.2 密码变更对运维监控和备份恢复的影响

Redis 密码设置完毕,受影响的不只是线上业务,还有运维体系里的一堆工具。定时备份脚本如果是用redis-cli -a或redis-cli -p直接连的,密码一变,备份就静默失败或告警刷屏。监控系统比如基于INFO命令采集指标的,同样需要更新认证配置。建议密码变更流程里加一步:全盘搜索仓库里所有 Redis 连接地址、CLI 命令、客户端配置,确认没有遗漏。

备份恢复场景也要注意。从 RDB 或 AOF 恢复数据时,Redis 会先完成数据加载,再进入正常服务状态。恢复过程中如果还设置了同样密码,客户端在加载阶段的连接会被拒绝,但这个是正常现象。要注意的是备份工具如果从其他节点拉数据,恢复节点可能需要 masterauth 才能建立复制关系。

集群模式(Cluster)影响范围更大,每个节点都要统一配置 requirepass,客户端连接时同样要带密码。官方 Redis Cluster 节点之间通信,如果 ACL 下每个节点都需要认证,还要配置masterauth,否则分片之间会出现节点握手成功但数据迁移失败的情况。我见过太多人把单机密码设置成后高枕无忧,结果集群一扩容,新节点始终cluster-state:fail,查到最后全是认证问题。

5.3 ACL 是比 requirepass 更精细的加分项

如果 Redis 版本允许(6.0+),我非常推荐在密码之外使用 ACL 做用户细分。比如给只读业务创建一个专用账号:

ACL SETUSER readonly-user on >'readonly-pass' ~readonly::* +@readonly +PING +AUTH

这个命令创建了一个名为readonly-user的用户,密码是readonly-pass,只能访问匹配readonly::*模式的 key,只能执行只读命令。这样即便密码被泄露,攻击者也没办法做FLUSHALL这种破坏操作。

ACL 和 requirepass 的关系要理解清楚:requirepass 相当于给 default 用户设密码,ACL 是给每个用户设密码和权限。两者可以共存,不代表设置了 ACL 就不需要masterauth,因为主从节点之间复制连接使用的也是特定用户的认证,通常用 default 用户。

6. 常见问题与排查技巧实录

6.1 密码正确却提示 NOAUTH 或 ERR AUTH

我收到过很多次这类求助:“我用 redis-cli 测试密码是对的,但业务就是连不上。”核心原因大多是连接认证时机不对。Redis 客户端库拿到连接后,不会自动发送AUTH,它需要配置里的 password 字段。如果你只是复制了连接地址、改了端口,忘记同步 password 参数,就必然出现 NOAUTH。

另外ERR AUTH <password> called without any password configured for the default user这个报错很特殊,它出现在你执行AUTH xxx时,但当前 Redis 的 default 用户根本没有启用密码认证。换句话说,你在一个无密码实例上执行 AUTH,无论密码对不对,都会报这个错。排查思路是先用CONFIG GET requirepass确认到底有没有设置密码。

还有个隐蔽点:多个 Redis 实例共用一份启动脚本,脚本里硬编码了密码参数,但你改的是另一个实例的密码,结果连接时拿着 A 实例密码去连 B 实例,自然是认证失败。排查时先确认连的是不是目标实例,用CLIENT INFO或INFO server看一下运行端口和进程信息。

6.2 Docker 容器重启后密码消失、配置文件挂载不生效

这个坑出现的频率极高。容器重启后你发现redis-cli ping不需要密码了,或者用密码连接反而报WRONGPASS,大概率是启动容器时没有把--requirepass给到 redis-server,或者是挂载了 redis.conf 但没有指定command去加载它。

解决思路按步骤来:

  1. 确认容器当前启动命令,用docker inspect redis-server查看Args部分,看是否带--requirepass或redis-server /etc/redis/redis.conf。
  2. 确认挂载的配置文件在容器内是否可见,是否被容器内 Redis 读取。挂载文件时注意文件权限,容器内进程以 redis 用户运行,对挂载配置文件至少要有读权限。
  3. 如果要彻底解决,重新创建容器,把command写清楚。不要试图在运行中的容器上修,容器设计里就没有“动态改配置”的优雅方案。

这里再补充一个细节:用 docker-compose 挂载 redis.conf 时,配置文件内部不要写daemonize yes。在容器里 Redis 前台运行的启动方式是默认的,如果你在配置文件里开了 daemonize,redis-server 会 fork 到后台,容器会因为没有前台进程而直接退出。

6.3 三个容易忽略的运维安全和易用性细节

  • 命令行参数泄露:docker run里直接写--requirepass <明文>,以及redis-cli -a <明文>,都会被ps、docker inspect、shell 历史记录记录下来。如果机器被入侵,密码等同白给。更好的做法是用配置文件或环境变量方案。
  • 密码变更时先改客户端,还是先改服务端?这是一个经典问题。如果先改服务端,旧客户端瞬间全部认证失败,业务会先中断一段时间。如果先改客户端,客户端连的还是无密码实例,等客户端全部就绪再改服务端,才能实现平滑切换。线上变更建议走后者:提前在客户端配置里准备好新密码,然后再更新 Redis 端。
  • CONFIG REWRITE 权限坑:配置文件在/etc/redis/redis.conf,但 Redis 进程没有写权限时,REWRITE 会失败。生产用 systemd 部署,有些发行版把 redis 的ProtectSystem=full打开了,导致 Redis 即使有目录写权限,也无法通过 systemd 限制写入 /etc。这种情况要么改 systemd 配置,要么干脆回到场景一,人工改配置文件后重启。

记住一个实操心法

在这三种 Redis 设置密码的场景里,没有绝对优劣,适用场景完全不同。日常临时调试,命令行是最快的;本地或测试用 Docker,--requirepass参数最省事;生产环境无论是裸机还是容器化,配置文件挂载始终是最可控、最安全的方案。我自己踩过的坑就是 docker-compose 里只挂载了配置,没有重新指定 command,反过来又遇到过在运行中 container 里执行 CONFIG REWRITE,重启后配置全部丢失。从那以后我养成了一个习惯:每次改完密码,立刻CONFIG GET requirepass确认生效值,再做重启测试验证配置能持久。这个验证顺序看着简单,却能省下后面和业务方反复确认的大量时间。Redis 密码设置只是安全第一步,如果后续有余力,建议继续把 ACL、TLS、网络访问控制这些联动项补上,每做一步,你的 Redis 安全性就往前提一层。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进