背景:

工作中发现k8s集群中命名空间B-test中的某服务的域名返回404,该请求链路为:
client ——> traefik(namespace:A-test) ——> ingress(namespace:B-test) ——> pod(namespace:B-test)

使用的traefik模板如下:

点击查看代码
---
# rbac配置: role
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress-controller
  namespace: A-test
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses/status
    verbs:
    - update
---
# rbac配置: rolebinding
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress-controller
  namespace: A-test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
  name: traefik-ingress-controller
  namespace: test
---
# rbac配置: serviceaccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller
  namespace: A-test
---
# daemonset配置
kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: traefik-ingress-controller
  namespace: A-test
  labels:
    k8s-app: traefik-ingress-lb
spec:
  selector:
    matchLabels:
      k8s-app: traefik-ingress-lb
      name: traefik-ingress-lb
  template:
    metadata:
      labels:
        k8s-app: traefik-ingress-lb
        name: traefik-ingress-lb
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 60
      containers:
      - image: traefik:v1.7
        name: traefik-ingress-lb
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: admin
          containerPort: 8080
          hostPort: 8080
        securityContext:
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        args:
        - --api
        - --kubernetes
        - --kubernetes.namespaces=A-test    # 该配置为重点
        - --logLevel=INFO
---
kind: Service
apiVersion: v1
metadata:
  name: traefik-ingress-service
  namespace: A-test
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
    - protocol: TCP
      port: 80
      name: web
    - protocol: TCP
      port: 8080
      name: admin

现象:

无论如何修改ingress规则,通过域名访问均返回404,但通过后端服务的serviceName,clusterIP,PodIP均能正常返回页面

解决思路:

检查后发现该traefik ds配置使用的rbac为namespace级别(即role-rolebinding),若需访问跨namespace的后端pod需要新增对应rbac权限(在B-test命名空间中增加对应role和rolebinding),并在traefik参数--kubernetes.namespaces中添加后端pod所在的namespace

官方文档中关于该参数的描述如下:

image
翻译:对于命名空间限制,每个监视的命名空间都需要一个 RoleBinding 以及 Traefik 的 kubernetes.namespaces 参数的相应配置。

修改方式如下:

1. 添加应用所在的B-test命名空间下的traefik rbac权限配置,否则traefik将无权限获取到B-test命名空间下的ingress规则及service-endpoints对应关系

# 添加B-test命名空间下的rbac,并关联至A-test命名空间下的serviceaccount: traefik-ingress-controller
# cat rbac-traefik-B-test.yaml
---
# B-test下的role配置文件(权限集)
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress-controller
  namespace: B-test
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses/status
    verbs:
    - update
---
# B-test下的rolebinding配置文件(sa与role的绑定关系)
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress-controller
  namespace: B-test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
  name: traefik-ingress-controller
  namespace: A-test    # 该namespace为traefik的sa所在namespace,无需修改,即将A-test下的traefik sa与B-test下的role进行关联,使A-test中的traefik拥有查看B-test下的ing、ep、svc权限
  
# 生效rbac配置
kubectl create -f rbac-traefik-B-test.yaml

# 生效后可通过如下命令验证,可以查看到ingress规则即权限正常
kubectl get ing -n B-test --as=system:serviceaccount:A-test:traefik-ingress-controller

2. 修改traefik ds中的--kubernetes.namespaces参数

# 根据官方文档介绍,namespace级rbac配置的traefik需要在参数中根据所监视的namespace修改--kubernetes.namespaces参数
kubectl edit ds -n A-test traefik-ingress-controller
...omit...
        args:
        - --api
        - --kubernetes
        - --kubernetes.namespaces=A-test,B-test    # 在原有基础上追加B-test命名空间
        - --logLevel=INFO
...omit...

# 修改后保存退出即可

3. 验证发现通过A-test命名空间下的traefik访问B-test命名空间下的pod已恢复正常

最后:

1. 若同一套k8s物理集群内存在namespace隔离的多个项目环境,尽量使用namespace级rbac配置(role/rolebinding)并通过--kubernetes.namespaces参数对traefik进行namespace级的ingress路由规则限制,以免项目间ingress配置互相干扰。
2. 若同一套k8s物理集群内所有namespace均属于同一项目,则可以使用cluster级rbac配置(clusterrole/clusterrolebinding),且无需在traefik配置中指定--kubernetes.namespaces参数(即集群内所有namespace),官方给出的traefik模板即为cluster级rbac鉴权,可直接参考:
https://doc.traefik.io/traefik/v1.7/user-guide/kubernetes/
https://github.com/traefik/traefik/tree/v1.7.11/examples/k8s

 posted on 2022-08-14 18:07  shelterCJJ  阅读(306)  评论(0)    收藏  举报