056.Kubernetes cert-manager Root CA自签实战

文章目录

自签 Root CA实践

SelfSigned 三个主要的使用场景:

  • 自签证书;
  • 自签来构建Root CA,然后由此CA 签发业务证书;
  • 合法的CA颁发的根证书,然后由此根证书签发业务证书;

集群级 Root CA

该步骤主要用 SelfSigned 引导生成"集群级 Root CA",并创建 ClusterIssuer(全集群可签)。

shell 复制代码
[root@master01 cert-manager]# vim cluster-ca-bootstrap.yaml
# 1) 一个 SelfSigned 的 ClusterIssuer(只用来签 Root CA)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-bootstrap
spec:
  selfSigned: {}

---
# 2) 生成 Root CA 证书(isCA: true),把 CA 私钥/证书落到 cert-manager namespace 的 Secret 里
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: cluster-root-ca
  namespace: cert-manager
spec:
  isCA: true
  commonName: cluster-root-ca
  subject:
    organizations:
    - linuxsb
  secretName: cluster-root-ca-secret
  duration: 87600h              # 设置10年
  privateKey:
    algorithm: ECDSA
    size: 256
    rotationPolicy: Always
  issuerRef:
    name: selfsigned-bootstrap
    kind: ClusterIssuer
    group: cert-manager.io

---
# 3) 用上面的 Root CA Secret,创建一个真正用来"签业务证书"的 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: cluster-ca
spec:
  ca:
    secretName: cluster-root-ca-secret

[root@master01 cert-manager]# kubectl apply -f cluster-ca-bootstrap.yaml

提示:Root CA 和业务证书都会过期(默认都是90天),一般生产环境中Root CA 很少变,如图 Root CA 过期了,所有基于此办法的业务证书都会不受信任,因此在如上实验中,直接将 Root CA 设置为 10 年。

确认验证:

shell 复制代码
[root@master01 cert-manager]# kubectl get clusterissuer selfsigned-bootstrap cluster-ca
NAME                   READY   AGE
selfsigned-bootstrap   True    2m29s
cluster-ca             True    2m29s
[root@master01 cert-manager]# kubectl -n cert-manager get certificate cluster-root-ca
NAME              READY   SECRET                   AGE
cluster-root-ca   True    cluster-root-ca-secret   2m32s
[root@master01 cert-manager]# kubectl -n cert-manager get secret cluster-root-ca-secret
NAME                     TYPE                DATA   AGE
cluster-root-ca-secret   kubernetes.io/tls   3      2m33s

签名证书

该步骤主要用"cluster-ca"给所需的域名签一张证书(落到 test namespace 的 TLS Secret)。

shell 复制代码
[root@master01 cert-manager]# kubectl create namespace test

[root@master01 cert-manager]# vim test-flask-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: flask-linuxsb-com
  namespace: test
spec:
  secretName: flask-linuxsb-com-cert
  duration: 8760h           # 设置 1 年时间
  dnsNames:
  - flask.linuxsb.com
  issuerRef:
    name: cluster-ca
    kind: ClusterIssuer
  privateKey:
    rotationPolicy: Always

[root@master01 cert-manager]# kubectl apply -f test-flask-cert.yaml

[root@master01 cert-manager]# kubectl -n test get certificate flask-linuxsb-com
NAME                READY   SECRET                   AGE
flask-linuxsb-com   True    flask-linuxsb-com-cert   16s
[root@master01 cert-manager]# kubectl -n test get secret flask-linuxsb-com-cert
NAME                     TYPE                DATA   AGE
flask-linuxsb-com-cert   kubernetes.io/tls   3      16s

提示:Root CA 和业务证书都会过期(默认都是90天),一般生产环境中Root CA 很少变,业务证书 会基于 cert-manager 自动续期:只要 Certificate 资源还在、Issuer 可用,它会在到期前(默认在证书有效期的约 2/3 处开始尝试,具体由版本/策略决定)自动重新签发并更新 Secret。但实验环境也给与 1 年有效期。

