From af1cecd34db02e54661ebed7b33f946d8818da37 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Mon, 9 Sep 2024 19:56:47 -0700 Subject: [PATCH] Update pki issuer target secret output to include ca cert and chain --- build/install.yaml | 14 +----- build/kustomize/kustomization.yaml | 2 +- .../certificaterequest_controller.go | 5 +- internal/issuer/signer/signer.go | 49 +++++++++++++------ 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/build/install.yaml b/build/install.yaml index 737e24d..e035b71 100644 --- a/build/install.yaml +++ b/build/install.yaml @@ -48,12 +48,6 @@ spec: description: IssuerSpec defines the desired state of Issuer properties: authentication: - description: |- - A reference to a Secret in the same namespace as the referent. If the - referent is a ClusterIssuer, the reference instead refers to the resource - with the given name in the configured 'cluster resource namespace', which - is set as a flag on the controller component (and defaults to the - namespace that the controller runs in). properties: universalAuth: properties: @@ -182,12 +176,6 @@ spec: description: IssuerSpec defines the desired state of Issuer properties: authentication: - description: |- - A reference to a Secret in the same namespace as the referent. If the - referent is a ClusterIssuer, the reference instead refers to the resource - with the given name in the configured 'cluster resource namespace', which - is set as a flag on the controller component (and defaults to the - namespace that the controller runs in). properties: universalAuth: properties: @@ -600,7 +588,7 @@ spec: - --health-probe-bind-address=:8081 command: - /manager - image: docker.io/infisical/pki-issuer:v0.1.1-2-gb384f71 + image: docker.io/infisical/pki-issuer:v0.1.1-3-gc2030ef livenessProbe: httpGet: path: /healthz diff --git a/build/kustomize/kustomization.yaml b/build/kustomize/kustomization.yaml index 8f0f1ba..44662a5 100644 --- a/build/kustomize/kustomization.yaml +++ b/build/kustomize/kustomization.yaml @@ -5,4 +5,4 @@ resources: images: - name: controller newName: docker.io/infisical/pki-issuer - newTag: v0.1.1-2-gb384f71 + newTag: v0.1.1-3-gc2030ef diff --git a/internal/controller/certificaterequest_controller.go b/internal/controller/certificaterequest_controller.go index 5e45ee1..a5e1464 100644 --- a/internal/controller/certificaterequest_controller.go +++ b/internal/controller/certificaterequest_controller.go @@ -246,12 +246,13 @@ func (r *CertificateRequestReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, fmt.Errorf("%w: %v", errSignerBuilder, err) } - signed, err := signer.Sign(certificateRequest) + pem, ca, err := signer.Sign(certificateRequest) if err != nil { return ctrl.Result{}, fmt.Errorf("%w: %v", errSignerSign, err) } - certificateRequest.Status.Certificate = signed + certificateRequest.Status.Certificate = pem + certificateRequest.Status.CA = ca report(cmapi.CertificateRequestReasonIssued, "Signed", nil) return ctrl.Result{}, nil diff --git a/internal/issuer/signer/signer.go b/internal/issuer/signer/signer.go index 2860e07..32fb88e 100644 --- a/internal/issuer/signer/signer.go +++ b/internal/issuer/signer/signer.go @@ -1,6 +1,7 @@ package signer import ( + "bytes" "encoding/pem" "fmt" "time" @@ -17,7 +18,7 @@ type HealthChecker interface { type HealthCheckerBuilder func(*v1alpha1.IssuerSpec, map[string][]byte) (HealthChecker, error) type Signer interface { - Sign(certmanager.CertificateRequest) ([]byte, error) + Sign(certmanager.CertificateRequest) ([]byte, []byte, error) } type SignerBuilder func(*v1alpha1.IssuerSpec, map[string][]byte) (Signer, error) @@ -82,7 +83,6 @@ type AuthResponse struct { TokenType string `json:"tokenType"` } -// NOTE (dangtony98): Add support for certificate template in the future type SignCertificateRequest struct { CaId string `json:"caId,omitempty"` CertificateTemplateId string `json:"certificateTemplateId,omitempty"` @@ -97,11 +97,11 @@ type SignCertificateResponse struct { SerialNumber string `json:"serialNumber"` } -func (o *signer) Sign(cr certmanager.CertificateRequest) ([]byte, error) { +func (o *signer) Sign(cr certmanager.CertificateRequest) ([]byte, []byte, error) { // Ensure either caId or certificateTemplateId is provided if o.caId == "" && o.certificateTemplateId == "" { - return nil, fmt.Errorf("Either caId or certificateTemplateId must be provided") + return nil, nil, fmt.Errorf("Either caId or certificateTemplateId must be provided") } csrBytes := cr.Spec.Request @@ -127,7 +127,7 @@ func (o *signer) Sign(cr certmanager.CertificateRequest) ([]byte, error) { // Check for errors if err != nil { - return nil, err + return nil, nil, err } // Define the request body based on your CSR @@ -155,16 +155,35 @@ func (o *signer) Sign(cr certmanager.CertificateRequest) ([]byte, error) { SetResult(&signCertificateResponse). Post(o.siteUrl + "/api/v1/pki/certificates/sign-certificate") - certificate := signCertificateResponse.Certificate + certificate := signCertificateResponse.Certificate // Leaf certificate + chainPem := signCertificateResponse.CertificateChain // Full chain (intermediate certs + root cert) - block, _ := pem.Decode([]byte(certificate)) - pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: block.Bytes, - }) + caChainCerts, rootCACert, err := splitRootCACertificate([]byte(chainPem)) + certPem := []byte(certificate + "\n") + certPem = append(certPem, caChainCerts...) - return pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: block.Bytes, - }), nil + return certPem, rootCACert, nil +} + +func splitRootCACertificate(caCertChainPem []byte) ([]byte, []byte, error) { + var caChainCerts []byte + var rootCACert []byte + for { + block, rest := pem.Decode(caCertChainPem) + if block == nil || block.Type != "CERTIFICATE" { + return nil, nil, fmt.Errorf("failed to read certificate") + } + var encBuf bytes.Buffer + if err := pem.Encode(&encBuf, block); err != nil { + return nil, nil, err + } + if len(rest) > 0 { + caChainCerts = append(caChainCerts, encBuf.Bytes()...) + caCertChainPem = rest + } else { + rootCACert = append(rootCACert, encBuf.Bytes()...) + break + } + } + return caChainCerts, rootCACert, nil }