×
1 Views

接着上一篇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 评论

发表回复

作者

kebin8@qq.com

相关文章

k3s安装实战

4 Views k3s 是一个轻量级的 Kubernetes 发行版,专为在资源有限的环境中运行而设计。以下是 […]

读出全部