使用证书

该步骤主要是让 Ingress 使用这个自签 TLS Secret(对外暴露 HTTPS)。

创建一个测试的的demo应用。

shell 复制代码
[root@master01 cert-manager]# vim test-flask-demo.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-flask-dp
  namespace: test
spec:
  selector:
    matchLabels:
      name: hello-flask
  template:
    metadata:
      name: hello-flask
      labels:
        name: hello-flask
    spec:
      containers:
        - name: hello-flask
          image: registry.cn-hangzhou.aliyuncs.com/xhyimages/hello-flask:v1.0.0
          ports:
            - containerPort: 5000

---
apiVersion: v1
kind: Service
metadata:
  name: hello-flask-svc
  namespace: test
spec:
  selector:
    name: hello-flask
  ports:
    - port: 80
      targetPort: 5000

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-flask-ingress
  namespace: test
spec:
  ingressClassName: "nginx"
  tls:
  - hosts:
    - flask.linuxsb.com
    secretName: flask-linuxsb-com-cert
  rules:
  - host: flask.linuxsb.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-flask-svc
            port:
              number: 80

[root@master01 cert-manager]# kubectl apply -f test-flask-demo.yaml

确认验证

  • 访问验证

客户端进行访问,或者浏览器进行访问 https://flask.linuxsb.com/

shell 复制代码
[root@master01 cert-manager]# kubectl -n test get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
hello-flask-dp-cd7fc68b-v6g6c   1/1     Running   0          30s   10.10.30.119   worker02   <none>           <none>
[root@master01 cert-manager]# kubectl -n test get svc -o wide
NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE   SELECTOR
hello-flask-svc   ClusterIP   10.20.19.56   <none>        80/TCP    33s   name=hello-flask
[root@master01 cert-manager]# kubectl -n test get ingress -o wide
NAME                  CLASS   HOSTS               ADDRESS        PORTS     AGE
hello-flask-ingress   nginx   flask.linuxsb.com   10.20.60.120   80, 443   36s

[root@master01 cert-manager]# curl -k https://flask.linuxsb.com/
<p>Hello, Flask, Deployment Succuss!</p>

提示:由于自签名不受信任是预期内的。

  • 添加信任

可将 Root CA 导出,然后浏览器导入,从而实现证书受信。

shell 复制代码
[root@master01 cert-manager]# kubectl -n cert-manager get secret cluster-root-ca-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cluster-root-ca.crt

提示 :很多 CA Secret 不一定有 ca.crt 这个键;对"CA 证书"来说,通常 tls.crt 就是 CA 证书本体。
如果你的 Secret 里同时存在 ca.crt,也可以把上面的 tls.crt 换成 ca.crt 导出。
证书信息(确认 Subject/有效期)可通过如下查看:

shell 复制代码
openssl x509 -in cluster-root-ca.crt -noout -subject -issuer -dates -fingerprint -sha256

浏览器导入(导入过程略),然后再次访问:

可信 Root CA实践

准备 Root CA

该实践主要是指假设已有CA证书,或者是合法的CA机构,以及准备构建具备可信的PKI基础设施。

区别于自签名签发CA,然后使用该CA签发业务证书,可信CA是指假定已有用于签发业务证书的Root CA证书,然后用此来构建完整的PKI基础设施,即先使用 Root CA证书来创建secret,然后使用cert-manager基于此secret来签发和自动管理业务证书。

CA issuers 通常用于 cert-manager 演示,或供具备 PKI 运维经验和工具的高级用户使用。

若要安全地在生产环境中使用,CA 发行者需熟悉轮换机制、信任存储分发和灾难恢复制定复杂的规划要求。

CA 颁发机构必须配置存储在 Kubernetes Secret 中的证书和私钥。可选择在外部创建,或使用 SelfSigned 颁发机构引导根证书(参考集群级 Root CA步骤)。

