接着上一篇k3s安装实战介绍如何安装k3s,现在我准备给我的k3s集群安装cert-manager,这个组件可以帮我们管理集群上的证书。我们这个文章介绍如何使用cert-manager自助申请let’s encrypt的ssl证书,可以支持单独域名和泛域名。
那就让我们开始。
检查helm包管理工具
首先,确定我们已经有了helm包管理工具,并且执行下面的命令能正确返回版本号。
helm version
返回下面的输出。
version.BuildInfo{Version:”v3.14.3″, GitCommit:”f03cc04caaa8f6d7c3e67cf918929150cf6f3f12″, GitTreeState:”clean”, GoVersion:”go1.21.7″}
添加jetstack仓库,并且安装cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.14.4 --set installCRDs=true --values=values.yaml
上面的values.yaml内容如下:
# values.yaml
installCRDs: false
replicaCount: 1
extraArgs:
- --dns01-recursive-nameservers=1.1.1.1:53,9.9.9.9:53
- --dns01-recursive-nameservers-only
podDnsPolicy: None
podDnsConfig:
nameservers:
- 1.1.1.1
- 9.9.9.9
配置证书issuer
我使用的是阿里云的域名云解释,使用dns01作为生成证书的challenge,所以需要配置阿里云的accesskey和secretkey,let’s encrypt在颁布证书之前,先去dns记录中自动添加一条TXT记录来验证你是否有域名的所有权,只有所有权验证通过后才能正确颁布证书,所以也要确保这对AKSK有权限创建和修改要版本证书的域名的DNS记录。
在k8s/k3s的Secret中创建记录保存accesskey和secretkey
# ali-aksk.yaml
apiVersion: v1
kind: Secret
metadata:
name: alidns-secret
namespace: cert-manager
data:
access-key: <BAS64加密的ACCESSKEY>
secret-key: <Base64加密的SECRETKEY>
# ali-webhook.yaml
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
# stg-letsencrypt.yaml
# let's encrypt的测试环境,在确保正常颁布证书流程之前使用测试环境做测试,否则你的账号会在let's encrypt生产环境被锁一个星期。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# 请把下面的email地址改为你自己的email地址
email: <EMAIL ADDRESS>
server: https://acme-staging-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
# prod-letsencrypt.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# 请把下面的email地址改为你自己的email地址
email: <EMAIL ADDRESS>
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
把上面三个文件保存到服务器上,在k8s/k3s master上执行以下命令
kubectl apply -f ali-aksk.yaml
kubectl apply -f ali-webhook.yaml
kubectl apply -f stg-letsencrypt.yaml
kubectl apply -f prod-letsencrypt.yaml
以上一旦全部执行成功,颁布证书的环境就已经准备好了。接下来就是配置具体要颁布哪些域名的证书了。
# stg-example-com.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-stg
namespace: kube-public # 生成的证书放哪个名字空间,如果要在多个名字空间都存放,可以每次申请证书之前修改这个名字空间为你需要的名称。例如: default
spec:
secretName: example-com-stg-tls # 要生成的证书在k8s Secret中的名称
issuerRef:
name: letsencrypt-stg # 指向上面stg-letsencrypt.yaml的name,如果是生产环境,请改为prod-letsencrypt.yaml
kind: ClusterIssuer
commonName: "example.com" # 要申请证书的域名,显示在证书中
dnsNames:
- example.com # 要申请证书的域名,顶级域名
- "*.example.com" # 要申请证书的域名,顶级域名的泛域名
申请证书
kubectl apply -f stg-example-com.yaml
查看challenge,看申请证书的进度。
kubectl get challenges
也可以通过查看cert-manager pod的日志查看证书申请的具体过程的日志,是否出错等,方便排错。
kubectl logs -n cert-manager -f cert-manager-xxxx # 其中后面的xxxx为cert-manager pod的名字,请自行通过kubectl get pods -n cert-manager 获取。
如果一切正常,你会得到一份由let’s encrypt测试环境颁布的证书,但是这个证书并不能用于线上环境,因为这并不属于可信机构颁发的证书。你可以使用以下命令申请let’s encrypt生产环境颁布的证书。
kubectl apply -f prod-example-com.yaml
到现在,如果一切正常,那么恭喜你,你的K8s集群有了ssl证书,你可以把该ssl证书部署到你的ingress上,让你的网站加上安全锁。
下一篇我会介绍如何使用这些颁布的证书。Good luck!Happy Tech happy Life.
1 评论