最好的K8S 安全機制介紹 1 ——認證部分

K8S 的用戶系統

K8S 有兩種類型的用戶

  1. service account
  2. 一般用戶(人)

一般用戶

一般用戶被認為是由外部獨立的服務(比如公司的員工)管理的。例如:一個分發私鑰的管理員,一個像Keystone或谷歌帳戶這樣的用戶存儲,甚至一個包含用戶名和密碼列表的文件。在這方面,Kubernetes沒有表示普通用戶帳戶的對象。不能通過API調用將普通用戶添加到集群中。

service account

相反,服務帳戶是由Kubernetes API管理的用戶。它們被綁定到特定的名稱空間,并由API服務器自動創建或通過API調用手動創建。服務帳戶被關聯到一組用作憑證的secret中,這些secret憑證被掛載到pod中,允許集群內進程與Kubernetes API通信。

API請求要么綁定到普通用戶,要么綁定到服務帳戶,要么作為匿名請求處理。這意味著集群內外的每個進程,不論是PC客戶端上使用kubectl的人工用戶或者節點上的kubelets,再到控制平面的成員,向API服務器發出請求時都必須進行身份驗證,或者被視為匿名用戶。

認證

API SERVER 認證方式(K8S 的所有訪問都是通過 api server)

  • https 證書認證: 基于CA根證書簽名的雙向數字證書認證方式
  • http token 認證: 通過一個token來識別合法用戶
  • http basic 認證: 通過用戶名密碼的方式認證
  • authenticating proxy: 第三方授權協議

認證策略

api server 擁有一條鏈式的認證插件, 沒個請求被認證插件驗證時,插件會試圖將請求與以下屬性進行關聯

  • 用戶名(username):標識最終用戶的字符串。常見的值可能是kube-admin或jane@example.com

  • UID:標識最終用戶并試圖比username更一致和惟一的字符串。

  • 組(group):一組字符串,它將用戶與一組通常分組的用戶相關聯。

  • 額外字段(extra fileds):字符串映射到包含附加信息授權方可能會發現有用的字符串列表。

所有值對身份驗證系統都是不透明的,只有在由授權方( authorizer)使用時才具有意義。

您可以同時啟用多個身份驗證方法。通常應該使用至少兩種方法:

  • 服務帳戶(service account) 的服務帳戶令牌(service account token)

  • 一種用于用戶身份驗證的方法。

當啟用多個驗證器模塊時,第一個模塊將成功地驗證 "請求短路評估" (request short-circuits evaluation)。,如果驗證失敗,則進行斷路操作,API服務器不保證運行驗證器的執行順序。

所有通過驗證的用戶都會被添加進system:authenticated組。

可以使用authenticating proxyauthentication webhook與其他身份驗證協議(LDAP、SAML、Kerberos、備用x509方案等)集成。

額外知識補充:https證書認證原理

CA: PKI 系統中通信雙方都信任的實體, 被稱為可信第三方(trusted third party TTP)

CA通過證書證實他人的公鑰信息,證書上有CA的簽名. 證書中綁定了公鑰數據和相應私鑰用后者的身份信息,并帶有CA的數字簽名;在證書中也包含的CA的名稱,以方便依賴方找到CA的公鑰,驗證數字證書上的簽名

CA 涉及的概念

**根證書, 自簽名證書, 密鑰, 私鑰, 加密算法 **

CA 認證步驟

  1. https 通信雙方的服務器端, 想CA 機構申請證書. CA 機構下發根證書,服務端證書,私鑰給申請者
  2. https 通信雙方的客戶端向CA機構申請證書, CA 機構下發根證書,服務端證書,私鑰給申請者
  3. 客戶端向服務端發起請求,服務端下發服務端證書給客戶端,客戶端接收到證書后, 通過私鑰揭秘證書, 利用服務端證書中的公鑰認證證書信息比較證書里的消息. 例如,比較域名和公鑰, 與服務器剛發送的相關信息是否一致, 如果一致, 則認為服務端是可信的
  4. 客戶端發送客戶端證書給服務端,服務端通過私鑰解密證書,獲得客戶端公鑰,并用該公鑰認證證書信息
  5. 客戶端通過隨機密鑰加密信息發送給服務端. 服務端和客戶端協商好加密方案后,客戶端會產生一個隨機的密鑰,客戶端通過協商好的加密方案加密該密鑰,并發送該隨機密鑰給服務端. 服務器接收密鑰后, 雙方所有內容通過該隨機密鑰加密
