redis

redis安全配置

通常情况redis服务器总是放在内网并只允许内部服务器访问的,所以redis生来就不怎么关注安全问题,默认的redis-server配置允许任何访问。但总会有某些情况下,我们需要将redis暴露给外网,这时候就需要给redis-server加上些安全措施,你总不会希望有其他人能访问你的redis-server吧。 1. 设置防火墙 在redis服务器的防火墙(或者iptables)上设置只允许受信任的主机访问redis端口。这是最基本的安全策略。 2. 绑定本地网卡 修改redis.conf文件,添加 bind 127.0.0.1 这样做使得redis-server只接受本地访问。即使有外部主机通过了防火墙,也无法访问redis-server。 注意,bind指令不能绑定除本地网卡ip外的其他ip。也就是说,不能通过bind外部主机的ip来允许外部主机的访问,这只能通过防火墙来实现。 3. 添加密码验证 修改redis.conf文件,添加 requirepass your-password redis的执行效率非常快,外部设备每秒可以测试相当多数量的密码,所以密码要尽量长尽量复杂。 redis的密码是明文存储在redis.conf文件,因此不需要管理员记住。所以可以使用相当长的密码。 密码验证的目标是提供第二层的安全保障。这样当防火墙失效的话,外部主机在没有密码的情况下仍然不能访问redis。 4. 指令重命名 修改redis.conf文件,将一些高危的指令重命名为难以猜出的名字,或者直接重命名为空字符串""来禁用该指令。 # 重命名CONFIG指令 rename-command CONFIG XXX_CONFIG # 禁用FLUSHALL指令 rename-command FLUSHALL "" rename-command FLUSHDB "" # 禁用EVAL指令 rename-command EVAL "" 4.1 处理CONFIG命令改名后phpRedisAdmin无法使用的问题 由于我部署了一个phpRedisAdmin网站来管理redis。phpRedisAdmin需要用到redis的CONFIG命令,所以改名的话,phpRedisAdmin就无法识别了。这时需要修改phpRedisAdmin源码中的/vendor/src/Command/ServerConfig.php文件,让ServerConfig->getId()方法返回改名后的XXX_CONFIG即可。 5. 修改redis运行账户 给系统新建一个无登陆权限的redis用户 useradd -s /sbin/nologin redis 然后修改redis目录的所有者 最后使用sudo -u redis来执行redis命令 sudo -u redis /usr/local/bin/redis-server /etc/redis/redis.conf    

wtf! Redis Crackit,我被黑了 =。=#

