From db4b11bbf0e233ff56c206df53964738ab5a9ce3 Mon Sep 17 00:00:00 2001 From: share2kanna Date: Sun, 28 Apr 2024 07:23:10 +0530 Subject: [PATCH 1/4] First draft of cert issuer --- capten/agent/internal/app/app.go | 5 + capten/agent/internal/app/ca_cert_issuer.go | 149 ++++++++++++++++ capten/common-pkg/cert/generate_certs.go | 161 ++++++++++++++++++ capten/common-pkg/cert/generate_certs_test.go | 13 ++ capten/common-pkg/k8s/cert_issuer.go | 79 +++++++++ capten/common-pkg/k8s/client.go | 25 ++- .../internal/activities/plugin_activity.go | 2 +- 7 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 capten/agent/internal/app/ca_cert_issuer.go create mode 100644 capten/common-pkg/cert/generate_certs.go create mode 100644 capten/common-pkg/cert/generate_certs_test.go create mode 100644 capten/common-pkg/k8s/cert_issuer.go diff --git a/capten/agent/internal/app/app.go b/capten/agent/internal/app/app.go index 3b4d9eea..7cd6f822 100644 --- a/capten/agent/internal/app/app.go +++ b/capten/agent/internal/app/app.go @@ -88,6 +88,11 @@ func Start() { } }() + err = setupCACertIssuser() + if err != nil { + log.Fatalf("Failed to setupt CA Cert Issuer in cert-manager %v", err) + } + err = registerK8SWatcher(as) if err != nil { log.Fatalf("Failed to initialize k8s watchers %v", err) diff --git a/capten/agent/internal/app/ca_cert_issuer.go b/capten/agent/internal/app/ca_cert_issuer.go new file mode 100644 index 00000000..6b21f12e --- /dev/null +++ b/capten/agent/internal/app/ca_cert_issuer.go @@ -0,0 +1,149 @@ +package app + +import ( + "context" + "fmt" + "os" + "time" + + v1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + cmclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" + "github.com/kube-tarian/kad/capten/common-pkg/cert" + "github.com/kube-tarian/kad/capten/common-pkg/k8s" + "github.com/pkg/errors" + k8serror "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" +) + +const ( + certFileName = "server.cert" + keyFileName = "server.key" + agentIssuerName = "agent-ca-issuer" + namespace = "capten" + serverCertSecretName = "agent-server-mtls" +) + +func setupCACertIssuser() error { + k8sclient, err := k8s.NewK8SClient(log) + if err != nil { + log.Errorf("failed to initalize k8s client, %v", err) + return err + } + + _, err = setupCertificateIssuer(k8sclient) + if err != nil { + log.Errorf("Setup Certificates Issuer failed, %v", err) + return err + } + + err = generateServerCertificates(k8sclient) + if err != nil { + log.Errorf("Server certificates generation failed, %v", err) + return err + } + + // r.RunTLS(fmt.Sprintf("%s:%d", cfg.Host, cfg.RestPort), certFileName, keyFileName) + // r.Run(fmt.Sprintf("%s:%d", cfg.Host, cfg.RestPort)) + return nil +} + +// Setup agent certificate issuer +func setupCertificateIssuer(k8sclient *k8s.K8SClient) (*cert.CertificatesData, error) { + // TODO: Check certificates exist in Vault + // If exist skip + // Else + // 1. generate root certificates + // 2. Create Certificate Issuer + // 3. Store in Vault + certsData, err := cert.GenerateRootCerts() + if err != nil { + return nil, err + } + + err = k8s.CreateOrUpdateClusterCAIssuerSecret(k8sclient, certsData.InterCert.CertData, certsData.InterKey.KeyData, certsData.CaChainCertData) + if err != nil { + return nil, fmt.Errorf("failed to create/update CA Issuer Secret: %v", err) + } + + err = k8s.CreateOrUpdateClusterIssuer(agentIssuerName) + if err != nil { + return nil, fmt.Errorf("failed to create/update CA Issuer %s in cert-manager: %v", agentIssuerName, err) + } + + return certsData, nil +} + +func generateServerCertificates(k8sClient *k8s.K8SClient) error { + config, err := rest.InClusterConfig() + if err != nil { + return errors.WithMessage(err, "error while building kubeconfig") + } + cmClient, err := cmclient.NewForConfig(config) + if err != nil { + return err + } + + err = k8sClient.CreateNamespace(context.Background(), namespace) + if err != nil { + return fmt.Errorf("failed to create namespace: %v", err) + } + + err = generateCertManagerServerCertificate(cmClient, namespace, serverCertSecretName, agentIssuerName) + if err != nil { + return fmt.Errorf("failed to genereate server certificate: %v", err) + } + + // TODO: it may take some time for certificate to get create + // So have to keep wait and retry + time.Sleep(10 * time.Second) + secretData, err := k8sClient.GetSecretData(namespace, serverCertSecretName) + if err != nil { + return fmt.Errorf("failed to fetch certificates from secret, %v", err) + } + + // Write certificates to files + os.WriteFile(certFileName, []byte(secretData.Data["cert"]), cert.FilePermission) + os.WriteFile(keyFileName, []byte(secretData.Data["key"]), cert.FilePermission) + return nil +} + +func generateCertManagerServerCertificate(cmClient *cmclient.Clientset, namespace string, certName string, issuerRefName string) error { + usages := []v1.KeyUsage{v1.UsageDigitalSignature, v1.UsageKeyEncipherment, v1.UsageServerAuth} + + _, err := cmClient.CertmanagerV1().Certificates(namespace).Create( + context.TODO(), + &v1.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + }, + Spec: v1.CertificateSpec{ + IssuerRef: cmmeta.ObjectReference{ + Name: issuerRefName, // "capten-ca-issuer" + Kind: v1.ClusterIssuerKind, + }, + SecretName: certName, + CommonName: certName, + Usages: usages, + PrivateKey: &v1.CertificatePrivateKey{ + Algorithm: v1.RSAKeyAlgorithm, + Size: 2048, + Encoding: v1.PKCS1, + }, + }, + }, + metav1.CreateOptions{}, + ) + if k8serror.IsAlreadyExists(err) { + log.Infof("%v Certificate already exists", certName) + return nil + } + if err != nil { + log.Infof("%v Certificate generation failed, reason: %v", certName, err) + } else { + log.Infof("%v Certificate generation successful", certName) + } + + return err +} diff --git a/capten/common-pkg/cert/generate_certs.go b/capten/common-pkg/cert/generate_certs.go new file mode 100644 index 00000000..ea54664e --- /dev/null +++ b/capten/common-pkg/cert/generate_certs.go @@ -0,0 +1,161 @@ +package cert + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "os" + "time" + + "github.com/intelops/go-common/logging" + "github.com/pkg/errors" +) + +const ( + FilePermission os.FileMode = 0644 + caBitSize = 4096 + certBitSize = 2048 + rootCAKeyFileName = "root.key" + rootCACertFileName = "root.crt" + interCAKeyFileName = "inter-ca.key" + interCACertFileName = "inter-ca.crt" + CAFileName = "ca.crt" + OrgName = "Intelops" + RootCACommonName = "Capten Agent Root CA" + IntermediateCACommonName = "Capten Agent Cluster CA" + ClusterCACertSecretName = "agent-ca-cert" + CertManagerNamespace = "cert-manager" +) + +var ( + log = logging.NewLogger() +) + +type Key struct { + Key *rsa.PrivateKey + KeyData []byte +} + +type Cert struct { + Cert *x509.Certificate + CertData []byte +} + +type CertificatesData struct { + RootKey *Key + RootCert *Cert + InterKey *Key + InterCert *Cert + CaChainCertData []byte +} + +func GenerateRootCerts() (*CertificatesData, error) { + rootKey, rootCertTemplate, err := generateCACert() + if err != nil { + return nil, err + } + + interKey, interCACertTemplate, err := generateIntermediateCACert(rootKey.Key, rootCertTemplate.Cert) + if err != nil { + return nil, err + } + + caCertChain, err := generateCACertChain(rootCertTemplate.CertData, interCACertTemplate.CertData) + if err != nil { + return nil, err + } + log.Infof("%v\n%v\n", interKey, interCACertTemplate, caCertChain) + return &CertificatesData{ + RootKey: rootKey, + RootCert: rootCertTemplate, + InterKey: interKey, + InterCert: interCACertTemplate, + CaChainCertData: caCertChain, + }, nil +} + +func generateCACert() (*Key, *Cert, error) { //(rootKey *rsa.PrivateKey, rootCertTemplate *x509.Certificate, err error) { + rootKey, err := rsa.GenerateKey(rand.Reader, caBitSize) + if err != nil { + err = errors.WithMessage(err, "failed to generate RSA key for root certificate") + return nil, nil, err + } + + rootCertTemplate := &x509.Certificate{ + Subject: pkix.Name{ + Organization: []string{OrgName}, + CommonName: RootCACommonName, + }, + SerialNumber: big.NewInt(1), + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(5, 0, 0), + IsCA: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + rootCert, err := x509.CreateCertificate(rand.Reader, rootCertTemplate, rootCertTemplate, &rootKey.PublicKey, rootKey) + if err != nil { + err = errors.WithMessage(err, "failed to create root CA certificate") + return nil, nil, err + } + + rootCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert}) + rootKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootKey)}) + + return &Key{ + Key: rootKey, + KeyData: rootKeyPEM, + }, + &Cert{ + Cert: rootCertTemplate, + CertData: rootCertPEM, + }, nil +} + +func generateIntermediateCACert(rootKey *rsa.PrivateKey, rootCertTemplate *x509.Certificate) (*Key, *Cert, error) { + interKey, err := rsa.GenerateKey(rand.Reader, caBitSize) + if err != nil { + err = errors.WithMessage(err, "failed to generate RSA key for intermediate certificate") + return nil, nil, err + } + + interCACertTemplate := &x509.Certificate{ + Subject: pkix.Name{ + Organization: []string{OrgName}, + CommonName: IntermediateCACommonName, + Locality: []string{"agent"}, + }, + SerialNumber: big.NewInt(1), + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(2, 0, 0), + IsCA: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + interCert, err := x509.CreateCertificate(rand.Reader, interCACertTemplate, rootCertTemplate, &interKey.PublicKey, rootKey) + if err != nil { + err = errors.WithMessage(err, "failed to create intermediate CA certificate") + return nil, nil, err + } + + interCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: interCert}) + interKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(interKey)}) + + return &Key{ + Key: interKey, + KeyData: interKeyPEM, + }, + &Cert{ + Cert: interCACertTemplate, + CertData: interCertPEM, + }, nil +} + +func generateCACertChain(caCertPEMFromFile, interCACertPEMFromFile []byte) ([]byte, error) { + return append(caCertPEMFromFile, interCACertPEMFromFile...), nil +} diff --git a/capten/common-pkg/cert/generate_certs_test.go b/capten/common-pkg/cert/generate_certs_test.go new file mode 100644 index 00000000..24491405 --- /dev/null +++ b/capten/common-pkg/cert/generate_certs_test.go @@ -0,0 +1,13 @@ +package cert + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateRootCerts(t *testing.T) { + certInfo, err := GenerateRootCerts() + assert.NoError(t, err) + t.Log(certInfo) +} diff --git a/capten/common-pkg/k8s/cert_issuer.go b/capten/common-pkg/k8s/cert_issuer.go new file mode 100644 index 00000000..0f03db1c --- /dev/null +++ b/capten/common-pkg/k8s/cert_issuer.go @@ -0,0 +1,79 @@ +package k8s + +import ( + "context" + + "github.com/intelops/go-common/logging" + "github.com/kube-tarian/kad/capten/common-pkg/cert" + "github.com/pkg/errors" + + certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + cmclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" +) + +var log = logging.NewLogger() + +func CreateOrUpdateClusterIssuer(clusterCAIssuer string) error { + config, err := rest.InClusterConfig() + if err != nil { + return errors.WithMessage(err, "error while building kubeconfig") + } + + cmClient, err := cmclient.NewForConfig(config) + if err != nil { + return err + } + + issuer := &certmanagerv1.ClusterIssuer{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterCAIssuer, + }, + Spec: certmanagerv1.IssuerSpec{ + IssuerConfig: certmanagerv1.IssuerConfig{ + CA: &certmanagerv1.CAIssuer{ + SecretName: cert.ClusterCACertSecretName, + }, + }, + }, + } + + serverIssuer, err := cmClient.CertmanagerV1().ClusterIssuers().Get(context.Background(), issuer.Name, metav1.GetOptions{}) + if err != nil && k8serrors.IsNotFound(err) { + result, err := cmClient.CertmanagerV1().ClusterIssuers().Create(context.Background(), issuer, metav1.CreateOptions{}) + if err != nil { + return errors.WithMessage(err, "error in creating cert issuer") + } + log.Debugf("ClusterIssuer %s created successfully", result.Name) + return nil + } + + serverIssuer.Spec.IssuerConfig.CA.SecretName = cert.ClusterCACertSecretName + issuerClient := cmClient.CertmanagerV1().ClusterIssuers() + result, err := issuerClient.Update(context.TODO(), serverIssuer, metav1.UpdateOptions{}) + if err != nil { + return errors.WithMessage(err, "error while updating cluster issuer") + } + log.Debugf("ClusterIssuer %s updated successfully", result.Name) + return nil +} + +func CreateOrUpdateClusterCAIssuerSecret(k8sClient *K8SClient, interCACertData, interCAKeyData, caCertChainData []byte) error { + // Create the Secret object + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: cert.ClusterCACertSecretName, + Namespace: cert.CertManagerNamespace, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: interCACertData, + corev1.TLSPrivateKeyKey: interCAKeyData, + "ca.crt": caCertChainData, + }, + Type: corev1.SecretTypeTLS, + } + return k8sClient.CreateOrUpdateSecretObject(context.TODO(), secret) +} diff --git a/capten/common-pkg/k8s/client.go b/capten/common-pkg/k8s/client.go index 657702aa..d1439f48 100644 --- a/capten/common-pkg/k8s/client.go +++ b/capten/common-pkg/k8s/client.go @@ -6,7 +6,6 @@ import ( "github.com/intelops/go-common/logging" "github.com/kelseyhightower/envconfig" - corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" k8serror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -105,7 +104,7 @@ func GetK8SConfig(log logging.Logger) (*rest.Config, error) { return k8sConfig, nil } -func (k *K8SClient) ListPods(namespace string) ([]corev1.Pod, error) { +func (k *K8SClient) ListPods(namespace string) ([]v1.Pod, error) { pods, err := k.Clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err @@ -173,8 +172,13 @@ func (k *K8SClient) GetSecretData(namespace, secretName string) (*SecretData, er }, nil } -func (k *K8SClient) CreateOrUpdateSecret(ctx context.Context, namespace, secretName string, secretType v1.SecretType, - data map[string][]byte, annotation map[string]string) error { +func (k *K8SClient) CreateOrUpdateSecret( + ctx context.Context, + namespace, secretName string, + secretType v1.SecretType, + data map[string][]byte, + annotation map[string]string, +) error { _, err := k.Clientset.CoreV1().Secrets(namespace).Create(ctx, &v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: secretName, Annotations: annotation}, @@ -194,6 +198,19 @@ func (k *K8SClient) CreateOrUpdateSecret(ctx context.Context, namespace, secretN return nil } +func (k *K8SClient) CreateOrUpdateSecretObject(ctx context.Context, secret *v1.Secret) error { + _, err := k.Clientset.CoreV1().Secrets(secret.Namespace).Create(ctx, secret, metav1.CreateOptions{}) + if k8serror.IsAlreadyExists(err) { + _, err := k.Clientset.CoreV1().Secrets(secret.Namespace).Update(ctx, secret, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to update k8s secret, %v", err) + } + } else if err != nil { + return fmt.Errorf("failed to create k8s secret, %v", err) + } + return nil +} + func (k *K8SClient) DeleteSecret(ctx context.Context, namespace, secretName string) error { err := k.Clientset.CoreV1().Secrets(namespace).Delete(ctx, secretName, metav1.DeleteOptions{}) if k8serror.IsNotFound(err) { diff --git a/capten/deployment-worker/internal/activities/plugin_activity.go b/capten/deployment-worker/internal/activities/plugin_activity.go index 1790baef..60d24736 100644 --- a/capten/deployment-worker/internal/activities/plugin_activity.go +++ b/capten/deployment-worker/internal/activities/plugin_activity.go @@ -278,7 +278,7 @@ func (p *PluginActivities) PluginDeployPreActionMTLSActivity(ctx context.Context } pluginInitConfigmapName := req.PluginName + pluginConfigmapNameTemplate - err = captenSDKClient.CreateCertificates(req.PluginName, req.DefaultNamespace, "capten-issuer", pluginInitConfigmapName, p.k8sClient) + err = captenSDKClient.CreateCertificates(req.PluginName, req.DefaultNamespace, "agent-ca-issuer", pluginInitConfigmapName, p.k8sClient) if err != nil { return &model.ResponsePayload{ Status: "FAILED", From 723451afa66c388ed4d9281aec561d119891b337 Mon Sep 17 00:00:00 2001 From: share2kanna Date: Thu, 2 May 2024 14:57:32 +0530 Subject: [PATCH 2/4] Incorporated review comments --- capten/agent/internal/app/app.go | 3 +- capten/agent/internal/app/ca_cert_issuer.go | 4 +- capten/common-pkg/cert/generate_certs.go | 84 ++------------------- capten/common-pkg/k8s/cert_issuer.go | 6 +- 4 files changed, 13 insertions(+), 84 deletions(-) diff --git a/capten/agent/internal/app/app.go b/capten/agent/internal/app/app.go index 7cd6f822..0f7fe238 100644 --- a/capten/agent/internal/app/app.go +++ b/capten/agent/internal/app/app.go @@ -7,8 +7,6 @@ import ( "os/signal" "syscall" - "google.golang.org/grpc" - "github.com/intelops/go-common/logging" agentapi "github.com/kube-tarian/kad/capten/agent/internal/api" captenstore "github.com/kube-tarian/kad/capten/agent/internal/capten-store" @@ -24,6 +22,7 @@ import ( "github.com/kube-tarian/kad/capten/common-pkg/cluster-plugins/clusterpluginspb" pluginconfigtore "github.com/kube-tarian/kad/capten/common-pkg/pluginconfig-store" "github.com/pkg/errors" + "google.golang.org/grpc" "google.golang.org/grpc/reflection" ) diff --git a/capten/agent/internal/app/ca_cert_issuer.go b/capten/agent/internal/app/ca_cert_issuer.go index 6b21f12e..7306599e 100644 --- a/capten/agent/internal/app/ca_cert_issuer.go +++ b/capten/agent/internal/app/ca_cert_issuer.go @@ -51,7 +51,7 @@ func setupCACertIssuser() error { // Setup agent certificate issuer func setupCertificateIssuer(k8sclient *k8s.K8SClient) (*cert.CertificatesData, error) { - // TODO: Check certificates exist in Vault + // TODO: Check certificates exist in Vault and control plan cluster // If exist skip // Else // 1. generate root certificates @@ -62,7 +62,7 @@ func setupCertificateIssuer(k8sclient *k8s.K8SClient) (*cert.CertificatesData, e return nil, err } - err = k8s.CreateOrUpdateClusterCAIssuerSecret(k8sclient, certsData.InterCert.CertData, certsData.InterKey.KeyData, certsData.CaChainCertData) + err = k8s.CreateOrUpdateClusterCAIssuerSecret(k8sclient, certsData.RootCert.CertData, certsData.RootKey.KeyData, certsData.CaChainCertData) if err != nil { return nil, fmt.Errorf("failed to create/update CA Issuer Secret: %v", err) } diff --git a/capten/common-pkg/cert/generate_certs.go b/capten/common-pkg/cert/generate_certs.go index ea54664e..59b10893 100644 --- a/capten/common-pkg/cert/generate_certs.go +++ b/capten/common-pkg/cert/generate_certs.go @@ -10,28 +10,16 @@ import ( "os" "time" - "github.com/intelops/go-common/logging" "github.com/pkg/errors" ) const ( - FilePermission os.FileMode = 0644 - caBitSize = 4096 - certBitSize = 2048 - rootCAKeyFileName = "root.key" - rootCACertFileName = "root.crt" - interCAKeyFileName = "inter-ca.key" - interCACertFileName = "inter-ca.crt" - CAFileName = "ca.crt" - OrgName = "Intelops" - RootCACommonName = "Capten Agent Root CA" - IntermediateCACommonName = "Capten Agent Cluster CA" - ClusterCACertSecretName = "agent-ca-cert" - CertManagerNamespace = "cert-manager" -) - -var ( - log = logging.NewLogger() + FilePermission os.FileMode = 0644 + caBitSize = 4096 + OrgName = "Intelops" + RootCACommonName = "Capten Agent Root CA" + ClusterCACertSecretName = "agent-ca-cert" + CertManagerNamespace = "cert-manager" ) type Key struct { @@ -47,8 +35,6 @@ type Cert struct { type CertificatesData struct { RootKey *Key RootCert *Cert - InterKey *Key - InterCert *Cert CaChainCertData []byte } @@ -58,22 +44,10 @@ func GenerateRootCerts() (*CertificatesData, error) { return nil, err } - interKey, interCACertTemplate, err := generateIntermediateCACert(rootKey.Key, rootCertTemplate.Cert) - if err != nil { - return nil, err - } - - caCertChain, err := generateCACertChain(rootCertTemplate.CertData, interCACertTemplate.CertData) - if err != nil { - return nil, err - } - log.Infof("%v\n%v\n", interKey, interCACertTemplate, caCertChain) return &CertificatesData{ RootKey: rootKey, RootCert: rootCertTemplate, - InterKey: interKey, - InterCert: interCACertTemplate, - CaChainCertData: caCertChain, + CaChainCertData: rootCertTemplate.CertData, }, nil } @@ -115,47 +89,3 @@ func generateCACert() (*Key, *Cert, error) { //(rootKey *rsa.PrivateKey, rootCer CertData: rootCertPEM, }, nil } - -func generateIntermediateCACert(rootKey *rsa.PrivateKey, rootCertTemplate *x509.Certificate) (*Key, *Cert, error) { - interKey, err := rsa.GenerateKey(rand.Reader, caBitSize) - if err != nil { - err = errors.WithMessage(err, "failed to generate RSA key for intermediate certificate") - return nil, nil, err - } - - interCACertTemplate := &x509.Certificate{ - Subject: pkix.Name{ - Organization: []string{OrgName}, - CommonName: IntermediateCACommonName, - Locality: []string{"agent"}, - }, - SerialNumber: big.NewInt(1), - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(2, 0, 0), - IsCA: true, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - interCert, err := x509.CreateCertificate(rand.Reader, interCACertTemplate, rootCertTemplate, &interKey.PublicKey, rootKey) - if err != nil { - err = errors.WithMessage(err, "failed to create intermediate CA certificate") - return nil, nil, err - } - - interCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: interCert}) - interKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(interKey)}) - - return &Key{ - Key: interKey, - KeyData: interKeyPEM, - }, - &Cert{ - Cert: interCACertTemplate, - CertData: interCertPEM, - }, nil -} - -func generateCACertChain(caCertPEMFromFile, interCACertPEMFromFile []byte) ([]byte, error) { - return append(caCertPEMFromFile, interCACertPEMFromFile...), nil -} diff --git a/capten/common-pkg/k8s/cert_issuer.go b/capten/common-pkg/k8s/cert_issuer.go index 0f03db1c..6559eead 100644 --- a/capten/common-pkg/k8s/cert_issuer.go +++ b/capten/common-pkg/k8s/cert_issuer.go @@ -61,7 +61,7 @@ func CreateOrUpdateClusterIssuer(clusterCAIssuer string) error { return nil } -func CreateOrUpdateClusterCAIssuerSecret(k8sClient *K8SClient, interCACertData, interCAKeyData, caCertChainData []byte) error { +func CreateOrUpdateClusterCAIssuerSecret(k8sClient *K8SClient, caCertData, caKeyData, caCertChainData []byte) error { // Create the Secret object secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -69,8 +69,8 @@ func CreateOrUpdateClusterCAIssuerSecret(k8sClient *K8SClient, interCACertData, Namespace: cert.CertManagerNamespace, }, Data: map[string][]byte{ - corev1.TLSCertKey: interCACertData, - corev1.TLSPrivateKeyKey: interCAKeyData, + corev1.TLSCertKey: caCertData, + corev1.TLSPrivateKeyKey: caKeyData, "ca.crt": caCertChainData, }, Type: corev1.SecretTypeTLS, From 71bc3976a5363c99805256ce748a158240881131 Mon Sep 17 00:00:00 2001 From: share2kanna Date: Thu, 2 May 2024 15:19:26 +0530 Subject: [PATCH 3/4] common paramter agent cluster ca issuer introduced through configmap --- capten/agent/internal/app/app.go | 2 +- capten/agent/internal/app/ca_cert_issuer.go | 17 ++++++++--------- capten/agent/internal/config/config.go | 1 + .../internal/activities/plugin_activity.go | 8 +++++++- charts/kad/templates/agent-deployment.yaml | 5 +++++ charts/kad/templates/configmap-agent_data.yaml | 6 ++++++ 6 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 charts/kad/templates/configmap-agent_data.yaml diff --git a/capten/agent/internal/app/app.go b/capten/agent/internal/app/app.go index 0f7fe238..7bcdbc27 100644 --- a/capten/agent/internal/app/app.go +++ b/capten/agent/internal/app/app.go @@ -87,7 +87,7 @@ func Start() { } }() - err = setupCACertIssuser() + err = setupCACertIssuser(cfg.ClusterCAIssuerName) if err != nil { log.Fatalf("Failed to setupt CA Cert Issuer in cert-manager %v", err) } diff --git a/capten/agent/internal/app/ca_cert_issuer.go b/capten/agent/internal/app/ca_cert_issuer.go index 7306599e..f0ca0780 100644 --- a/capten/agent/internal/app/ca_cert_issuer.go +++ b/capten/agent/internal/app/ca_cert_issuer.go @@ -20,25 +20,24 @@ import ( const ( certFileName = "server.cert" keyFileName = "server.key" - agentIssuerName = "agent-ca-issuer" namespace = "capten" serverCertSecretName = "agent-server-mtls" ) -func setupCACertIssuser() error { +func setupCACertIssuser(clusterIssuerName string) error { k8sclient, err := k8s.NewK8SClient(log) if err != nil { log.Errorf("failed to initalize k8s client, %v", err) return err } - _, err = setupCertificateIssuer(k8sclient) + _, err = setupCertificateIssuer(k8sclient, clusterIssuerName) if err != nil { log.Errorf("Setup Certificates Issuer failed, %v", err) return err } - err = generateServerCertificates(k8sclient) + err = generateServerCertificates(k8sclient, clusterIssuerName) if err != nil { log.Errorf("Server certificates generation failed, %v", err) return err @@ -50,7 +49,7 @@ func setupCACertIssuser() error { } // Setup agent certificate issuer -func setupCertificateIssuer(k8sclient *k8s.K8SClient) (*cert.CertificatesData, error) { +func setupCertificateIssuer(k8sclient *k8s.K8SClient, clusterIssuerName string) (*cert.CertificatesData, error) { // TODO: Check certificates exist in Vault and control plan cluster // If exist skip // Else @@ -67,15 +66,15 @@ func setupCertificateIssuer(k8sclient *k8s.K8SClient) (*cert.CertificatesData, e return nil, fmt.Errorf("failed to create/update CA Issuer Secret: %v", err) } - err = k8s.CreateOrUpdateClusterIssuer(agentIssuerName) + err = k8s.CreateOrUpdateClusterIssuer(clusterIssuerName) if err != nil { - return nil, fmt.Errorf("failed to create/update CA Issuer %s in cert-manager: %v", agentIssuerName, err) + return nil, fmt.Errorf("failed to create/update CA Issuer %s in cert-manager: %v", clusterIssuerName, err) } return certsData, nil } -func generateServerCertificates(k8sClient *k8s.K8SClient) error { +func generateServerCertificates(k8sClient *k8s.K8SClient, clusterIssuerName string) error { config, err := rest.InClusterConfig() if err != nil { return errors.WithMessage(err, "error while building kubeconfig") @@ -90,7 +89,7 @@ func generateServerCertificates(k8sClient *k8s.K8SClient) error { return fmt.Errorf("failed to create namespace: %v", err) } - err = generateCertManagerServerCertificate(cmClient, namespace, serverCertSecretName, agentIssuerName) + err = generateCertManagerServerCertificate(cmClient, namespace, serverCertSecretName, clusterIssuerName) if err != nil { return fmt.Errorf("failed to genereate server certificate: %v", err) } diff --git a/capten/agent/internal/config/config.go b/capten/agent/internal/config/config.go index d5df2836..5274f1cf 100644 --- a/capten/agent/internal/config/config.go +++ b/capten/agent/internal/config/config.go @@ -14,6 +14,7 @@ type SericeConfig struct { TektonSyncJobEnabled bool `envconfig:"TEKTON_SYNC_JOB_ENABLED" default:"true"` TektonSyncJobInterval string `envconfig:"TEKTON_SYNC_JOB_INTERVAL" default:"@every 1h"` DomainName string `envconfig:"DOMAIN_NAME" default:"example.com"` + ClusterCAIssuerName string `envconfig:"AGENT_CLUSTER_CA_ISSUER_NAME" default:"agent-ca-issuer"` } func GetServiceConfig() (*SericeConfig, error) { diff --git a/capten/deployment-worker/internal/activities/plugin_activity.go b/capten/deployment-worker/internal/activities/plugin_activity.go index 60d24736..6e3742f8 100644 --- a/capten/deployment-worker/internal/activities/plugin_activity.go +++ b/capten/deployment-worker/internal/activities/plugin_activity.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "os" "strings" "github.com/kelseyhightower/envconfig" @@ -277,8 +278,13 @@ func (p *PluginActivities) PluginDeployPreActionMTLSActivity(ctx context.Context }, err } + agentClusterCAIssuerName := os.Getenv("AGENT_CLUSTER_CA_ISSUER_NAME") + if len(agentClusterCAIssuerName) == 0 { + agentClusterCAIssuerName = "agent-ca-issuer" + } + pluginInitConfigmapName := req.PluginName + pluginConfigmapNameTemplate - err = captenSDKClient.CreateCertificates(req.PluginName, req.DefaultNamespace, "agent-ca-issuer", pluginInitConfigmapName, p.k8sClient) + err = captenSDKClient.CreateCertificates(req.PluginName, req.DefaultNamespace, agentClusterCAIssuerName, pluginInitConfigmapName, p.k8sClient) if err != nil { return &model.ResponsePayload{ Status: "FAILED", diff --git a/charts/kad/templates/agent-deployment.yaml b/charts/kad/templates/agent-deployment.yaml index 79da3ddc..ef261d1e 100644 --- a/charts/kad/templates/agent-deployment.yaml +++ b/charts/kad/templates/agent-deployment.yaml @@ -81,6 +81,11 @@ spec: value: {{ .Values.cassandra.keyspace }} - name: CASSANDRA_SECRET_NAME value: {{ .Values.cassandra.secretName }} + - name: AGENT_CLUSTER_CA_ISSUER_NAME + valueFrom: + configMapKeyRef: + name: kad-agent-config + key: clusterIssuerName resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} diff --git a/charts/kad/templates/configmap-agent_data.yaml b/charts/kad/templates/configmap-agent_data.yaml new file mode 100644 index 00000000..42a26858 --- /dev/null +++ b/charts/kad/templates/configmap-agent_data.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kad-agent-config +data: + clusterIssuerName: agent-ca-issuer From 3df7b70c1fdfc85ecaa1e8d8c363d0d66f514a8f Mon Sep 17 00:00:00 2001 From: share2kanna Date: Thu, 2 May 2024 15:20:40 +0530 Subject: [PATCH 4/4] added agent cluster ca issuer in deployment worker env --- charts/kad/templates/deployment-worker-deployment.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/charts/kad/templates/deployment-worker-deployment.yaml b/charts/kad/templates/deployment-worker-deployment.yaml index 0c004ae7..57c672d1 100644 --- a/charts/kad/templates/deployment-worker-deployment.yaml +++ b/charts/kad/templates/deployment-worker-deployment.yaml @@ -69,6 +69,11 @@ spec: value: {{ .Values.cassandra.secretName }} - name: AGENT_ADDRESSES value: {{ include "kad.fullname" . }}-agent + - name: AGENT_CLUSTER_CA_ISSUER_NAME + valueFrom: + configMapKeyRef: + name: kad-agent-config + key: clusterIssuerName resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: