kubernetes API Server安全

用戶訪問API Server(如下簡稱Server),K8S的安全檢查步驟:認證和受權。nginx

認證解決用戶是誰的問題,就是驗證用戶名密碼;受權解決用戶能作什麼的問題,就是檢查該用戶是否擁有權限訪問請求的資源。經過合理的權限管理,可以保證系統的安全可靠。web

網絡

Server經過本地端口(Localhost Port)和安全端口(Secure Port)對外提供API服務,其中本地端口是基於HTTP協議的,用於本地無限制訪問,安全端口是基於HTTPS協議的,用於遠程有限制訪問。docker

本地端口

默認配置中,Server的本地端口默認綁定到地址127.0.0.1上,只能在本機訪問。因爲本地端口將繞過了Server的認證和受權,只要可以訪問本地端口,能夠無限制訪問Server。基於安全考慮,儘可能不要將本地端口綁定到127.0.0.1之外的地址上。bootstrap

本地端口默認綁定到端口8080上,能夠經過Server啓動參數--insecure-port進行指定,若是爲0關閉本地端口。參數--insecure-bind-address指定綁定地址。api

安全端口

安全端口是Server對外提供的,用於外部訪問的安全的可控的API調用接口,Server只容許經過認證的用戶(認證信息來源於User Account或者Service Account)纔可以經過安全端口訪問,對於匿名用戶401拒絕訪問。緩存

默認綁定到端口6443上,經過Server的啓動參數--secure-port進行指定,若是爲0關閉安全端口。默認綁定到地址0.0.0.0上,經過參數--bind-address進行指定。安全

經過參數--tls-cert-file和--tls-private-key-file指定證書和私鑰。服務器

代理和防火牆

在實際應用中,可能現有的認證體系沒法與K8S集成或者須要執行特殊認證和受權邏輯的狀況,能夠考慮引入代理(Proxy)來解決認證和受權的問題,在認證經過後,代理將請求轉發到Server。網絡

當代理可以與Server部署在同一臺主機時,建議按照下面的方式進行集成:app

關閉安全端口,確保全部的API請求只能經過代理接入
將本地端口綁定到地址127.0.0.1上,確保只能在本機訪問
設置防火牆規則,僅開放本機的443端口
配置nginx監聽443端口,而且在此端口上配置認證和HTTPS
配置nginx將請求轉發到本地端口,默認狀況下爲127.0.0.1:8080

當代理沒法與Server部署在同一臺主機時,從安全角度看,再試圖經過本地端口與Server集成不是好的選擇,使用安全端口與Server集成更好更安全。

認證

只能用於HTTPS(安全端口),對http(非安全端口)來講無效,緣由請看上節的「本地端口」。

認證方式有不少種,這裏主要介紹如下幾種:

靜態密碼/用戶帳號

用戶帳號(User Accounts,如下簡稱UA),也稱靜態密碼,是用於管理者經過web訪問Server的認證用戶名和密碼。

靜態密碼是提早在某個文件中保存了用戶名和密碼的信息,而後經過Server啓動參數 --basic-auth-file=SOMEFILE指定文件路徑。

文件是CSV格式,每行對應一個用戶信息,前面三列密碼、用戶名、UID 是必須的,第四列是可選的組名(多個組,必須用雙引號):password,user,uid,"group1,group2,group3" 例如 cat /etc/kubernetes/useraccount.csv 1qaz2wsx,lykops,1 1qaz2wsx,lykchat,2

若是是經過客戶端發送請求時(非用戶經過web頁面請求的),須要指定ca證書、用戶名和密碼。例如:

curl -u lykops:1qaz2wsx https://192.168.20.128:6443/ --cacert /etc/ssl/kube/ca.pem

注意:不能動態更新,須要重啓api server。

服務帳號

服務帳號(Service Accounts,如下簡稱SA)並非給K8S集羣的用戶使用的,而是用於Pod中的程序訪問API的account,它爲Pod中的程序提供了一種身份標識。UA的做用域爲K8S集羣全局,是全局性權限,SA的做用域爲命名空間(簡稱ns)。SA做爲一種資源對象存在於K8S中。具體請看資源對象—service acecount章節。

原理

查看一下kube-system ns下名爲默認sa的詳細信息: kubectl describe serviceaccount/default -n kube-system Name: default Namespace: kube-system Labels: Image pull secrets: Mountable secrets: default-token-hpni0 Tokens: default-token-hpni0

看到sa並不複雜,只是關聯了一個secret資源對象做爲token,該token也叫service-account-token,該token纔是真正在Server驗證(authentication)環節起做用的: kubectl get secret -n kube-system NAME TYPE DATA AGE default-token-hpni0 kubernetes.io/service-account-token 3 140d

