Phân tích và hướng dẫn bảo mật Kurbernetes Dashboard

cloudFun

Gần đây công ty xe hơi Tesla đã được cảnh báo bởi công ty bảo mật RedLock, rằng Kubernetes infratructure của họ đã bị xâm phạm. Những kẻ tấn công đã sử dụng tài infrastructure Tesla để khai thác tiền điện tử. Kiểu tấn công này đã được gọi “cryptojacking”, một loại hình tấn công để ăn cắp tiền điện tử.

Vectơ tấn công trong trường hợp này là một Kubernetes Dashboard được tiếp xúc với internet nói chung không có xác thực cũng như đặc quyền nâng cao. Không chỉ điều này, mà các key và secret của API AWS cốt lõi cũng có thể nhìn thấy được. Làm thế nào để ngăn chặn điều này xảy ra?

Câu trả lời sẽ được bật mí tại bài đăng này với nội dung cập nhật mới nhất được chia sẻ bởi Joe Beda, CTO của Heptio.
0_agAXL4yjzEkyQAIr_.jpg


Sự cố bảo mật tại Telsa
Theo nhận định của Joe Beda, có 2 lý do dẫn tới sự cố nghiêm trọng nói trên.

Đầu tiên, Kubernetes Dashboard có các đặc quyền nâng cao trên cluster. Điều này xảy ra bằng cách chạy một cluster mà không có RBAC (Role Based Access Control) hoặc được phân cấp rõ ràng các đặc quyền nâng cao tài khoản dịch vụ daskboard.

Thứ hai, Kubernetes Dashboard được tiếp xúc với internet. Theo mặc định, Dashboard được hiển thị rõ ràng bên ngoài cluster. Tuy nhiên, sự dễ dàng trong đó người dùng có thể phơi bày các dịch vụ khiến cho việc tiếp cận internet của dashboard. Việc hiển thị dashboard thường có thể là một thay đổi một dòng trong file YAML Kubernetes.


Không bỏ qua những vấn đề cơ bản

Việc tránh các cuộc tấn công như thế này có thể được thực hiện thông qua security hygiene (vệ sinh an ninh) đơn giản. Để bắt đầu chạy phiên bản Kubernetes gần đây với RBAC được bật.

Các phiên bản gần đây của Kubernetes đã có những bước tiến lớn trong việc bảo vệ cluster. Khi được thiết lập đúng, giao tiếp giữa các phần của cluster được xác thực và mã hóa. Hiện tại có các cơ chế bootstrap (được sử dụng bởi kubeadm và các dự án khác) giúp thiết lập encryption (mã hóa) đó. Ngoài ra, cấu hình mặc định để cài đặt dashboard đã liên tục bị khóa trong vài phiên bản trước.

RBAC là một yêu cầu bắt buộc tuyệt đối cho mọi cài đặt Kubernetes an toàn. Hầu hết các trình cài đặt và phân phối, tại thời điểm này, sẽ kích hoạt RBAC cho các cluster mới. Nên tận dụng điều đó. Tuy nhiên, lưu ý rằng AKS (Azure Kubernetes Service) và kops đều không bật RBAC theo mặc định tại thời điểm của bài viết này. (AKS sẽ sớm thêm hỗ trợ và là một gate (cổng) cho sự sẵn có chung của dịch vụ.)

An ninh không chỉ dành cho Production! Trong thế giới của infratructure, ý định của cluster không quan trọng. Mặc dù có thể không tiết lộ data người dùng, nhưng có thể infratructure đang có nguy cơ rơi vào các cuộc tấn công như tiền điện tử. Điều này có thể dễ dàng làm tăng hóa đơn Cloud. Ngoài ra, nó có thể là bước đầu tiên để tấn công sâu hơn, nhắm mục tiêu hơn vào production cluster của doanh nghiệp.

Brad Geesaman đã có một buổi chia sẻ tuyệt vời về việc hardening (làm cứng) Kubernetes tại KubeCon ở Austin. Các videoslides có sẵn và đáng để dành thời gian tìm hiểu.

