在部署 Web 项目时, SSL 证书的实施是每个工程师都可能面临的共同挑战——我也不例外。
通常,初创公司会选择免费证书,例如 Let's Encrypt 提供的证书。但是,这些都具有局限性和不便之处,证书提供商的网站上对此进行了详细说明。
让我们仔细看看我个人在使用免费证书时遇到的问题:
在定期面对这些问题后,我开发了一个利用 Let's Encrypt 证书的定制解决方案配置。在这篇文章中,我将分享我的发现和一路走来的经验教训。
最近,我一直专注于特定的技术堆栈,并想在 Azure 云提供商的上下文中讨论基于Kubernetes集群的基础架构解决方案。虽然 cert-manager 是该领域的流行解决方案,但我更喜欢通过 Helm 安装它以获得更大的便利。
所以,事不宜迟,让我们开始吧:
helm repo add jetstack https: //charts.jetstack.io
helm repo update kubectl apply -f https: //github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.crds.yaml
helm install cert-manager jetstack/cert-manager -- namespace cert - manager -- create - namespace -- version v1 . 6 . 1
之后,我们可以使用以下 YAML 文件创建一个 ClusterIssuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: p…[email protected] #your e-mail
privateKeySecretRef:
name: letsencrypt-cluster-issuer
solvers:
- http01:
ingress:
class: nginx
展望未来,有两种实施证书的选择:
让我们探讨这两种选择。
在第一种情况下,我的 YAML 文件如下所示:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: myservice2 namespace : test
Spec : duration : 2160h
renewBefore : 72h
dnsNames : - myservice2 . mydomain . org # you resources
secretName : myservice2 - tls
issuerRef : name : letsencrypt - cluster - issuer
kind : ClusterIssuer
值得注意的是,在特定服务的 TLS 部分的入口中仅提到了“secretName:myservice2-tls”。
顺便说一句,YAML 文件包含一些有用的参数,例如:
如果您更习惯于使用控制台,让我以证书的综合视图为例为您提供。
kubectl describe certificates <cert name > -n <namespace name >
那么,我们到底有什么?
就个人而言,我发现通过 Ingress 管理 Let's Encrypt 证书更加可靠和方便,这就是我最近一直在使用它的原因。使用这种方法,除了 TLS 部分中的 secretName 和主机名之外,您只需要在入口 YAML 文件中指定注释即可。
annotations : cert-manager .io/cluster-issuer: "letsencrypt-cluster-issuer" cert-manager .io/renew-before: 72h
你有它,这一切的魔力!证书现在会自动重新颁发,在此示例中,证书在过期前有三天的缓冲期。值得注意的是,就 Let's Encrypt 而言,默认期限为 90 天。
然而,由于 Let's Encrypt 免费证书的限制,我们的团队最终考虑需要一个不仅可以保护我们的域而且可以保护子域的综合证书。随着我们继续在 Azure 上开发项目,我们发现 Azure Key Vault 提供了一个方便的位置来存储此类证书。我们一直在 Kubernetes 集群中使用 akv2k8s 实用程序。如果您有兴趣,我鼓励您进一步了解它。
在 Azure 中获得证书后,下一步就是将其添加到 Azure Key Vault (AKV)。虽然此过程相对简单,但验证域所有权可能有点棘手。但是,一旦成功完成所有确认步骤,证书将出现在密钥保管库的“机密”部分中。
这种方法的主要好处之一是自动更新证书。证书将在一年后在AKV中补发和更新,并自动与Kubernetes中的Secret同步。
为了让 Kubernetes 集群使用获得的证书,您需要授予它某些权限和访问权限。
为此,您首先需要获取集群的 identityProfile.kubeletidentity.objectId。您可以使用以下命令执行此操作:
az aks show -g < RG > -n < AKS_name >
资源组 (RG) 是存储集群的位置,AKS_name 是您的集群的名称。
获取到identityProfile.kubeletidentity.objectId后,需要进行复制。接下来,将值添加到命令以授予秘密访问权限:
az keyvault set-policy --name < name AKV > --object-id < get from first step value > --secret-permissions get
接下来,您可以继续安装 akv2k8s,这可以通过 Helm 或其他首选方法完成,如 安装指南中所述。
按照官方文档,您可以将 Azure Key Vault 证书与特定 Kubernetes 命名空间中的 Secret 同步。这是我的 YAML 文件:
apiVersion: spv.no/v1 kind: AzureKeyVaultSecret metadata: name: wildcard-cert #any name namespace : default
spec : vault : name : SandboxKeyVault # name you keyvault in Azure
object : name : name_object_id # name object id from Azure AKV this cert
type : secret
output : secret : name : wildcard - cert # any name for secret in your namespace
type : kubernetes . io / tls
chainOrder : ensureserverfirst # very important values !!!
我强调一下最后一行的意义,因为它对解决我遇到的一个问题起到了至关重要的作用。最初,我能够将证书成功上传到 Kubernetes,但它没有按预期运行。诊断问题需要一些时间。
事实证明,当从 Key Vault 导出 PFX 证书时,服务器证书有时位于链的末尾,而不是它应该位于的开头。当与 ingress-nginx 等参数一起使用时,这可能会导致问题,因为证书无法加载并默认返回其原始值。但是,通过将 chainOrder 设置为 ensureserverfirst,服务器证书将放在链中的第一位。
仔细检查证书后,我发现链条是按以下顺序排列的:
在讨论了技术方面和配置之后,让我们重新深入研究 Azure 证书的特性。
Azure 提供了两种用于订购证书的选项,这两种选项均由 GoDaddy 提供:
我们选择了后者,希望它能保护我们所有的应用程序和服务。但是,有一些细微差别。
Azure 通配符证书仅保护一级子域。例如,如果我们有一个名为mydomain.com的域,则证书将仅覆盖.mydomain.com形式的一级子域。
因此,证书将适用于service1.mydomain.com、service2.mydomain.com、service3.mydomain.com等资源,但不会涵盖service1.test.mydomain.com或mail.service1.mydomain.com 。
那我们有什么选择呢?
第一个选项不太可能实用,因为子域的数量,尤其是二级域的数量可能非常庞大。因此,为每个子域( .service1.mydomain.com、*.dev.mydomain.com… )支付通配符证书并不是最合理的解决方案。
至于第二个选项,我和Azure支持团队就此事进行了长时间的交谈,经历了否认、沮丧和愤怒的所有阶段,最后才意识到证书的SAN能力还没有实现。
直到最后,我都希望 Azure 永远不会出现这样的问题。相比之下,他们的竞争对手 AWS Amazon 通过其 AWS Certificate Manager (ACM) 提供证书,支持多达 10 个备用主题名称,包括通配符。它允许您创建 10 个带有通配符 (*) 的子域,甚至可以在 AWS 上请求增加高达 100k 的配额。
最后,我将分享如何将证书与 Azure 上的 Front Door 服务结合使用。
对我来说,Azure Front Door (AFD) 是一个全球性的可扩展网关,它利用 Microsoft 的全球边缘网络将传入流量定向到适当的端点,这些端点可以是 Web 应用程序或服务。 Front Door 在 HTTP/HTTPS 层(第 7 层)运行,将客户端请求路由到池中可用的应用程序服务器。应用程序的服务器端可以是任何可通过 Internet 访问的服务,无论它托管在 Azure 内部还是外部。
来自文档网站https://docs.microsoft.com/的示例
Azure Front Door 是一种方便的工具,可让你平衡和代理访问全球分布式应用程序和服务的传入流量。它提供了一系列功能,包括通过配置规则处理程序、加入策略和防火墙设置来绑定各种规则的能力。在本文中,我不会深入探讨 AFD 服务的细节,而是重点介绍证书的服务特性。
如你所料,到 Azure Front Door 的传入流量可以是http或https 。如果选择https ,则有三个选项:在 Azure Front Door 服务本身生成证书、上传自己的证书或将现有证书同步到 Azure Key Vault。要允许 Front Door 服务访问 Key Vault,您需要配置必要的权限。
我建议使用最后一个选项并选择最新版本的证书,以避免必须手动更新或重新生成它。通过连接来自 AKV 的证书,一切都会自动保持最新状态。
此设置将为您提供以下结果:
在将流量从 Azure Front Door 引导到 AKS 时,这是另一个特点。
处理http流量不是问题,但在设置资源池和指定 AKS 群集的外部 IP 地址时,需要牢记一个微妙的细节。确保将“服务器组件节点标头”字段留空,以确保它自动填充在“IP 或节点名称”字段中输入的值。
假设您有一个通过 AKV 附加的域通配符证书,它由 Front Door 服务使用并通过 akv2k8s 刷新到 AKS 集群中。通过 Front Door 访问的所有应用程序和服务的接口主机名(和 DNS 中的 CNAME 记录)如下:
这将允许*.mydomain.com格式的所有服务正常运行。完成此配置后,一切就绪。
在某些情况下,通过 https 将流量从 Azure Front Door 重定向到 AKS 可能更有利。为确保 Azure Front Door 在服务器池设置中正常运行,指定与您的 AKS 集群对应的 DNS 名称至关重要,这与 SNI 和健康检查有关。否则,设置将无法运行。
在我的例子中,没有为我的 AKS 集群分配名称,我只有以前直接工作但必须通过 Azure Front Door 运行的服务。为了解决这个问题,我必须为 AKS 集群创建一个单独的 DNS 名称,配置 DNS,并设置一个单独的服务,并将证书附加到入口。只有这样,我才能将https流量重定向到 AKS 集群,并确保它对所有可用服务都能正常工作。
在为 AKS 设置连接权限时考虑安全措施很重要。为确保安全连接,您可以限制仅从 AKS 网络安全组中的 Azure Front Door IP 地址连接到 AKS 的权限(如下图所示)。
此外,您可以使用X-Azure-FDID 参数将 AKS 入口设置为按 ID 专门接受来自 Azure Front Door 标头的连接。
1. Azure 不提供有关其证书的功能和缺点的全面信息。但是,值得一提的是,他们及时退还了我们购买的证书。
2. 在我们的开发过程中,我们继续使用 Let's Encrypt。尽管它有其局限性,但它并不是最糟糕的选择。
3. 如果您的项目需要多个不同资源级别的子域,您可能需要考虑第三方供应商的“Wildcard (also known as Multidomain) with SAN”证书。这些证书可以导入到 Azure 中并充分发挥其潜力。
4. 如果配置正确,Azure Front Door 是一项出色的服务。我强烈推荐它。
由 Social Discovery Group 首席 DevOps 工程师 Pavel Shapurau 撰写