概述
一直对cert-manager项目很感兴趣,今天着重研究了一下他的架构,并做了个尝试,这里做个记录。
cert-manager简介
它支持从Let’s Encrypt,HashiCorp Vault,Venafi等颁发证书。
架构如下:
它由以下组件组成:
Issuer
Issuer和ClusterIssuers是Kubernetes资源,它们代表证书颁发机构(CA),能够通过执行证书签名请求来生成签名证书。
Issuers只能在当前命名空间下使用,如果要创建可以在多个名称空间中使用的单个Issuer,则应考虑创建ClusterIssuer资源。
它支持的证书颁发机构如下:
[Configuration | cert-manager](https://cert-manager.io/docs/configuration/)
Certificate
“Certificate”定义了所需的x509证书,该证书将被更新并保持最新状态。证书是一个命名空间资源,它引用Issuer或ClusterIssuer,它们确定将接受证书请求的内容。
CertificateRequest
CertificateRequest是cert-manager中的命名空间资源,用于从颁发者请求x509证书。该资源包含PEM编码的证书请求的base64编码的字符串,该字符串被发送到引用的Issuer。成功发行后,将根据证书签名请求返回已签名的证书。证书请求通常由控制器或其他系统使用和管理,除非特别需要,否则不应由我们自己使用。
ACME Orders and Challenges
cert-manager支持使用ACME颁发者向ACME服务器(包括Let’s Encrypt)请求证书。大多数计算机通常在公共Internet上信任这些证书。要成功请求证书,证书管理者必须解决ACME Challenges,这些Challenges必须完成才能证明客户端拥有所请求的DNS地址。
为了完成 Challenges,cert-manager引入了两种CustomResource类型,Order与Challenge。
ACME使用Orders资源来管理签名的TLS证书的ACME“Order”的生命周期。Order代表单个证书申请,一旦创建了引用ACME颁发者的新CertificateRequest资源,该订单便会自动创建。创建证书资源,更改其规范或需要更新证书资源后,cert-manager会自动创建CertificateRequest资源。
作为最终用户,您将不需要手动创建Order资源。创建后,便无法更改Order。而是,必须创建一个新的Order资源。
Order资源为该“订单”封装了多个ACME Challenges,因此将管理一个或多个Challenges资源。
ACME Issuer使用Challenge资源来管理必须完成的ACME Challenge的生命周期,以完成单个DNS名称/标识符的“授权”。
创建Order资源后,订单控制器将为ACME服务器授权的每个DNS名称创建Challenge资源。
作为最终用户,您将无需手动创建Challenge资源。创建Challenge后,便无法更改。相反,必须创建一个新的Challenge资源。
Webhook
cert-manager利用Webhook服务器扩展Kubernetes API服务器,以提供对cert-manager资源的动态准入控制。
Webhook组件被部署为另一个Pod,与主要的证书管理器控制器和CA注入器组件一起运行。
为了使API服务器与webhook组件进行通信,webhook需要配置为apiserver信任的TLS证书。
为了使API服务器与webhook组件进行通信,webhook需要配置为apiserver信任的TLS证书。这是由cainjector创建的,并由以下两个secret实现:
secret /cert-manager-webhook-ca:一种自签名的根CA证书,用于签署Webhook容器的证书。
secret /cert-manager-webhook-tls:由上面的根CA颁发的TLS证书,由Webhook提供。
CA Injector
证书管理器CA注入程序控制器负责将CA捆绑软件注入到Webhook的ValidatingWebhookConfiguration和MutatingWebhookConfiguration资源中,以允许Kubernetes API服务器“信任” Webhook API服务器。
## 配置使用(v0.12.0)
1. 下载并配置crd资源
wget -c https://raw.githubusercontent.com/jetstack/cert-manager/release-0.12/deploy/manifests/00-crds.yaml
kubectl apply -f 00-crds.yaml
2. 下载,这里选择v0.12.0,并解压
helm fetch --untar jetstack/cert-manager --version v0.12.0
3. 编辑values.yaml
#修改安装的node结点
#94
nodeSelector:
node: sre
…
#160
nodeSelector:
node: sre
#207
nodeSelector:
node: sre
4. 通过helm安装cert-manager
kubectl create ns cert-manager
helm install cert-manager -n cert-manager -f values.yaml ./
5. 验证cert-manager是否安装正确
#创建如下测试资源test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
commonName: example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
# 执行以下命令
kubectl apply -f test-resources.yaml
# 观察以下命令输出,最后一行看到Certificate issued successfully,就代表安装成功
kubectl describe certificate -n cert-manager-test
# 清空测试
kubectl delete -f test-resources.yaml
6. 安装alidns-webhook,这里选择官方推荐的alidns-webhook,[DNS01 | cert-manager](https://cert-manager.io/docs/configuration/acme/dns01/)
#下载alidns-webhook
git clone https://github.com/pragkent/alidns-webhook
#执行以下安装,cert-manager的v0.11以上,选择bundle.yaml版本
kubectl apply -f deploy/bundle.yaml
#创建secret
kubectl -n cert-manager create secret generic alidns-secret --from-literal=access-key=‘xxxxx’ --from-literal=secret-key=‘xxxx’
7. 创建ClusterIssuer
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: xxx@example.org
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- dns01:
webhook:
groupName: acme.yourcompany.com
solverName: alidns
config:
region: ""
accessKeySecretRef:
name: alidns-secret
key: access-key
secretKeySecretRef:
name: alidns-secret
key: secret-key
8. 创建测试ingress
#创建以下yarn文件,test-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
namespace: test
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- 'test-ingress.yourdomain.com'
secretName: test-ingress1-yourdomain-com-tls
rules:
- host: test-yourdomain.insyunmi.com
http:
paths:
- path: /
backend:
serviceName: mynginx
servicePort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: mynginx
name: mynginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
run: mynginx
template:
metadata:
labels:
run: mynginx
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: mynginx
ports:
- containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: mynginx
namespace: test
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: mynginx
#执行
kubectl apply -f test-ingress.yaml
9. 查看生成的证书
kubectl get certificates -n test
NAME READY SECRET AGE
test-ingress1-yourdomain-com-tls True test-ingress1-yourdomain-com-tls 106m
总结
在安装使用alidns-webhook时,需要注意,alidns-webhook给出的示例是letsencrypt测试环境,实际使用时,需要改为正式环境。
配置完后,只需要在ingress中增加以下annotations:cert-manager.io/cluster-issuer: "letsencrypt-prod"