You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Go从Azure Vault证书创建Kubernetes TLS Secret?

自定义从Azure Key Vault同步证书到Kubernetes Secret的实现方案

原本我可以直接用AKS的密钥存储CSI驱动对接Azure Key Vault,但因为需要通过自研的Kubernetes管理API实现更精细的证书管控,过程中遇到了不少问题,目前摸索出一套可行的实现方案,在这里分享出来,希望有相关经验的朋友能给些意见。

实现步骤

  • 在Azure Vault中创建或上传证书时,证书会以Secret形式存储,我通过Azure SDK for Go获取这些证书;
  • 使用base64包解码Azure返回的、包含公私钥的PFX文件;
  • 调用pkcs12包的pkcs12.ToPEM函数,将PFX文件解析为pem.Block数组;
  • 解析得到的每个Block中会包含额外的头部信息;
  • 在将证书内容存入Kubernetes Secret之前,需要先去除这些头部信息。

实现代码

package secretcreator

import (
    "context"
    "encoding/base64"
    "encoding/pem"
    "log"
    "time"

    "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates"
    "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
    "golang.org/x/crypto/pkcs12"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
)

type MyStruct struct {
    kubeClientSet          *kubernetes.Clientset
    azureVaultSecrets      *azsecrets.Client
    azureVaultCertificates *azcertificates.Client
    beNamespace            *v1.Namespace
    identitySecrests       *v1.Secret
}

func (t *MyStruct) createSecrets() error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // tlsSecret.Value是经过base64编码的PEM/PFX内容,包含私钥和证书块
    tlsSecret, err := t.azureVaultSecrets.GetSecret(ctx, `myCertName`, ``, nil)
    if err != nil {
        log.Printf(`获取证书失败:%s`, err.Error())
        return err
    }

    // 将tlsSecret.Value中的字符串解码为字节数组,得到PFX文件的原始内容
    pfxBytes, err := base64.StdEncoding.Strict().DecodeString(*tlsSecret.Value)
    if err != nil {
        log.Printf(`解码PFX证书失败:%s`, err.Error())
        return err
    }

    // pemBlocks是*pem.Block类型的数组,在我的场景里包含1个私钥块和3个证书块
    // 这些块会附带头部信息,比如私钥块编码后会是这样的格式:
    // -----BEGIN PRIVATE KEY-----
    // Microsoft CSP Name: Microsoft Enhanced Cryptographic Provider v1.0
    // friendlyName: {D06B3D5A-98D1-45F1-A8C2-DC091232D6A7}
    // localKeyId: 01000000
    //
    // MIIEAI.......ymfjsQ==
    // -----END PRIVATE KEY-----
    pemBlocks, err := pkcs12.ToPEM(pfxBytes, "")
    if err != nil {
        log.Printf(`从PEM块中解析密钥或证书失败:%s`, err.Error())
        return err
    }

    // Kubernetes要求TLS Secret的data字段包含tls.key和tls.crt两个键值对
    // 这里遍历所有块,根据类型拆分出私钥和证书内容
    // 因为K8s的Ingress-Nginx不兼容这些头部信息,所以需要去掉它们:
    // 先将Block内容重新编码为base64字符串,再手动添加BEGIN/END标识
    var tlsKey []byte
    var tlsCert []byte
    for _, b := range pemBlocks {
        if b.Type == "PRIVATE KEY" {
            block, _ := pem.Decode(pem.EncodeToMemory(b))

            tlsKey = append(tlsKey, "-----BEGIN PRIVATE KEY-----\n"...)
            tlsKey = append(tlsKey, base64.StdEncoding.EncodeToString(block.Bytes)...)
            tlsKey = append(tlsKey, "-----END PRIVATE KEY-----\n"...)
        }
        if b.Type == "CERTIFICATE" {
            block, _ := pem.Decode(pem.EncodeToMemory(b))

            tlsCert = append(tlsCert, "-----BEGIN CERTIFICATE-----\n"...)
            tlsCert = append(tlsCert, base64.StdEncoding.EncodeToString(block.Bytes)...)
            tlsCert = append(tlsCert, "-----END CERTIFICATE-----\n"...)
        }
    }

    // 使用client-go在Kubernetes中创建TLS Secret
    tlsData := make(map[string][]byte)
    tlsData[`tls.key`] = tlsKey
    tlsData[`tls.crt`] = tlsCert

    beTls := &v1.Secret{
        ObjectMeta: metav1.ObjectMeta{
            Name:      `mycertname`,
            Namespace: t.beNamespace.Name,
        },
        Data: tlsData,
        Type: v1.SecretTypeTLS,
    }
    _, err = t.kubeClientSet.CoreV1().Secrets(t.beNamespace.Name).Create(ctx, beTls, metav1.CreateOptions{})
    if err != nil {
        log.Printf(`创建TLS Secret失败:%s`, err.Error())
        return err
    }

    return nil
}

内容的提问来源于stack exchange,提问作者williamohara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 13:55:36