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_admincap_net_raw)
- TCP代理(cap_net_admincap_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:
由图可知容器内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:
由图可知容器内 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特权特性了。
OpenNJet 最早是基于 NGINX1.19 基础 fork 并独立演进,具有高性能、稳定、易扩展的特点,同时也解决了 NGINX 长期存在的难于动态配置、管理功能影响业务等问题。 邮件组 官网