來到了鐵人賽的最後三天,讓我們為我們的CICD Pipeline加入更多的功能吧!
這二十多天以來,我們一直都利用Jenkins的Credentials功能去儲存所有服務的連接認證。如果我們所儲存的認證是用於CICD部署方面,這個做法是非常合理的。
但是有一些情況,我們需要有一個安全的地方去儲存程式內部使用的重要資料。例如跟其他服務的API金鑰,又或是其他一些重要的檔案。這個時候,單靠Jenkins的Credentials功能可能就不太合適了。
因此,我們今日會嘗試利用Ansible其中一個功能,Ansible Vault,去把一些程式內部的機密資料加密,然後再應用到我們開發的程序上面。
首先,我們假設我們的專案有一個頁面,需要在GET
的時候傳入password
這個Query參數。如果傳入的參數等於我們設定的密碼,那麼我們才返回Hello World!
,否則則傳回404
的頁面。
在app.js
中更改為以下內容。
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
const secret = process.env.SECRET_PASSWORD;
if (req.query.password === secret) {
res.send('Hello World!')
} else {
res.sendStatus(404);
}
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
其中一行const secret = process.env.SECRET_PASSWORD
代表我們從環境變數中取得SECRET_PASSWORD
這個值,然後再在下面的判斷式中進行比對。如果密碼正確就返回Hello World!
的內容。
然後在Terminal中運行以下指令。
SECRET_PASSWORD=secret node app.js
SECRET_PASSWORD=secret
代表我們要把secret
作為我們的密碼傳入環境變數中,讓我們的程式取得其值。
運行成功後用瀏覽器登入http://localhost:3000,應該會返回404
。然後登入http://localhost:3000?password=secret,應該可以返回Hello World!
由於我們在專案中加入了環境變數去傳遞我們的密碼。因此我們利用Ansible去進行步署時,亦必須傳入這個環境變數。
因此,在Deploy docker
這個部份,加入以下內容去傳入環境變數。
env:
SECRET_PASSWORD: "{{ secret_password }}"
{{ secret_password}}
: 一會我們會把密碼從加密了的變數文件中取得並傳入此變數中然後,我們在vars_file
的部份中加入一個新的變數檔案secret.yml
,變成以下內容。
vars_files:
- vars.yml
- secret.yml
(完整的main.yml
可參考附錄)
然後我們在專案中新增一個secret.yml
,並以YAML的格式加入我們的密碼。
secret_password: secret
然後,我們要利用Ansible Vault去對secret.yml
進行加密。在Terminal中輸入以下指令。
ansible-vault encrypt secret.yml
輸入指令後,Ansible Vault會要求你輸入你的加密密碼。輸入以後即可為secret.yml
進行加密。
加密完成後,打開secret.yml
,應該會變成類似以下的內容。
$ANSIBLE_VAULT;1.1;AES256
61636633646161316633643562373232363532313134663065323361343831393339343038333164
6463383433643965643435393634313838373834373161310a663763346232396431333638366565
65666530646635343130346331303439383132646566613236616331383833343961323663393033
6634386434363337340a353932366633666237613465316332663261663630383934383339643733
65313465643465366432316661653966333666373439616365303532393161393963
這個就是利用了Ansible Vault進行過加密後的檔案,這個加密後的檔案可以上傳到版本管理系統讓CICD Pipeline讀取。當我們需要把類似的機密資料部署到伺服器上,但又不想資料被人存取或修改時。Ansible Vault就可以在此起到作用了。
下一步,我們嘗試在本機運行Ansible,同時利用Ansible Vault解密我們的秘密密碼。在Terminal中運行以下指令。
ansible-playbook -i "{VM_EXTERNAL_IP}", main.yml -u {USERNAME} --private-key {SSH_PRIVATE_KEY} --ask-vault-pass
{SSH_PRIVATE_KEY}
: Private Key的檔案位罝{USERNAME}
: 用戶名稱{VM_EXTERNAL_IP}
: VM的公共IP位址--ask-vault-pass
: 輸入加密密碼並解密所需檔案然後應該會要求你輸入Vault的密碼。輸入成功後應該可以看到成功部署。
今天,我們成功利用Ansible Vault把機密資料部署到伺服器上。明天,我們又是例行工作,把整個過程自動化起來了!
---
- hosts: all
become: true
vars:
ansible_python_interpreter: /usr/bin/python3
vars_files:
- vars.yml
- secret.yml
tasks:
- name: Test Sever Connection
ping:
- name: Install dependencies
apt:
name: "{{ item }}"
state: latest
update_cache: true
loop: "{{ docker_dependencies }}"
- name: Add docker's official GPG key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: Add docker repository
apt_repository:
repo: deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bullseye stable
state: present
- name: Install docker engine
apt:
name: "{{ item }}"
state: latest
update_cache: true
loop: "{{ docker_engines }}"
- name: Verify docker installation
become: true
command: docker run --rm hello-world
- name: Log into harbor registry
docker_login:
registry_url: {IMAGE_REGISTRY}
username: {HARBOR_USERNAME}
password: {HARBOR PASSWORD}
reauthorize: yes
- name: Deploy docker
docker_container:
name: "ironman-helloworld"
image: {IMAGE_REGISTRY}/ironman-helloworld:1.0.0
state: started
restart: yes
pull: yes
ports:
- "80:3000"
env:
SECRET_PASSWORD: "{{ secret_password }}"
看到終點了,應該可以毫無疑問成功完賽了!