本实验仅演示基于已有 Root CA 情况下,做业务证书签发的整个过程。

提示:证书的 Secret 应位于与 Issuer 相同的命名空间内,若想创建 ClusterIssuer ,则需要 Secret 和 ClusterIssuer 都位于 Cluster Resource Namespace (即默认的 cert-manager 命名空间)中。

  • 准备根证书
shell 复制代码
[root@master01 cert-manager]# kubectl -n cert-manager get secret cluster-root-ca-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cluster-root-ca.crt
[root@master01 cert-manager]# kubectl -n cert-manager get secret cluster-root-ca-secret -o jsonpath='{.data.tls\.key}' | base64 -d > cluster-root-ca.key
[root@master01 cert-manager]# ll cluster-root-ca.crt cluster-root-ca.key 
-rw-r--r-- 1 root root 619 Mar  6 16:52 cluster-root-ca.crt
-rw-r--r-- 1 root root 227 Mar  9 10:52 cluster-root-ca.key

提示:该指南使用已有的Root CA证书进行演示,即假定如上证书为合法的CA根证书。

  • 创建secret

CA 签发者代表一个证书颁发机构,其证书和私钥以 Kubernetes Secret 的形式存储在集群内部。

shell 复制代码
[root@master01 cert-manager]# cat cluster-root-ca.crt | base64 -w0
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJuRENDQVVLZ0F3SUJBZ0lVRzV5M1hmVTU4MzRNVWxlZmJ2bjV5Qi9scFVFd0NnWUlLb1pJemowRUF3SXcKTERFUU1BNEdBMVVFQ2hNSGJHbHVkWGh6WWpFWU1CWUdBMVVFQXhNUFkyeDFjM1JsY2kxeWIyOTBMV05oTUI0WApEVEkyTURNd05qQTRNVEl3TUZvWERUSTJNRFl3TkRBNE1USXdNRm93TERFUU1BNEdBMVVFQ2hNSGJHbHVkWGh6CllqRVlNQllHQTFVRUF4TVBZMngxYzNSbGNpMXliMjkwTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMEQKQVFjRFFnQUVWVno0RkVkNFMzNFpZSXl1NEUxL1IrMC9FaXBtQU1yYThJQXhtVWp5cFkxZ1JPMlFWb09CVkdMcAp6WjdsM1FBZDhsRFdWbnREQTU1Z2lLR3QvSUFsYmFOQ01FQXdEZ1lEVlIwUEFRSC9CQVFEQWdLa01BOEdBMVVkCkV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGRnRRZDcybnZuenFkM2J0LzJwYjhjdEladFQ3TUFvR0NDcUcKU000OUJBTUNBMGdBTUVVQ0lRQ2h4eUFvbmVMbFFCeVVFM2JoeVMzMjcvOHRmZmJCUXZpSnZPdENnSVByb1FJZwpJWklWNWVESEcwUUIwaGFJUkw0a2JxUFdkelZXalp1REhBam0xZVl4SVlBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
[root@master01 cert-manager]# cat cluster-root-ca.key | base64 -w0
LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFxZXlUV2hRdjVEdXJ4OENNRVRzK0loNjJzZmZnZS9DL24wUXZsalZhUGxvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVlZ6NEZFZDRTMzRaWUl5dTRFMS9SKzAvRWlwbUFNcmE4SUF4bVVqeXBZMWdSTzJRVm9PQgpWR0xwelo3bDNRQWQ4bERXVm50REE1NWdpS0d0L0lBbGJRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=

