草庐IT

Cert-Manager 实现 K8s 服务域名证书自动化续签

Marionxue 2023-03-28 原文

简介

Cert-Manager[1]是一款用于 Kubernetes 集群中自动化管理 TLS 证书的开源工具,它使用了 Kubernetes 的自定义资源定义(CRD)机制,让证书的创建、更新和删除变得非常容易。

设计理念

Cert-Manager 是将 TLS 证书视为一种资源,就像 Pod、Service 和 Deployment 一样,可以使用 Kubernetes API 进行管理。它使用了自定义资源定义(CRD)机制,通过扩展 Kubernetes API,为证书的生命周期提供了标准化的管理方式。

架构设计

Cert-Manager 的架构分为两层:控制层和数据层。

控制层: 负责证书的管理,包括证书的创建、更新和删除等。

数据层: 负责存储证书相关的数据,包括证书的私钥、证书请求、证书颁发机构等。

Cert-Manager 支持多种证书颁发机构,包括**自签名证书selfSigned**、Let's Encrypt、HashiCorp Vault、Venafi 等。它还支持多种验证方式,包括 HTTP 验证、DNS 验证和 TLS-SNI 验证等。这些验证方式可以帮助确保证书的颁发机构是可信的,并且确保证书的私钥不会泄露。

使用场景

Cert-Manager 的使用场景非常广泛,包括以下几个方面:

  1. HTTPS 访问:通过 Cert-Manager 可以方便地为 Kubernetes 集群中的 Service 和 Ingress 创建 TLS 证书,以便实现 HTTPS 访问。
  2. 部署安全:Cert-Manager 可以为 Kubernetes 集群中的 Pod 创建 TLS 证书,以确保 Pod 之间的通信是加密的。
  3. 服务间认证:Cert-Manager 可以为 Kubernetes 集群中的 Service 创建 TLS 证书,以确保 Service 之间的通信是加密的。
  4. 其他应用场景:Cert-Manager 还可以用于为其他应用程序创建 TLS 证书,以确保通信是加密的。

解决的实际问题

  1. 自动化管理证书:Cert-Manager 可以自动化地管理 TLS 证书,无需人工干预,自动签发证书以及过期前 renew 证书等问题,避免了证书管理的复杂性和错误。
  2. 安全性:Cert-Manager 可以帮助确保证书的颁发机构是可信的,并确保证书的私钥不会泄露,从而提高了通信的安全性。
  3. 管理成本:Cert-Manager 可以通过标准化证书的管理方式,简化证书管理的成本和流程。

cert-manager 创建证书的过程

在 Kubernetes 中,cert-manager 通过以下流程创建资源对象以签发证书:

  1. 创建一个 CertificateRequest 对象,包含证书的相关信息,例如证书名称、域名等。该对象指定了使用的 Issuer 或 ClusterIssuer,以及证书签发完成后,需要存储的 Secret 的名称。
  2. Issuer 或 ClusterIssuer 会根据证书请求的相关信息,创建一个 Order 对象,表示需要签发一个证书。该对象包含了签发证书所需的域名列表、证书签发机构的名称等信息。
  3. 证书签发机构根据 Order 对象中的信息创建一个或多个 Challenge 对象,用于验证证书申请者对该域名的控制权。Challenge 对象包含一个 DNS 记录或 HTTP 服务,证明域名的所有权。
  4. cert-manager 接收到 Challenge 对象的回应ChallengeResponse后,会将其更新为已解决状态。证书签发机构会检查所有的 Challenge 对象,如果全部通过验证,则会签发证书。
  5. 签发证书完成后,证书签发机构会将证书信息写入 Secret 对象,同时将 Order 对象标记为已完成。证书信息现在可以被其他部署对象使用。
cert-manager 在 k8s 中创建证书的整个过程可以通过以下流程图来描述:

+-------------+
| |
| Ingress/ |
| annotations |
| |
+------+------+
|
| watch ingress change
|
v
+-------------+
| |
| Issuer/ |
| ClusterIssuer |
| |
+------+------+
|
| Create CertificateRequest
|
v
+------+------+
| |
|CertificateRequest|
| |
+------+------+
|
| Create Order
|
v
+------+------+
| |
| Order |
| |
+------+------+
|
| Create Challenges
|
v
+------+------+
| |
| Challenge |
| |
+------+------+
|
| Respond to Challenge
|
v
+------+------+
| |
|ChallengeResponse|
| |
+------+------+
|
| Issue Certificate
|
v
+------+------+
| |
| Secret |
| |
+------+------+
实际上在我们手动实践的时候,可以通过以下命令查看各个过程的信息:

kubectl get CertificateRequests,Orders,Challenges
到这里,在了解了 cert-manager 的设计理念、架构设计、使用场景、实际解决的问题之后,动手操作利用 cert-manager 给实际项目创建证书。

安装和配置

安装 cert-manager。

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml

NAME READY STATUS RESTARTS AGE
cert-manager-5d495db6fc-6rtxx 1/1 Running 0 9m56s
cert-manager-cainjector-5f9c9d977f-bxchd 1/1 Running 0 9m56s
cert-manager-webhook-57bd45f9c-89q87 1/1 Running 0 9m56s
使用 cmctl 命令行工具检查 cert-manager 是否正常

