Kubernetes管理员的11条 安全军规
生活随笔
收集整理的這篇文章主要介紹了
Kubernetes管理员的11条 安全军规
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
自從Kubernetes項目開天辟地以來, 其安全性已經取得了長足的發展, 但它目前依然還有些要點值得注意。 本文列舉了11條軍規來幫助讓你的集群在穩定運行時加固安全,以及在受到危害時對抗沖擊。這些軍規涵蓋了對控制面板的配置, 對工作負載的防護, 乃至對未來的展望。
需要注意的是, 一些組件在安裝時可能會有默認設置啟用http端口。管理員需要熟悉每個組件的設置從而識別出這種潛在會產生不安全流量的情況。
出處 這份來自Lucas K?ldstr?m的網絡圖展示了幾處應該配置TLS的地方, 包括組件與主節點的交互, 以及Kubelet與API Server的交互。 Kelsey Hightower的大作Kubernetes The Hard Way中對此提供了詳細的手工操作指導。 etcd的安全模型文檔里也有細致描述。
自動伸縮Kubernetes的節點在過去是非常困難的操作, 因為每個節點都需要一個TLS的密鑰來連接主節點, 而將密鑰打包放進基礎鏡像又不是一個好的實踐方式。 現在Kubelet的TLS引導程序提供了讓新的kubelet在啟動時生成證書簽名申請的能力。
ABAC于Kubernetes的1.6版開始為RBAC所取代,已不建議啟用。 在普通的Kubernetes集群中通過設置以下啟動參數在API Server中啟用RBAC: --authorization-mode=RBAC
而在GKE中通過另一個參數來禁用ABAC:
--no-enable-legacy-authorization
網上有很多不錯的例子和文檔描述了如何在集群中使用RBAC策略。 除此之外, 管理員還可以通過audit2rbac生成的審計日志來分析調優RBAC規則。
如果將RBAC規則設置得過大或者不正確, 一旦集群中出現有問題的Pod會對整個集群產生安全威脅。 RBAC規則應該基于最小特權原則進行維護, 并持續地加之以審閱和改善。 這應被團隊視為技術負債的清除手段被整合進開發流程之中。
審計日志功能(1.10中為beta階段)提供了可定制化地對集群各組件的訪問流量內容(例如請求和響應)及元數據(例如發起用戶和時間戳)記錄日志的功能。 日志等級可以根據組織內的安全策略進行調整。 在GKE上也有相應的設置來配置這個功能。
對于讀取類請求(比如get, list和watch) ,只有請求內容會被記錄在審計日志中, 響應內容不會保存。 對于涉及到敏感數據(比如Configmap和Secret)的請求, 只有元數據會被記錄。 對于其他類型的請求, 請求和相應對象都會被記錄。
切記:如果將審計日志保留在集群內部, 在集群已被入侵時會有安全威脅。 像這樣的所有安全相關的日志都應轉移到集群之外, 以避免出現安全漏洞時被篡改。
通過將Kubernetes與第三方的身份驗證服務(比如Google和GitHub)整合,這樣可以使用第三方平臺的身份保證機制(包括雙因子驗證等機制), 以避免管理員不得不重新配置API Server來添加或刪除用戶。
Dex是個OpenID Connect(OIDC)和OAuth2.0的身份服務組件。 它帶有可插拔的連接器。 Pusher公司通過這個機制將Dex作為認證鏈的中間件將Kubernetes與其他第三方認證服務關聯。 除此之外還有其他工具可以達成類似目的。
對API Server的etcd擁有寫權限相當于獲取了整個集群的root權限。 甚至僅通過對etcd的讀取操作都可以相當簡單地自行提權。
Kubernetes的調度器會搜索etcd找出那些已定義但還沒被調度到節點上的Pod, 然后把這樣的Pod發送到空閑的Kubelet節點進行部署。 在Pod信息被寫進etcd之前, API Server會檢查提交的Pod定義。 因此一些有惡意使用者會直接把Pod定義寫入etcd, 以跳過許多諸如PodSecurityPolicy這樣的安全機制。
無論是etcd集群的節點與節點, 還是節點與API Server, 他們的通信都應該配置TLS證書, 并且etcd集群應部署在專屬的節點之上。 etcd集群與Kubernetes集群間也應該設置防火墻, 以避免由于私鑰被盜而被從工作節點上發起攻擊。
Kubernetes會在某些現有證書過期時創建新的證書簽名申請來自動替換Kubelet的客戶端和服務器端證書。
但是API Server用來加密etcd數據的對稱密鑰是無法自動替換的。 它只能手工替換。 這樣的操作需要有對主節點操作的權限, 因此托管Kubernetes服務(比如谷歌的GKE和微軟的AKS)會自行解決這個問題而無需管理員操心。
像bane這樣的工具可以用來生成AppArmor的配置文件和seccomp的docker-slim配置文件。 然而用戶需要詳細測試自己應用的所有路徑, 驗證這些配置對應用是否會造成副作用。
而Pod安全規則可以用來授權使用Kubernetes的安全擴展和其他安全指令。 這些規則描述了一個Pod提交到API Server后所必須遵守的最小安全契約。 這些契約包括了安全配置,提權標志,以及共享主機網絡,進程或進程間通信的命名空間。
這些安全規則相當重要, 因為他們有助于防止容器內的進程超越其隔離邊界。 Tim Allclair提供的PodSecurityPolicy范例相當詳盡。 你可以自定義這個范例, 將其用在自己的使用場景里。
在Pod類型(比如Deployment, Pod, Set等)的YAML文件中不應該存放敏感數據, 而包含敏感數據的Configmap和Secret應該由諸如vault(通過CoreOS提供的operator), git-crypt, sealed secret或者云廠商提供的密鑰管理服務來進行加密處理。
靜態分析YAML配置可以對運行時的安全情況構建一條基準線。 以下是kubesec工具為某個資源生成風險評分的例子:
{ "score": -30, "scoring": { "critical": [{"selector": "containers[] .securityContext .privileged == true","reason": "Privileged containers can allow almost completely unrestricted host access" }], "advise": [{"selector": "containers[] .securityContext .runAsNonRoot == true","reason": "Force the running image to run as a non-root user to ensure least privilege" }, {"selector": "containers[] .securityContext .capabilities .drop","reason": "Reducing kernel capabilities available to a container limits its attack surface","href": "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" }] } }
而kubetest工具是個針對Kubernetes的YAML文件的單元測試框架。 代碼例子如下:
#// vim: set ft=python: def test_for_team_label(): if spec["kind"] == "Deployment":labels = spec["spec"]["template"]["metadata"]["labels"]assert_contains(labels, "team", "should indicate which team owns the deployment")test_for_team_label()
以上這些工具都通過將檢查和驗證工作在軟件開發周期中提前(shift left)到更早的開發階段的方式, 使開發人員能更早地獲得對于代碼和配置的反饋, 以避免提交在之后的人工或自動檢查中被退回。這樣也可以減少引入更多安全實踐的障礙。
容器技術依然基于傳統的Unix安全模型, 叫做自主訪問控制(簡稱DAC)。在這個模型之下,所有東西都是文件, 而權限是可以被賦予用戶或用戶組。
用戶命名空間在Kubernetes下并沒有啟用, 這意味著容器中的用戶表會被映射到宿主機的用戶表中, 而在容器里由root身份運行的進程相當于在宿主機上也是以root身份運行。 盡管說我們有層級安全機制來防范容器發生問題, 但在容器中用root身份運行進程依然是不推薦的做法。
許多容器鏡像使用root用戶運行一號進程。 如果這個進程被攻破, 那么攻擊者在容器中就有了root的權限, 從而會輕易放大由于集群誤配置造成的安全漏洞。
Bitnami公司在將容器鏡像遷移到非root用戶這方面做了很多工作(主要由于OpenShift平臺默認要求非root身份運行容器)。參考他們提供的文檔可以降低管理員實施類似遷移的難度。
下列Pod安全規則的代碼片段給出了防止容器中的進程以root身份運行, 以及防止進程提權到root身份的方法:
# Required to prevent escalations to root. allowPrivilegeEscalation: false runAsUser: # Require the container to run without root privileges. rule: 'MustRunAsNonRoot'
非root的容器無法綁定小于1024的端口(可以通過配置內核參數CAP_NET_BIND_SERVICE來啟用), 但使用service的特性可以使對外端口配置為1024以下。 在以下例子中,MyApp這個應用在容器中綁定了8443端口,而service將相關流量代理到443這個端口中對外暴露應用:
kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 443 targetPort: 8443
在用戶命名空間在Kubernetes中可用之前,或者非root功能在容器運行時組件中獲得直接支持之前, 使用非root用戶運行容器依然是推薦的做法。
傳統的服務一般給每個應用配置靜態IP和端口范圍。 這樣的靜態IP一般很少會改變,從而會被當作服務的一種標識來對待。 因此傳統服務可以通過防火墻來加以限制和保護。 容器為了能快速失敗快速重新調度,一般很少使用固定IP,而是通過使用服務發現的機制來替代。 容器這樣的特性使得防火墻會更難配置和審查。?
由于Kubernetes將所有系統狀態都存儲在etcd里, 只要CNI網絡插件支持網絡規則, 借助etcd中的數據就可以配置動態防火墻。 當前Calico, Cilium, kube-router, Romana和Weave Net這些插件都能支持網絡規則。
值得注意的是,這些網絡規則是失效關閉的(fail-closed), 因此在下列YAML中缺少podSelector配置意味著這個規則會應用到所有容器:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector:
下列的網絡規則的例子描述了如何關閉除了UDP 53(DNS端口)之外的所有對外流量。 這樣也防止了進入應用的連接——這是因為網絡規則是有狀態面向連接的, 同一個網絡連接中應用對外請求的響應也依舊會返回到應用中。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: myapp-deny-external-egress spec: podSelector: matchLabels:app: myapp policyTypes: - Egress egress: - ports: - port: 53protocol: UDP - to: - namespaceSelector: {}
Kubernetes的網絡規則并不能被應用到DNS名字上。 這是因為一個DNS名字會可能被輪詢調度解析到許多個IP地址,或者依據調用IP動態被解析到不同的目標IP地址, 而網絡規則只能被應用到靜態的IP或podSelector(也就是Kubernetes的動態IP機制)上。
安全上有一條最佳實踐建議一開始對Kubernetes的namespace先拒絕所有流量, 然后再逐漸添加路由允許應用能通過測試場景。 這樣做是非常復雜的, 可以通過下列ControlPlane公司出品的netassert這個開源工具來幫助達成最佳實踐。 netassert是一個安全運維工作流方面的網絡安全工具, 通過高度并發運用nmap來掃描和嗅探網絡:
k8s: # used for Kubernetes pods deployment: # only deployments currently supported test-frontend: # pod name, defaults to `default` namespacetest-microservice: 80 # `test-microservice` is the DNS name of the target servicetest-database: -80 # `test-frontend` should not be able to access test-database’s port 80169.254.169.254: -80, -443 # AWS metadata APImetadata.google.internal: -80, -443 # GCP metadata APInew-namespace:test-microservice: # `new-namespace` is the namespace nametest-database.new-namespace: 80 # longer DNS names can be used for other namespacestest-frontend.default: 80169.254.169.254: -80, -443 # AWS metadata APImetadata.google.internal: -80, -443 # GCP metadata API
云廠商的元數據API一般也會是被攻擊的源頭之一(參見最近發生的Shopify受攻擊的案例), 因此也需要有專門的測試來確定這一類API在容器網絡中被關閉, 以避免誤配置的可能。
Kubernetes通過一系列的Admission Controller來控制Pod類型的資源(如Deployment等)是否能被部署進集群。 Admission controller會檢驗每個被提交進來的Pod的定義,或者有時會修改Pod定義的內容。 現在已經支持后臺webhook掛載外部應用。
Webhook功能可以和容器鏡像掃描工具結合起來。 在容器被部署進集群之前掃描鏡像內容。 一旦未通過掃描檢查, 容器便會被Admission Controller拒絕部署。
使用工具掃描容器鏡像中是否包含已有的漏洞, 這樣能減小攻擊者利用公開漏洞(CVE, Common Vulnerabilities & Exposures)的時間窗口。 像CoreOS出品的Clair和Aqua出品的Micro Scanner都應該被整合到部署管道中, 以避免部署的容器中包含致命漏洞。
像Grafeas這樣的工具可以存儲鏡像的元數據, 用來針對容器的特有簽名(基于內容尋址的散列哈希)進行持續的合規與漏洞檢查。 通過這個簽名來掃描本地容器鏡像等同于掃描部署在生產環境的容器, 這樣就可以持續地做本地檢查而不需要連接到生產環境中。
而未知的瞬時攻擊漏洞(Zero Day)永遠會存在。 為了應對這樣的威脅, 需要在集群中部署一些諸如Twistlock, Aqua和Sysdig Security這樣的工具。而另外一些IDS會檢測出容器中發生的不尋常的行為, 暫停或者終止這樣的容器。 典型的工具有Sysdig出品的開源規則引擎Falco。
服務網格意味著微服務中的安全與網絡管理相關的代碼可以被去除, 而這部分責任將被轉移到經過實戰驗證的公共組件中。 之前通過Linkerd就已經可以達成這樣的功能。 如今由Google, IBM和Lyft聯合推出了Istio在服務網格領域也可以作為一個可選方案。 Istio通過基于SPIFFE規范的Pod間相互進行身份識別的能力以及其他一系列的功能, 來簡化服務網格這個下一代網絡安全的部署。 在“永不信任,始終驗證”(Zero Trust)的網絡模型中, 每次交互都應在互信TLS(mTLS, mutual TLS)下發生, 以保證交互雙方不僅鏈路安全,而且身份已知。 這樣的話或許就沒有必要使用傳統的防火墻或者Kubernetes的網絡規則了。
對于仍懷有傳統網絡思維的那些人來說,我們預計向云原生安全原則的思維轉變不會容易。 此處推薦閱讀來自SPIFFE項目委員會的Evan Gilman撰寫的Zero Trust Networking這本書來了解這一領域的入門知識。
Istio 0.8 LTS版本已經推出。 這個項目正快速接近1.0版本的發布(譯者:Istio 1.0版已于2018年7月31號發布)。 其版本編號習慣會與Kubernetes遵循的模型相同:核心版本穩定增長, 每個API都會通過自己版本中的alpha/beta來描述其穩定性。 可以期待Istio在之后幾個月的采用率會有上升。
防護工具層出不窮, 但管理員仍需警惕誤配置的潛在可能, 并盡量減少對外易受攻擊的點。
然而如果安全性要求會減緩組織交付功能的速度, 那么安全就永遠無法成為一類需求。通過在軟件交付流程中應用持續交付的原則, 可以讓組織在不影響業務的情況下也能合規和治理目標,實現持續審計。
第一部分:控制面板
作為Kubernetes的核心大腦, 控制面板全面展示了在集群中所有容器和Pod的運行情況。 它可以直接調度新的Pod(可能包含對宿主節點有root權限的容器), 還可以用來讀取集群中所有的secret。 控制面板中展示的內容非常重要, 需要好好的保護起來以免發生意外泄漏和惡意訪問——無論這些內容是被訪問時, 在存儲狀態, 又或者是在網絡中傳輸時。1. 全面啟用TLS
應該在所有組件上都使用TLS, 以防止網絡嗅探, 驗證服務器端的身份,以及在啟動雙向TLS認證時驗證客戶端的身份。需要注意的是, 一些組件在安裝時可能會有默認設置啟用http端口。管理員需要熟悉每個組件的設置從而識別出這種潛在會產生不安全流量的情況。
出處 這份來自Lucas K?ldstr?m的網絡圖展示了幾處應該配置TLS的地方, 包括組件與主節點的交互, 以及Kubelet與API Server的交互。 Kelsey Hightower的大作Kubernetes The Hard Way中對此提供了詳細的手工操作指導。 etcd的安全模型文檔里也有細致描述。
自動伸縮Kubernetes的節點在過去是非常困難的操作, 因為每個節點都需要一個TLS的密鑰來連接主節點, 而將密鑰打包放進基礎鏡像又不是一個好的實踐方式。 現在Kubelet的TLS引導程序提供了讓新的kubelet在啟動時生成證書簽名申請的能力。
2. 以最小特權原則設置RBAC, 關閉ABAC, 以及監控日志
RBAC提供了細粒度的規則管理功能, 以限制用戶對資源(比如namespace)的訪問。ABAC于Kubernetes的1.6版開始為RBAC所取代,已不建議啟用。 在普通的Kubernetes集群中通過設置以下啟動參數在API Server中啟用RBAC: --authorization-mode=RBAC
而在GKE中通過另一個參數來禁用ABAC:
--no-enable-legacy-authorization
網上有很多不錯的例子和文檔描述了如何在集群中使用RBAC策略。 除此之外, 管理員還可以通過audit2rbac生成的審計日志來分析調優RBAC規則。
如果將RBAC規則設置得過大或者不正確, 一旦集群中出現有問題的Pod會對整個集群產生安全威脅。 RBAC規則應該基于最小特權原則進行維護, 并持續地加之以審閱和改善。 這應被團隊視為技術負債的清除手段被整合進開發流程之中。
審計日志功能(1.10中為beta階段)提供了可定制化地對集群各組件的訪問流量內容(例如請求和響應)及元數據(例如發起用戶和時間戳)記錄日志的功能。 日志等級可以根據組織內的安全策略進行調整。 在GKE上也有相應的設置來配置這個功能。
對于讀取類請求(比如get, list和watch) ,只有請求內容會被記錄在審計日志中, 響應內容不會保存。 對于涉及到敏感數據(比如Configmap和Secret)的請求, 只有元數據會被記錄。 對于其他類型的請求, 請求和相應對象都會被記錄。
切記:如果將審計日志保留在集群內部, 在集群已被入侵時會有安全威脅。 像這樣的所有安全相關的日志都應轉移到集群之外, 以避免出現安全漏洞時被篡改。
3. 為API Server啟用第三方認證
在一個組織內部通過集中化的手段管理認證和授權(又被稱為單點登錄)有助于管理用戶的添加, 刪除以及一致的權限控制。通過將Kubernetes與第三方的身份驗證服務(比如Google和GitHub)整合,這樣可以使用第三方平臺的身份保證機制(包括雙因子驗證等機制), 以避免管理員不得不重新配置API Server來添加或刪除用戶。
Dex是個OpenID Connect(OIDC)和OAuth2.0的身份服務組件。 它帶有可插拔的連接器。 Pusher公司通過這個機制將Dex作為認證鏈的中間件將Kubernetes與其他第三方認證服務關聯。 除此之外還有其他工具可以達成類似目的。
4. 將etcd集群隔離出來并加上防火墻控制
etcd中存儲了集群的狀態和secret, 對Kubernetes而言是至關重要的組件。 它的防護措施應該與集群的其他部分區別處理。對API Server的etcd擁有寫權限相當于獲取了整個集群的root權限。 甚至僅通過對etcd的讀取操作都可以相當簡單地自行提權。
Kubernetes的調度器會搜索etcd找出那些已定義但還沒被調度到節點上的Pod, 然后把這樣的Pod發送到空閑的Kubelet節點進行部署。 在Pod信息被寫進etcd之前, API Server會檢查提交的Pod定義。 因此一些有惡意使用者會直接把Pod定義寫入etcd, 以跳過許多諸如PodSecurityPolicy這樣的安全機制。
無論是etcd集群的節點與節點, 還是節點與API Server, 他們的通信都應該配置TLS證書, 并且etcd集群應部署在專屬的節點之上。 etcd集群與Kubernetes集群間也應該設置防火墻, 以避免由于私鑰被盜而被從工作節點上發起攻擊。
5. 定期替換密鑰
定期替換密鑰和證書是一條安全方面的最佳實踐。 這樣能減小當密鑰被盜時所遭受的損害范圍。Kubernetes會在某些現有證書過期時創建新的證書簽名申請來自動替換Kubelet的客戶端和服務器端證書。
但是API Server用來加密etcd數據的對稱密鑰是無法自動替換的。 它只能手工替換。 這樣的操作需要有對主節點操作的權限, 因此托管Kubernetes服務(比如谷歌的GKE和微軟的AKS)會自行解決這個問題而無需管理員操心。
第二部分:工作負載
通過對控制面板實施最小化可用安全策略,可以使集群工作得更安全。 但這樣還不夠。 打個比方, 對于一艘裝運了危險貨物的船,船上的集裝箱也必須加以防護,這樣在出現意外事故或破壞時集裝箱還能承載貨物。對于Kubernetes的工作負載對象(Pod, Deployment,Job和Set等)也是一樣。 它們在部署時還是可信的,然而當面對外網流量時總還是會有被攻破的風險。 要減輕此類風險,除了針對工作負載對象實施最小特權原則外,還需要加固它們運行時的配置。6. 使用Linux的安全功能以及Kubernetes的Pod安全規則
Linux內核提供了許多互相有功能重疊的安全擴展(capabilities, SELinux, AppArmor, seccomp-bpf)。 他們可被配置用來為應用提供最小特權。像bane這樣的工具可以用來生成AppArmor的配置文件和seccomp的docker-slim配置文件。 然而用戶需要詳細測試自己應用的所有路徑, 驗證這些配置對應用是否會造成副作用。
而Pod安全規則可以用來授權使用Kubernetes的安全擴展和其他安全指令。 這些規則描述了一個Pod提交到API Server后所必須遵守的最小安全契約。 這些契約包括了安全配置,提權標志,以及共享主機網絡,進程或進程間通信的命名空間。
這些安全規則相當重要, 因為他們有助于防止容器內的進程超越其隔離邊界。 Tim Allclair提供的PodSecurityPolicy范例相當詳盡。 你可以自定義這個范例, 將其用在自己的使用場景里。
7. 靜態分析YAML文件
在使用Pod安全規則來控制Pod訪問API Server的同時, 也可以在開發工作流中使用靜態文件分析來構筑組織的合規需求或滿足風險偏好。在Pod類型(比如Deployment, Pod, Set等)的YAML文件中不應該存放敏感數據, 而包含敏感數據的Configmap和Secret應該由諸如vault(通過CoreOS提供的operator), git-crypt, sealed secret或者云廠商提供的密鑰管理服務來進行加密處理。
靜態分析YAML配置可以對運行時的安全情況構建一條基準線。 以下是kubesec工具為某個資源生成風險評分的例子:
{ "score": -30, "scoring": { "critical": [{"selector": "containers[] .securityContext .privileged == true","reason": "Privileged containers can allow almost completely unrestricted host access" }], "advise": [{"selector": "containers[] .securityContext .runAsNonRoot == true","reason": "Force the running image to run as a non-root user to ensure least privilege" }, {"selector": "containers[] .securityContext .capabilities .drop","reason": "Reducing kernel capabilities available to a container limits its attack surface","href": "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" }] } }
而kubetest工具是個針對Kubernetes的YAML文件的單元測試框架。 代碼例子如下:
#// vim: set ft=python: def test_for_team_label(): if spec["kind"] == "Deployment":labels = spec["spec"]["template"]["metadata"]["labels"]assert_contains(labels, "team", "should indicate which team owns the deployment")test_for_team_label()
以上這些工具都通過將檢查和驗證工作在軟件開發周期中提前(shift left)到更早的開發階段的方式, 使開發人員能更早地獲得對于代碼和配置的反饋, 以避免提交在之后的人工或自動檢查中被退回。這樣也可以減少引入更多安全實踐的障礙。
8. 使用非root的用戶運行容器
運行在root用戶下的容器大多擁有了大大超過其所承載的服務需要的權限。 當集群被侵入時,這樣的容器會讓攻擊者有能力執行更進一步的破壞。容器技術依然基于傳統的Unix安全模型, 叫做自主訪問控制(簡稱DAC)。在這個模型之下,所有東西都是文件, 而權限是可以被賦予用戶或用戶組。
用戶命名空間在Kubernetes下并沒有啟用, 這意味著容器中的用戶表會被映射到宿主機的用戶表中, 而在容器里由root身份運行的進程相當于在宿主機上也是以root身份運行。 盡管說我們有層級安全機制來防范容器發生問題, 但在容器中用root身份運行進程依然是不推薦的做法。
許多容器鏡像使用root用戶運行一號進程。 如果這個進程被攻破, 那么攻擊者在容器中就有了root的權限, 從而會輕易放大由于集群誤配置造成的安全漏洞。
Bitnami公司在將容器鏡像遷移到非root用戶這方面做了很多工作(主要由于OpenShift平臺默認要求非root身份運行容器)。參考他們提供的文檔可以降低管理員實施類似遷移的難度。
下列Pod安全規則的代碼片段給出了防止容器中的進程以root身份運行, 以及防止進程提權到root身份的方法:
# Required to prevent escalations to root. allowPrivilegeEscalation: false runAsUser: # Require the container to run without root privileges. rule: 'MustRunAsNonRoot'
非root的容器無法綁定小于1024的端口(可以通過配置內核參數CAP_NET_BIND_SERVICE來啟用), 但使用service的特性可以使對外端口配置為1024以下。 在以下例子中,MyApp這個應用在容器中綁定了8443端口,而service將相關流量代理到443這個端口中對外暴露應用:
kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 443 targetPort: 8443
在用戶命名空間在Kubernetes中可用之前,或者非root功能在容器運行時組件中獲得直接支持之前, 使用非root用戶運行容器依然是推薦的做法。
9. 使用網絡規則
默認狀態下, Kubernetes中Pod與Pod之間的網絡是互通的。 可以通過使用網絡規則來對此加以限制。傳統的服務一般給每個應用配置靜態IP和端口范圍。 這樣的靜態IP一般很少會改變,從而會被當作服務的一種標識來對待。 因此傳統服務可以通過防火墻來加以限制和保護。 容器為了能快速失敗快速重新調度,一般很少使用固定IP,而是通過使用服務發現的機制來替代。 容器這樣的特性使得防火墻會更難配置和審查。?
由于Kubernetes將所有系統狀態都存儲在etcd里, 只要CNI網絡插件支持網絡規則, 借助etcd中的數據就可以配置動態防火墻。 當前Calico, Cilium, kube-router, Romana和Weave Net這些插件都能支持網絡規則。
值得注意的是,這些網絡規則是失效關閉的(fail-closed), 因此在下列YAML中缺少podSelector配置意味著這個規則會應用到所有容器:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector:
下列的網絡規則的例子描述了如何關閉除了UDP 53(DNS端口)之外的所有對外流量。 這樣也防止了進入應用的連接——這是因為網絡規則是有狀態面向連接的, 同一個網絡連接中應用對外請求的響應也依舊會返回到應用中。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: myapp-deny-external-egress spec: podSelector: matchLabels:app: myapp policyTypes: - Egress egress: - ports: - port: 53protocol: UDP - to: - namespaceSelector: {}
Kubernetes的網絡規則并不能被應用到DNS名字上。 這是因為一個DNS名字會可能被輪詢調度解析到許多個IP地址,或者依據調用IP動態被解析到不同的目標IP地址, 而網絡規則只能被應用到靜態的IP或podSelector(也就是Kubernetes的動態IP機制)上。
安全上有一條最佳實踐建議一開始對Kubernetes的namespace先拒絕所有流量, 然后再逐漸添加路由允許應用能通過測試場景。 這樣做是非常復雜的, 可以通過下列ControlPlane公司出品的netassert這個開源工具來幫助達成最佳實踐。 netassert是一個安全運維工作流方面的網絡安全工具, 通過高度并發運用nmap來掃描和嗅探網絡:
k8s: # used for Kubernetes pods deployment: # only deployments currently supported test-frontend: # pod name, defaults to `default` namespacetest-microservice: 80 # `test-microservice` is the DNS name of the target servicetest-database: -80 # `test-frontend` should not be able to access test-database’s port 80169.254.169.254: -80, -443 # AWS metadata APImetadata.google.internal: -80, -443 # GCP metadata APInew-namespace:test-microservice: # `new-namespace` is the namespace nametest-database.new-namespace: 80 # longer DNS names can be used for other namespacestest-frontend.default: 80169.254.169.254: -80, -443 # AWS metadata APImetadata.google.internal: -80, -443 # GCP metadata API
云廠商的元數據API一般也會是被攻擊的源頭之一(參見最近發生的Shopify受攻擊的案例), 因此也需要有專門的測試來確定這一類API在容器網絡中被關閉, 以避免誤配置的可能。
10. 掃描容器鏡像和運行IDS(入侵檢測系統)
Web服務器作為它所部署的網絡上的一個可被攻擊的切入口,它鏡像上的文件系統需要被完全掃描,以避免存在已知的漏洞被攻擊者利用來取得遠程控制容器的權限。使用IDS可以檢測已知漏洞。Kubernetes通過一系列的Admission Controller來控制Pod類型的資源(如Deployment等)是否能被部署進集群。 Admission controller會檢驗每個被提交進來的Pod的定義,或者有時會修改Pod定義的內容。 現在已經支持后臺webhook掛載外部應用。
Webhook功能可以和容器鏡像掃描工具結合起來。 在容器被部署進集群之前掃描鏡像內容。 一旦未通過掃描檢查, 容器便會被Admission Controller拒絕部署。
使用工具掃描容器鏡像中是否包含已有的漏洞, 這樣能減小攻擊者利用公開漏洞(CVE, Common Vulnerabilities & Exposures)的時間窗口。 像CoreOS出品的Clair和Aqua出品的Micro Scanner都應該被整合到部署管道中, 以避免部署的容器中包含致命漏洞。
像Grafeas這樣的工具可以存儲鏡像的元數據, 用來針對容器的特有簽名(基于內容尋址的散列哈希)進行持續的合規與漏洞檢查。 通過這個簽名來掃描本地容器鏡像等同于掃描部署在生產環境的容器, 這樣就可以持續地做本地檢查而不需要連接到生產環境中。
而未知的瞬時攻擊漏洞(Zero Day)永遠會存在。 為了應對這樣的威脅, 需要在集群中部署一些諸如Twistlock, Aqua和Sysdig Security這樣的工具。而另外一些IDS會檢測出容器中發生的不尋常的行為, 暫停或者終止這樣的容器。 典型的工具有Sysdig出品的開源規則引擎Falco。
第三部分: 展望未來
目前看來服務網格當屬安全在“云原生進化(cloud native evolution)”發展中的下一階段形態。 當然真正應用服務網格尚需時日。 遷移工作涉及到將應用層中含有的相關復雜邏輯轉移為依賴服務網格的基礎構件, 而企業也會很想詳細理解遷移和運用服務網格相關的最佳實踐。11. 使用服務網格
服務網格是通過類似Envoy和Linkerd這樣的高性能邊車(sidecar)代理服務器在集群中組建應用間加密網絡的基礎設施。 它提供了流量管理, 監控和規則控制的能力而無需微服務為此修改代碼。服務網格意味著微服務中的安全與網絡管理相關的代碼可以被去除, 而這部分責任將被轉移到經過實戰驗證的公共組件中。 之前通過Linkerd就已經可以達成這樣的功能。 如今由Google, IBM和Lyft聯合推出了Istio在服務網格領域也可以作為一個可選方案。 Istio通過基于SPIFFE規范的Pod間相互進行身份識別的能力以及其他一系列的功能, 來簡化服務網格這個下一代網絡安全的部署。 在“永不信任,始終驗證”(Zero Trust)的網絡模型中, 每次交互都應在互信TLS(mTLS, mutual TLS)下發生, 以保證交互雙方不僅鏈路安全,而且身份已知。 這樣的話或許就沒有必要使用傳統的防火墻或者Kubernetes的網絡規則了。
對于仍懷有傳統網絡思維的那些人來說,我們預計向云原生安全原則的思維轉變不會容易。 此處推薦閱讀來自SPIFFE項目委員會的Evan Gilman撰寫的Zero Trust Networking這本書來了解這一領域的入門知識。
Istio 0.8 LTS版本已經推出。 這個項目正快速接近1.0版本的發布(譯者:Istio 1.0版已于2018年7月31號發布)。 其版本編號習慣會與Kubernetes遵循的模型相同:核心版本穩定增長, 每個API都會通過自己版本中的alpha/beta來描述其穩定性。 可以期待Istio在之后幾個月的采用率會有上升。
結語
云原生應用擁有一系列帶有細粒度配置能力的輕量級安全組件來控制工作負載與基礎架構。 這些工具的威力和靈活性對管理員來說既是祝福又是詛咒。 如果自動化安全能力不足, 這些工具很容易會暴露不安全的網絡流量,導致容器或隔離結構爆發問題。防護工具層出不窮, 但管理員仍需警惕誤配置的潛在可能, 并盡量減少對外易受攻擊的點。
然而如果安全性要求會減緩組織交付功能的速度, 那么安全就永遠無法成為一類需求。通過在軟件交付流程中應用持續交付的原則, 可以讓組織在不影響業務的情況下也能合規和治理目標,實現持續審計。
在有完整的測試套件的支持之下,想要在安全方面快速迭代是非常容易的。 而這樣的迭代并非是用定點運行滲透測試來運作,而是持續安全(Continuous Security)。 持續安全通過持續的管道驗證的方式來保證組織的受攻擊點清晰, 相關風險明確并能有效地被管理起來。
本文轉自DockOne-Kubernetes管理員的11條安全軍規
總結
以上是生活随笔為你收集整理的Kubernetes管理员的11条 安全军规的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sqlplus: error while
- 下一篇: java new java.text.S