Skip to content

Bảo mật & Cường hóa

Tư thế bảo mật cấp production cho cụm Kubernetes BANA — bao phủ các hạn chế cấp pod, cô lập namespace, RBAC, chuỗi cung ứng image và ưu tiên scheduling.

Pod Security Standards (PSS)

Kubernetes Pod Security Standards định nghĩa ba profile: privileged, baseline, và restricted. BANA enforce chúng ở cấp namespace qua label.

Label Namespace

Production namespaces — restricted profile
yaml
# Production namespaces — restricted profile
apiVersion: v1
kind: Namespace
metadata:
  name: nx-backend
  labels:
    app.kubernetes.io/part-of: bana
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: Namespace
metadata:
  name: nx-app
  labels:
    app.kubernetes.io/part-of: bana
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
Staging namespaces — also use restricted:latest enforce mode
yaml
# Staging namespaces — also use restricted:latest enforce mode
# (matches production — all namespaces including nx-broker use restricted)
apiVersion: v1
kind: Namespace
metadata:
  name: nx-backend
  labels:
    app.kubernetes.io/part-of: bana
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted

INFO

Staging dùng cùng enforce mode restricted như production trên tất cả namespace (bao gồm nx-broker). Điều này đảm bảo đồng đẳng bảo mật và phát hiện vi phạm PSS sớm.

Tóm tắt Profile

ProfileNamespacesSử dụng
restrictednx-backend, nx-app, nx-persistent, nx-broker, nx-search, nx-internal, nx-watcher (cả staging và production)Tất cả namespace enforce profile restricted

Template SecurityContext

Mọi container trong BANA phải chạy với SecurityContext đã được cường hóa. Template này là baseline cho tất cả Deployment backend và frontend.

Dockerfile dùng user bun (UID 1000) built-in từ base image oven/bun:*-alpine qua USER bun. SecurityContext của K8s khớp với điều này bằng runAsUser: 1000 / runAsGroup: 1000.

SecurityContext Cấp Pod

### Pod-Level SecurityContext
yaml
spec:
  template:
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000   # matches 'bun' user in Dockerfile
        runAsGroup: 1000  # matches 'bun' group in Dockerfile
        fsGroup: 1000
        seccompProfile:
          type: RuntimeDefault

SecurityContext Cấp Container

### Container-Level SecurityContext
yaml
containers:
  - name: <service>
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
          - ALL

Thư mục Có thể Ghi

readOnlyRootFilesystem: true ngăn ghi vào filesystem container, các service cần thư mục có thể ghi dùng volume emptyDir:

Since readOnlyRootFilesystem: true prevents writes to the ...
yaml
containers:
  - name: <service>
    volumeMounts:
      - name: tmp
        mountPath: /tmp
volumes:
  - name: tmp
    emptyDir:
      sizeLimit: 64Mi

TIP

Bun và Node.js có thể ghi vào /tmp để cache. Luôn mount emptyDir tại /tmp khi dùng readOnlyRootFilesystem: true.

Ví dụ Deployment Đã Cường hóa Đầy đủ

Deployment: nx-commerce
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nx-commerce
  namespace: nx-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: commerce
  template:
    metadata:
      labels:
        app.kubernetes.io/name: commerce
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 1000
        fsGroup: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: commerce
          image: bcr.bana.com.vn/nx-commerce:0.0.1
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
          ports:
            - containerPort: 3000
          volumeMounts:
            - name: tmp
              mountPath: /tmp
      volumes:
        - name: tmp
          emptyDir:
            sizeLimit: 64Mi

Cường hóa ServiceAccount

Mặc định, Kubernetes mount token ServiceAccount vào mọi pod. Hầu hết pod ứng dụng không cần gọi Kubernetes API, nên token này là bề mặt tấn công không cần thiết.

Tắt Auto-Mount

yaml
spec:
  template:
    spec:
      automountServiceAccountToken: false

Áp dụng điều này cho tất cả Deployment backend và frontend.

ServiceAccount Chuyên dụng

Service cần truy cập Kubernetes API có ServiceAccount riêng với quyền tối thiểu:

ServiceAccount: nx-traefik
yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nx-traefik
  namespace: nx-internal
  labels:
    app.kubernetes.io/name: traefik
    app.kubernetes.io/part-of: bana
automountServiceAccountToken: false  # Traefik uses file provider, no K8s API access needed

TIP

Traefik trong BANA dùng cấu hình file provider, không phải Kubernetes CRD discovery. Điều này có nghĩa nó không cần watch CRD traefik.io và yêu cầu truy cập Kubernetes API tối thiểu hoặc không có, giữ dấu chân RBAC nhỏ gọn.

ServiceAccountNamespaceMục đíchTruy cập API
defaultTất cảApp podsTắt (automountServiceAccountToken: false)
nx-traefiknx-internalTraefik file providerTối thiểu (không cần watch CRD)
nx-cert-managercert-managercert-managerSecrets, Ingress, CRDs
nx-prometheusnx-watcherPrometheus scrapingRead-only pods, services, endpoints

RBAC

Service Account GitLab CI/CD

Pipeline CI/CD cần quyền kubectl apply phạm vi cho các namespace cụ thể — không bao giờ cluster-admin.

ServiceAccount: gitlab-deployer
yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-deployer
  namespace: nx-backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gitlab-deployer
  namespace: nx-backend
