如何使用Kubernetes Go-Client审批证书签名请求(CSR)
问题分析与解决方案
核心问题总结
- 创建CSR时直接设置
Status字段无效:Kubernetes的Status字段由集群控制器维护,客户端创建资源时传入的Status会被API Server忽略,因此CSR始终处于Pending状态。 - 审批函数的错误根源:
- 未使用官方枚举值设置Condition的
Status字段,直接用字符串"True"会触发API字段验证错误。 - 使用创建时的旧CSR对象更新,未获取集群中最新的CSR状态,导致字段缺失。
- 缺少
LastTransitionTime这个必填的Condition字段。
- 未使用官方枚举值设置Condition的
修正后的代码实现
1. 修正CSR构造函数(移除无效的Status字段)
func PopulateCSR(UserName string, csrPemBlock []byte) corev1.CertificateSigningRequest { var seconds int32 = 315569260 // 使用官方KeyUsage枚举值,避免字符串拼写错误 usages := []corev1.KeyUsage{ corev1.UsageDigitalSignature, corev1.UsageKeyEncipherment, corev1.UsageClientAuth, } csr := corev1.CertificateSigningRequest{ TypeMeta: v1.TypeMeta{ Kind: "CertificateSigningRequest", APIVersion: "certificates.k8s.io/v1", }, ObjectMeta: v1.ObjectMeta{ Name: UserName + "-csr", }, Spec: corev1.CertificateSigningRequestSpec{ Request: csrPemBlock, SignerName: "kubernetes.io/kube-apiserver-client", ExpirationSeconds: &seconds, Usages: usages, }, // 移除Status字段,创建时集群会忽略该字段 } return csr }
2. 修正CSR审批函数(获取最新对象+规范设置Condition)
func approveCSR(csrName string, clientSet *kubernetes.Clientset) { // 先获取集群中最新的CSR对象,避免使用旧对象导致字段缺失 csr, err := clientSet.CertificatesV1().CertificateSigningRequests().Get(context.Background(), csrName, v1.GetOptions{}) if err != nil { fmt.Printf("failed to fetch CSR: %v\n", err) os.Exit(1) } // 检查是否已存在审批条件,避免重复添加 hasApproved := false for _, cond := range csr.Status.Conditions { if cond.Type == corev1.CertificateApproved { hasApproved = true break } } if hasApproved { fmt.Println("CSR is already approved") return } // 使用官方枚举值构建审批条件,确保所有必填字段齐全 approvalCondition := corev1.CertificateSigningRequestCondition{ Type: corev1.CertificateApproved, Status: corev1.ConditionTrue, // 必须用官方枚举,不能直接用字符串"True" Reason: "UserActivation", Message: "CSR approved for client authentication", LastUpdateTime: v1.Now(), LastTransitionTime: v1.Now(), // 该字段为必填项,之前缺失会触发验证错误 } csr.Status.Conditions = append(csr.Status.Conditions, approvalCondition) // 调用UpdateApproval API更新审批状态 _, err = clientSet.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.Background(), csrName, csr, v1.UpdateOptions{}) if err != nil { fmt.Printf("failed to approve CSR: %v\n", err) os.Exit(1) } fmt.Println("CSR approved successfully") }
关键说明
- Status字段的只读特性:Kubernetes资源的
Status字段仅由集群内部控制器更新,客户端创建/更新资源时传入的Status会被直接忽略,因此创建CSR时无需设置该字段。 - 枚举值的必要性:
corev1.ConditionStatus是强类型枚举,直接使用字符串可能触发API的字段验证逻辑,导致status.conditions[0].status: Required value错误。 - 获取最新对象:使用创建时的旧CSR对象更新审批,会丢失集群中已生成的状态元数据,必须先通过
Get接口获取最新的CSR对象再进行修改。 - 证书签署延迟:审批完成后,需要等待kube-controller-manager中的CSR签署控制器完成证书生成,此时CSR的
Status.Certificate字段才会被填充,可通过轮询该字段获取最终证书。
内容的提问来源于stack exchange,提问作者Maximilian Koch
相关产品推荐
相关产品推荐

