如何基於 spiped 建立一個安全的 Redis 集羣

       Redis 本身不提供 SSL/TLS 的支持,在需要安全訪問的環境下,推薦使用 spiped 在 Redis 服務器和客戶端建立一個對稱性加密的安全通道。在單機模式下,Redis 只在一個端口下提供服務,這種安全通道很容易建立。但如果使用 Redis 集羣,服務端口則一下拓展到 N*2 個,並且除了服務器到客戶端,還需要建立 Redis 服務器節點之間的安全通道,本文將爲您詳細介紹如何去配製這樣一個安全的 Redis 集羣環境。

Redis 安全性簡介

       Redis 設計的初衷是應用於一個可信任的環境,因此 Redis 本身並沒有在安全性上做更多的實現,而把重點放在了性能和易用性上面。當 Redis 服務運行於一個外網可以訪問的環境下,Redis 的服務端口應該被防火牆禁止訪問,Redis 客戶端可以通過本機的回送地址 127.0.0.1 訪問本機上的 Redis 服務,不足之處是其他機器上的客戶端不能訪問位於本機之外的 Redis 服務。除了使用防火牆外,Redis 還提供了保護模式,其本質是隻監聽在本機回送地址 127.0.0.1 這個網絡接口上的 Redis 訪問,並且這個保護模式是默認打開的。

       無論通過防火牆禁用 Redis 服務端口,還是直接使用 Redis 保護模式,其本質都是隻允許位於同一主機的 Redis 客戶端通過本機回送地址 127.0.0.1 去訪問 Redis 服務,而有些時候我們需要位於不同主機的 Redis 客戶端去訪問同一個 Redis 服務,這時 Redis 服務就不能只綁定在本機回送地址 127.0.0.1 上,而當 Redis 服務運行在一個公網環境下的時候,這就意味着其他主機也可以訪問這個 Redis 服務,正如我們之前說到的,Redis 本身在安全性上並沒有做過多的實現,客戶端到服務端的通信也是不支持 SSL 訪問的,這就存在一個很大的安全漏洞,因此 Redis 官網也推薦在公網或非信任的網絡環境下,需要實現額外的安全配置,比如說使用 SSL 代理,並推薦使用 spiped。

