跳至主要内容

7.7 如何在 Swarm 中傳遞敏感資料

上一章說明了如何在 Swarm 模式中儲存資料,不知道大家有沒有想過,要如何把敏感的資料 ( 例如,資料庫密碼等等 ) 在 Swarm 模式中傳遞呢?

畢竟是跨機器的,直接把敏感資訊在 service 啟動時寫入,也會因為儲存在 bash 的歷史紀錄中而不太安全。

這時候 Docker 就給出了 secret 以及 config 兩種解決方案,如同名字一樣,一個是拿來儲存機密資料,一個則是設定檔,至於要如何使用呢?做做簡單的範例就會了解了。

首先一樣先移除掉上一個小節做示範的 drupal 以及 postgres 服務。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service rm pg drupal
pg
drupal

接著先用 secret 來做示範,首先在機器上隨意建立一個檔案,把它當作裡面放著敏感的資訊。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# echo "I'm secret." >> secret.txt
root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# cat secret.txt
I'm secret.

接著建立一個 secret 的物件。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker secret create my_secret ./secret.txt
j1onanm0d6wkqai2xhsvwhez5
root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker secret list
ID NAME DRIVER CREATED UPDATED
j1on.. my_secret 4 sec... 4 sec...

接著建立一個有 3 個副本的 nginx 服務,並且將 secret 物件注入服務中,在三個節點中都能夠拿到這份敏感資訊。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service create --name nginx --publish 80:80 --replicas 3 --secret my_secret nginx
tk3pgny6w1nclsfqvzfjuvnzn
overall progress: 3 out of 3 tasks
1/3: running [==============================================>]
2/3: running [==============================================>]
3/3: running [==============================================>]
verify: Service converged

接著要如何確認這份 secret 有沒有注入到每一個容器中呢?我們可以直接透過向容器傳遞指令的方式來確認檔案是有注入到容器的,首先我們拿到當前節點的容器 ID。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker container list
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a6080cb999d0 nginx "/doc.." 2 m... Up 2.. 80/tcp nginx.2

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker container exec a6080cb999d0 cat /run/secrets/my_secret
I'm secret.

可以看到透過 cat /run/secrets/my_secret 的指令,拿到了檔案中訊息,而為什麼是這個路徑呢?這是 Docker 官方對於 secret 的預設路徑,所有的 secret 都會預設被注入到容器中的 /run/secrets 內,當然可以透過指令自己指定路徑,而 Docker 也透過加密的方式來傳遞此檔案,所以在安全性上是不需要擔心的。

接著來試試看使用 config 這個物件,相較於 secret,config 物件就比較偏向非敏感資訊,可以拿來存放某些服務的設定檔。

一樣移除原有的 nginx 服務,等等改用 config 物件來把資料注入服務內。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service rm nginx
nginx

接著利用剛剛同一個檔案來建立 config 物件,使用的方式和 secret 一樣。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker config create my_config ./secret.txt
lyx1mu7m4wxk4pn3fftcl1vzp

接著一樣建立 3 個副本的 nginx 服務,並且使用 --config 的方式把檔案傳入,這邊可以直接輸入 config 物件的名稱,檔案就會出現在容器的根目錄內,一樣可以透過 cat 的方式來拿到檔案的內容。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service create --name nginx --publish 80:80 --replicas 3 --config my_config  nginx <- 不換行
1xjedznxpk8im443fbhdyhosr

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker container exec 518 cat ./my_config
I'm secret.

先移除掉 nginx 的服務,在試著把 config 物件放到想要的路徑。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service rm nginx
nginx

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service create --name nginx --publish 80:80 --replicas 3 --config source=my_config,target=/custom-dir/my_config nginx <- 不換行
seuj2mlqpyvrlubsw6c88xvjo
overall progress: 3 out of 3 tasks
1/3: running [==============================================>]
2/3: running [==============================================>]
3/3: running [==============================================>]
verify: Service converged

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker container exec 89a cat /custom-dir/my_config
I'm secret.

透過 source=『 config 物件的名字 』, target=『 容器內的路徑 』就可以把 config 物件的檔案放到自己想要的位置。

這時候可能會想說,使用 secret 的道理能理解,透過 Docker 的加密傳輸方式來保證安全性。

那 config 呢?說實在的設定檔寫死放在映像檔用 COPY 的方式也可以吧?沒錯,是可以的,但寫死在映像檔內要更新服務就只能更新映像檔。

那如果採用 Bind Mount 的方式呢?也可以,沒有問題,但問題就在於要更新設定時需要暫停服務再重啟,而用 config 都可以避免掉這些問題,讓我們在不停止 nginx 服務的情況下來更新這個 config,來試試看更新剛剛的設定檔。

首先更新一下原本的設定檔案,並且再次建立一個新的 config 等等要拿來覆蓋掉舊的設定。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# echo "New Config" >> secret.txt
root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker config create my_config_2 ./secret.txt
t3uqy5a9ec807sv9byhwyipdx

接著用 docker service update --config-add 的方式來更新 nginx 的服務,並且覆蓋掉原本的設定檔。

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker service update --config-add source=my_config_2,target=/custom-dir/my_config nginx
nginx
overall progress: 3 out of 3 tasks
1/3: running [===============================================>]
2/3: running [===============================================>]
3/3: running [===============================================>]
verify: Service converged

接著一樣來檢查新的容器內設定檔是否有更新:

root@ubuntu-s-1vcpu-512mb-10gb-sgp1-01:~# docker container exec 021 cat /custom-dir/my_config
I'm secret.
New Config

這樣就可以在不中斷服務的情況下去更動設定檔,使用的方式五花八門,但這是最基本的想法,其實都可以多做嘗試,會有意想不到的結果!