brew install cmctl
cmctl check api
安装完成后,Cert-manager 将自动创建 CRD(Custom Resource Definitions)和相关的资源,如证书、密钥。

检查 cert-manager 的webhook是否正常。

cat <<EOF > 02-test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
EOF

kubectl apply -f 02-test-resources.yaml
kubectl delete -f 02-test-resources.yaml

创建 cert-manager 的证书颁发实体对象

cert-manager 的 Issuer 和 ClusterIssuer 都是用来定义证书颁发的实体的资源对象。

  • Issuer 是命名空间级别的资源,用于在命名空间内颁发证书。例如,当您需要使用自签名证书来保护您的服务,或者使用 Let's Encrypt 等公共证书颁发机构来颁发证书时,可以使用 Issuer。
  • ClusterIssuer 是集群级别的资源,用于在整个集群内颁发证书。例如,当您需要使用公司的内部 CA 来颁发证书时,可以使用 ClusterIssuer。
知道两者之间的区别之后,你就可以根据自己的使用情况来决定自己的 issuer 的类型。这里列出几种常用的 issuer 使用模板:

  • 创建 staging 环境的证书颁发者 issuer。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: xxx@qq.com #此处填写你的邮箱地址
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx

使用 staging 环境颁发的证书无法正常在公网使用,需要本地添加受信任根证书。


  • 创建 prod 环境的证书颁发者 issuer。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 欢迎关注·云原生生态圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
  • 创建 staging 环境的证书颁发者 ClusterIssuer。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 欢迎关注·云原生生态圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
  • 创建 Prod 环境的证书颁发者 ClusterIssuer。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 欢迎关注·云原生生态圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx

通过应用实际测试一下

这里我们基本上就完成了 cert-manager 签署证书的所有前置工作,下面通过一个简单实例测试证书:这里我们部署一个开源小项目文件传递柜

apiVersion: v1
kind: PersistentVolume
metadata:
name: filecodebox-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/filecodebox"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filecodebox-pvc
namespace: blogs
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: filecodebox
namespace: blogs
labels:
app: filecodebox
spec:
replicas: 1
template:
metadata:
name: filecodebox
labels:
app: filecodebox
spec:
containers:
- name: filecodebox
image: lanol/filecodebox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /app/data
name: filecodeboxdata
- mountPath: /etc/localtime
name: timezone
readOnly: true
restartPolicy: Always
volumes:
- name: filecodeboxdata
persistentVolumeClaim:
claimName: filecodebox-pvc
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
selector:
matchLabels:
app: filecodebox
---
apiVersion: v1
kind: Service
metadata:
name: filecodebox-svc
namespace: blogs
spec:
selector:
app: filecodebox
ports:
- port: 12345
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: filecodebox-ingress
namespace: blogs
labels:
exposed_by: ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" #此处我们是基于issuer颁发一个prod的证书
spec:
ingressClassName: nginx
tls:
- hosts:
- file.devopsman.cn
secretName: filecodebox-tls
rules:
- host: file.devopsman.cn
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: filecodebox-svc
port:
number: 12345
创建之后,这里就可以检验一下证书的有效期,查看是否生效。

root# echo | openssl s_client -servername file.devopsman.cn -connect file.devopsman.cn:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Mar 1 04:02:01 2023 GMT
notAfter=May 30 04:02:00 2023 GMT
这里我们也可以通过 kubectl 查看签发生成的证书来确定。

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
creationTimestamp: "2023-03-01T05:01:18Z"
generation: 1
labels:
exposed_by: ingress
name: filecodebox-tls
namespace: blogs
ownerReferences:
- apiVersion: networking.k8s.io/v1
blockOwnerDeletion: true
controller: true
kind: Ingress
name: filecodebox-ingress
uid: 3e2972a3-934b-431f-afee-4f649f5e1df3
resourceVersion: "26802670"
uid: 3d58d600-87aa-4119-bbdd-6566a8a0331b
spec:
dnsNames:
- file.devopsman.cn
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-prod
secretName: filecodebox-tls
usages:
- digital signature
- key encipherment
status:
conditions:
- lastTransitionTime: "2023-03-01T05:02:03Z"
message: Certificate is up to date and has not expired
observedGeneration: 1
reason: Ready
status: "True"
type: Ready
notAfter: "2023-05-30T04:02:00Z"
notBefore: "2023-03-01T04:02:01Z"
renewalTime: "2023-04-30T04:02:00Z"
revision: 1
在上面了解完证书颁发到签发的过程后,就可以通过以下命令查看整个过程大概的细节

kubectl get CertificateRequests,Orders,Challenges
写到这里,cert-manager 签署证书请求的方式基本上了解了,有感兴趣的话题,可以一起交流,下一篇准备记录一下 cert-manager 如何在内部局域网如何通过创建自签颁发者来颁发以及签发我们需要的证书来在尽可能节省成本的基础上模拟真实环境。

有关Cert-Manager 实现 K8s 服务域名证书自动化续签的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  4. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  7. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

随机推荐