Spiped 簡介及如何用 spiped 去支持 Redis 單機版的安全訪問

       Spiped 是一個專門用來做對稱加密和服務認證的應用,它的工作原理和 SSH 通道有些相似,但並不使用 SSH 協議,並且 spiped 依賴於一個認證雙方共享的安全密鑰來進行通信的對稱加密。接下來我們將演示如何使用 spiped 來實現單機版 Redis 的安全訪問。

  1. 確保 Redis.conf 配置文件中只綁定了 127.0.0.1 網絡接口,並且 Redis 的服務端口爲默認的 6379,啓動單機版 Redis 服務。服務啓動後,可以通過 redis-cli 來驗證服務狀態,直接運行 redis-cli 命令,就會默認連接本機回送地址 127.0.0.1 上端口爲 6379 的服務。

    [root@kvm-010367 opt]# redis-cli

    127.0.0.1:6379> keys *

    (empty list or set)

    我們還可以同時測試下從物理網卡 IP 去連接 Redis 服務,這時連接會報錯,因爲 Redis 並沒有在物理網卡 IP 上綁定服務。

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    Could not connect to Redis at 10.0.15.52:6379: Connection refused

    Could not connect to Redis at 10.0.15.52:6379: Connection refused

  2. 創建 spiped 安全通道共享密鑰,如:

    dd if=/dev/urandom bs=32 count=1 of=/etc/spiped/redis.key

    在執行上述命令後,會生成一個隨機的安全密鑰文件在"/etc/spiped/redis.key"。

  3. 啓動 Redis 服務端 spiped,如:

    spiped -F -d -s [10.0.15.52]:6379 -t [127.0.0.1]:6379 -k /etc/spiped/redis.key &

    這裏 10.0.15.52 是 Redis 服務器的物理網卡地址,這條命令的意思是讓 spiped 進程在源(source -s)IP 爲 10.0.15.52 的網絡接口上的 6379 端口監聽,並將收到的消息用指定的共享密鑰解密(-k 指定步驟 2 生成的共享密鑰文件, -d 標誌爲解密 decrypt),並轉發給目的(target -t)IP 爲 127.0.0.1 網絡接口的 6379 端口,即 Redis 的服務端口。

    在啓動好 spiped 進程後,我們可以再次測試下步驟 1 中的從物理網卡 IP 去連接 Redis 服務:

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    10.0.15.52:6379>

    由於 spiped 進程在物理網卡的 6379 端口上監聽,redis-cli 連接成功,但當我們去執行任何 Redis 命令時,都會失敗,因爲我們發送的命令都會被 spiped 用共享密鑰解密,導致 Redis 服務接收到的命令無法被識別,這是正常的,因爲我們還沒有配置 spiped 安全通道的另外一端。

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    10.0.15.52:6379> keys *

    Error: Protocol error, got "/" as reply type byte

  4. 將步驟 2 生成的共享密鑰文件複製到網絡上的另一臺主機,並在該主機上運行 Redis 客戶端 spiped,如:

    spiped -F -e -s '[127.0.0.1]:6379' -t '[10.0.15.52]:6379' -k /etc/spiped/redis.key

    這裏 10.0.15.52 是 Redis 服務器的物理網卡地址,這條命令的意思是讓 spiped 進程在源(source -s)IP 爲 127.0.0.1 的網絡接口(redis 客戶端本機回送地址)上的 6379 端口監聽,並將收到的消息用指定的共享密鑰加密(-k 指定步驟 2 生成的共享密鑰文件, -e 標誌爲加密 encrypt),並轉發給目的(target -t)IP 爲 10.0.15.52 的 6379 端口,即步驟 3 在 Redis 服務器上開的 spiped 進程的監聽地址。

    在啓動好客戶端 spiped 進程後,我們就可以在另外一臺主機上以安全的方式訪問運行在主機 10.0.15.52 上的 Redis 服務了。

    [root@kvm-010648 opt]# redis-cli

    127.0.0.1:6379> keys *

    (empty list or set)

    雖然我們在 Redis 客戶端主機並沒有運行 Redis 服務,但通過 spiped 我們在客戶端的 127.0.0.1 的 6379 端口虛擬了一個 Redis 服務,並將請求以加密的方式轉發到了真正的 Redis 服務器

    通過建立 spiped 安全通道,我們很好的解決了 Redis 的兩個安全性問題,跨主機之間的 Redis 通信的認證和數據加密,只有擁有共享密鑰的客戶端才能使用在 Redis 服務器在物理網卡上提供的服務,並保證客戶端和服務器端的通信是加密的。

Redi 集羣簡介

       Redis 集羣是在 Redis3.0 之後加入的,它爲 Redis 提供了負載均衡和高可用性。

       負載均衡是通過多個主節點共同存儲數據來實現的,在 Redis 集羣中,數據存儲被劃分成 16384 個分片,假設集羣中的主節點數量爲 N,則每個主節點存儲 16384/N 個分片。在向 Redis 集羣存儲數據時,會根據數據鍵值的 CRC16 值去除以 16384 取餘,並根據這個值去確定這個數據應該存儲在哪一個 Redis 主節點。

       高可用性是通過爲每一個 Redis 主節點配置備份的從節點來實現的,在配置 Redis 集羣的時候,每一個主節點都應該配置至少一個從節點,當主節點出錯的情況下,Redis 集羣會自動升級出錯主節點的備份從節點做主節點,從而保證了 Redis 服務的高可用行。在主節點和它的所有從節點都宕機的情況下,由這個節點負責的存儲分片則變的不可用,這時整個 Redis 集羣將變的不可用。

       Redis 集羣節點與單機版的 Redis 節點略有不同,一個 Redis 集羣節點需要開放兩個服務端口,一個是命令端口,用於 Redis 數據存儲和操作,這點與單節點的 Redis 一樣,另外一個是集羣總線端口,用於集羣狀態的管理,這個端口永遠是節點的命令端口+10000,在配置 Redis 集羣的時候只需要指定集羣節點的命令端口,集羣總線端口將自動生成,如命令端口爲 6379,則集羣總線端口爲 16379,在配置的集羣的時候需要保證這兩個端口都沒有被佔用,並能夠被其他集羣節點訪問。

       當我們使用 Redis 集羣的時候,我們需要的是它的負載均衡和高可用性,這也要求集羣中的 Redis 節點位於不同的主機,也就是說 Redis 集羣節點的命令端口和總線端口都必須綁定到物理網卡 IP 上,這樣節點才能被其他 Redis 集羣節點訪問,組成 Redis 集羣。而當我們部署一個 Redis 集羣的時候,在特殊的網絡環境下,我們往往需要客戶端到集羣節點,集羣節點之間的數據通信是加密的,並且只有信任的客戶端才能訪問 Redis 服務,使用 spiped 同樣能很好的解決這個問題,與單節點不同的是,因爲涉及到多個節點,並且每個節點的服務端口數量是 2,我們需要開更多的 spiped 安全通道,接下來本文將爲您介紹如何配置一個這樣安全的 Redis 集羣。