image.png

http 其他認證方式

token 認證原理

token 是一個難以被模仿的字符串, 每個token對應一個用戶名, 存放在API server能訪問的一個文件中. 當客戶端發起API調用時, token放在header中, API 就能識別是否非法.

http basic 認證

這種認證方式是把 用戶名+冒號+密碼 用base64 算法進行編碼后放到header中進行身份識別

K8S 的 X509 Client Certs 認證

要啟用 X509證書認證,需要在apiserver的啟動參數中添加--client-ca-file=SOMEFILE
, api server X509 認證的完整啟動參數如下


    kube-apiserver
     --advertise-address=192.168.10.50
     --allow-privileged=true
     --authorization-mode=Node,RBAC
     --client-ca-file=/etc/kubernetes/pki/ca.crt
     --enable-admission-plugins=NodeRestriction
     --enable-bootstrap-token-auth=true
     --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
     --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
     --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
     --etcd-servers=https://127.0.0.1:2379
     --insecure-port=0
     --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
     --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
     --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
     --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
     --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
     --requestheader-allowed-names=front-proxy-client
     --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
     --requestheader-extra-headers-prefix=X-Remote-Extra-
     --requestheader-group-headers=X-Remote-Group
     --requestheader-username-headers=X-Remote-User
     --secure-port=6443
     --service-account-key-file=/etc/kubernetes/pki/sa.pub
     --service-cluster-ip-range=10.96.0.0/12
     --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
     --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

K8S 組件的X509證書認證配置

證書管理工具有一下三種

  • easyrsa
  • openssl
  • cfssl

使用openssl 的方式

主要步驟如下

  1. 生成自簽名 CA 證書
  2. 為kube-apiserver 生成數字證書, 并用CA證書簽名
  3. 為kube-apiserver 配置相關啟動參數
  4. 為每個kube-apiserver的客戶端(kube-controller-manager, kube-scheduler, kubelet, kube-proxy, kubectl, etcd ) 都生成自己的證書,也用CA 進行簽名,并配置起啟動參數

生成 CA 證書

# 生成CA的私鑰
openssl genrsa -out ca.key 2048
# 通過ca私鑰生成ca證書,注意CN= 的部分必須是master的主機名或IP地址
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt

準備master_ssl.cnf文件,用戶生成X509 V3 版本的證書.該文件中主要設置master服務器的ip地址(192.168.10.3),以及k8s master service的虛擬服務域名(kubernetes.default),以及虛擬服務的cluster ip(10.96.0.1)

master_ssl.cnf

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = <country>
ST = <state>
L = <city>
O = <organization>
OU = <organization unit>
CN = <MASTER_IP>

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
# apiserver 所在主機的IP
IP.1 = <MASTER_IP>
# 一般為 api server --service-cluster-ip-range=10.96.0.0/12 參數的第一位ip,也就是10.96.
IP.2 = <MASTER_CLUSTER_IP>

