NJet KIC(K8s Ingress Controller) capabilities管理

🙈 By 刘琪 2024-02-23

NJet KIC(K8s Ingress Controller) capabilities管理

NGINX 向云原生演进,All in OpenNJet 概述


前言

从Linux 2.2开始,Linux将传统上与超级用户关联的特权划分为不同的单元(units),称为能力(capabilities),能力可以独立启用和禁用。能力是每个线程的属性。

Linux 有了capabilities机制,基于最小特权原则,可以按需给每个线程赋予需要的能力,而不是全部。从而降低了安全风险。

本文章,重点在于介绍在k8s环境中,使用NJet高级特性时,如何授予相应的能力。而不是介绍Linux capabilities机制和Linux capabilities 在docker中的应用。

NJet 哪些特性需要特权呢?

KIC中使用到的NJet特性,需要特权的特性如下:

  • •UDP代理(cap_net_admin\cap_net_raw)
  • •TCP代理(cap_net_admin\cap_net_raw)
  • •Bind 1024以下端口(cap_net_bind_service)
  • •修改进程用户id(cap_setuid)

NJet KIC capabilities管理

通过对NJet KIC进行 capabilities管理,使用101用户启动容器后,使KIC中使用到的需要特权的NJet特性可以正常工作。

K8s环境

K8s版本 容器运行时 Docker版 节点操作系统
v1.23.8 Docker 20.10.11 CentOS Linux release 7.9.2009

容器

通过deployment设置容器capability sets,deployment清单如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: njet-ingress
  namespace: njet-ingress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: njet-ingress
  template:
    metadata:
      labels:
        app: njet-ingress
     #annotations:
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
       #prometheus.io/scheme: http
    spec:
      serviceAccountName: njet-ingress
      automountServiceAccountToken: true
      containers:
      - image: tmlake/njet-ingress:1.2
        imagePullPolicy: IfNotPresent
        name: njet-ingress
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        - name: readiness-port
          containerPort: 8081
        - name: prometheus
          containerPort: 12001
        readinessProbe:
          httpGet:
            path: /nginx-ready
            port: readiness-port
          periodSeconds: 1
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
         #limits:
         #  cpu: "1"
         #  memory: "1Gi"
        securityContext:
          allowPrivilegeEscalation: true
          runAsUser: 101 #njet
          runAsNonRoot: true
          capabilities:
          drop:
            - ALL
            # Containers can start njet binaries, Excluding SETGID
            add:
            - NET_BIND_SERVICE
            - NET_ADMIN
            - NET_RAW
            - SETGID #You can use sudo
            - SETUID #You can use sudo
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:
          - -nginx-configmaps=$(POD_NAMESPACE)/njet-config
          - -ingress-class=njet
          - -v=2
          - -ingress-version=networking/v1
          - -watch-endpointslices=true #true: k8s version > 1.21
         # - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
         #- -include-year
         #- -enable-cert-manager
         #- -enable-external-dns
         #- -v=3 # Enables extensive logging. Useful for troubleshooting.
         #- -report-ingress-status
         #- -external-service=nginx-ingress
         #- -enable-prometheus-metrics
         #- -global-configuration=$(POD_NAMESPACE)/nginx-configuration

正常启动后,登录njet-ingress容器内可以查看容器进程的capability sets:

img

由图可知容器内1 号进程/njet-ingress继承了 cap_setgid,cap_setuid,cap_net_bind_service,cap_net_admin,cap_net_raw能力集。effective set(一种Thread capability sets)没有被设置。

容器设置上述能力集,以便1号进程有权限创建子进程NJet。

NJet binary file

使用101用户启动容器后,容器中的进程effective set(一种Thread capability sets)是没有进程需要的capability sets。所以在制作容器镜像时需要对二进制文件设置需要的capability sets,设置方式如下:

RUN setcap 'cap_net_bind_service,cap_setuid,cap_net_admin,cap_net_raw=+eip' 
/usr/local/njet/sbin/njet 

正常启动后,登录njet-ingress容器内查看NJet进程的capability sets:

img

由图可知容器内17号进程njet继承了

cap_setgid,cap_setuid,cap_net_bind_service,cap_net_admin,cap_net_raw 能力集。CapEff被授予二进制文件设置的

cap_setuid,cap_net_bind_service,cap_net_admin,cap_net_raw能力集,这样njet进程具有权限使用NJet特权特性了。