为了更多地了解 K8S,我开始运行单个服务器/节点 K3S 集群作为家庭实验室。但我相信我对网络模型的理解已经陷入僵局,也许是针对 K3S 的。
到目前为止一切顺利,除了我想将 TLS 证书应用于我设置的一些服务+入口。
在其中一个中,我将 TLS 证书配置为机密并将其应用到与该服务关联的 Ingress,但是我总是得到TRAEFIK DEFAULT CERT
,您可以在此处查看。
据我了解,K3S 附带了预先打包的 Traefik 和 ServiceLB,以便不依赖云服务的外部负载均衡器(AWS 等)。我的第一个猜测是 Traefik 会“发现”我的 Ingress 中设置的路由并代理 TLS 流量,从而使用我设置的证书。显然情况并非如此,所以我想我需要为 Traefik 实例本身设置一个 TLS 证书。
我的问题是
- 如何在 K3S 中设置此证书?如果我计划让多个项目/域访问此集群,我是否需要通配符证书?(我更喜欢管理每个项目的证书)
- ServiceLB和Traefik在K3S网络模型中的作用是什么?如果 Traefik 收到 80 和 443 流量,是否只是将流量转发到 ServiceLB,然后由 ServiceLB 将其转发到 Ingress 资源?
如果需要,这是我的入口/服务配置
resource kubernetes_service_v1 snitch_service {
metadata {
name = "snitch"
namespace = module.namespace.name
}
spec {
selector = {
app = "snitch"
}
type = "LoadBalancer"
port {
name = "main"
port = 3010
target_port = 3000
node_port = 30003
}
}
}
resource kubernetes_secret_v1 tls_secret {
metadata {
name = "snitch-tls-cert"
namespace = "my-namespace"
}
type = "kubernetes.io/tls"
data = {
"tls.crt" = base64encode(my_certificate)
"tls.key" = base64encode(my_certificate_private_key)
}
}
resource kubernetes_ingress_v1 snitch_ingress {
metadata {
name = "snitch"
namespace = "my-namespace"
annotations = {
"ingress.kubernetes.io/ssl-redirect" = "false"
}
}
spec {
tls {
hosts = [local.subdomain]
secret_name = "snitch-tls-cert"
}
rule {
host = local.subdomain
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = "snitch"
port {
number = 3010
}
}
}
}
}
}
}
}
谢谢你!
入口服务通常是 TLS 终止发生的地方 - 也就是说,当您有一个客户端(例如 Web 浏览器)访问
https://
指向您的 kubernetes 集群的 url 时,该客户端将连接到入口服务,该服务会协商安全连接,然后进行代理与后端服务的连接(许多入口服务器确实支持“直通”tls,其中终止实际上发生在后端,但由入口服务处理终止通常更容易、更高效)。来自kubernetes 文档:
k3s 使用 traefik 作为入口服务,因此您需要在 traefik 中配置您的 ssl 证书。
配置默认证书
如果没有特定于入口的 tls 证书,traefik 将使用默认证书来保护 tls 流量。traefik 将立即使用自签名证书。假设我的 k3s 集群在主机名上可用
k3s.virt
,我们可以看到如下:我们可以按照本文的说明来替换默认证书。如果我们的大多数服务将托管在同一域中,则使用通配符证书是有意义的。如果我按照链接文章中的描述创建新证书
*.example.com
并设置证书TLSStore
,我们可以看到 Traefik 现在正在使用更新后的证书:如果我部署一个 pod、服务和入口,如下所示:
然后(假设
whoami.example.com
解析到集群)我们将看到入口正在使用默认证书:配置每个 Ingress 证书
如果我们不想依赖默认证书(例如,如果我们需要使用不属于通配符所覆盖域的主机名),我们可以为我们的服务配置唯一的证书。traefik ingress 文档对此进行了描述。
首先,我们需要创建一个证书并将其填充到 kubernetes 密钥中。然后我们需要通过添加以下部分来更新 Ingress 以引用证书
spec.tls
:有了这个资源,我们看到入口不再使用默认证书:
希望这能让事情变得更清楚一些。我在这里提供的文档链接涵盖了更详细的内容。
我已将用于测试此配置的所有清单放置在此存储库中。
回复您的评论:
ServiceLB 是监视服务的东西
type: LoadBalancer
,并直接在集群节点上公开这些端口(例如参见这些文档)。例如,Traefik 作为kube-system
命名空间中的服务,如下所示:因此,ServiceLB 将集群节点上的端口 80 和 443 映射到此服务。
我已经成功地使 TLS 工作,部分感谢 @larsks 的回答,它让我了解到 K8S 配置与 Traefik 实例一起使用,因此能够找到日志并查看问题。
我正在写一个答案,以防它将来对其他人有帮助。
本质上,当您添加/修改
Ingress
资源时,K8S 会告诉 Ingress 控制器“配置”自身。在我们的例子中,Traefik 实例根据定义(即:添加路由)自行启动配置Ingress
,如果定义了 TLS,它会尝试将密钥中的证书添加到其 TLSStore。由于 Traefik 实例正在应用新配置,因此可以在日志中找到大量必要信息。就我而言,存在不同的问题阻止将证书添加到 TLSStore。这意味着 Traefik 只有“DEFAULT TLS CERT”可用于终止。我期望它使用我放入秘密中的任何内容,即使它们是随机字符串。
对于 K3S,您可以通过以下方式跟踪日志:
创建自签名证书使我能够验证该理论,因为现在我的 HTTPS 流量是由该自签名证书而不是默认证书终止的。@larsks 的回答验证了我的配置是有意义的。如果它对任何人都有帮助,您可以使用以下命令创建自签名证书和新密钥:
作为最后的接触,多个教程讨论了将“base64 编码证书”输入到密钥中,这仅意味着以 PEM 格式输入它们,而不是对 PEM 本身进行 Base64 编码(内部包含 b64 块)。Traefik 日志也让我能够检测到这个问题。
base64encode
您可以在我在秘密上使用的原始问题中看到。如果您碰巧使用 Let's Encrypt,则可以连接 issueser_pem 和certificate_pem 以创建链(在我的例子中,certificate_pem + issuer_pem
按照该顺序完成工作)。