[root@master01 cert-manager]# vim cluster-root-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: ca-key-pair
  namespace: cert-manager
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJuRENDQVVLZ0F3SUJBZ0lVRzV5M1hmVTU4MzRNVWxlZmJ2bjV5Qi9scFVFd0NnWUlLb1pJemowRUF3SXcKTERFUU1BNEdBMVVFQ2hNSGJHbHVkWGh6WWpFWU1CWUdBMVVFQXhNUFkyeDFjM1JsY2kxeWIyOTBMV05oTUI0WApEVEkyTURNd05qQTRNVEl3TUZvWERUSTJNRFl3TkRBNE1USXdNRm93TERFUU1BNEdBMVVFQ2hNSGJHbHVkWGh6CllqRVlNQllHQTFVRUF4TVBZMngxYzNSbGNpMXliMjkwTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMEQKQVFjRFFnQUVWVno0RkVkNFMzNFpZSXl1NEUxL1IrMC9FaXBtQU1yYThJQXhtVWp5cFkxZ1JPMlFWb09CVkdMcAp6WjdsM1FBZDhsRFdWbnREQTU1Z2lLR3QvSUFsYmFOQ01FQXdEZ1lEVlIwUEFRSC9CQVFEQWdLa01BOEdBMVVkCkV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGRnRRZDcybnZuenFkM2J0LzJwYjhjdEladFQ3TUFvR0NDcUcKU000OUJBTUNBMGdBTUVVQ0lRQ2h4eUFvbmVMbFFCeVVFM2JoeVMzMjcvOHRmZmJCUXZpSnZPdENnSVByb1FJZwpJWklWNWVESEcwUUIwaGFJUkw0a2JxUFdkelZXalp1REhBam0xZVl4SVlBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  tls.key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFxZXlUV2hRdjVEdXJ4OENNRVRzK0loNjJzZmZnZS9DL24wUXZsalZhUGxvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVlZ6NEZFZDRTMzRaWUl5dTRFMS9SKzAvRWlwbUFNcmE4SUF4bVVqeXBZMWdSTzJRVm9PQgpWR0xwelo3bDNRQWQ4bERXVm50REE1NWdpS0d0L0lBbGJRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=

[root@master01 cert-manager]# kubectl apply -f cluster-root-secret.yaml

提示 :若后续使用 Issuer 而不是 ClusterIssuer ,则需要把 secret 创建到 Issuer 同命名空间,即后续真正业务证书所在的命名空间。

准备 Issuer

使用上一步骤的 Root CA Secret,创建一个真正用来"签业务证书"的 ClusterIssuer。

提示:也可创建Issuer,如下为创建Issuer,但创建Issuer必须和签发业务证书在同一个namespace,而创建ClusterIssuer可以在任何命名空间引用,因此建议创建ClusterIssuer。

shell 复制代码
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: ca-issuer
  namespace: test
spec:
  ca:
    secretName: ca-key-pair

创建ClusterIssuer。

shell 复制代码
[root@master01 cert-manager]# vim cluster-root-issuer.yaml
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ca-issuer
spec:
  ca:
    secretName: ca-key-pair

[root@master01 cert-manager]# kubectl apply -f cluster-root-issuer.yaml

确认验证:

shell 复制代码
[root@master01 cert-manager]# kubectl -n cert-manager get secrets ca-key-pair -o wide
NAME          TYPE     DATA   AGE
ca-key-pair   Opaque   2      70s
[root@master01 cert-manager]# kubectl get clusterissuers.cert-manager.io ca-issuer -o wide
NAME        READY   STATUS                AGE
ca-issuer   True    Signing CA verified   7m44s

签名证书

该步骤主要用 ca-issuer 给所需的域名签一张证书(落到 test namespace 的 TLS Secret)。

shell 复制代码
[root@master01 cert-manager]# kubectl create namespace test

[root@master01 cert-manager]# vim test-spring-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: spring-linuxsb-com
  namespace: test
spec:
  secretName: spring-linuxsb-com-cert
  duration: 8760h           # 设置 1 年时间
  dnsNames:
  - spring.linuxsb.com
  issuerRef:
    name: ca-issuer
    kind: ClusterIssuer
  privateKey:
    rotationPolicy: Always

[root@master01 cert-manager]# kubectl apply -f test-spring-cert.yaml