如何用 spiped 建立一個安全的 Redis 集羣

在配置一個工作的 Redis 集羣的時,要求最少主節點的數量是 3,與 zookeeper 集羣的最低節點數量類似,這裏就不再多說。而要保證集羣的高可用性,我們需要爲每個主節點配置至少一個從節點,也就是說一個工作的 Redis 集羣,至少需要 6 個節點,3 個主節點,3 個從節點,拓撲結構如下圖 1,接下來將爲您演示如何結合 spiped 和 Redis 來創建一個這樣拓撲結構的安全集羣。

                                   

                                                                                    圖 1.Redis 集羣拓撲

  1. 準備三臺物理機或虛擬機,在每臺物理機上準備兩個 Redis 集羣節點配置文件(每個配置文件需要在不同的目錄),每個節點的配置文件應包含至少以下配置:

    bind 127.0.0.1

    port 7000

    cluster-enabled yes

    cluster-config-file nodes.conf

    這裏面的 port 值根圖 1 的拓撲結構一致,在 Host1 爲 7000 7005, Host2 爲 7001 7003,Host3 爲 7002 7004。

  2. 分別在三個主機上用步驟 1 創建的配置文件,起兩個 Redis 集羣節點服務。
  3. 在主機 1 上面我們需要創建 4 個 Redis 服務端安全通道,分別綁定主機 1 上兩個 Redis 節點的命定端口和集羣總線端口。

    spiped -F -d -s [REDIS_HOST1_IP]:7000 -t [127.0.0.1]:7000 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:17000 -t [127.0.0.1]:17000 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:7005 -t [127.0.0.1]:7005 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:17005 -t [127.0.0.1]:17005 -k /etc/spiped/redis.key &

    同時主機 1 還需要訪問主機 2 和主機 3 上面的命令端口和集羣總線端口,進行主從節點的數據備份和集羣狀態的管理,因此我們還需爲主機 2 和主機 3 分別配置 4 個 Redis 客戶端安全通道。

    用於連接主機 2 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17001 -t [REDIS_HOST2_IP]:17001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17003 -t [REDIS_HOST2_IP]:17003 -k /etc/spiped/redis.key &

    用於連接主機 3 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17002 -t [REDIS_HOST3_IP]:17002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17004 -t [REDIS_HOST3_IP]:17004 -k /etc/spiped/redis.key &

  4. 配置主機 2 上的 spiped 安全通道

    主機 2 上的 Redis 服務端安全通道:

    spiped -F -d -s [REDIS_HOST2_IP]:7001 -t [127.0.0.1]:7001 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:17001 -t [127.0.0.1]:17001 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:17003 -t [127.0.0.1]:17003 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:7003 -t [127.0.0.1]:7003 -k /etc/spiped/redis.key &

    用於連接主機 1 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17000 -t [REDIS_HOST1_IP]:17000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17005 -t [REDIS_HOST1_IP]:17005 -k /etc/spiped/redis.key &

    用於連接主機 3 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17002 -t [REDIS_HOST3_IP]:17002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17004 -t [REDIS_HOST3_IP]:17004 -k /etc/spiped/redis.key &

  5. 配置主機 3 上的 spiped 安全通道。

    主機 3 上的 Redis 服務端安全通道:

    spiped -F -d -s [REDIS_HOST3_IP]:7002 -t [127.0.0.1]:7002 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:17002 -t [127.0.0.1]:17002 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:7004 -t [127.0.0.1]:7004 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:17004 -t [127.0.0.1]:17004 -k /etc/spiped/redis.key &

    用於連接主機 1 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17000 -t [REDIS_HOST1_IP]:17000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17005 -t [REDIS_HOST1_IP]:17005 -k /etc/spiped/redis.key &

    用於連接主機 2 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17001 -t [REDIS_HOST2_IP]:17001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17003 -t [REDIS_HOST2_IP]:17003 -k /etc/spiped/redis.key &

  6. 在全部三臺主機上配置好 spiped 安全通道後,我們需要在主機 1(或任意一臺主機)上運行 Reids 集羣配置腳本:

    <path_to_redis_script_dir>/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

    Redis 目前只提供 ruby 集羣配置腳本,你需要在運行前確保集羣配置腳本已經安裝,在配置過程中,腳本會自動分配主從節點,我們只需確定分配的默認拓撲是我們在圖 1 所指定的並接受默認配置就可以了。

    在集羣配置腳本完成後,我們可以通過 redis-cli 檢查集羣的狀態:

    [root@kvm-010651 ~]# redis-cli -p 7000

    127.0.0.1:7000> cluster nodes

    43eda54b2ccfc21e166fbb891c0dc3bd1584d702 127.0.0.1:7001 master - 0 1508990608117 2 connected 5461-10922

    80924aee1c579ace330140d8b8d856e16e91fb60 127.0.0.1:7005 slave 1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 1508921602233 1508921601773 3 connected

    a3c975465ac7d1db35c10652b6f68231fb3035a0 127.0.0.1:7003 slave fa0752ec076871dab5d414158baa63b2dae50f98 1508332039016 1508332036453 4 connected

    1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 127.0.0.1:7002 master - 0 0 3 connected 10923-16383

    284e6389c43306ea1dc99884d5c37a6d69105ae4 127.0.0.1:7004 slave 43eda54b2ccfc21e166fbb891c0dc3bd1584d702 0 1508990608578 5 connected

    fa0752ec076871dab5d414158baa63b2dae50f98 127.0.0.1:7000 myself,master - 1508921602234 1508921600970 1 connected 0-546

  7. 在 Redis 集羣配置完成後,我們還需要在允許連接 Redis 集羣服務的客戶端上創建 6 個 spiped 安全通道,用來連接 Redis 集羣 6 個節點的命令端口:

    用於連接主機 1 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    用於連接主機 2 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    用於連接主機 3 的客戶端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

  8. 在配置好客戶端安全通道後,我們同樣可以在客戶端運行 redis-cli 去測試客戶端到 Redis 集羣的連接,我們將會看到和 Redis 集羣節點上運行 redis-cli 一樣的結果:

    [root@kvm-010656 ~]# redis-cli -p 7000

    127.0.0.1:7000> cluster nodes

    43eda54b2ccfc21e166fbb891c0dc3bd1584d702 127.0.0.1:7001 master - 0 1508990608117 2 connected 5461-10922

    80924aee1c579ace330140d8b8d856e16e91fb60 127.0.0.1:7005 slave 1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 1508921602233 1508921601773 3 connected

    a3c975465ac7d1db35c10652b6f68231fb3035a0 127.0.0.1:7003 slave fa0752ec076871dab5d414158baa63b2dae50f98 1508332039016 1508332036453 4 connected

    1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 127.0.0.1:7002 master - 0 0 3 connected 10923-16383

    284e6389c43306ea1dc99884d5c37a6d69105ae4 127.0.0.1:7004 slave 43eda54b2ccfc21e166fbb891c0dc3bd1584d702 0 1508990608578 5 connected

    fa0752ec076871dab5d414158baa63b2dae50f98 127.0.0.1:7000 myself,master - 1508921602234 1508921600970 1 connected 0-546

  9. 這樣我們就配好了一個安全的 Redis 集羣,以及它的客戶端。接下來我們可以爲每一個 spiped 進程配置一個可自動恢復的 Linux 服務,來確保 spiped 進程被 kill 或退出的時候,可以自動重啓。Spiped 進程做成可恢復的 Linux 服務很重要,因爲如果服務端 spiped 進程退出,則對應的 Redis 節點將會變的不可用,如果客戶端 spiped 進程退出,客戶端則無法連接對應的服務端口。每個 Linux 系統的服務配置率有不同,本文將不在舉例。

小結

       Redis 集羣爲我們提供了一定的負載均衡與高可用性,在安全性要求比較高的網絡環境下,通過合理的創建 spiped 安全通道,我們可以很方便的部署一個安全的 Redis 集羣。

參考資源

本文僅代表作者個人觀點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章