先前学redis时候是放在亚马逊的云主机上部署的redis-server,因为亚马逊云的默认安全策略是禁止所有端口的外网访问,要想从外网访问云主机,必须手动在安全策略开启所需端口,这能有效防止无意识的端口暴露。而阿里云的默认安全策略则是允许所有端口的外网访问权限,简直日了狗了,以前从没注意过。 昨天想着要重构下我的betspider爬虫,将一些实时数据放到redis缓存中,所以在阿里云也开了redis-server。redis的默认配置是允许所有远程连接,并且无需密码。 这种情况下:阿里云无安全策略,所有端口暴露给外网;redis-server无需密码登陆、允许远程连接。那么就相当于将我的redis-server暴露在所有人面前,谁都可以访问到。活生生的Redis Crackit肉鸡。 Redis Crackit漏洞: 黑客远程访问redis服务,清空redis数据库后写入他自己的ssh登录公钥,然后将redis数据库备份为/root/.ssh/authotrized_keys。 这就成功地将自己的公钥写入到ssh的authotrized_keys,无需密码直接root登录被黑的主机。大写的SAD.   事情的经过是这样的,应该是今天中午的时候吧大概,正好用phpRedisAdmin查看我的redis-server,发现里面有一个很陌生的key,值为“ssh-ras xxxx”一大串字符串,当时我还没反应过来这是什么玩意,就奇怪了一下怎么莫名其妙多了一个key,然后随手就把他删除了,这个时候,应该就是黑客正在作案的时候,还真巧=。=# 后来,再登录的时候,发下root目录下多了一个奇怪的脚本get.sh,内容是下载xx程序后台执行,然后删除程序文件。想了一会觉得特别不对劲,卧槽难道我被黑了,赶紧history检查历史命令,发现没有什么异常,估计这时候history记录已经被黑客清理干净了,但却忘删get.sh这个脚本文件了。 后来正好看手机短信,发现有条未读的阿里云短信,说我的服务器在荷兰(89.248.162.167)处登录,可能是黑客入侵。what the hell,我居然现在才看到短信!!! 当时想了好一会儿,卧槽怎么回事,怎么会被黑了,赶紧改密码,日了狗了。到底怎么回事。咦,我的redis好像没有做访问控制,可以被所有人访问到呀,是不是redis有漏洞?赶紧百度一下,what the fuck!果然是redis的漏洞,靠!赶紧停redis-server。 处理方法: 修改redis配置文件,打开被注释的bind 127.0.0.1,只允许本地连接。(还可以设置需要账户密码访问redis) 修改阿里云的默认安全策略,禁止所有端口暴露给外网。(这坑爹的阿里云) 其他后续: 现在怕的是get.sh(还有没有已经被黑客抹掉了的其他程序)种到系统中的木马程序。 检查ps -aux,看今天运行的所有进程,果然有一个进程是get.sh下载的程序在运行。 这个进程果然连接着红毛鬼子的服务器呢,89.248.162.146。下载个抓包工具tcpdump看里面有什么猫腻。 额。。。看不懂=。=# 罢了罢了,就这么着吧先。  

docker入门 - 使用docker在单机上搭建redis集群

