不同 kubernetes 命名空间中的多个 Traefik 实例
Multiple instances of Traefik in different kubernetes namespaces
我们正在尝试 运行 具有三个命名空间的 kubernetes 集群:
public
包含任何人都可以访问的服务
internal
包含仅应由工作人员访问的服务
engineering
包含应该只对开发人员可见的服务
internal
和 engineering
命名空间通过相互身份验证进行保护,每个命名空间使用不同的证书颁发机构。
我们使用 Traefik 来管理这些服务的入口,但是,在 kubernetes guide 设置 Traefik 之后,授予 Traefik 的每个实例权限以查看所有命名空间的入口。这意味着您可以通过 public
命名空间中的 Traefik 实例 运行ning 使用 internal
命名空间中的服务,绕过相互身份验证。
我们正在通过在入口上设置主机来解决这个问题,但这意味着必须为每个环境单独定义入口(例如,host: engineering.example.com
不同于 host: engineering.staging.example.com
)。我们更愿意将主机留在入口配置之外。
理论上,使用 RBAC,我们应该能够将允许 Traefik 看到的内容限制在它自己的入口中,如 this guide on RBAC 中所建议的那样。
我的理解是它仍然需要这样的ClusterRole权限:
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
但是使用 Role 绑定而不是 ClusterRole 绑定会将这些权限限制为仅给定服务帐户命名空间中的权限。因此,如果服务帐户在工程命名空间中:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: engineering
那么角色绑定将是:
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
namespace: engineering
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
然后我们将服务帐户绑定到 Traefik 部署:
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: engineering
spec:
replicas: 1
template:
spec:
serviceAccountName: traefik-ingress-controller
...
我们还根据 kubernetes configuration guide
在配置中设置了命名空间
[kubernetes]
namespaces = ["engineering"]
然而,当 Traefik 启动时,我们得到错误:
E0313 11:15:57.971237 1 reflector.go:199] github.com/containous/traefik/vendor/k8s.io/client-go/tools/cache/reflector.go:94: Failed to list *v1.Endpoints: endpoints is forbidden: User "system:serviceaccount:engineering:traefik-ingress-controller" cannot list endpoints at the cluster scope: Unknown user "system:serviceaccount:engineering:traefik-ingress-controller"
Unknown user
令人困惑,因为这显然绑定了 ServiceAccount
而不是用户。此外,我们可以看到 ServiceAccount
已通过 kubectl 创建。
我在这里有点死胡同。
如何让 Traefik 只在它自己的命名空间中获取 Ingresses?
当Traefik认为没有配置命名空间时,可能会出现这个错误;即您概述的 TOML 配置
[kubernetes]
namespaces = ["engineering"]
未生效。
我可以想到两个原因:
- 除了 TOML 配置文件之外,您还向 Traefik 传递了一个
--kubernetes
command-line 参数(通过部署清单中的 args
条目)。这将禁用 namespaces
选项。
- 该文件未正确安装到 Deployment 中,导致默认
namespaces
值(空列表)有效。要判断是否确实如此,我们需要查看您的完整 ConfigMap 和部署清单的相关卷部分。
我们正在尝试 运行 具有三个命名空间的 kubernetes 集群:
public
包含任何人都可以访问的服务internal
包含仅应由工作人员访问的服务engineering
包含应该只对开发人员可见的服务
internal
和 engineering
命名空间通过相互身份验证进行保护,每个命名空间使用不同的证书颁发机构。
我们使用 Traefik 来管理这些服务的入口,但是,在 kubernetes guide 设置 Traefik 之后,授予 Traefik 的每个实例权限以查看所有命名空间的入口。这意味着您可以通过 public
命名空间中的 Traefik 实例 运行ning 使用 internal
命名空间中的服务,绕过相互身份验证。
我们正在通过在入口上设置主机来解决这个问题,但这意味着必须为每个环境单独定义入口(例如,host: engineering.example.com
不同于 host: engineering.staging.example.com
)。我们更愿意将主机留在入口配置之外。
理论上,使用 RBAC,我们应该能够将允许 Traefik 看到的内容限制在它自己的入口中,如 this guide on RBAC 中所建议的那样。
我的理解是它仍然需要这样的ClusterRole权限:
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
但是使用 Role 绑定而不是 ClusterRole 绑定会将这些权限限制为仅给定服务帐户命名空间中的权限。因此,如果服务帐户在工程命名空间中:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: engineering
那么角色绑定将是:
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
namespace: engineering
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
然后我们将服务帐户绑定到 Traefik 部署:
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: engineering
spec:
replicas: 1
template:
spec:
serviceAccountName: traefik-ingress-controller
...
我们还根据 kubernetes configuration guide
在配置中设置了命名空间[kubernetes]
namespaces = ["engineering"]
然而,当 Traefik 启动时,我们得到错误:
E0313 11:15:57.971237 1 reflector.go:199] github.com/containous/traefik/vendor/k8s.io/client-go/tools/cache/reflector.go:94: Failed to list *v1.Endpoints: endpoints is forbidden: User "system:serviceaccount:engineering:traefik-ingress-controller" cannot list endpoints at the cluster scope: Unknown user "system:serviceaccount:engineering:traefik-ingress-controller"
Unknown user
令人困惑,因为这显然绑定了 ServiceAccount
而不是用户。此外,我们可以看到 ServiceAccount
已通过 kubectl 创建。
我在这里有点死胡同。
如何让 Traefik 只在它自己的命名空间中获取 Ingresses?
当Traefik认为没有配置命名空间时,可能会出现这个错误;即您概述的 TOML 配置
[kubernetes]
namespaces = ["engineering"]
未生效。
我可以想到两个原因:
- 除了 TOML 配置文件之外,您还向 Traefik 传递了一个
--kubernetes
command-line 参数(通过部署清单中的args
条目)。这将禁用namespaces
选项。 - 该文件未正确安装到 Deployment 中,导致默认
namespaces
值(空列表)有效。要判断是否确实如此,我们需要查看您的完整 ConfigMap 和部署清单的相关卷部分。