ca.crt restore endpoint
This commit is contained in:
@@ -2,13 +2,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cloudflare/cfssl/certinfo"
|
|
||||||
"github.com/cloudflare/cfssl/config"
|
"github.com/cloudflare/cfssl/config"
|
||||||
"github.com/cloudflare/cfssl/helpers/derhelpers"
|
"github.com/cloudflare/cfssl/helpers/derhelpers"
|
||||||
"github.com/cloudflare/cfssl/log"
|
"github.com/cloudflare/cfssl/log"
|
||||||
@@ -61,7 +62,11 @@ func loadSecretData(config *config.Config) (sd *SecretData, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkCertUsable(certPEM []byte) error {
|
func checkCertUsable(certPEM []byte) error {
|
||||||
cert, err := certinfo.ParseCertificatePEM(certPEM)
|
block, _ := pem.Decode(certPEM)
|
||||||
|
if block == nil {
|
||||||
|
return errors.New("no PEM block found")
|
||||||
|
}
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,12 @@ func (ca CA) ParseKey() (key crypto.Signer, err error) {
|
|||||||
return helpers.ParsePrivateKeyPEM(ca.Key)
|
return helpers.ParsePrivateKeyPEM(ca.Key)
|
||||||
}
|
}
|
||||||
func (ca CA) ParseCert() (cert *x509.Certificate, err error) {
|
func (ca CA) ParseCert() (cert *x509.Certificate, err error) {
|
||||||
return helpers.ParseCertificatePEM(ca.Cert)
|
block, _ := pem.Decode(ca.Cert)
|
||||||
|
if block == nil {
|
||||||
|
err = errors.New("no PEM block found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return x509.ParseCertificate(block.Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca CA) Signer(policy *config.Signing) (result *local.Signer, err error) {
|
func (ca CA) Signer(policy *config.Signing) (result *local.Signer, err error) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cloudflare/cfssl/helpers"
|
"github.com/cloudflare/cfssl/helpers"
|
||||||
@@ -50,16 +51,25 @@ func getUsableClusterCA(cluster, name string) (ca CA, err error) {
|
|||||||
if checkErr != nil {
|
if checkErr != nil {
|
||||||
log.Infof("cluster %s: CA %s: regenerating certificate: %v", cluster, name, checkErr)
|
log.Infof("cluster %s: CA %s: regenerating certificate: %v", cluster, name, checkErr)
|
||||||
|
|
||||||
|
ca, err = opMutex("renew-ca:"+key, func() (CA, error) {
|
||||||
|
ca, found, err := clusterCAs.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return ca, err
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return ca, fmt.Errorf("CA not found")
|
||||||
|
}
|
||||||
|
|
||||||
prevCerts, _ := helpers.ParseCertificatesPEM(ca.Cert)
|
prevCerts, _ := helpers.ParseCertificatesPEM(ca.Cert)
|
||||||
|
|
||||||
err = ca.RenewCert()
|
err = ca.RenewCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("renew: %w", err)
|
return ca, fmt.Errorf("renew: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
for _, cert := range prevCerts {
|
for _, cert := range prevCerts {
|
||||||
if cert.NotAfter.After(now) {
|
if cert.NotAfter.Before(now) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
certPEM := helpers.EncodeCertificatePEM(cert)
|
certPEM := helpers.EncodeCertificatePEM(cert)
|
||||||
@@ -67,6 +77,11 @@ func getUsableClusterCA(cluster, name string) (ca CA, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = clusterCAs.Put(key, ca)
|
err = clusterCAs.Put(key, ca)
|
||||||
|
return ca, err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return ca, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -98,3 +113,51 @@ func wsClusterCASignedKey(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
clusterCASignedKeys.WsGet(resp, clusterName+"/"+caName+"/"+name)
|
clusterCASignedKeys.WsGet(resp, clusterName+"/"+caName+"/"+name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wsClusterCACertPut(req *restful.Request, resp *restful.Response) {
|
||||||
|
clusterName := req.PathParameter("cluster-name")
|
||||||
|
caName := req.PathParameter("ca-name")
|
||||||
|
key := clusterName + "/" + caName
|
||||||
|
|
||||||
|
body, err := io.ReadAll(req.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
wsError(resp, fmt.Errorf("read body: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
certs, err := helpers.ParseCertificatesPEM(body)
|
||||||
|
if err != nil {
|
||||||
|
wsError(resp, fmt.Errorf("invalid certificate(s): %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ca, found, err := clusterCAs.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
wsError(resp, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
wsNotFound(resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
caCert, err := ca.ParseCert()
|
||||||
|
if err != nil {
|
||||||
|
wsError(resp, fmt.Errorf("parse CA cert: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range certs {
|
||||||
|
if err := c.CheckSignatureFrom(caCert); err != nil {
|
||||||
|
wsError(resp, fmt.Errorf("certificate not signed by this CA: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ca.Cert = body
|
||||||
|
|
||||||
|
if err := clusterCAs.Put(key, ca); err != nil {
|
||||||
|
wsError(resp, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ func registerWS(rest *restful.Container) {
|
|||||||
cluster(GET, "/CAs/{ca-name}/certificate").To(wsClusterCACert).
|
cluster(GET, "/CAs/{ca-name}/certificate").To(wsClusterCACert).
|
||||||
Produces(mime.CACERT).
|
Produces(mime.CACERT).
|
||||||
Doc("Get cluster CA's certificate"),
|
Doc("Get cluster CA's certificate"),
|
||||||
|
cluster(PUT, "/CAs/{ca-name}/certificate").To(wsClusterCACertPut).
|
||||||
|
Consumes(mime.CACERT).
|
||||||
|
Doc("Set cluster CA's certificate(s)"),
|
||||||
cluster(GET, "/CAs/{ca-name}/signed").To(wsClusterSignedCert).
|
cluster(GET, "/CAs/{ca-name}/signed").To(wsClusterSignedCert).
|
||||||
Produces(mime.CERT).
|
Produces(mime.CERT).
|
||||||
Param(ws.QueryParameter("name", "signed reference name").Required(true)).
|
Param(ws.QueryParameter("name", "signed reference name").Required(true)).
|
||||||
|
|||||||
Reference in New Issue
Block a user