kubectl get secret default-token-hpni0 -o yaml -n kube-system
apiVersion: v1
data:
  ca.crt: {base64 encoding of ca.crt data}
  namespace: a3ViZS1zeXN0ZW0=
  token: {base64 encoding of bearer token}
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
  name: default-token-hpni0
  namespace: kube-system
type: kubernetes.io/service-account-token

看到這個類型爲service-account-token的secret資源包含的數據有三部分:ca.crt、namespace和token。

ca.crt是Server的CA公鑰證書;
namespace是Secret所在ns值的base64編碼
token是一段用Server私鑰(在建立sa時用Server參數--service-account-key-file指定的,若是未指定,那麼將默認使用--tls-private-key-file值,即Server的私鑰server.key)文件內容簽發(sign)的bearer tokens的base64編碼。

認證過程

在K8S的認證環節中,以某個sa提供身份的Pod的用戶名爲:system:serviceaccount:(ns):(sa)。以kube-system ns下的默認sa爲例,使用它的Pod的username全稱爲:system:serviceaccount:kube-system:default。有了用戶名,那麼credentials(憑證)呢?就是上面提到的service-account-token中的token。

若是客戶端使用sa token方式(攜帶service account token)訪問api,Server採用signed bearer token方式進行身份校驗。 經過身份校驗後,Server將根據Pod用戶名所在的group:system:serviceaccounts和system:serviceaccounts:(NAMESPACE)的權限分配權限(authority和admission control兩個環節)。在這兩個環節中,管理員能夠對service account的權限進行細化設置。

引用

若是Pod中沒有顯式指定spec.serviceAccount字段值,那麼K8S會將該ns下的默認sa自動mount到在該ns中建立的Pod裏。

kubectl describe pod/index-api-2822468404-4oofr
Name:        index-api-2822468404-4oofr
Namespace:    default
... ...
Containers:
  index-api:
   ... ...
    Volume Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-40z0x (ro)
    Environment Variables:    <none>
... ...
Volumes:
... ...
  default-token-40z0x:
    Type:    Secret (a volume populated by a Secret)
    SecretName:    default-token-40z0x

QoS Class:    BestEffort
Tolerations:    <none>
No events.

能夠看到,K8S將default ns中的默認sa的service account token掛載(mount)到了Pod中容器的/var/run/secrets/kubernetes.io/serviceaccount路徑下。

深刻容器內部,查看mount的sa路徑下的結構:

docker exec 3d11ee06e0f8 ls  /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

這三個文件與上面提到的sa中的數據是一一對應的。

雙向認證

客戶端證書認證叫做TLS雙向認證,就是服務器客戶端互相驗證證書的正確性,在都正確的狀況下協調通訊加密方案。

雙向認證方式是最爲嚴格和安全的集羣安全配置方式,主要配置流程以下:

生成根證書、Server服務端證書、服務端私鑰、各個組件所用的客戶端證書和客戶端私鑰。
修改K8S各個服務進程的啓動參數,啓用雙向認證模式。

靜態Token文件

相似於靜態密碼,只是經過token來代替密碼。

當在命令行指定--token-auth-file=SOMEFILE選項時,Server從文件中讀取bearer tokens。令牌文件是一個至少包含3列的csv文件: token, user name, user uid,後跟可選的組名。注意,若是有多個組,則列必須是雙引號,例如:token,user,uid,"group1,group2,group3" 當客戶端使用bearer token認證時,須要發送一個「Authorization: Bearer 」+token(token必須是一個能夠放在HTTP請求頭中且值不須要轉碼和引用)的字符串。例如:token是31ada4fd-adec-460c-809a-9e56ceb75269,客戶端的HTTP頭必須添加:Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

注意:不能動態更新,須要重啓api server,很不靈活,也不安全,不推薦使用。

OpenID Connect Tokens

OpenID Connect是由OAuth2提供商支持的OAuth2,特別是Azure Active Directory,Salesforce和Google。OAuth2的協議的主要擴展是增長一個額外字段,返回了一個叫ID token的access token。這個token是被服務器簽名的JSON Web Token (JWT) ,具備衆所周知的字段,好比用戶的email。

爲了識別用戶,驗證使用來自OAuth2 token響應的idtoken (而不是accesstoken)做爲bearer token。

使用OpenID認證,API Server須要配置

- --oidc-issuer-url,如https://accounts.google.com
- --oidc-client-id,如kubernetes
- --oidc-username-claim,如sub
- --oidc-groups-claim,如groups
- --oidc-ca-file,如/etc/kubernetes/ssl/kc-ca.pem

Webhook Token

Webhook Token認證方式可讓用戶使用本身的認證方式(相似於單點登陸),用戶按照約定的請求格式和應答格式提供HTTPS服務,當用戶把Bearer Token放到請求的頭部,K8S會把token發送給事先配置的地址進行認證,若是認證結果成功,則認爲請求用戶合法。這種方式下有兩個參數 能夠配置:

–authentication-token-webhook-config-file :認證URL地址的配置文件