Truy cập dashboard
Theo mặc định, Dashboard không thể truy cập được bên ngoài cluster. Trên thực tế, trong một số cấu hình (chẳng hạn như Bắt đầu nhanh cho Kubernetes của Heptio trên AWS) network policy (chính sách mạng) được sử dụng để hạn chế xâm nhập vào dashboard trong cluster sao cho các semi-trusted applications (ứng dụng bán tin cậy) khác trong cluster có thể nâng cao đặc quyền thông qua dashboard khi dashboard được cấu hình sai.

Cách dễ nhất và phổ biến nhất để truy cập cluster là thông qua proxy kubectl. Điều này tạo ra một local web server (máy chủ web cục bộ) cung cấp dữ liệu an toàn cho dashboard thông qua máy chủ API Kubernetes.


Đây là một quy trình 2 bước dễ dàng trong trường hợp đã xác thực với cluster thông qua kubectl đã được setup (thiết lập). Chỉ cần nhập proxy kubectl và sau đó điều hướng trình duyệt đến http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ (một bản setup phiên bản cũ có thể sử dụng thay thế: http://localhost:8001/api/v1/namespaces/kube-system/services/kubernetes-dashboard:/proxy/)

Tuy nhiên, khi muốn truy cập dashboard mà không cần phải xử lý bằng dòng lệnh thì cần làm như thế nào? Doanh nghiệp có thể muốn đặt loại đơn giản: LoadBalancer trên dịch vụ dashboard. Thì lời khuyên là: Đừng sử dụng! Điều này thường làm cho dashboard có thể dễ dàng truy cập toàn cầu. Với một cluster hoạt động tốt với RBAC, đây không phải là một thảm họa ngay lập tức nhưng nó vẫn không được khuyến khích. Đầu tiên, nếu doanh nghiệp vô tình trao quyền cho dashboard ServiceAccount, họ mở quyền truy cập các key cluster công khai. Nhưng ngay cả khi không làm điều đó, doanh nghiệp vẫn có nguy cơ nếu có một lỗi trong dashboard. Điều đó có thể cho phép kẻ tấn công chiếm quyền điều khiển dashboard và thỏa hiệp thông tin đăng nhập từ người dùng thực khi họ sử dụng nó.

Nếu dashboard phải được hiển thị mà không có proxy kubectl, có hai tùy chọn:
  • Ưu tiên: Sử dụng proxy xác thực (ví dụ trong phần hướng dẫn).
  • Hiển thị proxy bằng loại: dịch vụ NodePort và bảo mật mạng của doanh nghiệp. Điều này sẽ làm cho dashboard có sẵn cho bất kỳ ai có thể trực tiếp tiếp cận bất kỳ cluster node. Điều này có thể phù hợp hoặc không phù hợp tùy thuộc vào cấu hình.
Nếu muốn tìm hiểu thêm về các loại Kubernetes Service khác nhau, hãy xem TGIK 002. Tham khảo thêm nội dung này tron Chương Dịch vụ của cuốn sách: Kubernetes Up and Running. Chương đó có sẵn trong một đoạn trích được cung cấp miễn phí bởi Heptio.

Xác thực và Dashboard
Tất cả xác thực và ủy quyền trong Kubernetes được thực hiện tại máy chủ API. Xác thực trong Kubernetes là một hệ thống cực kỳ linh hoạt giúp tích hợp hầu hết mọi hệ thống ủy quyền. Tuy nhiên, vì tính linh hoạt này, hiện tại không có cách chung nào để người dùng thực hiện bất kỳ loại ủy quyền nào của họ truy cập vào ứng dụng khác.

Các thành phần trong Kubernetes control plane sử dụng một người dùng tổng hợp có tên là ServiceAccount để xác thực với máy chủ API. Khi sử dụng phiên bản gần đây của YAML deployment được đề xuất cho dashboard, dashboard ServiceAccount có rất ít đặc quyền trên cluster. Điều này có nghĩa là trên chính nó, dashboard có rất ít quyền. Điều này thật tuyệt vời từ góc độ bảo mật nhưng không quá tuyệt vời từ một người có khả năng làm bất cứ điều gì ở tất cả các phối cảnh của người dùng.

Dashboard github repo có một trang hữu ích chia sẻ chi tiết một số chi tiết kỹ thuật về Xác thực và Ủy quyền cho dashboard, tham khảo tại đây.

Tránh trao quyền cho dashboard ServiceAccount
Vì ServiceAccount cho dashboard có ít quyền, nên dashboard dường như gặp sự cố với nhiều quyền của Cameron bị từ chối lỗi. Người dùng thường giải quyết vấn đề này bằng cách cấp các đặc quyền gốc Service Service trên cluster. Đây có thể là một hoạt động quản trị một dòng. Nó thậm chí còn được tham chiếu (có cảnh báo) trên dashboard wiki. Không nên cung cấp đặc quyền gốc dashboard. Bất kỳ cài đặt nào của Kubernetes, hầu hết đều không thích hợp cho để cấp quyền truy cập gốc dashboard. Ngay cả trong “development” hoặc “toy” cluster, điều này có thể tạo ra những thói quen xấu.

Ưu tiên: per-user credentials (thông tin theo người dùng)
Cách tốt nhất hiện tại để làm cho dashboard hoạt động là cung cấp thông tin đăng nhập cho người dùng chỉ khi người dùng đó hoạt động. Có 2 cách chính mà điều này có thể được thực hiện.

Cách đầu tiên để cung cấp thông tin đăng nhập cho dashboard là thông qua login page (trang đăng nhập). Nếu truy cập dashboard mà không có thông tin xác thực, nó sẽ hiển thị một trang đăng nhập. Mục tiêu của trang đăng nhập này là thu thập thông tin đăng nhập từ người dùng, mã hóa chúng và sau đó lưu trữ chúng trong cookie để truy cập trong tương lai.
0_x2RAWv-eW6OgtRAF_.png

Lưu ý: Trang đăng nhập chỉ hoạt động khi sử dụng token xác thực (token auth) để truy cập API Server. Đây thường không phải là trường hợp khi lần đầu tiên thực hiện bootstrapping một cluster. Ví dụ: không có xác thực dựa trên token chung được thiết lập với stock kubeadm cluster. (Tên người dùng cơ bản: mật khẩu xác thực cũng được dashboard hỗ trợ nhưng việc sử dụng nó không được khuyến khích)

Cơ chế thứ hai để có đưa thông tin đăng nhập vào dashboard là có một thành phần chắn trước Dashboard đặt một header cho phép ủy quyền. Bất cứ thông tin trong header đó đều được chuyển đến máy chủ API Kubernetes. Điều này có thể được thực hiện với một phần mở rộng trình duyệt (chẳng hạn như Requestly) hoặc thông qua proxy xác thực.

Với cả hai cách tiếp cận thì việc hết hạn token cũng có thể là một vấn đề. Thông thường, token được sử dụng là một phần của flow OAuth mà dashboard không nhận biết được. Điều này có nghĩa là trang đăng nhập sẽ thiết lập lại sau vài phút đến vài giờ. Sau đó, người dùng được yêu cầu đăng nhập lại bằng token cập nhật.

Sử dụng một ServiceAccount token
Một cách để khắc phục cả hai vấn đề này và dùng long lived token (token tồn tại lâu dài) để tạo ServiceAccount, đồng thời trích xuất và sử dụng token của chính ServiceAccount. Đây là một sự lạm dụng nhẹ của cơ chế ServiceAccount và có thể có những cách tốt hơn trong tương lai. Cũng có thể có các tùy chọn khác tùy thuộc vào việc và cách các cơ chế xác thực thay thế được triển khai trong cluster.

Để tạo một service accoint để truy cập vào cluster, thực hiện các bước sau:
Mã:
# Create the service account in the current namespace
# (we assume default)
kubectl create serviceaccount my-dashboard-sa
# Give that service account root on the cluster
kubectl create clusterrolebinding my-dashboard-sa \
  --clusterrole=cluster-admin \
  --serviceaccount=default:my-dashboard-sa
# Find the secret that was created to hold the token for the SA
kubectl get secrets
# Show the contents of the secret to extract the token
kubectl describe secret my-dashboard-sa-token-xxxxx
Token trong service account đó là root password (mật khẩu gốc). Thực hiện các bước trên để bảo vệ mật khẩu. Hiện tại có thể đặt nó trong màn hình đăng nhập (hoặc cấu hình Requestly) và có xác thực đáng tin cậy cho dashboard.

Người đọc thông minh có thể tự hỏi tại sao việc sử dụng token ServiceAccount tốt hơn thay vì chỉ cấp quyền truy cập vào dashboard ServiceAccount. Có một vài lý do. Đầu tiên, khi sử dụng token, có thể tạo nhiều ServiceAccounts với nhiều quyền hạn chế hơn. Thông thường, người dùng có thể tự tạo ServiceAccounts phản ảnh các quyền của chính họ. Thứ hai, nếu dashboard vô tình bị lộ công khai, bộ quyền mặc định bị giới hạn. Người dùng truy cập dashboard được yêu cầu mang thêm thông tin để làm cho nó hoạt động.

Kết luận
Dashboard là một cách tuyệt vời để hình dung và hiểu những gì đang diễn ra trong cluster. Nhưng sức mạnh đó có thể cắt giảm cả hai cách. Nếu không cẩn thận, nó rất dễ bị hiểu nhầm sẽ cung cấp quá nhiều quyền truy cập cho không đúng đối tượng. Kubernetes là một dự án nhanh nhạy và rất dễ dàng để tìm ra thông tin cập nhật khiến mọi thứ hoạt động nhưng theo cách không an toàn. Từ giờ trở đi, hãy đảm bảo việc sử dụng các tính năng bảo mật mới nhất cho cluster của mình (RBAC, chính sách mạng…) và suy nghĩ thấu đáo trước khi công khai bất cứ điều gì bên ngoài cluster.

Có thể bắt đầu thực hiện điều này ngay bây giờ với hướng dẫn sau để sử dụng oauth2_proxy trước dashboard Kubernetes.

Hướng dẫn: Screening với oauth2_proxy

Cách tốt nhất để hiển thị Dashboard Kubernetes (hoặc bất kỳ dashboard nào khác như Jenkins) là sử dụng proxy xác thực. Đây là một proxy nằm trước một service và chỉ cho phép lưu lượng truy cập nếu người dùng đã xác thực. Bitly đã đủ tốt để mở mã xác thực dựa trên oauth2. Nó hoạt động khá tốt với Dashboard Kubernetes.

Trong ví dụ này, GitHub được sử dụng làm nhà cung cấp xác thực của. Oauth2_proxy hỗ trợ nhiều nhà cung cấp. Tham khảo tài liệu trên để biết chi tiết.

Khi hoàn thành, kết quả sẽ có dạng giống như hình bên dưới. Request traffic (Yêu cầu lưu lượng) sẽ theo các mũi tên đậm. Ingress sẽ sử dụng Let Enc Encrypt để lấy các chứng chỉ sẽ được sử dụng qua internet. Oauth2_proxy sau đó sẽ xác thực proxy đó bằng GitHub (điều này sẽ bao gồm chuyển hướng người dùng đến GitHub). Cuối cùng, lưu lượng sẽ chuyển đến dashboard và sử dụng API server.
1_My-azKvnd_VgJsbRKWPlNw.png


Bước 1: Sử dụng một cluster với cấu hình Ingress và TLS
Để bắt đầu, cần một cluster có thể hiển thị các service trên một URL được hỗ trợ và với TLS. Trong trường hợp này, giả sử dự án đang sử dụng Contour với Let Enc Encrypt và cert-manager (trình quản lý chứng chỉ) JetStack. Tham khảo thêm về nội dụng này trên blog của Dave Cheney.

Đối với hướng dẫn này, giả sử dashboard đang được lưu trữ trên k8s.i.example.com. Phần “i” trong domain dành cho “internal” (tên miền nội bộ) và là một cách tốt để biểu thị cho người dùng rằng đây không phải là domain công khai. Thay thế bằng tên miền chính xác bất cứ vị trí nào có thể nhìn thấy trong các hướng dẫn này.

Bước 2: Tạo một ứng dụng GitHub
Truy cập https://github.com/settings/developers và tạo một ứng dụng mới. Người dùng sẽ thấy thông tin này khi đặng nhập vào proxy (uỷ quyền), vì vậy hãy chắc chắn rằng nó đáng tin cậy.

Điều quan trọng là callback URL, đặt nó thành: https://k8s.i.example.com/oauth2/callback.

Trong số này, người dùng sẽ nhận được một Client ID và một Client Secret có dạng như sau:
0_X4OdCkObjrdAm-HM_.png


Bước 3: Tạo một Kubernetes Secret cho những value trên
Chạy lệnh sau với những values được thay thế trong:
Mã:
kubectl create secret generic dashboard-proxy-secret \
  -o yaml --dry-run \
  -n kube-system \
  --from-literal=client-id=97a5d47e775f844b06d0 \
  --from-literal=client-secret=f2fbea21867b40b4964716eedf23eccdab5a2487 \
  --from-literal=cookie=$(openssl rand 16 -hex) > dashboard-proxy-secret.yaml
Đến đây, thêm vào kubectl apply -f dashboard-proxy-secret.yaml

Nếu bạn đang kiểm tra vấn đề này này trong source control repository (kho lưu trữ kiểm soát nguồn), có thể điều tra một hệ thống như Sealed Secrets của Bitnami.



Bước 4: Khởi chạy proxy với Ingress
Tại ví dụ này, 4 đối tượng được tạo ra với một loạt YAML:
  • Deployment cho chính proxy. Điều này thực sự sẽ chạy proxy. Cấu hình của nó sẽ là sự kết hợp của các dòng lệnh flag và các biến enviroment được lấy từ Secret đã tạo ở bước trước. Hãy đảm bảo rằng các flags tham số redirect-url và github-org đã được sửa để phù hợp với cấu hình.
  • Một đối tượng Service. Điều này rất hữu ích để hệ thống Ingress có thể tìm thấy proxy.
  • Một đối tượng Certificate (Chứng chỉ). Điều này được sử dụng để yêu cầu người quản lý chứng chỉ cung cấp chứng chỉ với Let Enc Encrypt. Đảm bảo sửa tên DNS thành tên đang sử dụng.
  • Cấu hình Ingress. Điều này cho biết hệ thống xâm nhập để định tuyến lưu lượng đến proxy.
Mã:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: dashboard-proxy
  name: dashboard-proxy
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dashboard-proxy
  template:
    metadata:
      labels:
        app: dashboard-proxy
    spec:
      containers:
      - args:
        - --cookie-secure=false
        - --provider=github
        - --upstream=http://kubernetes-dashboard.kube-system.svc.cluster.local
        - --http-address=0.0.0.0:8080
        - --redirect-url=https://k8s.i.example.com/oauth2/callback
        - --email-domain=*
        - --github-org=YOUR-ORG
        - --pass-basic-auth=false
        - --pass-access-token=false
        env:
        - name: OAUTH2_PROXY_COOKIE_SECRET
          valueFrom:
            secretKeyRef:
              key: cookie
              name: dashboard-proxy-secret
        - name: OAUTH2_PROXY_CLIENT_ID
          valueFrom:
            secretKeyRef:
              key: client-id
              name: dashboard-proxy-secret
        - name: OAUTH2_PROXY_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              key: client-secret
              name: dashboard-proxy-secret
        image: a5huynh/oauth2_proxy:2.2
        name: oauth-proxy
        ports:
        - containerPort: 8080
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: dashboard-proxy
  name: dashboard-proxy
  namespace: kube-system
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: dashboard-proxy
  type: ClusterIP
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: dashboard-proxy-tls
  namespace: kube-system
spec:
  secretName: dashboard-proxy-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName:  k8s.i.example.com
  dnsNames:
  -  k8s.i.example.com
  acme:
    config:
    - http01: {}
      domains:
      -  k8s.i.example.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-proxy
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: contour
spec:
  rules:
  - host: k8s.i.example.com
    http:
      paths:
      - backend:
          serviceName: dashboard-proxy
          servicePort: 8080
        path: /
  tls:
  - hosts:
    - k8s.i.example.com
    secretName: dashboard-proxy-tls
Bước 5: Sử dụng HTTP giữa proxy và dashboard

Theo mặc định, dashboard cấu hình HTTPS với self signed certificate (chứng chỉ tự ký). Đây là một cách tiếp cận tuyệt vời. Trong tình huống khi có thể có một chứng chỉ công khai, chứng chỉ tự ký sẽ tốt hơn. Nó cung cấp bảo vệ khỏi nghe lén, trừ trường hợp các cuộc tấn công trung gian.

Vấn đề là oauth2_proxy không biết cách xử lý các chứng chỉ tự ký trên các upstream service. Điều này có nghĩa là phải hiển thị dashboard trên HTTP cũ thay vì HTTPS.

Thực hiện điều này bằng cách chỉnh sửa cả Dashboard Deployment và Dashboard Service.

Đầu tiên, chỉnh sửa Deployment với kubectl -n kube-system chỉnh sửa deployment kubernetes-dashboard. Điều này sẽ khởi chạy trình soạn thảo để có thể cấu hình lại Deployment. Thực hiện các thay đổi sau:
  • Thay đổi tất cả các phiên bản 8443 thành 9090
  • Đặt lược đồ livenessProbe thành HTTP (thay vì HTTPS)
  • Đặt đối số và xóa auto-generate-certificates :
Mã:
- --insecure-bind-address=0.0.0.0
- --insecure-port=9090
- --enable-insecure-login
Đến đây, sửa Service với kubectl -n kube-system chỉnh sửa service kubernetes-dashboard. Sửa phần port như sau:
Mã:
ports:
- port: 80
  protocol: TCP
  targetPort: 9090
Cuối cùng, một số cluster có thể bị nhầm lẫn về quyền truy cập vào dashboard. Ví dụ, Heptio quickstart thực hiện chính sách mạng để chặn tất cả quyền truy cập vào dashboard. Có thể vô hiệu hóa điều này với kubectl -n kube-system xóa Networkpolicy deny-dashboard. Ngoài ra, có thể viết chính sách mạng thay thế tốt hơn để chỉ cho phép traffic truy cập vào dashboard từ proxy tùy thuộc vào mô hình mối đe dọa.

Lưu ý: nếu muốn truy cập dashboard với proxy kubectl sau này, phải sử dụng URL: http://localhost:8001/api/v1/namespaces/kube-system/services/kubernetes-dashboard:/proxy/#!/login.


Bước 6: Thử nghiệm
Nếu các bước trên được hoàn thiện, có thể nhấn https://k8s.i.example.com và sử dụng trang đăng nhập. Nhấp vào đó và cấp cho dashboard quyền truy cập vào danh tính của dự án (phải bao gồm quyền truy cập vào GitHub Org trong câu hỏi). Sau đó, người dùng nên được chuyển tiếp đến Dashboard Kubernetes nơi có thể sử dụng token khi cần thiết.

Trong tương lai, có thể có oauth2_proxy chuyển tiếp xác thực đến API Server và được API Server tin tưởng token đó để xác thực. Như vậy, có thể bỏ qua màn hình đăng nhập Dashboard hoàn toàn!

Kỹ thuật sử dụng oauth2_proxy không chỉ hữu ích cho dashboard. Đây là một cách tuyệt vời để bảo mật truy cập vào bất kỳ loại dịch vụ web nội bộ nào mà không phải thiết lập VPN.

Nguồn: https://blog.heptio.com/
 
Top