当前位置: 首页 > 科技观察

使用k3s轻松管理SSL证书

时间:2023-03-20 15:03:22 科技观察

如何使用k3s和Let'sEncryptonRaspberryPi来加密您的网站。在上一篇文章中,我们在k3s集群上部署了几个简单的网站。这些是未加密的网站。不错,它们可以工作,但未加密的网站有点过时了!如今,大多数网站都是加密的。在本文中,我们将安装cert-manager并在集群上使用它来部署一个TLS加密的网站。这些网站不仅会被加密,而且还会使用有效的公共证书,这些证书是从Let'sEncrypt自动获取和更新的!开始吧!要准备好继续阅读本文,您将需要我们在上一篇文章中构建的k3sRaspberryPi集群。此外,您需要有一个公共静态IP地址和一个可以为其创建DNS记录的域名。如果您有一个为您提供域名的动态DNS提供商,它也可能会起作用。但是,在本文中,我们使用静态IP和CloudFlare手动创建DNSA记录。由于我们在本文中创建配置文件,如果您不想键入它们,可以在这里下载它们。我们为什么要使用证书管理器?Traefik(预先捆绑在k3s中)实际上内置了Let'sEncrypt支持,所以您可能想知道为什么我们安装第三方包来做同样的事情。在撰写本文时,Traefik中的Let'sEncrypt支持检索证书并将它们存储在文件中。相反,cert-manager检索证书并将其存储在Kubernetes“秘密”中。在我看来,“机密信息”可以简单地通过名称来引用,这样更容易使用。这是我们在本文中使用cert-manager的主要原因。安装cert-manager通常,我们只是按照cert-manager的文档在Kubernetes上进行安装。但是,由于我们使用的是ARM体系结构,因此我们需要进行一些更改才能执行此操作。第一步是创建证书管理器命名空间。命名空间有助于将cert-manager的pod排除在我们的默认命名空间之外,因此当我们使用我们自己的pod执行诸如kubectlgetpods之类的操作时,我们不必看到它们。创建命名空间很简单:kubectlcreatenamespacecert-manager安装说明将让您下载cert-manager的YAML配置文件,并一步将其全部应用到您的集群。我们需要将其分为两步,以便为基于ARM的RaspberryPi修改文件。我们将下载文件并逐步转换:curl-sL\https://github.com/jetstack/cert-manager/releases/download/v0.11.0/cert-manager.yaml|\sed-r's/(image:.*):(v.*)$/\1-arm:\2/g'>cert-manager-arm.yaml这将下载配置文件并将所有包含的docker映像更新为ARM版本。要检查它的作用:$grepimage:cert-manager-arm.yamlimage:"quay.io/jetstack/cert-manager-cainjector-arm:v0.11.0"image:"quay.io/jetstack/cert-manager-controller-arm:v0.11.0"image:"quay.io/jetstack/cert-manager-webhook-arm:v0.11.0"正如我们所见,这三个图像现在在图像名称中添加了-arm。现在我们有了正确的文件,我们只需要将它应用到集群:kubectlapply-fcert-manager-arm.yaml这将安装所有cert-manager。我们可以使用kubectl--namespacecert-managergetpods检查安装何时完成,直到所有pod都处于Running状态。这样就完成了证书管理器的安装!Let'sEncrypt概述Let'sEncrypt的伟大之处在于它免费为我们提供经过公开验证的TLS证书!这意味着我们可以拥有一个任何人都可以访问的完全有效的TLS加密网站,而无需在家中或业余活动中赚钱,也无需自掏腰包购买TLS证书!而且,当通过证书管理器使用Let'sEncrypt证书时,获取证书的整个过程都是自动化的,证书的更新也是如此!但是它是如何工作的呢?以下是该过程的简化描述。我们(或代表我们的证书经理)向Let'sEncrypt发出我们拥有的域名的证书请求。Let'sEncrypt通过使用ACMEDNS或HTTP验证机制验证我们拥有域。如果验证成功,Let'sEncrypt将为我们提供证书,这些证书将由cert-manager安装在我们的网站(或其他TLS加密端点)中。在需要重复该过程之前,这些证书的有效期为90天。但是,cert-manager会自动为我们更新证书。在本文中,我们将使用HTTP身份验证方法,因为它更容易设置并且适用于大多数情况。这是幕后发生的基本过程。证书管理器向Let'sEncrypt发出证书请求。作为回应,Let'sEncrypt发出所有权验证挑战。挑战在于将HTTP资源放置在请求证书的域名下的特定URL中。从理论上讲,如果我们可以将该资源放在该URL并让Let'sEncrypt远程获取它,那么我们实际上必须是该域的所有者。否则,我们要么无法将资源放置在正确的位置,要么无法操纵DNS让Let'sEncrypt访问它。在这种情况下,cert-manager会将资源放置在正确的位置,并自动创建临时Ingress记录以将流量路由到正确的位置。如果Let'sEncrypt可以读取挑战请求的资源并且是正确的,它将把证书发回给证书管理器。cert-manager将证书存储为“机密”,我们的网站(或与此相关的任何其他网站)将使用这些证书通过TLS保护我们的流量。为这个问题设置你的网络我假设你在你的家庭网络上设置它并且有一个路由器/接入点以某种方式连接到更广泛的互联网。如果不是这种情况,则可能不需要以下过程。为了让挑战过程起作用,我们需要一个域名,我们正在为其请求证书以路由到端口80上的k3s集群。为此,我们需要告诉世界的DNS系统它在哪里。因此,我们需要将域名映射到我们的公网IP地址。如果您不知道您的公共IP地址是什么,请转到WhatsMyIP之类的网站,它会告诉您。接下来,我们需要输入我们的DNSA记录,它将我们的域名映射到我们的公共IP地址。为了使此功能可靠地工作,您需要一个静态公共IP地址,或者您可以使用动态DNS提供商。一些动态DNS提供商会为您提供一个域名,您可以按照以下说明使用该域名。我还没有尝试过,所以不能肯定地说它适用于所有提供商。对于本文,我们假设一个静态公共IP并使用CloudFlare来设置DNSA记录。如果愿意,您可以使用自己的DNS服务器。重要的是你可以设置A记录。在本文的其余部分,我将使用k3s.carpie.net作为示例域名,因为这是我拥有的域。您显然会用您拥有的任何域名替换它。举个例子,假设我们的公共IP地址是198.51.100.42。我们转到我们的DNS提供商的DNS记录部分,并添加一个名为k3s.carpie.net的类型A的记录(CloudFlare已经假定了域部分,因此我们只需输入k3s),然后是198.51。100.42作为IPv4地址。请注意,有时DNS更新需要一段时间才能传播。解析名称可能需要几个小时。在继续之前,名称必须是可解析的。否则,我们所有的证书请求都将失败。我们可以使用dig命令检查名称是否已解析:$dig+shortk3s.carpie.net198.51.100.42继续运行上述命令,直到可以返回IP。关于CloudFlare的一个小提示:ClouldFlare提供了一种通过代理流量来隐藏您的实际IP的服务。在这种情况下,我们取回CloudFlare的IP,而不是我们的。但出于我们的目的,这应该可以正常工作。网络配置的最后一步是配置路由器,将端口80和443上的传入流量路由到我们的k3s集群。遗憾的是,路由器配置页面千差万别,所以我无法确切地说出您的配置页面是什么样的。大多数时候,我们需要的管理页面在“端口转发”或类似的东西下。我什至看到它列在“游戏”下(这显然是端口转发的主要用途)!让我们看看我的路由器是如何配置的。如果你的环境和我一样,那就去192.168.0.1登录路由器管理应用。对于此路由器,它位于“NAT/QoS”->“端口转发”下。这里我们设置80端口/TCP协议转发到192.168.0.50(主节点kmaster的IP)的80端口。我们还将端口443也设置为映射到kmaster。从技术上讲,这不是挑战所必需的,但在这篇文章的最后,我们将部署一个支持TLS的网站,该网站需要映射443才能访问。所以现在做映射很方便。我们保存并应用更改,您应该可以开始了!配置证书管理器以使用Let'sEncrypt(暂存环境)现在,我们需要配置证书管理器以通过Let'sEncrypt颁发证书。Let'sEncrypt为我们提供了一个暂存(例如用于测试)环境,可以在其中检查我们的配置。这样它对错误和请求频率的容忍度更高。如果我们的生产环境做错了,我们很快就会发现自己被暂时禁止了!因此,我们将使用暂存环境手动测试请求。创建一个包含以下内容的文件letsencrypt-issuer-staging.yaml:apiVersion:cert-manager.io/v1alpha2kind:ClusterIssuermetadata:name:letsencrypt-stagingspec:acme:#TheACMEserverURLserver:https://acme-staging-v02.api.letsencrypt.org/directory#用于ACME注册的电子邮件地址email:@example.com#用于存储ACME帐户私钥的秘密名称privateKeySecretRef:name:letsencrypt-staging#启用HTTP-01challengeprovidersolvers:-http01:ingress:class:traefik确保用你的电子邮件地址更新。如果出现问题或我们破坏了某些东西,这就是Let'sEncrypt联系我们的方式!现在,我们创建发行者发行者:kubectlapply-fletsencrypt-issuer-staging.yaml我们可以检查发行者是否已成功创建:kubectlgetclusterissuersclusterissuers是由cert-manager资源类型创建的一种新型Kubernetes。现在让我们手动申请一个测试证书。对于我们的站点,我们不需要这样做;我们只是在测试流程以确保我们的配置正确。创建具有以下内容的证书请求文件le-test-certificate.yaml:apiVersion:cert-manager.io/v1alpha2kind:Certificatemetadata:name:k3s-carpie-netnamespace:defaultspec:secretName:k3s-carpie-net-tlsissuerRef:name:letsencrypt-stagingkind:ClusterIssuercommonName:k3s.carpie.netdnsNames:-k3s.carpie.net这条记录只是意味着我们要使用名为letsencrypt-staging的ClusterIssuer(我们在上一步中创建的)来请求域k3s.carpie.net并将其存储在Kubernetessecrets中名为k3s-carpie-net-tls的文件中。像往常一样应用它:kubectlapply-fle-test-certificate.yaml我们可以看到状态:kubectlgetcertificates如果我们看到类似的东西:NAMEREADYSECRETAGEk3s-carpie-netTruek3s-carpie-net-tls30s我们在幸福的路上!(这里的关键是READY应该是True)。解决上面的发证问题,就是幸福之路。如果READY为False,我们可以等待它并花点时间再次检查状态。如果它始终为False,则说明我们有问题需要解决。此时,我们可以遍历Kubernetes资源链,直到找到告诉我们问题的状态消息。假设我们执行了上面的请求,READY为False。我们可以开始排查问题:kubectldescribecertificatesk3s-carpie-net这将返回很多信息。通常,有用的内容位于事件:部分,通常位于底部。假设最后一个事件是CreatednewCertificateRequestresource"k3s-carpie-net-1256631848。然后我们描述请求:kubectldescribecertificaterequestk3s-carpie-net-1256631848现在例如,最后一个事件是Waitingoncertificateissuedfromorderdefault/k3s-carpie-net-1256631848-2342473830然后,我们可以描述命令:kubectldescribeordersdefault/k3s-carpie-net-1256631848-2342473830假设有一个事件,事件是CreatedChallengeresource"k3s-carpie-net-1256631848-2342473830-1892150396”,用于域“k3s.carpie.net”。让我们描述挑战:kubectldescribechallengesk3s-carpie-net-1256631848-2342473830-1892150396从这里返回的最后一个事件是使用http01挑战机制呈现的。看起来不错,所以我们查看描述的输出,看到一条消息Waitingforhttp-01challengepropagation:failedtoperformselfcheckGETrequest...nosuchhost.Finally!wefoundtheproblem!Inthiscase,no这样的主机意味着DNSl查找失败,因此我们需要返回并手动检查我们的DNS设置,正确解析域的DNS,并进行任何所需的更改。清理我们的测试证书我们实际上想为域名使用真实证书,所以让我们继续清理我们刚刚创建的证书和秘密:kubectldeletecertificatesk3s-carpie-netkubectldeletesecretsk3s-carpie-net-tlsconfigcert-manager使用Let'sEncrypt(生产)现在我们有了测试证书,是时候转移到生产了。就像我们在Let'sEncrypt暂存环境中配置cert-manager一样,我们现在需要为生产环境做同样的事情。使用以下内容创建一个名为letsencrypt-issuer-production.yaml的文件(如果需要,复制并修改暂存环境的文件):apiVersion:cert-manager.io/v1alpha2kind:ClusterIssuermetadata:name:letsencrypt-prodspec:acme:#TheACME服务器URL服务器:https://acme-v02.api.letsencrypt.org/directory#用于ACME注册电子邮件的电子邮件地址:@example.com#用于存储ACME帐户私钥的秘密名称privateKeySecretRef:name:letsencrypt-prod#EnabletheHTTP-01challengeprovidersolvers:-http01:ingress:class:traefik(如果你是从临时环境复制的,唯一的变化是服务器:URL。不要忘记编辑电子邮件!)来申请:kubectlapply-fletsencrypt-issuer-production.yaml为我们的网站申请证书需要注意的是,到目前为止我们所做的所有步骤只需要做一次!对于将来的任何其他应用程序,我们都可以从该指令开始!让我们部署我们在上一篇文章中部署的相同站点。(如果YAML文件仍然可用,您可以修改它。如果不可用,您可能需要重新创建并重新部署它)。我们只需要将mysite.yaml的Ingress部分修改为:---apiVersion:networking.k8s.io/v1beta1kind:Ingressmetadata:name:mysite-nginx-ingressannotations:kubernetes.io/ingress.class:"traefik"cert-manager.io/cluster-issuer:letsencrypt-prodspec:rules:-host:k3s.carpie.nethttp:paths:-path:/backend:serviceName:mysite-nginx-service服务端口:80tls:-hosts:-k3s.carpie.netsecretName:k3s-carpie-net-tls请注意,上面只显示了mysite.yaml的Ingress部分。更改是添加注释cert-manager.io/cluster-issuer:letsencrypt-prod。这告诉traefik在创建证书时使用哪个颁发者。唯一的其他添加是tls:块。这告诉traefik我们希望主机k3s.carpie.net具有TLS功能,并且我们希望TLS证书文件存储在秘密的k3s-carpie-net-tls中。请记住,我们没有创建这些证书!(好吧,我们创建了类似命名的测试证书,但我们删除了它们。)Traefik会读取这些配置并继续寻找秘密。当它找不到它时,它会看到一条说明我们要使用letsencrypt-prod发行者来获取它。从那里,它将为我们发出请求并将证书安装到秘密中!你完成了!让我们试试看。