[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names

基于master_ssl.cnf 創建server.csr(證書請求) 和server.crt(證書) 文件. 在生成server.csr 時, -subj 參數中 "/CN" 的值需為master的主機名

#### 生成 api server的私鑰
openssl genrsa -out server.key 2048
生成證書請求
openssl req -new -key server.key -subj "CN=k8s-master" -config master_ssl.cnf -out server.csr
# 生成ca 簽名的證書
openssl x509 -req server.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out server.crt

執行完之后 生成ca.srl server.crt server.csr server.key 將生成的文件和之前生成的ca.key ca.crt 復制到/etc/kubernetes/ssl 文件夾下

設置kuber-apiserver 的三個啟動參數

--client-ca-file=/etc/kubernetes/ssl/ca.crt
--tls-private-key=/etc/kubernetes/ssl/server.key
--tls-cert-file=/etc/kubernetes/ssl/server.crt

同事關閉非安全端口 --insecure-port = 0 并設安全端口 --secure-port=6443 重啟kube-apiserver 服務

生成kube-controller-manager 的證書

openssl genrsa -out cs_client.key  2048
openssl req - new -key cs_client.key  -subj "CN=k8s-master" -config master_ssl.cnf -out cs_client.csr
openssl x509 -req cs_client.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out cs_client.crt

編寫kuber-controller-manager 配置文件

vim /etc/kubernetes/ssl/kubeconfig
# kubeconfig for kube-controller-manager
apiVersion: v1
kind: config
users:
- name: controllermanager
  user: 
    client-certificate: /etc/kubernetes/ssl/cs_client.crt
    client-key: /etc/kubernetes/ssl/cs_client.key
clusters:
- name: local
  cluster: 
    certificate-authority: /etc/kubernetes/ssl/ca.crt
    server: http://192.168.18.3:6443
contexts:
- context:
    cluster: local
    user: controllermanager
  name: mycontext
current-context: mycontext

修改 kube-controller-manager 的啟動參數

--service-account-key-file=/etc/kubernetes/ssl/server.key
--root-ca-file=/etc/kubernetes/ssl/ca.crt
--kubeconfig=/etc/kubernetes/ssl/kubeconfig

生成kubelet的證書

openssl genrsa -out kubelet_client.key  2048
openssl req - new -key kubelet_client.key  -subj "CN=k8s-master" -config master_ssl.cnf -out kubelet_client.csr
openssl x509 -req kubelet_client.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out kubelet_client.crt

在非master節點編寫kuber-controller-manager 配置文件

vim /etc/kubernetes/ssl/kubeconfig
# kubeconfig for kube-controller-manager
apiVersion: v1
kind: config
users:
- name: controllermanager
  user: 
    client-certificate: /etc/kubernetes/ssl/kubelet_client.crt
    client-key: /etc/kubernetes/ssl/kubelet_client.key
clusters:
- name: local
  cluster: 
    certificate-authority: /etc/kubernetes/ssl/ca.crt
    server: http://192.168.18.3:6443
contexts:
- context:
    cluster: local
    user: controllermanager
  name: mycontext
current-context: mycontext

修改 kubelet的啟動參數, 添加--kubeconfig=/etc/kubernetes/kubeconfig

生成 admin的證書

openssl genrsa -out admin.key 2048
openssl req -new -key admin.key -out admin.csr -subj "/O=system:masters/CN=dmin"
openssl x509 -req -set_serial $(date +%s%N) -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt -days 365 -extensions v3_req -extfile req.conf

這樣,通過 證書認證的形式配置了K8S的認證

使用easyrsa 生成證書

1 下載 easy rsa

curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki

2 生成 ca 證書

# --batch 自動模式,--req-cn 設置默認的CN
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass

3 生成api server相關證書

./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:${MASTER_CLUSTER_IP},"\
"DNS:kubernetes,"\
"DNS:kubernetes.default,"\
"DNS:kubernetes.default.svc,"\
"DNS:kubernetes.default.svc.cluster,"\
"DNS:kubernetes.default.svc.cluster.local" \
--days=10000 \
build-server-full server nopass

4 修改 api server 啟動參數

--client-ca-file=/yourdirectory/ca.crt
--tls-cert-file=/yourdirectory/server.crt
--tls-private-key-file=/yourdirectory/server.key

5 生成 admin 證書

./easyrsa --dn-mode=org --req-cn=admin --req-org=system:masters --req-c= --req-st= --req-city= --req-email= --req-ou= build-client-full admin nopass

cfssl 方式

1編寫cfssl ca 配置文件
ca-config.json

{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}

2 變現 ca 證書請求配置文件
ca-csr.json

{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names":[{
    "C": "<country>",
    "ST": "<state>",
    "L": "<city>",
    "O": "<organization>",
    "OU": "<organization unit>"
  }]
}

3 生成CA證書文件

/opt/local/cfssl/cfssl gencert -initca csr.json | /opt/local/cfssl/cfssljson -bare ca

4 編寫api server 證書配置文件 server-crs.json

{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "<MASTER_IP>",
    "<MASTER_CLUSTER_IP>",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [{
    "C": "<country>",
    "ST": "<state>",
    "L": "<city>",
    "O": "<organization>",
    "OU": "<organization unit>"
  }]
}

5 生成 api server 證書文件

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
--config=ca-config.json -profile=kubernetes \
server-csr.json | ../cfssljson -bare server

6 編輯 admin 配置文件 admin-csr.json

{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}

7 生成 admin 證書

