集群信息
kubernetes: 1.19.16
Linux kernel: 3.10.0
helm: 3.5.4
安装 Cert-Manager
(1)安装 CRD
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.crds.yaml
安装完成后可以看到如下 CRD 信息:
# kubectl get crd | grep cert
certificaterequests.cert-manager.io 2021-12-13T04:26:04Z
certificates.cert-manager.io 2021-12-13T04:26:04Z
challenges.acme.cert-manager.io 2021-12-13T04:26:04Z
clusterissuers.cert-manager.io 2021-12-13T04:26:05Z
issuers.cert-manager.io 2021-12-13T04:26:05Z
orders.acme.cert-manager.io 2021-12-13T04:26:05Z
(2)安装 cert-manager
# 添加helm repo
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 安装cert-manager
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.6.1 \
待安装完成后,可以看到如下 Pod 信息。
# kubectl get po -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-57d89b9548-cq78f 1/1 Running 0 4h3m
cert-manager-cainjector-5bcf77b697-hmjj2 1/1 Running 0 4h3m
cert-manager-startupapicheck-hn5g5 0/1 Completed 4 4h3m
cert-manager-webhook-8687fc66d4-ppllm 1/1 Running 0 4h3m
待所以 Pod 变成 Running
过后,cert-manager
安装完成。
创建 ClusterIssuer
cert-manager
提供了 Issuer
和 ClusterIssuer
两种类型的签发机构,Issuer
只能用来签发自己所在命名空间下的证书,ClusterIssuer
可以签发任意命名空间下的证书。
ACME
验证证书的方式有 http01
和 dns01
两种,这里会分别进行测试。
http01
1、创建测试 ClusterIssuer
创建测试证书主要是为了验证证书是否能正常生成,而生产环境对接口的调用有限制【1】,避免不可用,建议先生成测试证书。
# cat letsencrypt-staging.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# 务必将此处替换为你自己的邮箱, 否则会配置失败。当证书快过期时 Let's Encrypt 会与你联系
email: gavin.tech@qq.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# 将用来存储 Private Key 的 Secret 资源
name: letsencrypt-staging
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
2、创建正式 ClusterIssuer
# cat letsencrypt-prod.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: gavin.tech@qq.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
3、手动生成证书
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: coolops-tls
spec:
secretName: coolops-tls
duration: 2160h # 90d
renewBefore: 360h # 15d
isCA: false
dnsNames:
- "coolops.cn"
- "*.coolops.cn"
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
group: cert-manager.io
创建过后,通过以下命令查看状态
# kubectl get certificate
NAME READY SECRET AGE
coolops-tls True coolops-tls 122m
待测试证书生成无误后,就可以生成生产证书了,如下定义 YAML。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: coolops-tls-prod
spec:
secretName: coolops-tls-prod
duration: 2160h # 90d
renewBefore: 360h # 15d
isCA: false
dnsNames:
- "coolops.cn"
- "*.coolops.cn"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
group: cert-manager.io
4、自动生成证书
自动生成证书通过在 ingress
中添加 annotaions
实现,如下。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-coolops
annotations:
# 务必添加以下两个注解, 指定 ingress 类型及使用哪个 cluster-issuer
kubernetes.io/ingress.class: "nginx"
kubernetes.io/tls-acme: "true"
cert-manager.io/cluster-issuer:"letsencrypt-staging" # 这里先用测试环境的证书测通后,就可以替换成正式服证书
# 如果你使用 issuer, 使用以下注解
# cert-manager.io/issuer: "letsencrypt-staging"
spec:
tls:
- hosts:
- test-nginx.coolops.cn # TLS 域名 - 这里仅支持单域名,下面会讲通配符的域名配置
secretName: test-nginx-coolops-tls # 用于存储证书的 Secret 对象名字,可以是任意名称,cert-manager会自动生成对应名称的证书名称
rules:
- host: test-nginx.coolops.cn
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80
dns01
这里使用阿里 DNS 进行校验。其他 webhook 可以到这里【2】进行查看。
1、部署 wehbook
这里使用的是 https://github.com/pragkent/alidns-webhook。
由于改项目很多地方没有及时更新,对于我这个版本的 apiVersion
是不一样的,所以更改后如下:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: alidns-webhook
namespace: cert-manager
labels:
app: alidns-webhook
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: alidns-webhook
namespace: cert-manager
labels:
app: alidns-webhook
rules:
- apiGroups:
- ''
resources:
- 'secrets'
- 'configmaps'
verbs:
- 'get'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alidns-webhook
namespace: cert-manager
labels:
app: alidns-webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: alidns-webhook
subjects:
- apiGroup: ""
kind: ServiceAccount
name: alidns-webhook
namespace: cert-manager
---
# Grant the webhook permission to read the ConfigMap containing the Kubernetes
# apiserver's requestheader-ca-certificate.
# This ConfigMap is automatically created by the Kubernetes apiserver.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alidns-webhook:webhook-authentication-reader
namespace: kube-system
labels:
app: alidns-webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- apiGroup: ""
kind: ServiceAccount
name: alidns-webhook
namespace: cert-manager
---
# apiserver gets the auth-delegator role to delegate auth decisions to
# the core apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alidns-webhook:auth-delegator
namespace: cert-manager
labels:
app: alidns-webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- apiGroup: ""
kind: ServiceAccount
name: alidns-webhook
namespace: cert-manager
---
# Grant cert-manager permission to validate using our apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: alidns-webhook:domain-solver
labels:
app: alidns-webhook
rules:
- apiGroups:
- acme.yourcompany.com
resources:
- '*'
verbs:
- 'create'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alidns-webhook:domain-solver
labels:
app: alidns-webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alidns-webhook:domain-solver
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager
namespace: cert-manager
---
# Source: alidns-webhook/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: alidns-webhook
namespace: cert-manager
labels:
app: alidns-webhook
spec:
type: ClusterIP
ports:
- port: 443
targetPort: https
protocol: TCP
name: https
selector:
app: alidns-webhook
---
# Source: alidns-webhook/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: alidns-webhook
namespace: cert-manager
labels:
app: alidns-webhook
spec:
replicas:
selector:
matchLabels:
app: alidns-webhook
template:
metadata:
labels:
app: alidns-webhook
spec:
serviceAccountName: alidns-webhook
containers:
- name: alidns-webhook
image: pragkent/alidns-webhook:0.1.0
imagePullPolicy: IfNotPresent
args:
- --tls-cert-file=/tls/tls.crt
- --tls-private-key-file=/tls/tls.key
env:
- name: GROUP_NAME
value: "acme.yourcompany.com"
ports:
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
readinessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
volumeMounts:
- name: certs
mountPath: /tls
readOnly: true
resources:
{}
volumes:
- name: certs
secret:
secretName: alidns-webhook-webhook-tls
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.acme.yourcompany.com
labels:
app: alidns-webhook
annotations:
cert-manager.io/inject-ca-from: "cert-manager/alidns-webhook-webhook-tls"
spec:
group: acme.yourcompany.com
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: alidns-webhook
namespace: cert-manager
version: v1alpha1
---
# Create a selfsigned Issuer, in order to create a root CA certificate for
# signing webhook serving certificates
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: alidns-webhook-selfsign
namespace: cert-manager
labels:
app: alidns-webhook
spec:
selfSigned: {}
---
# Generate a CA Certificate used to sign certificates for the webhook
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: alidns-webhook-ca
namespace: cert-manager
labels:
app: alidns-webhook
spec:
secretName: alidns-webhook-ca
duration: 43800h # 5y
issuerRef:
name: alidns-webhook-selfsign
commonName: "ca.alidns-webhook.cert-manager"
isCA: true
---
# Create an Issuer that uses the above generated CA certificate to issue certs
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: alidns-webhook-ca
namespace: cert-manager
labels:
app: alidns-webhook
spec:
ca:
secretName: alidns-webhook-ca
---
# Finally, generate a serving certificate for the webhook to use
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: alidns-webhook-webhook-tls
namespace: cert-manager
labels:
app: alidns-webhook
spec:
secretName: alidns-webhook-webhook-tls
duration: 8760h # 1y
issuerRef:
name: alidns-webhook-ca
dnsNames:
- alidns-webhook
- alidns-webhook.cert-manager
- alidns-webhook.cert-manager.svc
- alidns-webhook.cert-manager.svc.cluster.local
部署完成后,可以看到如下 Pod 信息。
# kubectl get po -n cert-manager
NAME READY STATUS RESTARTS AGE
alidns-webhook-6cdb855fdb-lw7x4 1/1 Running 0 175m
cert-manager-57d89b9548-cq78f 1/1 Running 0 4h35m
cert-manager-cainjector-5bcf77b697-hmjj2 1/1 Running 0 4h35m
cert-manager-startupapicheck-hn5g5 0/1 Completed 4 4h35m
cert-manager-webhook-8687fc66d4-ppllm 1/1 Running 0 4h35m
2、在阿里云创建 secret key id 和 secret
建议创建一个 RAM
账户,然后授权 AliyunDNSFullAccess
权限,再创建 Accesskey。
3、创建 Secret
# cat aliyun-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: alidns-secret
namespace: cert-manager
data:
access-key: TFRBSTV0UUUzxxxxxxxxxxxxxxL
secret-key: NmtWQ1Mycmx0OWxxxxxxxxxxxxxxxx
4、创建测试 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging-dns
spec:
acme:
email: coolops@163.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-stagging-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
5、创建生产 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-dns
spec:
acme:
email: coolops@163.com
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
6、手动生成证书
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: coolops-tls
spec:
secretName: coolops-tls
duration: 2160h # 90d
renewBefore: 360h # 15d
isCA: false
dnsNames:
- "coolops.cn"
- "*.coolops.cn"
issuerRef:
name: letsencrypt-staging-dns
kind: ClusterIssuer
group: cert-manager.io
带测试证书生成无误后,可以替换为生产证书。
7、ingress 中使用证书
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-coolops
annotations:
# 务必添加以下两个注解, 指定 ingress 类型及使用哪个 cluster-issuer
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer:"letsencrypt-staging-dns" # 这里先用测试环境的证书测通后,就可以替换成正式服证书
spec:
tls:
- hosts:
- "*.coolops.cn" # 如果填写单域名就只会生产单域名的证书,如果是通配符请填写"*.example.com", 注意:如果填写example.com只会生成www.example.com一个域名。
secretName: coolops-tls # 测试的证书,填写刚刚创建Certificate的名称,注意更换环境时证书也要一起更换,这里并不会像单域名一样自动生成
rules:
- host: www.coolops.cn
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80
链接
【1】https://letsencrypt.org/zh-cn/docs/staging-environment/
【2】https://cert-manager.io/docs/configuration/acme/dns01/
【3】https://github.com/PowerDos/k8s-cret-manager-aliyun-webhook-demo