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
包