Skip to content

Commit

Permalink
update tls certs
Browse files Browse the repository at this point in the history
  • Loading branch information
leon-inf committed Jan 22, 2025
1 parent 2fea6c0 commit aa4c3ae
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 188 deletions.
4 changes: 2 additions & 2 deletions controllers/apps/cluster/transformer_cluster_sharding_tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (t *clusterShardingTLSTransformer) buildTLSSecret(transCtx *clusterTransfor
Name: sharding.Name,
}
secret := t.newTLSSecret(transCtx, sharding, compDef)
return plan.ComposeTLSSecret(compDef, synthesizedComp, secret)
return plan.ComposeTLSCertsWithSecret(compDef, synthesizedComp, secret)
}

func (t *clusterShardingTLSTransformer) newTLSSecret(transCtx *clusterTransformContext,
Expand All @@ -157,7 +157,7 @@ func (t *clusterShardingTLSTransformer) newTLSSecret(transCtx *clusterTransformC
AddLabelsInMap(compDef.Spec.Labels).
AddAnnotationsInMap(sharding.Template.Annotations).
AddAnnotationsInMap(compDef.Spec.Annotations).
SetStringData(map[string]string{}).
SetData(map[string][]byte{}).
GetObject()
}

Expand Down
3 changes: 1 addition & 2 deletions controllers/apps/component/component_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import (
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/builder"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/apecloud/kubeblocks/pkg/controller/plan"
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
"github.com/apecloud/kubeblocks/pkg/generics"
kbacli "github.com/apecloud/kubeblocks/pkg/kbagent/client"
Expand Down Expand Up @@ -1154,7 +1153,7 @@ var _ = Describe("Component Controller", func() {
By("check TLS secret")
secretKey := types.NamespacedName{
Namespace: compObj.Namespace,
Name: plan.GenerateTLSSecretName(clusterKey.Name, compName),
Name: tlsSecretName(clusterKey.Name, compName),
}
Eventually(testapps.CheckObj(&testCtx, secretKey, func(g Gomega, secret *corev1.Secret) {
g.Expect(secret.Data).Should(HaveKey(*tls.CAFile))
Expand Down
82 changes: 55 additions & 27 deletions controllers/apps/component/transformer_component_tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/builder"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/apecloud/kubeblocks/pkg/controller/graph"
"github.com/apecloud/kubeblocks/pkg/controller/model"
Expand Down Expand Up @@ -97,7 +99,7 @@ func (t *componentTLSTransformer) enabled(compDef *appsv1.ComponentDefinition,
if tls.Issuer == nil {
return false, fmt.Errorf("the issuer shouldn't be nil when the TLS is enabled")
}
if slices.Contains([]appsv1.IssuerName{appsv1.IssuerUserProvided, appsv1.IssuerKubeBlocks}, tls.Issuer.Name) {
if !slices.Contains([]appsv1.IssuerName{appsv1.IssuerUserProvided, appsv1.IssuerKubeBlocks}, tls.Issuer.Name) {
return false, fmt.Errorf("unknown TLS issuer %s", tls.Issuer.Name)
}
if compDef.Spec.TLS == nil {
Expand All @@ -110,7 +112,7 @@ func (t *componentTLSTransformer) secretObject(transCtx *componentTransformConte
synthesizedComp *component.SynthesizedComponent) (*corev1.Secret, error) {
secretKey := types.NamespacedName{
Namespace: synthesizedComp.Namespace,
Name: plan.GenerateTLSSecretName(synthesizedComp.ClusterName, synthesizedComp.Name),
Name: tlsSecretName(synthesizedComp.ClusterName, synthesizedComp.Name),
}
secret := &corev1.Secret{}
err := transCtx.Client.Get(transCtx.Context, secretKey, secret)
Expand Down Expand Up @@ -168,7 +170,7 @@ func (t *componentTLSTransformer) handleDelete(ctx context.Context, cli client.R
}
if secret != nil {
graphCli, _ := cli.(model.GraphClient)
graphCli.Delete(dag, secret)
graphCli.Delete(dag, secret) // TODO: notify the pods
}
return nil
}
Expand All @@ -181,7 +183,7 @@ func (t *componentTLSTransformer) handleUpdate(ctx context.Context, cli client.R
}
if secret != nil {
graphCli, _ := cli.(model.GraphClient)
graphCli.Update(dag, secretObj, secret)
graphCli.Update(dag, secretObj, secret) // TODO: notify the pods
}
return nil
}
Expand All @@ -192,17 +194,18 @@ type tlsIssuerKubeBlocks struct {
}

func (i *tlsIssuerKubeBlocks) create(ctx context.Context, cli client.Reader) (*corev1.Secret, error) {
return plan.ComposeTLSSecret(i.compDef, *i.synthesizedComp, nil)
proto := newTLSSecret(i.synthesizedComp)
return plan.ComposeTLSCertsWithSecret(i.compDef, *i.synthesizedComp, proto)
}

func (i *tlsIssuerKubeBlocks) delete(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
return secret, nil
}

func (i *tlsIssuerKubeBlocks) update(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
proto := plan.BuildTLSSecret(*i.synthesizedComp)
proto := newTLSSecret(i.synthesizedComp)

// TODO: update secret data if needed
// For TLS certs generated by KubeBlocks, we only support updating labels and annotations.
secretCopy := secret.DeepCopy()
secretCopy.Labels = proto.Labels
secretCopy.Annotations = proto.Annotations
Expand All @@ -219,12 +222,38 @@ type tlsIssuerUserProvided struct {
}

func (i *tlsIssuerUserProvided) create(ctx context.Context, cli client.Reader) (*corev1.Secret, error) {
return i.proto(ctx, cli)
}

func (i *tlsIssuerUserProvided) delete(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
return secret, nil
}

func (i *tlsIssuerUserProvided) update(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
proto, err := i.proto(ctx, cli)
if err != nil {
// the referenced secret not existing should not affect the reconciliation
return nil, client.IgnoreNotFound(err)
}

secretCopy := secret.DeepCopy()
secretCopy.Labels = proto.Labels
secretCopy.Annotations = proto.Annotations
secretCopy.Data = proto.Data

if !reflect.DeepEqual(secret, secretCopy) {
return secretCopy, nil
}
return nil, nil
}

func (i *tlsIssuerUserProvided) proto(ctx context.Context, cli client.Reader) (*corev1.Secret, error) {
secret, err := i.referenced(ctx, cli)
if err != nil {
return nil, err
}

proto := plan.BuildTLSSecret(*i.synthesizedComp)
proto := newTLSSecret(i.synthesizedComp)

secretRef := i.synthesizedComp.TLSConfig.Issuer.SecretRef
if i.compDef.Spec.TLS.CAFile != nil {
Expand All @@ -240,24 +269,6 @@ func (i *tlsIssuerUserProvided) create(ctx context.Context, cli client.Reader) (
return proto, nil
}

func (i *tlsIssuerUserProvided) delete(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
return secret, nil
}

func (i *tlsIssuerUserProvided) update(ctx context.Context, cli client.Reader, secret *corev1.Secret) (*corev1.Secret, error) {
proto := plan.BuildTLSSecret(*i.synthesizedComp)

// TODO: update secret data if needed
secretCopy := secret.DeepCopy()
secretCopy.Labels = proto.Labels
secretCopy.Annotations = proto.Annotations

if !reflect.DeepEqual(secret, secretCopy) {
return secretCopy, nil
}
return nil, nil
}

func (i *tlsIssuerUserProvided) referenced(ctx context.Context, cli client.Reader) (*corev1.Secret, error) {
var (
secretRef = i.synthesizedComp.TLSConfig.Issuer.SecretRef
Expand Down Expand Up @@ -326,7 +337,7 @@ func (t *componentTLSTransformer) composeTLSVolume(compDef *appsv1.ComponentDefi
tls := synthesizedComp.TLSConfig
switch tls.Issuer.Name {
case appsv1.IssuerKubeBlocks:
secretName = plan.GenerateTLSSecretName(synthesizedComp.ClusterName, synthesizedComp.Name)
secretName = tlsSecretName(synthesizedComp.ClusterName, synthesizedComp.Name)
ca = compDef.Spec.TLS.CAFile
cert = compDef.Spec.TLS.CertFile
key = compDef.Spec.TLS.KeyFile
Expand Down Expand Up @@ -404,3 +415,20 @@ func (t *componentTLSTransformer) removeVolumeNVolumeMount(compDef *appsv1.Compo

return nil
}

func tlsSecretName(clusterName, compName string) string {
return clusterName + "-" + compName + "-tls-certs"
}

func newTLSSecret(synthesizedComp *component.SynthesizedComponent) *corev1.Secret {
secretName := tlsSecretName(synthesizedComp.ClusterName, synthesizedComp.Name)
return builder.NewSecretBuilder(synthesizedComp.Namespace, secretName).
// priority: static < dynamic < built-in
AddLabelsInMap(synthesizedComp.StaticLabels).
AddLabelsInMap(synthesizedComp.DynamicLabels).
AddLabelsInMap(constant.GetCompLabels(synthesizedComp.ClusterName, synthesizedComp.Name)).
AddAnnotationsInMap(synthesizedComp.StaticAnnotations).
AddAnnotationsInMap(synthesizedComp.DynamicAnnotations).
SetData(map[string][]byte{}).
GetObject()
}
94 changes: 1 addition & 93 deletions controllers/apps/component/transformer_component_tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,11 @@ package component

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/apecloud/kubeblocks/pkg/controller/plan"
testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
)

var _ = Describe("TLS self-signed cert function", func() {
const (
compDefName = "test-compdef"
clusterNamePrefix = "test-cluster"
defaultCompName = "mysql"
caFile = "ca.pem"
certFile = "cert.pem"
keyFile = "key.pem"
)

var (
compDefObj *appsv1.ComponentDefinition
)

cleanEnv := func() {
// must wait until resources deleted and no longer exist before the testcases start,
// otherwise if later it needs to create some new resource objects with the same name,
Expand All @@ -62,75 +40,5 @@ var _ = Describe("TLS self-signed cert function", func() {

AfterEach(cleanEnv)

Context("tls is enabled/disabled", func() {
BeforeEach(func() {
By("Create a componentDefinition obj")
compDefObj = testapps.NewComponentDefinitionFactory(compDefName).
WithRandomName().
AddAnnotations(constant.SkipImmutableCheckAnnotationKey, "true").
SetDefaultSpec().
Create(&testCtx).
GetObject()
})

Context("when issuer is UserProvided", func() {
var (
synthesizedComp *component.SynthesizedComponent
secretObj *corev1.Secret
)

BeforeEach(func() {
// prepare self provided tls certs secret
var err error
compDef := &appsv1.ComponentDefinition{
Spec: appsv1.ComponentDefinitionSpec{
TLS: &appsv1.TLS{
CAFile: ptr.To(caFile),
CertFile: ptr.To(certFile),
KeyFile: ptr.To(keyFile),
},
},
}
synthesizedComp = &component.SynthesizedComponent{
Namespace: testCtx.DefaultNamespace,
ClusterName: "test",
Name: "self-provided",
FullCompName: "test-self-provided",
CompDefName: compDefObj.Name,
}
secretObj, err = plan.ComposeTLSSecret(compDef, *synthesizedComp, nil)
Expect(err).Should(BeNil())
Expect(k8sClient.Create(testCtx.Ctx, secretObj)).Should(Succeed())
})

AfterEach(func() {
// delete self provided tls secret
Expect(k8sClient.Delete(testCtx.Ctx, secretObj)).Should(Succeed())
Eventually(testapps.CheckObjExists(&testCtx, client.ObjectKeyFromObject(secretObj), secretObj, false)).Should(Succeed())
})

It("should create the component when secret referenced exist", func() {
issuer := &appsv1.Issuer{
Name: appsv1.IssuerUserProvided,
SecretRef: &appsv1.TLSSecretReference{
SecretReference: corev1.SecretReference{
Namespace: testCtx.DefaultNamespace,
Name: secretObj.Name,
},
CA: caFile,
Cert: certFile,
Key: keyFile,
},
}
By("create component obj")
compObj := testapps.NewComponentFactory(synthesizedComp.Namespace, synthesizedComp.FullCompName, synthesizedComp.CompDefName).
WithRandomName().
SetReplicas(3).
SetTLSConfig(true, issuer).
Create(&testCtx).
GetObject()
Eventually(k8sClient.Get(testCtx.Ctx, client.ObjectKeyFromObject(compObj), compObj)).Should(Succeed())
})
})
})
// TODO: test
})
45 changes: 11 additions & 34 deletions pkg/controller/plan/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,22 @@ import (
"text/template"

"github.com/Masterminds/sprig/v3"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"

appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/builder"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
)

func GenerateTLSSecretName(clusterName, componentName string) string {
return clusterName + "-" + componentName + "-tls-certs"
}

func BuildTLSSecret(synthesizedComp component.SynthesizedComponent) *v1.Secret {
name := GenerateTLSSecretName(synthesizedComp.ClusterName, synthesizedComp.Name)
return builder.NewSecretBuilder(synthesizedComp.Namespace, name).
// Priority: static < dynamic < built-in
AddLabelsInMap(synthesizedComp.StaticLabels).
AddLabelsInMap(synthesizedComp.DynamicLabels).
AddLabelsInMap(constant.GetCompLabels(synthesizedComp.ClusterName, synthesizedComp.Name)).
AddAnnotationsInMap(synthesizedComp.StaticAnnotations).
AddAnnotationsInMap(synthesizedComp.DynamicAnnotations).
SetStringData(map[string]string{}).
SetData(map[string][]byte{}).
GetObject()
}

// ComposeTLSSecret composes a TSL secret object.
// REVIEW/TODO:
// 1. missing public function doc
// 2. should avoid using Go template to call a function, this is too hacky & costly,
// should just call underlying registered Go template function.
func ComposeTLSSecret(compDef *appsv1.ComponentDefinition, synthesizedComp component.SynthesizedComponent, secret *v1.Secret) (*v1.Secret, error) {
func ComposeTLSCertsWithSecret(compDef *appsv1.ComponentDefinition,
synthesizedComp component.SynthesizedComponent, secret *corev1.Secret) (*corev1.Secret, error) {
var (
namespace = synthesizedComp.Namespace
clusterName = synthesizedComp.ClusterName
compName = synthesizedComp.Name
)
if secret == nil {
secret = BuildTLSSecret(synthesizedComp)
}

// TODO: should avoid using Go template to call a function, this is too hacky & costly, should just call underlying registered Go template function.
// use ca gen cert
// IP: 127.0.0.1 and ::1
// DNS: localhost and *.<clusterName>-<compName>-headless.<namespace>.svc.cluster.local
Expand All @@ -83,19 +59,20 @@ func ComposeTLSSecret(compDef *appsv1.ComponentDefinition, synthesizedComp compo
if err != nil {
return nil, err
}

parts := strings.Split(out, spliter)
if len(parts) != 3 {
return nil, errors.Errorf("generate TLS certificates failed with cluster name %s, component name %s in namespace %s",
clusterName, compName, namespace)
}
if compDef.Spec.TLS.CAFile != nil {
secret.StringData[*compDef.Spec.TLS.CAFile] = parts[0]
secret.Data[*compDef.Spec.TLS.CAFile] = []byte(parts[0])
}
if compDef.Spec.TLS.CertFile != nil {
secret.StringData[*compDef.Spec.TLS.CertFile] = parts[1]
secret.Data[*compDef.Spec.TLS.CertFile] = []byte(parts[1])
}
if compDef.Spec.TLS.KeyFile != nil {
secret.StringData[*compDef.Spec.TLS.KeyFile] = parts[2]
secret.Data[*compDef.Spec.TLS.KeyFile] = []byte(parts[2])
}
return secret, nil
}
Expand Down
Loading

0 comments on commit aa4c3ae

Please sign in to comment.