github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/plan/tls_utils.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package plan
    21  
    22  import (
    23  	"bytes"
    24  	"context"
    25  	"strings"
    26  	"text/template"
    27  
    28  	"github.com/Masterminds/sprig/v3"
    29  	"github.com/pkg/errors"
    30  	v1 "k8s.io/api/core/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  
    33  	dbaasv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    34  	"github.com/1aal/kubeblocks/pkg/constant"
    35  	"github.com/1aal/kubeblocks/pkg/controller/builder"
    36  	client2 "github.com/1aal/kubeblocks/pkg/controller/client"
    37  	"github.com/1aal/kubeblocks/pkg/controller/factory"
    38  )
    39  
    40  // ComposeTLSSecret composes a TSL secret object.
    41  // REVIEW/TODO:
    42  //  1. missing public function doc
    43  //  2. should avoid using Go template to call a function, this is too hacky & costly,
    44  //     should just call underlying registered Go template function.
    45  func ComposeTLSSecret(namespace, clusterName, componentName string) (*v1.Secret, error) {
    46  	name := GenerateTLSSecretName(clusterName, componentName)
    47  	secret := builder.NewSecretBuilder(namespace, name).
    48  		AddLabels(constant.AppInstanceLabelKey, clusterName).
    49  		AddLabels(constant.KBManagedByKey, constant.AppName).
    50  		SetStringData(map[string]string{}).
    51  		GetObject()
    52  
    53  	const tpl = `{{- $cert := genSelfSignedCert "KubeBlocks" nil nil 365 }}
    54  {{ $cert.Cert }}
    55  {{ $cert.Key }}
    56  `
    57  	out, err := buildFromTemplate(tpl, nil)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	index := strings.Index(out, "-----BEGIN RSA PRIVATE KEY-----")
    62  	if index < 0 {
    63  		return nil, errors.Errorf("wrong cert format: %s", out)
    64  	}
    65  	cert := out[:index]
    66  	key := out[index:]
    67  	secret.StringData[factory.CAName] = cert
    68  	secret.StringData[factory.CertName] = cert
    69  	secret.StringData[factory.KeyName] = key
    70  	return secret, nil
    71  }
    72  
    73  func GenerateTLSSecretName(clusterName, componentName string) string {
    74  	return clusterName + "-" + componentName + "-tls-certs"
    75  }
    76  
    77  func buildFromTemplate(tpl string, vars interface{}) (string, error) {
    78  	fmap := sprig.TxtFuncMap()
    79  	t := template.Must(template.New("tls").Funcs(fmap).Parse(tpl))
    80  	var b bytes.Buffer
    81  	err := t.Execute(&b, vars)
    82  	if err != nil {
    83  		return "", err
    84  	}
    85  	return b.String(), nil
    86  }
    87  
    88  func CheckTLSSecretRef(ctx context.Context, cli client2.ReadonlyClient, namespace string,
    89  	secretRef *dbaasv1alpha1.TLSSecretRef) error {
    90  	if secretRef == nil {
    91  		return errors.New("issuer.secretRef shouldn't be nil when issuer is UserProvided")
    92  	}
    93  
    94  	secret := &v1.Secret{}
    95  	if err := cli.Get(ctx, types.NamespacedName{Namespace: namespace, Name: secretRef.Name}, secret); err != nil {
    96  		return err
    97  	}
    98  	if secret.StringData == nil {
    99  		return errors.New("tls secret's data field shouldn't be nil")
   100  	}
   101  	keys := []string{secretRef.CA, secretRef.Cert, secretRef.Key}
   102  	for _, key := range keys {
   103  		if _, ok := secret.StringData[key]; !ok {
   104  			return errors.Errorf("tls secret's data[%s] field shouldn't be empty", key)
   105  		}
   106  	}
   107  	return nil
   108  }
   109  
   110  func GetTLSKeyWord(cType string) string {
   111  	switch cType {
   112  	case "mysql":
   113  		return "ssl_cert"
   114  	case "postgresql":
   115  		return "ssl_cert_file"
   116  	case "redis":
   117  		return "tls-cert-file"
   118  	default:
   119  		return "unsupported-character-type"
   120  	}
   121  }