Kubernetes 证书轮换

1. 简介

在 Kubernetes 集群中,证书是用于认证和加密通信的重要组成部分。证书的有效期是有限的,过期的证书会导致各种安全问题。为了解决这个问题,Kubernetes 提供了证书轮换机制,可以自动更新证书,确保集群的安全性。

本文将介绍 Kubernetes 证书轮换的原理和使用方法,并提供代码示例以帮助读者更好地理解和实践。

2. 证书轮换原理

证书轮换是通过 Kubernetes 中的控制器来实现的。控制器会定期检查集群中的证书,如果发现有即将过期的证书,就会自动创建新的证书,并将其更新到相应的资源中。

具体来说,控制器会监视 Kubernetes 集群中的 Secret 对象。Secret 对象是用于存储敏感信息的 Kubernetes 资源,包括证书、密码等。当控制器发现某个 Secret 对象中的证书即将过期时,它会创建新的证书,并将其存储到一个新的 Secret 对象中。然后,控制器会更新使用该证书的相关资源,如 Ingress、Service 等,使它们使用新的证书。

3. 配置证书轮换

要配置证书轮换,需要在 Kubernetes 中定义一个名为 CertificateSigningRequest 的资源。CertificateSigningRequest 描述了一个证书签名请求,包括证书的主题、有效期等信息。

以下是一个示例的 CertificateSigningRequest 的定义:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: my-csr
spec:
  request: <base64-encoded-certificate-request>
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - 'digital signature'
  - 'key encipherment'
  - 'server auth'

在上面的示例中,request 字段是一个 Base64 编码的证书签名请求,signerName 字段指定了用于签名的证书颁发机构,usages 字段指定了该证书的使用场景。

为了自动轮换证书,还需要在 Kubernetes 中定义一个 CertificateSigningRequest 的控制器。控制器会定期检查 CertificateSigningRequest 资源,并自动处理即将过期的证书。

以下是一个示例的 CertificateSigningRequest 的控制器定义:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cert-rotation-controller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cert-rotation-controller
  template:
    metadata:
      labels:
        app: cert-rotation-controller
    spec:
      containers:
      - name: cert-rotation-controller
        image: my-cert-rotation-controller:v1.0
        command: ["./controller"]
        volumeMounts:
        - name: certs
          mountPath: /certs
      volumes:
      - name: certs
        emptyDir: {}

在上面的示例中,template 字段定义了控制器的 Pod 模板。containers 字段定义了控制器的容器,其中的 image 字段指定了容器镜像,command 字段指定了容器的启动命令。volumes 字段定义了容器的卷,用于存储证书文件。

4. 代码示例

下面是一个使用 Go 语言编写的证书轮换控制器的示例代码:

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		ticker := time.NewTicker(24 * time.Hour)
		for {
			select {
			case <-stop:
				ticker.Stop()
				return
			case <-ticker.C:
				// 轮换证书的逻辑
				fmt.Println("Rotating certificates...")
			}
		}
	}()

	<-stop
	fmt.Println("Shutting down...")
}

在上面的示例中,我们使用了 Go 语言的 signal