guest@blog.cmj.tw: ~/posts $

CA on Kubernetes


因為工作上的需求,需要在 k8s 環境上設定一個進階功能:使用者可以透過 CNAME 指定自己的 domain 到服務上,例如使用者擁有 example.cc 可以透過 CNAME 指向到 hosting.example.com,之後在服務上的 web service 可以透過 virtual host 的方式使用自定義網域。

其中透過 CNAME 本身連到外部 web service 可以透過 virtual host 的方式完成,然而憑證就相對麻煩: 對於憑證本身會驗證 DNS 等相關欄位,這導致需要 1) 使用者自己匯入憑證 或者 2) 服務方替申請憑證。

就結論來說:

  • 自身服務的 sub-domain 使用 DNS-01
  • 使用者自行設定的網域則使用 HTTP-01

Cert Manager

cert-manager 是一個用 Go 寫的 k8s addon,可以用來偵測、申請、更新 letsencrypt 的憑證。 可以直接透過官方提供的釋出版本直接安裝 (目前最新版本為 v1.0.2 ),之後可以透過 kubectl apply -f 安裝。之後可以使用 kubectl -n cert-manager get pod 判斷是否已經安裝完成三個主要 POD 服務跟兩個 service。

之後撰寫自己需要的 Issuer 的設定檔,按照官方的 範例 來產生一個 selfsign 的憑證:

apiVersion: v1
kind: Namespace
metadata:
  name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: test-selfsigned
  namespace: cert-manager-test
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: selfsigned-cert
  namespace: cert-manager-test
spec:
  dnsNames:
    - example.com
  secretName: selfsigned-cert-tls
  issuerRef:
    name: test-selfsigned

之後就可以用 kubectl -n cert-manager-test describe certificate 檢查憑證的狀況

kubtctl plugin

針對 cert-manager 有推出自己的 k8s plugin (Linux-based),或者使用 kubectl-krew 安裝。

Web Hook

如果要使用 Godaddy 來使用 DNS-01 驗證方式,就需要安裝額外的 web-hook 套件。 找了一下之後使用 snowdrop 所提供的 webhook 套件

權限

如果需要全自動化設定域名、可以透過程式化的方式設定整個 k8s 環境:用 Python 當做例子就可以使用 kubernetes-client 所提供的套件。使用上可以設定 service account 管理相關權限: 需要注意的是 service account、issuer、certificate 跟 deployment 需要在同一個 namespace。下面是一個範例的設定檔:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: issuer
  namespace: cert-issuer
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: hostname-issuer
rules:
  # create new certificate by issuer
  - apiGroups:
      - cert-manager.io
    resources:
      - issuers
      - certificates
    verbs:
      - get
      - list
      - create
      - patch
      - delete
  # create related ingress
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses
    verbs:
      - get
      - list
      - create
      - delete
      - patch
      - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: issuer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: hostname-issuer
subjects:
  - kind: ServiceAccount
    name: issuer
    namespace: cert-issuer

透過安裝上面的設定檔之後,只要透過程式化的方式新增一個 Certificate 並指定 issuerRef 到上面的 Issuer, cert-manager 就看處裡後續憑證相關的部分。

權限檢查

K8S 是透過 RESTFul API 來控制資源,可以透過 kubectl auth can-i 來檢查是否有足夠權限控制資源。 如果是針對 service account,就需要使用 --as system:serviceaccount:<NAMESPACE>:<NAME>