天天看點

如何保護對外暴露的 Kubernetes 服務

有時候我們需要在 Kubernetes 中暴露一些沒有任何安全驗證機制的服務,比如沒有安裝 xpack 的 Kibana,沒有開啟登入認證的 Jenkins 服務之類的,我們也想通過域名來進行通路,比較域名比較友善,更主要的是對于 Kubernetes 裡面的服務,通過 Ingress 暴露一個服務太友善了,而且還可以通過 cert-manager 來自動的完成

HTTPS

化。是以就非常有必要對這些服務進行一些安全驗證了。

Basic Auth 認證

我們在前面更新 Dashboard 的文章中就給大家提到過兩種方式來為我們的服務添加 Basic Auth 認證:haproxy/nginx 和 traefik/nginx-ingress。

使用 haproxy/nginx 的方式非常簡單,就是直接添加 basic auth 認證,然後将請求轉發到後面的服務;而 traefik/nginx-ingress 都直接提供了 basic auth 的支援,我們這裡使用 nginx-ingress 來為 Jenkins 服務添加一個 basic auth 的認證服務。

首先,我們需要建立用于存儲使用者名和密碼的

htpasswd

檔案:

$ htpasswd -bc auth admin admin321
Adding password for user admin           

然後,建立一個基于上面 htpasswd 檔案的 Secret 對象:

$ kubectl create secret generic jenkins-basic-auth --from-file=auth -n kube-ops
secret "jenkins-basic-auth" created           

最後,我們需要在 Ingress 對象中添加

auth-type:basic

auth-jenkins-basic-auth

兩個 annotations:(ingress.yaml)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins
  namespace: kube-ops
  annotations:
    kubernetes.io/ingress.class: nginx
    # 認證類型
    nginx.ingress.kubernetes.io/auth-type: basic
    # 包含 user/password 的 Secret 名稱
    nginx.ingress.kubernetes.io/auth-secret: jenkins-basic-auth
    # 當認證的時候顯示一個合适的上下文資訊
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - admin'
spec:
  rules:
  - host: jenkins.qikqiak.com
    http:
      paths:
      - backend:
          serviceName: jenkins
          servicePort: web           

然後更新上面的資源對象:

$ kubectl apply -f ingress.yaml
ingress.extensions "jenkins" configured           

更新完成後,現在我們去通路我們的 Jenkins 服務可以看到需要輸入使用者名和密碼的提示資訊了:

OAuth 認證

除了上面的 Basic Auth 認證方式以為,我們還可以通過 Github、Google 等提供的 OAuth 服務來進行身份驗證。我們可以通過名為

OAuth2 Proxy

的工具來代理請求,它通過提供一個外部身份驗證的反向代理來實作,使用起來也相對簡單。

安裝

首先我們需要為我們的應用添加自動的 HTTPS,可以參考我們前面的文章

使用 Let's Encrypt 實作 Kubernetes Ingress 自動化 HTTPS

然後登入 Github,在

https://github.com/settings/applications/new

添加一個新的

OAuth

應用程式:

替換成你自己需要使用的域名,然後在回調 URL 上添加

/oauth2/callback

,點選注冊後,記錄下應用詳細頁面

Client ID

Client Secret

的值。然後還需要生成一個 cookie 密鑰,當然如果我們系統中安裝了 python 環境可以直接生成,沒有的話用 Docker 容器運作當然也行:

$ docker run -ti --rm python:3-alpine \
    python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'
b'<GENERATED_COOKIE_SECRET>'           

然後部署

OAuth2 Proxy

應用,這裡我們直接使用 Helm 來簡化安裝:

$ helm install --name authproxy \
    --namespace=kube-system \
    --set config.clientID=<YOUR_CLIENT_ID> \
    --set config.clientSecret=<YOUR_SECRET> \
    --set config.cookieSecret=<GENERATED_COOKIE_SECRET> \
    --set extraArgs.provider=github \
    --set extraArgs.email-domain="*" \
    stable/oauth2-proxy
NAME:   authproxy
LAST DEPLOYED: Sun Apr 14 01:11:50 2019
NAMESPACE: kube-system
STATUS: DEPLOYED

RESOURCES:
==> v1/Secret
NAME                    TYPE    DATA  AGE
authproxy-oauth2-proxy  Opaque  3     0s

==> v1/ConfigMap
NAME                    DATA  AGE
authproxy-oauth2-proxy  1     0s

==> v1/Service
NAME                    TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)  AGE
authproxy-oauth2-proxy  ClusterIP  10.109.110.219  <none>       80/TCP   0s

==> v1beta2/Deployment
NAME                    DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
authproxy-oauth2-proxy  1        0        0           0          0s

==> v1/Pod(related)
NAME                                     READY  STATUS             RESTARTS  AGE
authproxy-oauth2-proxy-798cff85fc-pc8x5  0/1    ContainerCreating  0         0s


NOTES:
To verify that oauth2-proxy has started, run:

  kubectl --namespace=kube-system get pods -l "app=oauth2-proxy"

$ # 執行下面的指令待程式設計 Running 狀态證明安裝成功了。
$ kubectl --namespace=kube-system get pods -l "app=oauth2-proxy"
NAME                                     READY     STATUS    RESTARTS   AGE
authproxy-oauth2-proxy-cdb4f675b-wvdg5   1/1       Running   0          1m           
對于 GitHub,我們可以通過

github-org

github-team

來限制通路,一般設定

email-doamin="*"

,我們可以通過

OAuth2 Proxy

示例文檔 來檢視更改 GitHub Provider 的配置。

測試

同樣我們這裡還是使用一個 Jenkins 服務,大家也可以使用任意的一個服務來驗證,當然最好是沒有身份驗證功能的,比如沒有安裝 x-pack 的 Kibana。

要實作外部服務來進行認證的關鍵點在于 nginx-ingress-controller 在 annotations 中為我們提供了

auth-url

auth-signin

兩個注解來允許配置外部身份驗證的入口。

上面這兩個 annotation 需要 nginx-ingress-controller 在 v0.9.0 版本或以上。

我們在 Jenkins 的核心 Ingress 對象中配置服務認證的 url:

https://$host/oauth2/auth

,然後通過建立一個同域的 Ingress 對象将

oauth2

路徑代理到

OAuth2 proxy

應用去處理認證服務:

nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"           

然後按照上面的思路重新建立 Jenkins 的兩個 Ingress 對象:

$ cat <<EOF | kubectl apply -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins
  namespace: kube-ops
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
spec:
  rules:
  - host: jenkins.qikqiak.com
    http:
      paths:
      - backend:
          serviceName: jenkins
          servicePort: web
        path: /
  tls:
  - hosts:
    - jenkins.qikqiak.com
    secretName: jenkins-tls

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: authproxy-oauth2-proxy
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
spec:
  rules:
  - host: jenkins.qikqiak.com
    http:
      paths:
      - backend:
          serviceName: authproxy-oauth2-proxy
          servicePort: 80
        path: /oauth2
  tls:
  - hosts:
    - jenkins.qikqiak.com
    secretName: jenkins-tls
EOF           

我們這裡通過

cert-manager

來自動為服務添加 HTTPS ,添加了

kubernetes.io/tls-acme=true

這個注解,然後我們在浏覽器中打開我們的 Jenkins 服務,正常就會跳轉到 GitHub 登入頁面了:

然後認證通過後就可以跳轉到我們的 Jenkins 服務了:

當然除了使用 GitHub 之外,還可以使用其他的 OAuth 認證服務,比如 Google,我們可以根據需要自行去添加即可。

相關連結

繼續閱讀