/opt/local/cfssl/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
  -ca-key=/etc/kubernetes/ssl/ca-key.pem \
  -config=/opt/ssl/config.json \
  -profile=kubernetes admin-csr.json | /opt/local/cfssl/cfssljson -bare admin

token 認證

傳統token

api server 支持token認證, 通過在啟動參數中添加 ----token-auth-file=SOMEFILE 進行支持,如果修改token file的內容,必須重啟api server才能生效

在API 請求中通過在請求的header 中添加token 進行驗證

Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

Bootstrap Tokens

為了允許對新的集群進行方便的初始化安裝引導,Kubernetes包含一個動態管理的承載令牌類型,稱為引導令牌(bootstrap token)。這些令牌作為secret存儲在kube-system名稱空間中,可以在其中動態管理和創建它們。Controller Manager包含一個TokenCleaner控制器,它在引導令牌過期時刪除它們。

令牌的形式是[a-z0-9]{6}.[a-z0-9]{16}。第一個組件是令牌ID(用戶ID),第二個組件是secret。在HTTP頭中指定令牌,如下所示:

Authorization: Bearer 781292.db7bc3a58fc5f07e

781292就是用戶ID

啟用bootstrap token

您必須在API服務器上使用--enable-bootstrap-token-auth 標志啟用引導令牌身份驗證器。并且必須同時通過--controllers=, tokencleaner*參數啟用TokenCleaner控制器。如果使用kubeadm引導集群,它將自動完成這一任務。

身份驗證器將身份驗證為system:bootstrap:<令牌ID>。它包含在system:bootstrappers組中。有意限制命名和組,以阻止用戶在引導之后使用這些令牌。可以使用用戶名和組(kubeadm也使用這些用戶名和組)來制定適當的授權策略,以支持集群的引導。

有關引導令牌身份驗證器和控制器的詳細文檔,以及如何使用kubeadm管理這些令牌,請參見引導令牌

Static Password File

啟用命令

通過在api server 啟動參數中添加--basic-auth-file=SOMEFILE 啟用靜態密碼驗證。如果修改靜態密碼文件,需要重啟api server 才能生效。

靜態密碼文件說明

基本的靜態密碼是一個csv文件,至少有3列:密碼、用戶名、用戶id。在Kubernetes 1.6或更高版本中,您可以指定一個可選的第4列,其中包含逗號分隔的組名。如果您有多個組,則必須將第四個列值括在雙引號(")中。請看下面的例子:

password,user,uid,"group1,group2,group3"

靜態密碼使用

當使用http客戶機的基本身份驗證時,API服務器期望header basic 的值為 base64編碼的用戶名密碼 (用戶:PASSWORD)。

service account token

服務帳戶(service account)是一個自動啟用的身份驗證器,它使用帶簽名的token來驗證請求。這個插件有兩個可選的標志:

  • --service-account-key-file包含PEM編碼密鑰的文件,用于對token進行簽名。如果未指定,將使用API服務器的TLS私鑰。

  • --service-account-lookup如果啟用,從API中刪除的令牌將被撤銷。

服務帳戶通常由API服務器自動創建,并通過ServiceAccount controller manager與集群中運行的pod相關聯。token被掛載到已知位置的pods中,并允許集群內進程與API服務器通信。帳戶可以使用PodSpec的serviceAccountName字段顯式地與pod關聯。

注意:serviceAccountName通常被省略,因為這是自動完成的。

kubectl create serviceaccount jenkins
serviceaccount "jenkins" created

kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  # ...
secrets:
- name: jenkins-token-1yvwg

# 創建的secret包含API服務器的公共CA和一個簽名的JSON Web令牌(JWT)。
kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: ZGVmYXVsdA==
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  # ...
type: kubernetes.io/service-account-token

值是用base64編碼的,因為secret總是用base64編碼的。

服務帳戶(service account)使用用戶名system:serviceaccount:(namespace):(serviceaccount)進行身份驗證,并分配給system:serviceaccounts和system:serviceaccounts:(namespace)兩個用戶組。

警告:由于服務帳戶令牌存儲在secret中,任何具有讀訪問這些機密的用戶都可以驗證為服務帳戶。在授予服務帳戶的權限和secret的讀取功能時要謹慎。

下一篇
最好的K8S 安全機制介紹 2——授權概述

如果文章對您有幫助,請點一下下面的 "喜歡"

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容