rules:
  - apiGroups: ["", "apps", "batch", "autoscaling", "policy"]
    resources:
      - deployments
      - services
      - configmaps
      - secrets
      - jobs
      - horizontalpodautoscalers
      - poddisruptionbudgets
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: ["traefik.io"]
    resources: ["ingressroutes", "middlewares"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: gitlab-deployer
  namespace: nx-backend
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: gitlab-deployer
subjects:
  - kind: ServiceAccount
    name: gitlab-deployer
    namespace: nx-backend

Lặp lại cho mỗi namespace mà pipeline triển khai đến (nx-app, nx-backend).

Role Read-Only cho Portainer

ClusterRole: nx-portainer-readonly
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nx-portainer-readonly
rules:
  - apiGroups: ["", "apps", "batch", "autoscaling", "policy", "networking.k8s.io"]
    resources: ["*"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nx-portainer-readonly
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nx-portainer-readonly
subjects:
  - kind: ServiceAccount
    name: portainer-readonly
    namespace: portainer

Tóm tắt RBAC

PrincipalPhạm viQuyềnMục đích
gitlab-deployerTheo namespaceFull CRUD trên deployments, services, configs, jobsPipeline CI/CD
nx-portainer-readonlyToàn clusterChỉ đọc tất cả resource + pod logsDashboard Portainer cho PM/QA
nx-traefiknx-internalTối thiểu (file provider, không watch CRD)Routing API gateway
nx-prometheusToàn clusterChỉ đọc pods, services, endpointsScraping metrics

Chuỗi Cung ứng Image

Trivy Scanning trong CI

Mọi image được scan lỗ hổng trước khi được push lên registry. Xem Operations để biết tích hợp .gitlab-ci.yml đầy đủ.

Added to .gitlab-ci.yml after docker build, before push
yaml
# Added to .gitlab-ci.yml after docker build, before push
scan-image:
  stage: scan
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  script:
    - trivy image --exit-code 1 --severity CRITICAL,HIGH --no-progress $REGISTRY/$SERVICE:$CI_COMMIT_SHORT_SHA
  allow_failure: false

Ký Image (cosign)

Ký image sau khi push để đảm bảo tính toàn vẹn:

bash
# In CI after push
cosign sign --key env://COSIGN_PRIVATE_KEY $REGISTRY/$SERVICE:$CI_COMMIT_SHORT_SHA

Admission Control

Dùng admission controller (ví dụ Kyverno) để chặn image chưa scan hoặc chưa ký trong production:

ClusterPolicy: require-image-scan
yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-image-scan
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: check-image-registry
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaces:
                - nx-backend
                - nx-app
      validate:
        message: "Images must come from the bcr.bana.com.vn registry"
        pattern:
          spec:
            containers:
              - image: "bcr.bana.com.vn/nx-*"
    - name: block-latest-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaces:
                - nx-backend
      validate:
        message: "Production images must use a specific tag, not :latest"
        pattern:
          spec:
            containers:
              - image: "!*:latest"

Image Pull Policy

Môi trườngPolicyLý do
StagingIfNotPresentRestart nhanh hơn, chấp nhận được việc cũ
ProductionAlwaysĐảm bảo nội dung của tag chính xác khớp với registry

PriorityClass

PriorityClass đảm bảo các service quan trọng tồn tại trước áp lực node và sự kiện OOM. Pod priority thấp hơn bị preempt trước.

Định nghĩa

PriorityClass: nx-system-critical
yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: nx-system-critical
value: 1000000
globalDefault: false
description: "Data layer, ingress controller"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: nx-high
value: 500000
globalDefault: false
description: "Identity (JWKS), API gateway"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: nx-default
value: 100000
globalDefault: true
description: "Backend services & frontends"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: nx-low
value: 10000
globalDefault: false
description: "Background workers, batch jobs"

Phân phối

PriorityClassValueServices
nx-system-critical1,000,000nginx-ingress, cert-manager, StatefulSet tầng dữ liệu
nx-high500,000identity, Traefik
nx-default100,000commerce, finance, inventory, ledger, pricing, sale, signal, payment-api, client, bo, overture, sale-renderer
nx-low10,000payment-worker, wiki

Sử dụng trong Deployment

yaml
spec:
  template:
    spec:
      priorityClassName: nx-high  # identity, Traefik

WARNING

Không bao giờ đặt preemptionPolicy: Never trên các class priority cao. Toàn bộ ý nghĩa của PriorityClass là service quan trọng có thể preempt service không quan trọng khi tranh chấp tài nguyên.

LimitRange

Mỗi namespace có LimitRange enforce resource request tối thiểu mỗi container, ngăn pod bị scheduled với tài nguyên quá thấp nguy hiểm.

NamespaceMin CPUMin MemoryDefault CPUDefault Memory
nx-backend50m64Mi500m512Mi
nx-app25m32Mi200m256Mi
nx-broker100m128Mi500m768Mi
nx-persistent100m256Mi500m1Gi
nx-search50m128Mi200m512Mi
nx-internal50m64Mi500m512Mi
nx-watcher25m32Mi200m256Mi

TIP

Namespace nx-broker enforce tối thiểu cpu 100m và memory 128Mi mỗi container. Tất cả namespace đều có giới hạn tối thiểu và tối đa để ngăn lạm dụng tài nguyên.

Checklist

Dùng checklist này khi triển khai service mới hoặc audit service hiện có:

  • [ ] SecurityContext Pod: runAsNonRoot, runAsUser: 1000, seccompProfile: RuntimeDefault
  • [ ] SecurityContext Container: allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, capabilities.drop: [ALL]
  • [ ] automountServiceAccountToken: false (trừ khi cần truy cập API)
  • [ ] ServiceAccount riêng nếu cần truy cập API
  • [ ] Image chỉ từ bcr.bana.com.vn/nx-*
  • [ ] Trivy scan pass (không lỗ hổng CRITICAL/HIGH)
  • [ ] Đã gán PriorityClass
  • [ ] Namespace có label PSS đúng
  • [ ] Không dùng tag :latest trong manifest production

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.