安装 cert-manager
官方安装文档:https://cert-manager.io/docs/installation/kubectl/
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yaml
安装完成后,会创建名字空间(namespace) cert-manager
,和部署(Deployment) cert-manager
cert-manager-cainjector
cert-manager-webhook
。
验证方式
Let's Encrypt 颁发 SSL 证书,需要认证申请人是否为域名的拥有者,可以使用 HTTP01 和 DNS01 两种方式进行域名认证。
HTTP01 认证方式在域名指定的路径 /.well-known/acme-challenge
存放一个文件,Let's Encrypt 访问这个文件进行判断。这种方式较为简单,但有失败的机率,且不支持泛域名证书。
DNS01 认证方式在域名中增加一个 TXT 记录,Let's Encrypt 访问这个 TXT 记录进行判断。这种方式成功率高,功能全,支持泛域名,是推荐的方式。但操作复杂,需要从域名服务商处获取访问密钥。
HTTP01 验证
创建 ClusterIssuer,使用 http01 的方式申请 Let's Encrypt 的证书。只需要一个即可,全局共享。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http01
spec:
acme:
# 测试时,请使用预生产环境(staging),以免证书限额被耗尽。每 7 天只能申请 5 个证书,每 34 小时恢复 1 个证书额度
#server: https://acme-staging-v02.api.letsencrypt.org/directory
server: https://acme-v02.api.letsencrypt.org/directory
# 使用自己的邮箱
email: certmaster@example.com
privateKeySecretRef:
name: letsencrypt-http01-account-key
solvers:
- http01:
ingress:
# 查看`集群管理 - 网络 - IngressClass` 的名称
ingressClassName: nginx
创建 Certificate。如果有多个域名,需要多个证书,可创建多个。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-http01-tls
# 放在网站所在的 namespace 里
namespace: default
spec:
# 证书的名称。在 namespace 下的 `配置空间 - 密文` 里
secretName: example-com-http01-tls
dnsNames:
# 需要申请 SSL 的域名
- "example-com"
issuerRef:
name: letsencrypt-http01
kind: ClusterIssuer
DNS01 验证
安装 webhook,由于不同域名服务商的 api 接口不同,需要安装不同的 webhook。
根据自己的域名服务商选择不同的 webhook:https://cert-manager.io/docs/configuration/acme/dns01/#webhook
创建 alidns-webhook
以 aliyun 为例:https://github.com/pragkent/alidns-webhook
# Install alidns-webhook to cert-manager namespace.
kubectl apply -f https://raw.githubusercontent.com/pragkent/alidns-webhook/master/deploy/bundle.yaml
如果无法下载文件,可将以下文件内容保存到本地文件执行。其中 docker 镜像地址 pragkent/alidns-webhook:0.1.1
改成了 docker.1ms.run/pragkent/alidns-webhook:0.1.1
,以免无法下载镜像。
完整文件内容如下:
---
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'
verbs:
- 'get'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: alidns-webhook:flowcontrol-solver
labels:
app: alidns-webhook
rules:
- apiGroups:
- "flowcontrol.apiserver.k8s.io"
resources:
- 'prioritylevelconfigurations'
- 'flowschemas'
verbs:
- 'list'
- 'watch'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alidns-webhook:flowcontrol-solver
labels:
app: alidns-webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alidns-webhook:flowcontrol-solver
subjects:
- apiGroup: ""
kind: ServiceAccount
name: alidns-webhook
namespace: cert-manager
---
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.1
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
安装成功后会创建负载(Deployment) alidns-webhook
。
创建阿里云密钥
从阿里云获取到密钥后,需保存在 cert-manager 名称空间的 配置中心 - 密文
中:
apiVersion: v1
kind: Secret
metadata:
name: alidns-secret
namespace: cert-manager
data:
access-key: YOUR_ACCESS_KEY
secret-key: YOUR_SECRET_KEY
如提示 YOUR_ACCESS_KEY 和 YOUR_SECRET_KEY 不是 base64 格式,可先留空,保存后再到界面中修改。
创建 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# 使用自己的邮箱
email: certmaster@example.com
# 测试时,请使用预生产环境(staging),以免证书限额被耗尽。每 7 天只能申请 5 个证书,每 34 小时恢复 1 个证书额度
#server: https://acme-staging-v02.api.letsencrypt.org/directory
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-staging-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
创建 Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-tls
# 放在网站所在的 namespace 里
namespace: default
spec:
# 证书的名称。在 namespace 下的 `配置空间 - 密文` 里
secretName: example-com-tls
dnsNames:
# 需要申请 SSL 的域名
- "example.com"
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
查看结果与使用
创建成功后,在 namespace 下的 配置空间 - 密文
里可以看到 SSL 证书。名称为 Certificate 中指定的 secretName,如 example-com-tls
example-com-http01-tls
,类型为 kubernetes.io/tls
。
如果看到名称为 example-com-tls-xxx
,且类型为 Opaque
,有可能证书正在生成中,稍作等候。或者到 namespace 下的 消息
中查看生成情况,是否有错误信息。
最后在部署(Deployment)的路由中,选择开启 HTTPS,即可选择相应的 SSL 证书。