Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kafkauser: copy ca to secret #1028

Merged
merged 11 commits into from
Aug 18, 2023
8 changes: 0 additions & 8 deletions pkg/pki/certmanagerpki/certmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package certmanagerpki

import (
"flag"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/banzaicloud/koperator/api/v1beta1"
Expand All @@ -25,12 +23,6 @@ import (

const spiffeIdTemplate = "spiffe://%s/ns/%s/kafkauser/%s"

var namespaceCertManager string

func init() {
flag.StringVar(&namespaceCertManager, "cert-manager-namespace", "cert-manager", "The namespace where cert-manager is running")
}

type CertManager interface {
pki.Manager
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/pki/certmanagerpki/certmanager_pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (c *certManager) FinalizePKI(ctx context.Context) error {
if c.cluster.Spec.ListenersConfig.SSLSecrets.IssuerRef == nil {
objNames = append(
objNames,
types.NamespacedName{Name: fmt.Sprintf(pkicommon.BrokerCACertTemplate, c.cluster.Name), Namespace: namespaceCertManager})
types.NamespacedName{Name: fmt.Sprintf(pkicommon.BrokerCACertTemplate, c.cluster.Name), Namespace: pkicommon.NamespaceCertManager})
}
for _, obj := range objNames {
// Delete the certificates first so we don't accidentally recreate the
Expand Down Expand Up @@ -183,7 +183,7 @@ func caSecretForProvidedCert(ctx context.Context, client client.Client, cluster
caSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf(pkicommon.BrokerCACertTemplate, cluster.Name),
Namespace: namespaceCertManager,
Namespace: pkicommon.NamespaceCertManager,
Labels: pkicommon.LabelsForKafkaPKI(cluster.Name, cluster.Namespace),
},
Data: map[string][]byte{
Expand Down Expand Up @@ -214,7 +214,7 @@ func caCertForCluster(cluster *v1beta1.KafkaCluster) *certv1.Certificate {
return &certv1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf(pkicommon.BrokerCACertTemplate, cluster.Name),
Namespace: namespaceCertManager,
Namespace: pkicommon.NamespaceCertManager,
Labels: pkicommon.LabelsForKafkaPKI(cluster.Name, cluster.Namespace),
},
Spec: certv1.CertificateSpec{
Expand Down
70 changes: 61 additions & 9 deletions pkg/pki/k8scsrpki/k8scsr_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
certutil "github.com/banzaicloud/koperator/pkg/util/cert"
pkicommon "github.com/banzaicloud/koperator/pkg/util/pki"

certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
certsigningreqv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -45,9 +46,12 @@ import (
)

const (
notApprovedErrMsg = "instance is not approved"
notFoundApprovedCsrErrMsg = "could not find approved csr and the operator is not capable of approving the csr"
approveReason = "ApprovedByPolicy"
notApprovedErrMsg = "instance is not approved"
notFoundApprovedCsrErrMsg = "could not find approved csr and the operator is not capable of approving the csr"
notFoundCAInClusterIssuerErrMsg = "could not extract CA from ClusterIssuer"
notFoundCertManagerSecretField = "could not find certificate field in cert-manager Secret"
approveReason = "ApprovedByPolicy"
defaultCertManagerIssuerSecretCertificateFile = "tls.crt"
)

// ReconcileUserCertificate ensures and returns a user certificate - should be idempotent
Expand Down Expand Up @@ -186,13 +190,11 @@ func (c *k8sCSR) ReconcileUserCertificate(
//Leaf cert
secret.Data[corev1.TLSCertKey] = certs[0].ToPEM()
//CA chain certs
var caChain []byte
for _, cr := range certs {
if cr.Certificate.IsCA {
caChain = append(caChain, cr.ToPEM()...)
caChain = append(caChain, byte('\n'))
}
caChain, err := c.getCAChain(ctx, signingReq, certs)
if err != nil {
return nil, err
}

secret.Data[v1alpha1.CaChainPem] = caChain
certBundleX509 := certutil.GetCertBundle(certs)

Expand Down Expand Up @@ -344,3 +346,53 @@ func (c *k8sCSR) Approve(ctx context.Context, signingReq *certsigningreqv1.Certi

return nil
}

func (c *k8sCSR) getCAChain(ctx context.Context, signingReq *certsigningreqv1.CertificateSigningRequest, certs []*certutil.CertificateContainer) ([]byte, error) {
var caChain []byte
signerName := strings.Split(signingReq.Spec.SignerName, "/")

if signerName[0] == v1alpha1.CertManagerSignerNamePrefix {
clusterIssuer := &certv1.ClusterIssuer{}
clusterIssuerName := signerName[1]
pregnor marked this conversation as resolved.
Show resolved Hide resolved
err := c.client.Get(ctx, types.NamespacedName{
Name: clusterIssuerName,
}, clusterIssuer)
if err != nil {
return caChain, errors.WrapIfWithDetails(err,
"failed to get ClusterIssuer from K8s", "clusterIssuer", clusterIssuerName)
}

if clusterIssuer.GetSpec().CA == nil {
return caChain, errorfactory.New(errorfactory.FatalReconcileError{}, errors.New(notFoundCAInClusterIssuerErrMsg),
"clusterIssuer doesn't contain CA secret reference", "clusterIssuer", clusterIssuerName)
}

certManagerSecret := &corev1.Secret{}
err = c.client.Get(ctx, types.NamespacedName{
Name: clusterIssuer.GetSpec().CA.SecretName,
Namespace: pkicommon.NamespaceCertManager,
}, certManagerSecret)
if err != nil {
return caChain, errors.WrapIfWithDetails(err,
"failed to get secret from K8s", "secretName", clusterIssuer.GetSpec().CA.SecretName,
"namespace", certManagerSecret.GetNamespace())
}

chain, ok := certManagerSecret.Data[defaultCertManagerIssuerSecretCertificateFile]
if !ok {
return caChain, errorfactory.New(errorfactory.FatalReconcileError{}, errors.New(notFoundCertManagerSecretField),
"failed to get field", "secretName", clusterIssuer.GetSpec().CA.SecretName,
"namespace", certManagerSecret.GetNamespace(), "field", defaultCertManagerIssuerSecretCertificateFile)
}
caChain = chain
} else {
for _, cr := range certs {
if cr.Certificate.IsCA {
caChain = append(caChain, cr.ToPEM()...)
caChain = append(caChain, byte('\n'))
}
}
}

return caChain, nil
}
8 changes: 8 additions & 0 deletions pkg/util/pki/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"crypto/sha256"
"crypto/tls"
"flag"
"fmt"
"sort"
"strings"
Expand Down Expand Up @@ -62,6 +63,13 @@ const (
MaxCNLen = 64
)

// NamespaceCertManager points to a namespace where cert-manager is located
var NamespaceCertManager string

func init() {
flag.StringVar(&NamespaceCertManager, "cert-manager-namespace", "cert-manager", "The namespace where cert-manager is running")
}

// Manager is the main interface for objects performing PKI operations
type Manager interface {
// ReconcilePKI ensures a PKI for a kafka cluster - should be idempotent.
Expand Down
Loading