昨天玩了一下docker,感觉官方Get Started教程里面那个whalesay的例子实在是太渣,没有一点实际用途。解释了image跟container的关系,但完全没有体现container与本地进程的关系。 在实际应用场景上,我感觉docker应该更经常会用在部署nginx、memcache这些无需持久化到本地文件的服务进程上面,一个container就相当于一个进程,随用随起,而且不受本机环境限制。docker应该还可以用在Online Judge这样的在线编程系统上,不用再担心恶意代码搞坏本机系统了。不知道Quantopian这些在线交易策略的后台是不是也用docker给每个用户一个container来跑他们的策略,有点意思嘿嘿。另外docker用来做测试环境也特方便,比如本文要做的redis集群,实际应用肯定是将每个redis-server部署在不同的服务器上,穷酸点的可以部署在不同虚拟机上,但用docker可以很方便的在一台机器起好几个redis-server进程。 1. 下载安装docker 2. 直接去docker hub拉取redis官方镜像 # docker pull redis 使用docker images可以列出当前所有的docker镜像。 docker镜像与容器的实际存储目录一般都在/var/lib/docker下面,关于docker的底层存储结构,这个应该得花大时间才能有所心得了。 3. 从redis镜像启动一个容器 # docker run -d --name redis redis -d表示在后台启动容器,并打印容器ID;--name redis表示给该容器指定一个名字(如果不指定,docker会随机指定一个略文艺的名字=。=#);最后一个redis表示容器所依赖的镜像。 运行成功会打印出该容器的长id号。我们可以使用docker ps命令来检查当前在运行的容器。 docker ps -a 表示打印系统中的所有容器(在运行的,不在运行的)。ps打印出来的数据,CONTAINER ID就是该容器的ID前12位;IMAGE就是容器的镜像;COMMAND就是启动容器后要执行的命令(在容器中),就是在这里启动了容器中的redis;PORTS表示该容器暴露给本机的端口。 检查本机系统的进程。有一个docker daemon进程,顾名思义这是docker的全局守护进程;然后一个redis-server *:6379这个其实就是我们刚刚启动的容器;第二个/user/bin/redis-server 127.0.0.1:6379是我本机原来就有的redis-server(我只是特意开起来做对比的)。所以现在直接敲redis-cli命令,连接的是我本机原来的redis。 4. 连接容器中的redis-server 那么要想连接到容器中的redis呢?我们已经知道了容器中的redis同样适占用了6379端口号,那么容器ip是多少呢?我们可以使用docker inspect命令来检查容器的基本信息。 这个IPAddress就是容器的ip。这样,就可以用redis-cli -h 172.17.0.3 -p 6379来连接我们容器中的redis-server了。 如果你以前用过虚拟机,这时候肯定会觉得容器有点像虚拟机(当然它启动速度比虚拟机要快多了),我们来检查一下本机的ip以及网关。 实际上安装完docker之后,docker就会在本机系统建立一个虚拟网卡docker0,并将这个docker0的ip做为一个网关加到本机路由中,之后docker每启动一个容器就给容器分配一个在该网段下的ip地址。 PS:上面这个例子,我们是通过容器ip:容器内端口号的方式来访问容器服务。但这并不是最好的方式,推荐的做法应该是将一个本机端口映射到容器暴露出来的端口号。然后通过这个本机端口来访问容器服务。 5. 重来,启动一个新的redis容器并绑定本机端口 # docker stop redis # docker run -d --name redis-1 -p 7001:6379 redis 先停止之前运行的redis容器,然后重新从redis镜像中启动一个叫redis-1的容器,第二句中参数-p 7001:6379的意思是将本机的7001端口映射到容器的6379端口。 这是我们再来检查一下进程。 首先显示docker ps,当前在运行的容器只有redis-1(之前的那个redis已经被stop了)。这次的PORTS列有了变化,表示我们将本机7001端口映射到了容器的6379端口。 然后ps -ef|grep docker,这时候除了原有的docker守护进程外,还多了一个docker-proxy进程,并且这个proxy进程就是由守护进程产生的,后面的参数就表示将本机(host)的7001端口映射到容器(container)172.17.0.2:6379上。 然后ps -ef|grep redis,这时的redis-server *:6379就是我们的容器redis-1。 端口映射后,就可以直接使用redis-cli -p 7001,通过本地端口来访问容器了。   PS: 我第一次使用端口映射的时候,提示错误ptables failed - No chain/target/match by that name。好不容易google到一条解决方法,重启docker服务就好了。但原因没有人说的清楚,总之是刚刚安装完的docker与iptables之间的问题。(github issue) # service docker restart 6. 以slave模式启动第二个redis容器 # docker run -d --name redis-2 -p 7002:6379 redis redis-server --slaveof 172.17.0.2 6379 使用-p将该redis-2容器与本机的7002端口绑定;然后在最后跟了redis-server --slaveof 172.17.0.2 6379,这是容器启动后要执行的命令,表示用--slaveof模式启动容器中的redis-server。这样我们就将redis-2容器中的redis-server作为redis-1的从服务启动了,redis-1作为主服务可读可写,redis-2作为从服务实时备份redis-1,但是可读不可写。   PS: 我参考的这篇文章用Docker构建分布式Redis集群在配置redis主从的时候,使用ssh登录到了容器中,并修改了容器内的文件。这好像是并不值得推荐的方法。因为docker的本意应该就是要封装服务,而不希望服务的内部配置被随便修改。所以大部分的docker镜像,都没有集成ssh,没有集成vi等等。容器的基本配置应该事先在Dockerfile中写好,然后生成镜像,在从镜像转换成容器的时候,可以在docker run的命令行参数中添加一些可选的配置,之后,容器的配置就不应该再有变化了。我想这应该是docker的本意。   又PS:redis的主从只能做到实时热备,但无法自动切换,主机挂掉的时候,得手动切换从服务的模式。后来出了redis sentinel,可以用来监控redis集群,做到自动切换主从,但还无法做到主从的ip漂移。所以现在实际应用上,redis集群通常是搭配keepalived来做主从切换的。   参考: https://docs.docker.com/linux/ http://dockone.io/article/180