fix: 解决证书面板过期问题 (#3102)

pull/3114/head
zhengkunwang 2023-11-29 22:04:08 +08:00 committed by GitHub
parent 82881273ea
commit fa9d855523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 131 additions and 168 deletions

View File

@ -110,7 +110,7 @@ func (b *BaseApi) ObtainWebsiteCA(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
if err := websiteCAService.ObtainSSL(req); err != nil { if _, err := websiteCAService.ObtainSSL(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
@ -131,7 +131,7 @@ func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
if err := websiteCAService.ObtainSSL(request.WebsiteCAObtain{ if _, err := websiteCAService.ObtainSSL(request.WebsiteCAObtain{
SSLID: req.SSLID, SSLID: req.SSLID,
Renew: true, Renew: true,
Unit: "year", Unit: "year",

View File

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"net" "net"
"os" "os"
"path" "path"
@ -21,7 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt" "github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/files" "github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
) )
@ -204,7 +204,6 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
}() }()
return nil return nil
} }
if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) { if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(secretDir, os.ModePerm); err != nil { if err = os.MkdirAll(secretDir, os.ModePerm); err != nil {
return err return err
@ -213,49 +212,61 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
if err := settingRepo.Update("SSLType", req.SSLType); err != nil { if err := settingRepo.Update("SSLType", req.SSLType); err != nil {
return err return err
} }
if req.SSLType == "self" { var (
secret string
key string
)
switch req.SSLType {
case "self":
if len(req.Domain) == 0 { if len(req.Domain) == 0 {
return fmt.Errorf("load domain failed") return fmt.Errorf("load domain failed")
} }
if err := ssl.GenerateSSL(req.Domain); err != nil { defaultCA, err := websiteCARepo.GetFirst(commonRepo.WithByName("1Panel"))
return err
}
}
if req.SSLType == "select" {
sslInfo, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
if err != nil { if err != nil {
return err return err
} }
req.Cert = sslInfo.Pem websiteSSL, err := NewIWebsiteCAService().ObtainSSL(request.WebsiteCAObtain{
req.Key = sslInfo.PrivateKey ID: defaultCA.ID,
req.SSLType = "import" KeyType: "P256",
Domains: req.Domain,
Time: 1,
Unit: "year",
AutoRenew: true,
})
if err != nil {
return err
}
secret = websiteSSL.Pem
key = websiteSSL.PrivateKey
if err := settingRepo.Update("SSLID", strconv.Itoa(int(websiteSSL.ID))); err != nil {
return err
}
case "select":
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
if err != nil {
return err
}
secret = websiteSSL.Pem
key = websiteSSL.PrivateKey
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil { if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
return err return err
} }
case "import":
secret = req.Cert
key = req.Key
} }
if req.SSLType == "import" {
cert, err := os.OpenFile(path.Join(secretDir, "server.crt.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) fileOp := files.NewFileOp()
if err != nil { if err := fileOp.WriteFile(path.Join(secretDir, "server.crt.tmp"), strings.NewReader(secret), 0600); err != nil {
return err return err
} }
defer cert.Close() if err := fileOp.WriteFile(path.Join(secretDir, "server.key.tmp"), strings.NewReader(key), 0600); err != nil {
if _, err := cert.WriteString(req.Cert); err != nil { return err
return err
}
key, err := os.OpenFile(path.Join(secretDir, "server.key.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
if _, err := key.WriteString(req.Key); err != nil {
return err
}
defer key.Close()
} }
if err := checkCertValid(req.Domain); err != nil { if err := checkCertValid(req.Domain); err != nil {
return err return err
} }
fileOp := files.NewFileOp()
if err := fileOp.Rename(path.Join(secretDir, "server.crt.tmp"), path.Join(secretDir, "server.crt")); err != nil { if err := fileOp.Rename(path.Join(secretDir, "server.crt.tmp"), path.Join(secretDir, "server.crt")); err != nil {
return err return err
} }

View File

@ -37,7 +37,7 @@ type IWebsiteCAService interface {
Create(create request.WebsiteCACreate) (*request.WebsiteCACreate, error) Create(create request.WebsiteCACreate) (*request.WebsiteCACreate, error)
GetCA(id uint) (*response.WebsiteCADTO, error) GetCA(id uint) (*response.WebsiteCADTO, error)
Delete(id uint) error Delete(id uint) error
ObtainSSL(req request.WebsiteCAObtain) error ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error)
} }
func NewIWebsiteCAService() IWebsiteCAService { func NewIWebsiteCAService() IWebsiteCAService {
@ -169,10 +169,17 @@ func (w WebsiteCAService) Delete(id uint) error {
if len(ssls) > 0 { if len(ssls) > 0 {
return buserr.New("ErrDeleteCAWithSSL") return buserr.New("ErrDeleteCAWithSSL")
} }
exist, err := websiteCARepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return err
}
if exist.Name == "1Panel" {
return buserr.New("ErrDefaultCA")
}
return websiteCARepo.DeleteBy(commonRepo.WithByID(id)) return websiteCARepo.DeleteBy(commonRepo.WithByID(id))
} }
func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error { func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error) {
var ( var (
domains []string domains []string
ips []net.IP ips []net.IP
@ -183,11 +190,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
if req.Renew { if req.Renew {
websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID)) websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
if err != nil { if err != nil {
return err return nil, err
} }
ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(websiteSSL.CaID)) ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(websiteSSL.CaID))
if err != nil { if err != nil {
return err return nil, err
} }
existDomains := []string{websiteSSL.PrimaryDomain} existDomains := []string{websiteSSL.PrimaryDomain}
if websiteSSL.Domains != "" { if websiteSSL.Domains != "" {
@ -203,7 +210,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
} else { } else {
ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(req.ID)) ca, err = websiteCARepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil { if err != nil {
return err return nil, err
} }
websiteSSL = &model.WebsiteSSL{ websiteSSL = &model.WebsiteSSL{
Provider: constant.SelfSigned, Provider: constant.SelfSigned,
@ -214,7 +221,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
} }
if req.PushDir { if req.PushDir {
if !files.NewFileOp().Stat(req.Dir) { if !files.NewFileOp().Stat(req.Dir) {
return buserr.New(constant.ErrLinkPathNotFound) return nil, buserr.New(constant.ErrLinkPathNotFound)
} }
websiteSSL.Dir = req.Dir websiteSSL.Dir = req.Dir
} }
@ -223,7 +230,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
for _, domain := range domainArray { for _, domain := range domainArray {
if !common.IsValidDomain(domain) { if !common.IsValidDomain(domain) {
err = buserr.WithName("ErrDomainFormat", domain) err = buserr.WithName("ErrDomainFormat", domain)
return err return nil, err
} else { } else {
if ipAddress := net.ParseIP(domain); ipAddress == nil { if ipAddress := net.ParseIP(domain); ipAddress == nil {
domains = append(domains, domain) domains = append(domains, domain)
@ -241,32 +248,32 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
rootCertBlock, _ := pem.Decode([]byte(ca.CSR)) rootCertBlock, _ := pem.Decode([]byte(ca.CSR))
if rootCertBlock == nil { if rootCertBlock == nil {
return buserr.New("ErrSSLCertificateFormat") return nil, buserr.New("ErrSSLCertificateFormat")
} }
rootCsr, err := x509.ParseCertificate(rootCertBlock.Bytes) rootCsr, err := x509.ParseCertificate(rootCertBlock.Bytes)
if err != nil { if err != nil {
return err return nil, err
} }
rootPrivateKeyBlock, _ := pem.Decode([]byte(ca.PrivateKey)) rootPrivateKeyBlock, _ := pem.Decode([]byte(ca.PrivateKey))
if rootPrivateKeyBlock == nil { if rootPrivateKeyBlock == nil {
return buserr.New("ErrSSLCertificateFormat") return nil, buserr.New("ErrSSLCertificateFormat")
} }
var rootPrivateKey any var rootPrivateKey any
if ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC256 || ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC384 { if ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC256 || ssl.KeyType(websiteSSL.KeyType) == certcrypto.EC384 {
rootPrivateKey, err = x509.ParseECPrivateKey(rootPrivateKeyBlock.Bytes) rootPrivateKey, err = x509.ParseECPrivateKey(rootPrivateKeyBlock.Bytes)
if err != nil { if err != nil {
return err return nil, err
} }
} else { } else {
rootPrivateKey, err = x509.ParsePKCS1PrivateKey(rootPrivateKeyBlock.Bytes) rootPrivateKey, err = x509.ParsePKCS1PrivateKey(rootPrivateKeyBlock.Bytes)
if err != nil { if err != nil {
return err return nil, err
} }
} }
interPrivateKey, interPublicKey, _, err := createPrivateKey(websiteSSL.KeyType) interPrivateKey, interPublicKey, _, err := createPrivateKey(websiteSSL.KeyType)
if err != nil { if err != nil {
return err return nil, err
} }
notAfter := time.Now() notAfter := time.Now()
if req.Unit == "year" { if req.Unit == "year" {
@ -287,16 +294,16 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
} }
interDer, err := x509.CreateCertificate(rand.Reader, interCsr, rootCsr, interPublicKey, rootPrivateKey) interDer, err := x509.CreateCertificate(rand.Reader, interCsr, rootCsr, interPublicKey, rootPrivateKey)
if err != nil { if err != nil {
return err return nil, err
} }
interCert, err := x509.ParseCertificate(interDer) interCert, err := x509.ParseCertificate(interDer)
if err != nil { if err != nil {
return err return nil, err
} }
_, publicKey, privateKeyBytes, err := createPrivateKey(websiteSSL.KeyType) _, publicKey, privateKeyBytes, err := createPrivateKey(websiteSSL.KeyType)
if err != nil { if err != nil {
return err return nil, err
} }
csr := &x509.Certificate{ csr := &x509.Certificate{
@ -314,11 +321,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
der, err := x509.CreateCertificate(rand.Reader, csr, interCert, publicKey, interPrivateKey) der, err := x509.CreateCertificate(rand.Reader, csr, interCert, publicKey, interPrivateKey)
if err != nil { if err != nil {
return err return nil, err
} }
cert, err := x509.ParseCertificate(der) cert, err := x509.ParseCertificate(der)
if err != nil { if err != nil {
return err return nil, err
} }
certBlock := &pem.Block{ certBlock := &pem.Block{
@ -335,11 +342,11 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
if req.Renew { if req.Renew {
if err := websiteSSLRepo.Save(websiteSSL); err != nil { if err := websiteSSLRepo.Save(websiteSSL); err != nil {
return err return nil, err
} }
} else { } else {
if err := websiteSSLRepo.Create(context.Background(), websiteSSL); err != nil { if err := websiteSSLRepo.Create(context.Background(), websiteSSL); err != nil {
return err return nil, err
} }
} }
@ -348,7 +355,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
logger := log.New(logFile, "", log.LstdFlags) logger := log.New(logFile, "", log.LstdFlags)
logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")})) logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
saveCertificateFile(websiteSSL, logger) saveCertificateFile(websiteSSL, logger)
return nil return websiteSSL, nil
} }
func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKeyBytes []byte, err error) { func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKeyBytes []byte, err error) {

View File

@ -7,6 +7,10 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"path"
"strconv"
"strings"
"time" "time"
) )
@ -17,7 +21,25 @@ func NewSSLJob() *ssl {
return &ssl{} return &ssl{}
} }
func getSystemSSL() (bool, uint) {
settingRepo := repo.NewISettingRepo()
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
if err != nil {
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
return false, 0
}
if sslSetting.Value == "enable" {
sslID, _ := settingRepo.Get(settingRepo.WithByKey("SSLID"))
idValue, _ := strconv.Atoi(sslID.Value)
if idValue > 0 {
return true, uint(idValue)
}
}
return false, 0
}
func (ssl *ssl) Run() { func (ssl *ssl) Run() {
systemSSLEnable, sslID := getSystemSSL()
sslRepo := repo.NewISSLRepo() sslRepo := repo.NewISSLRepo()
sslService := service.NewIWebsiteSSLService() sslService := service.NewIWebsiteSSLService()
sslList, _ := sslRepo.List() sslList, _ := sslRepo.List()
@ -34,7 +56,7 @@ func (ssl *ssl) Run() {
global.LOG.Errorf("Update the SSL certificate for the [%s] domain", s.PrimaryDomain) global.LOG.Errorf("Update the SSL certificate for the [%s] domain", s.PrimaryDomain)
if s.Provider == constant.SelfSigned { if s.Provider == constant.SelfSigned {
caService := service.NewIWebsiteCAService() caService := service.NewIWebsiteCAService()
if err := caService.ObtainSSL(request.WebsiteCAObtain{ if _, err := caService.ObtainSSL(request.WebsiteCAObtain{
ID: s.CaID, ID: s.CaID,
SSLID: s.ID, SSLID: s.ID,
Renew: true, Renew: true,
@ -52,6 +74,19 @@ func (ssl *ssl) Run() {
continue continue
} }
} }
if systemSSLEnable && sslID == s.ID {
websiteSSL, _ := sslRepo.GetFirst(repo.NewCommonRepo().WithByID(s.ID))
fileOp := files.NewFileOp()
secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
continue
}
if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
continue
}
}
global.LOG.Errorf("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain) global.LOG.Errorf("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain)
} }
} }

View File

@ -58,6 +58,7 @@ func Init() {
migrations.AddWebsiteCA, migrations.AddWebsiteCA,
migrations.AddDockerSockPath, migrations.AddDockerSockPath,
migrations.AddDatabaseSSL, migrations.AddDatabaseSSL,
migrations.AddDefaultCA,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)

View File

@ -1,7 +1,9 @@
package migrations package migrations
import ( import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/go-gormigrate/gormigrate/v2" "github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -55,3 +57,23 @@ var AddDatabaseSSL = &gormigrate.Migration{
return nil return nil
}, },
} }
var AddDefaultCA = &gormigrate.Migration{
ID: "20231129-add-default-ca",
Migrate: func(tx *gorm.DB) error {
caService := service.NewIWebsiteCAService()
if _, err := caService.Create(request.WebsiteCACreate{
CommonName: "1Panel-CA",
Country: "CN",
KeyType: "P256",
Name: "1Panel",
Organization: "FIT2CLOUD",
OrganizationUint: "1Panel",
Province: "Beijing",
City: "Beijing",
}); err != nil {
return err
}
return nil
},
}

View File

@ -1,113 +0,0 @@
package ssl
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"os"
"path"
"time"
"github.com/1Panel-dev/1Panel/backend/global"
)
func GenerateSSL(domain string) error {
rootPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
ipItem := net.ParseIP(domain)
isIP := false
if len(ipItem) != 0 {
isIP = true
}
rootTemplate := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "1Panel Root CA"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageCertSign,
}
if isIP {
rootTemplate.IPAddresses = []net.IP{ipItem}
} else {
rootTemplate.DNSNames = []string{domain}
}
rootCertBytes, _ := x509.CreateCertificate(rand.Reader, &rootTemplate, &rootTemplate, &rootPrivateKey.PublicKey, rootPrivateKey)
rootCertBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: rootCertBytes,
}
interPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
interTemplate := x509.Certificate{
SerialNumber: big.NewInt(2),
Subject: pkix.Name{CommonName: "1Panel Intermediate CA"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageCertSign,
}
if isIP {
interTemplate.IPAddresses = []net.IP{ipItem}
} else {
interTemplate.DNSNames = []string{domain}
}
interCertBytes, _ := x509.CreateCertificate(rand.Reader, &interTemplate, &rootTemplate, &interPrivateKey.PublicKey, rootPrivateKey)
interCertBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: interCertBytes,
}
clientPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
clientTemplate := x509.Certificate{
SerialNumber: big.NewInt(3),
Subject: pkix.Name{CommonName: domain},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
if isIP {
clientTemplate.IPAddresses = []net.IP{ipItem}
} else {
clientTemplate.DNSNames = []string{domain}
}
clientCertBytes, _ := x509.CreateCertificate(rand.Reader, &clientTemplate, &interTemplate, &clientPrivateKey.PublicKey, interPrivateKey)
clientCertBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: clientCertBytes,
}
pemBytes := []byte{}
pemBytes = append(pemBytes, pem.EncodeToMemory(clientCertBlock)...)
pemBytes = append(pemBytes, pem.EncodeToMemory(interCertBlock)...)
pemBytes = append(pemBytes, pem.EncodeToMemory(rootCertBlock)...)
certOut, err := os.OpenFile(path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer certOut.Close()
if _, err := certOut.Write(pemBytes); err != nil {
return err
}
keyOut, err := os.OpenFile(path.Join(global.CONF.System.BaseDir, "1panel/secret/server.key.tmp"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer keyOut.Close()
if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientPrivateKey)}); err != nil {
return err
}
return nil
}