–authentication-token-webhook-cache-ttl :認證結果要緩存多久,默認是兩分鐘

這種方式下,自定義認證的請求和應答都有必定的格式,具體的規範請參考官方文檔。

認證代理

Server配置文件須要制定如下配置

--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-
# 爲了防止頭部欺騙,證書是必選項
--requestheader-client-ca-file
# 設置容許的CN列表。可選。
--requestheader-allowed-names

Keystone Password

Keystone是OpenStack提供的認證和受權組件,這個方法對於已經使用openstack來搭建Iaas平臺的公司比較適用,直接使用keystone能夠保證Iaas和Caas平臺保持一致的用戶體系。

須要Server在啓動時指定--experimental-keystone-url=,而https時還須要設置--experimental-keystone-ca-file=SOMEFILE。

引導Token

在v1.6版本中,這個特性仍是alpha特性。爲了可以在新的集羣中使用bootstrapping認證。Kubernetes包括一種動態管理的Bearer(持票人) token,這種token以Secrets的方式存儲在kube-system命名空間中,在這個命名空間token能夠被動態的管理和建立。Controller Manager有一個管理中心,若是token過時了就會刪除。

建立的token證書知足[a-z0-9]{6}.[a-z0-9]{16}格式,Token的第一部分是一個Token ID,第二部分是token的祕鑰。你須要在http協議頭中加上相似的信息:

Authorization: Bearer 781292.db7bc3a58fc5f07e

若是要使用Bootstrap,須要在API Sever中開啓--experimental-bootstrap-token-auth。同時必須在Controller Manager中開啓管理中心的設置--controllers=*,tokencleaner。

在使用kubeadm部署Kubernetes時,kubeadm會自動建立默認token,可經過kubeadm token list命令查詢。

匿名請求

若是請求沒有經過以上任何方式的認證,正常狀況下應該是直接返回 401 錯誤。但K8S還提供另一種選擇,給沒有經過認證的請求一個特殊的用戶名system:anonymous和組名 system:unauthenticated 。 這樣能夠跟下面要講的受權結合起來,爲匿名請求設置一些特殊的權限,好比只能讀取當前ns的pod信息,方便用戶訪問。 若是使用AlwaysAllow、AlwaysDeny之外的認證模式,則匿名請求默認開啓,但可用--anonymous-auth=false禁止匿名請求。

受權插件

K8S的受權是經過插件方式來實現的,目前K8S內置提供了AlwaysDeny、AlwaysAllow、ABAC、RBAC以及WebHook等幾種受權插件(在1.5.2版本中,只有這五種),經過配置Server啓動參數--authorization-mode來指定受權模式。

受權處理如下的請求屬性: user, group, extra API、請求方法(如get、post、update、patch和delete)和請求路徑(如/api) 請求資源和子資源 Namespace API Group

AlwaysDeny

該模式將會拒絕任何對安全端口的請求。任何訪問,服務端老是返回Forbidden: "URL",表示訪問被拒絕。

AlwaysDeny模式主要用於測試,固然也能夠用來暫時中止集羣的對外服務。

AlwaysAllow

默認模式,該模式下只要經過認證,服務端將會接受任何對安全端口的請求,換句話說就是除了認證沒有任何權限限制。

當集羣不須要作受權限制時,直接使用該模式,以下降配置的複雜性。

ABAC

ABAC(Attribute-based access control,基於屬性的訪問控制),ABAC的核心是根據請求的相關屬性,例如用戶屬性、資源屬性以及環境屬性等屬性,做爲受權的基礎來進行訪問控制,以解決分佈式系統的可信任關係的訪問控制問題。

ABAC的策略文件是一個one JSON object per line格式的文本文件。ABAC的受權過程能夠簡單的理解爲將請求屬性轉換爲一個spec對象,而後拿到這個spec對象與策略文件中定義的spec對象進行匹配,若是這個spec對象可以與策略文件中定義的任何一條規則容許的spec對象匹配,那麼受權經過;若是這個spec對象沒法與任何一條規則匹配,那麼受權失敗。

RBAC

WebHook

WebHook模式是一種擴展受權模式,在這種模式下,API Server將受權過程委派到外部的一個REST服務,由外部的服務決定是否授予指定請求繼續訪問的權限。

WebHook模式的開啓很是的簡單,只須要經過API Server的啓動參數--authorization-mode設置爲WebHook而且經過啓動參數--authorization-webhook-config-file將外部受權服務的配置信息告訴API Server便可。

Admission Control 准入控制

當請求經過了前面的認證和受權後,還須要通過准入控制處理經過以後,server纔會處理這個請求。Admission Control 有一個准入控制列表,能夠經過命令行設置選擇執行哪幾個准入控制器。只有全部的准入控制器都檢查經過以後,apiserver 才執行該請求,不然返回拒絕。

相關文章
相關標籤/搜索