[root@master01 cert-manager]# kubectl -n test get certificate spring-linuxsb-com
NAME                 READY   SECRET                    AGE
spring-linuxsb-com   True    spring-linuxsb-com-cert   45s
[root@master01 cert-manager]# kubectl -n test get secret spring-linuxsb-com-cert
NAME                      TYPE                DATA   AGE
spring-linuxsb-com-cert   kubernetes.io/tls   3      49s

提示:Root CA 和业务证书都会过期(默认都是90天),一般生产环境中Root CA 很少变,业务证书 会基于 cert-manager 自动续期:只要 Certificate 资源还在、Issuer 可用,它会在到期前(默认在证书有效期的约 2/3 处开始尝试,具体由版本/策略决定)自动重新签发并更新 Secret。但实验环境也给与 1 年有效期。

使用证书

该步骤主要是让 Ingress 使用这个自签 TLS Secret(对外暴露 HTTPS)。

创建一个测试的的demo应用。

shell 复制代码
[root@master01 cert-manager]# vim test-spring-demo.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-spring-dp
  namespace: test
spec:
  selector:
    matchLabels:
      name: hello-spring
  template:
    metadata:
      name: hello-spring
      labels:
        name: hello-spring
    spec:
      containers:
        - name: hello-spring
          image: registry.cn-hangzhou.aliyuncs.com/xhyimages/hello-spring:v1.0.0
          ports:
            - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: hello-spring-svc
  namespace: test
spec:
  selector:
    name: hello-spring
  ports:
    - port: 80
      targetPort: 8080

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-spring-ingress
  namespace: test
spec:
  ingressClassName: "nginx"
  rules:
  - host: spring.linuxsb.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-spring-svc
            port:
              number: 80

[root@master01 cert-manager]# kubectl apply -f test-spring-demo.yaml

确认验证

  • 访问验证

客户端进行访问,或者浏览器进行访问 https://spring.linuxsb.com/

shell 复制代码
[root@master01 cert-manager]# kubectl -n test get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
hello-spring-dp-856699b7ff-2cxng   1/1     Running   0          3m11s   10.10.30.82   worker02   <none>           <none>
[root@master01 cert-manager]# kubectl -n test get svc -o wide
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
hello-spring-svc   ClusterIP   10.20.144.170   <none>        80/TCP    3m14s   name=hello-spring
[root@master01 cert-manager]# kubectl -n test get ingress -o wide
NAME                   CLASS   HOSTS                ADDRESS        PORTS   AGE
hello-spring-ingress   nginx   spring.linuxsb.com   10.20.60.120   80      3m16s

[root@master01 cert-manager]# curl -k https://spring.linuxsb.com/
Hello, Spring, Deployment Succuss!

提示:由于Root CA为模拟的,实际上也是自签名的,因此不受信任是预期内的。

  • 添加信任

可将 Root CA 在浏览器导入,从而实现证书受信,导入后(导入过程略),再次访问进行验证。

相关推荐
老赵聊算法、大模型备案2 小时前
网信办公示 2026 年 1-2 月生成式 AI 备案登记情况:新增 94 款,累计突破 1200 款
人工智能·算法·安全·aigc
x_xbx2 小时前
LeetCode:21. 合并两个有序链表
算法·leetcode·链表
2501_945423542 小时前
C++与Rust交互编程
开发语言·c++·算法
我能坚持多久2 小时前
【初阶数据结构10】——链式二叉树的功能实现
数据结构·算法
tankeven2 小时前
HJ131 数独数组
c++·算法
liuyao_xianhui2 小时前
优选算法_丢失的数字_位运算_C++
linux·数据结构·c++·算法·动态规划·哈希算法·散列表
woniu_buhui_fei2 小时前
Java 服务最常见的线上性能故障
java·jvm·算法
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章37-区域截图
图像处理·人工智能·opencv·算法·计算机视觉
DeepModel2 小时前
【概率分布】正态分布(高斯分布)原理、可视化与机器学习实战
python·算法·概率论