Day 25 - 保護你的系統:套用 SSL

本日共賞

希望你知道


認證、授權與加密

認證 (Authentication)、授權 (Authorization) 與加密 (Encryption),對於 Cloud Security 來說一直是很重要的議題。簡單來說

參考文章 Understanding Authentication, Authorization, and Encryption

針對部署在 k8s 中的應用程式,我們可以套用 SSL (Secure Sockets Layer) 來加強應用程式的安全性,今天將分享如何加入 SSL


加入 SSL

開始前,這裡先說明加入 SSL 的大略步驟

  1. 建立自我簽署憑證 (self-signed certificates)
  2. 建立 Secret 物件
  3. 為應用程式加入 SSL

建立自我簽署憑證

憑證選擇

要套用 SSL 需要有一份公正第三方簽署的憑證 (certificates) 而網路上可以找到很多 SSL 供應商提供不同等級與方案的憑證。當然也有提供免費 SSL 憑證的供應商,例如 Letsencrypt, sslforfree 等等。

付費的憑證效期長但是就是要付錢,而免費的憑證通常只會提供較短期 (三個月) 的期限,缺點是需要常常更新。需要使用哪一種方案請自行斟酌。

這裡用的憑證,是透過 openssl 產生的自我簽署憑證。雖無第三方認證機構的效力,不過使用上與第三方憑證無異。

首先透過指令建立金鑰與憑證

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt

接著會提示輸入憑證相關資訊。因為是測試用,只要填入 Email Address 即可,其他可以直接按 Enter 忽略。順利的話會產生 tls.key 與 tls.crt 這兩個檔案。 接下來我們要將 key 與 crt 部署到 k8s 中,k8s 就可以利用這兩個檔案來啟用加密

建立 Secret 物件

透過指令建立 Secret 物件

$ kubectl create secret generic tls-certificate --from-file=./tls.key --from-file=./tls.crt
secret "tls-certificate" created

--from-file:會需要使用金鑰與憑證

觀察一下名為 tls-certificate 的 Secret 物件

$ kubectl describe secret tls-certificate
Name:         tls-certificate
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
tls.key:  1704 bytes
tls.crt:  1021 bytes

我們可以看到 tls-certificate 包含兩個 Data 欄位即 tls.key 與 tls.crt 。

為應用程式加入 SSL

接著我們需要部署可以提供 SSL 服務的應用程式。我已經預先做好了 docker 映像檔,位置在 jlptf/ssl-nginx。照著之後的說明,如果一切順利無誤,則透過瀏覽器可存取以下畫面。

這邊顯示 “不安全”是正常的,因為我們是使用自我簽署憑證,就好像詐騙集團自己寫了一張“我們是合法機構”的告示貼在門口的意思是一樣的。

底下我先來解釋一下在映像檔中做了哪些事情。

首先修改 nginx 的 default.conf 設定檔,讓 nginx 能夠支援 SSL

# default.conf

server{
listen 80 default_server;
listen [::]:80 default_server;

listen 443 ssl default_server;
listen [::]:443 ssl default_server;

ssl_certificate /etc/nginx/ssl/tls.crt;
ssl_certificate_key /etc/nginx/ssl/tls.key;
}

其中 ssl_certificatessl_certificate_key 分別是憑證與金鑰的名稱與存放的位置。在部署到 k8s 後,我們會需要將上述的 tls-certificate (Secret 物件) ,放置到對應的位置上即 /etc/nginx/ssl/,因此名稱與路徑都十分重要。

接著攥寫部署需要用到的 .yaml 檔,這邊需要兩個檔案,分別是 deploy.ssl.yamlservice.ssl.yaml 內容如下

# deploy.ssl.yaml

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: ssl-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels: 
        app: ssl-nginx
    spec:
      containers:
      - name: ssl-nginx
        image: jlptf/ssl-nginx   <=== 使用預先做好的映像檔
        ports:
        - containerPort: 443   <=== SSL port 為 443
        volumeMounts:
        - name: nginx-ssl    <=== 將 Volume 掛載到 /etc/nginx/ssl 目錄下
          mountPath: /etc/nginx/ssl
          readOnly: true
      volumes:
      - name: nginx-ssl    <=== 掛載一個 Volume 並綁定名為 tls-certificate 的 Secret 物件
        secret:
          secretName: tls-certificate

大部分的內容已在前面文章解釋說明過,請參考之前文章內容。需要特別注意的是

# service.ssl.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: ssl-web
spec:
  type: NodePort
  selector:
    app: ssl-nginx
  ports:
    - protocol: TCP
      port: 443
      targetPort: 443

這裡的設定只要注意 selector, port 與 targetPort 即可

接下來執行指令部署物件

$ kubectl apply -f deploy.ssl.yaml
deployment "ssl-nginx" created

$ kubectl apply -f service.ssl.yaml 
service "ssl-web" created

查看新增的 Service

$ kubectl get service
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP         5d
ssl-web      NodePort    10.0.0.227   <none>        443:32525/TCP   1m

ssl-web 即為新增加的 Service 物件,我們可以透過 32525 port 存取 SSL server。還記得怎麼取得 minikube IP 嗎?取得 IP 後,打開瀏覽器輸入 https://[minikubeIP]:32525 就能存取有提供 SSL 服務的 nginx。

注意 port 會不同

本文與部署檔案同步發表於 https://jlptf.github.io/ironman2018-day25/