1. support tls

This commit is contained in:
jinchengsix 2022-10-24 16:56:08 +08:00
parent 51b860f4fd
commit c156c03efd
13 changed files with 490 additions and 26 deletions

View File

@ -30,6 +30,43 @@ type MongoDBClusterSpec struct {
MongoDBMonitoring *MongoDBMonitoring `json:"mongoDBMonitoring,omitempty"`
PodDisruptionBudget *MongoDBPodDisruptionBudget `json:"podDisruptionBudget,omitempty"`
MongoDBAdditionalConfig *string `json:"mongoDBAdditionalConfig,omitempty"`
Security Security `json:"security"`
}
type Security struct {
TLS TLS `json:"tls"`
}
// TLS is the configuration used to set up TLS encryption
type TLS struct {
Enabled bool `json:"enabled"`
// Optional configures if TLS should be required or optional for connections
// +optional
Optional bool `json:"optional,omitempty"`
// CertificateKeySecret is a reference to a Secret containing a private key and certificate to use for TLS.
// The key and cert are expected to be PEM encoded and available at "tls.key" and "tls.crt".
// This is the same format used for the standard "kubernetes.io/tls" Secret type, but no specific type is required.
// Alternatively, an entry tls.pem, containing the concatenation of cert and key, can be provided.
// If all of tls.pem, tls.crt and tls.key are present, the tls.pem one needs to be equal to the concatenation of tls.crt and tls.key
// +optional
CertificateKeySecret LocalObjectReference `json:"certificateKeySecretRef,omitempty"`
// CaCertificateSecret is a reference to a Secret containing the certificate for the CA which signed the server certificates
// The certificate is expected to be available under the key "ca.crt"
// +optional
CaCertificateSecret *LocalObjectReference `json:"caCertificateSecretRef,omitempty"`
// CaConfigMap is a reference to a ConfigMap containing the certificate for the CA which signed the server certificates
// The certificate is expected to be available under the key "ca.crt"
// This field is ignored when CaCertificateSecretRef is configured
// +optional
CaConfigMap *LocalObjectReference `json:"caConfigMapRef,omitempty"`
}
type LocalObjectReference struct {
Name string `json:"name"`
}
// MongoDBPodDisruptionBudget defines the struct for MongoDB cluster

View File

@ -1,5 +1,4 @@
## Append samples you want in your CSV to this file as resources ##
resources:
- _v1alpha1_mongodb.yaml
- _v1alpha1_mongodbcluster.yaml
- cluster.yaml
#+kubebuilder:scaffold:manifestskustomizesamples

View File

@ -130,6 +130,10 @@ func (o *optionBuilder) withRunningState() *optionBuilder {
return o.withState(_type.Running, -1)
}
func (o *optionBuilder) withExpandingState(retryAfter int) *optionBuilder {
return o.withState(_type.Expanding, retryAfter)
}
type stateOption struct {
state string
retryAfter int

View File

@ -23,7 +23,6 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"mongodb-operator/k8sgo/status"
"mongodb-operator/k8sgo/type"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@ -65,8 +64,40 @@ func (r *MongoDBClusterReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{RequeueAfter: time.Second * 10}, err
}
}
isValid, err := k8sgo.ValidateTLSConfig(instance)
if err != nil {
return status.Update(r.Client.Status(), instance,
statusOptions().
withMessage(Error, fmt.Sprintf("Error validating TLS config: %s", err)).
withFailedState(),
)
}
if !isValid {
return status.Update(r.Client.Status(), instance,
statusOptions().
withMessage(Info, "TLS config is not yet valid, retrying in 10 seconds").
withPendingState(10),
)
}
if err := k8sgo.EnsureTLSResources(instance); err != nil {
return status.Update(r.Client.Status(), instance,
statusOptions().
withMessage(Error, fmt.Sprintf("Error ensuring TLS resources: %s", err)).
withFailedState(),
)
}
err = k8sgo.CreateMongoClusterSetup(instance)
if err != nil {
if err.Error() == "Cannot create cluster StatefulSet for MongoDB,expanding" {
return status.Update(r.Client.Status(), instance, statusOptions().
withMessage(Info, "expanding pvc").
withExpandingState(5),
)
}
return ctrl.Result{RequeueAfter: time.Second * 10}, err
}
err = k8sgo.CreateMongoClusterMonitoringService(instance)
@ -83,8 +114,8 @@ func (r *MongoDBClusterReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
if instance.Status.State == "" {
instance.Status.State = _type.Creating
err := r.Status().Update(ctx, instance)
instance.Status.State = types.Creating
err := r.Client.Status().Update(ctx, instance)
if err != nil {
return ctrl.Result{}, err
}

View File

@ -9,14 +9,14 @@ import (
// CreateMongoClusterService is a method to create service for mongodb cluster
func CreateMongoClusterService(cr *opstreelabsinv1alpha1.MongoDBCluster) error {
logger := logGenerator(cr.ObjectMeta.Name, cr.Namespace, "Service")
appName := fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, "cluster")
appName := cr.ObjectMeta.Name
labels := map[string]string{
"app": appName,
"mongodb_setup": "cluster",
"role": "cluster",
}
params := serviceParameters{
ServiceMeta: generateObjectMetaInformation(appName, cr.Namespace, labels, generateAnnotations()),
ServiceMeta: generateObjectMetaInformation(fmt.Sprintf("%s-%s", appName, "service"), cr.Namespace, labels, generateAnnotations()),
OwnerDef: mongoClusterAsOwner(cr),
Namespace: cr.Namespace,
Labels: labels,
@ -36,7 +36,7 @@ func CreateMongoClusterService(cr *opstreelabsinv1alpha1.MongoDBCluster) error {
// CreateMongoClusterMonitoringService is a method to create a monitoring service for mongodb cluster
func CreateMongoClusterMonitoringService(cr *opstreelabsinv1alpha1.MongoDBCluster) error {
logger := logGenerator(cr.ObjectMeta.Name, cr.Namespace, "Service")
appName := fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, "cluster")
appName := cr.ObjectMeta.Name
labels := map[string]string{
"app": appName,
"mongodb_setup": "cluster",
@ -81,7 +81,7 @@ func CreateMongoClusterSetup(cr *opstreelabsinv1alpha1.MongoDBCluster) error {
// CreateMongoClusterMonitoringSecret is a method to create secret for monitoring
func CreateMongoClusterMonitoringSecret(cr *opstreelabsinv1alpha1.MongoDBCluster) error {
logger := logGenerator(cr.ObjectMeta.Name, cr.Namespace, "Secret")
err := CreateSecret(getMongoDBClusterSecretParams(cr))
err := CreateSecret(getMongoDBClusterSecretParams(cr), "password")
if err != nil {
logger.Error(err, "Cannot create mongodb monitoring secret for cluster")
return err
@ -92,19 +92,19 @@ func CreateMongoClusterMonitoringSecret(cr *opstreelabsinv1alpha1.MongoDBCluster
// getMongoDBClusterSecretParams is a method to create secret for MongoDB Monitoring
func getMongoDBClusterSecretParams(cr *opstreelabsinv1alpha1.MongoDBCluster) secretsParameters {
password := randstr.String(16)
appName := fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, "cluster-monitoring")
appName := cr.ObjectMeta.Name
labels := map[string]string{
"app": appName,
"mongodb_setup": "cluster",
"role": "cluster",
}
params := secretsParameters{
SecretsMeta: generateObjectMetaInformation(appName, cr.Namespace, labels, generateAnnotations()),
SecretsMeta: generateObjectMetaInformation(fmt.Sprintf("%s-%s", appName, "monitoring"), cr.Namespace, labels, generateAnnotations()),
OwnerDef: mongoClusterAsOwner(cr),
Namespace: cr.Namespace,
Labels: labels,
Annotations: generateAnnotations(),
Password: password,
Data: password,
Name: appName,
}
return params
@ -114,8 +114,8 @@ func getMongoDBClusterSecretParams(cr *opstreelabsinv1alpha1.MongoDBCluster) sec
func getMongoDBClusterParams(cr *opstreelabsinv1alpha1.MongoDBCluster) statefulSetParameters {
trueProperty := true
falseProperty := false
appName := fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, "cluster")
monitoringSecretName := fmt.Sprintf("%s-%s", appName, "monitoring")
appName := cr.ObjectMeta.Name
monitoringSecretName := fmt.Sprintf("%s-%s", appName, "monitoring-secret")
labels := map[string]string{
"app": appName,
"mongodb_setup": "cluster",
@ -176,19 +176,24 @@ func getMongoDBClusterParams(cr *opstreelabsinv1alpha1.MongoDBCluster) statefulS
} else {
params.ContainerParams.PersistenceEnabled = &falseProperty
}
if cr.Spec.Security.TLS.Enabled {
params.TLS = true
}
return params
}
// getPodDisruptionParams is a method to create parameters for pod disruption budget
func getPodDisruptionParams(cr *opstreelabsinv1alpha1.MongoDBCluster) PodDisruptionParameters {
appName := fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, "cluster")
appName := cr.ObjectMeta.Name
labels := map[string]string{
"app": appName,
"mongodb_setup": "cluster",
"role": "cluster",
}
params := PodDisruptionParameters{
PDBMeta: generateObjectMetaInformation(appName, cr.Namespace, labels, generateAnnotations()),
PDBMeta: generateObjectMetaInformation(fmt.Sprintf("%s-%s", appName, "Pod-Disruption"), cr.Namespace, labels, generateAnnotations()),
OwnerDef: mongoClusterAsOwner(cr),
Namespace: cr.Namespace,
Labels: labels,

15
k8sgo/configmap.go Normal file
View File

@ -0,0 +1,15 @@
package k8sgo
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// ReadData extracts the contents of the Data field in a given config map
func ReadData(namespace string, cmName string) (map[string]string, error) {
configmap, err := generateK8sClient().CoreV1().ConfigMaps(namespace).Get(context.TODO(), cmName, metav1.GetOptions{})
if err != nil {
return nil, err
}
return configmap.Data, nil
}

View File

@ -24,11 +24,12 @@ type containerParameters struct {
MonitoringResources *corev1.ResourceRequirements
ExtraVolumeMount *corev1.VolumeMount
AdditonalConfig *string
TLS bool
}
// generateContainerDef is to generate container definition for MongoDB
func generateContainerDef(name string, params containerParameters) []corev1.Container {
volumeMounts := getVolumeMount(name, params.PersistenceEnabled, params.AdditonalConfig)
volumeMounts := getVolumeMount(name, params.PersistenceEnabled, params.AdditonalConfig, params.TLS)
if params.ExtraVolumeMount != nil {
volumeMounts = append(volumeMounts, *params.ExtraVolumeMount)
}
@ -58,7 +59,7 @@ func generateContainerDef(name string, params containerParameters) []corev1.Cont
}
// getVolumeMount is a method to create volume mounting list
func getVolumeMount(name string, persistenceEnabled *bool, additionalConfig *string) []corev1.VolumeMount {
func getVolumeMount(name string, persistenceEnabled *bool, additionalConfig *string, tls bool) []corev1.VolumeMount {
var volumeMounts []corev1.VolumeMount
if persistenceEnabled != nil && *persistenceEnabled {
volumeMounts = []corev1.VolumeMount{
@ -75,6 +76,20 @@ func getVolumeMount(name string, persistenceEnabled *bool, additionalConfig *str
MountPath: "/etc/mongo.d/extra",
})
}
if tls {
// mount ca volume
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: tlsCAVolumeName,
MountPath: tlsCAMountPath,
})
// mount crt volume
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: tlsCertVolumeName,
MountPath: tlsOperatorSecretMountPath,
})
}
return volumeMounts
}

View File

@ -2,6 +2,7 @@ package k8sgo
import (
"context"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -10,7 +11,7 @@ import (
type secretsParameters struct {
Name string
OwnerDef metav1.OwnerReference
Password string
Data string
Namespace string
Labels map[string]string
Annotations map[string]string
@ -20,8 +21,8 @@ type secretsParameters struct {
}
// CreateSecret is a method to create secret
func CreateSecret(params secretsParameters) error {
secretDef := generateSecret(params)
func CreateSecret(params secretsParameters, key string) error {
secretDef := generateSecret(params, key)
logger := logGenerator(params.Name, params.Namespace, "Secret")
_, err := generateK8sClient().CoreV1().Secrets(params.Namespace).Create(context.TODO(), secretDef, metav1.CreateOptions{})
if err != nil {
@ -33,13 +34,13 @@ func CreateSecret(params secretsParameters) error {
}
// generateSecret is a method that will generate a secret interface
func generateSecret(params secretsParameters) *corev1.Secret {
password := []byte(params.Password)
func generateSecret(params secretsParameters, key string) *corev1.Secret {
data := []byte(params.Data)
secret := &corev1.Secret{
TypeMeta: generateMetaInformation("Secret", "v1"),
ObjectMeta: params.SecretsMeta,
Data: map[string][]byte{
"password": password,
key: data,
},
}
AddOwnerRefToObject(secret, params.OwnerDef)
@ -66,3 +67,28 @@ func CheckSecretExist(namespace string, secret string) bool {
}
return true
}
// ReadStringData reads the StringData field of the secret with the given objectKey
func ReadStringData(namespace string, secretName string) (map[string]string, error) {
secret, err := generateK8sClient().CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
if err != nil {
return nil, err
}
return dataToStringData(secret.Data), nil
}
func dataToStringData(data map[string][]byte) map[string]string {
stringData := make(map[string]string)
for k, v := range data {
stringData[k] = string(v)
}
return stringData
}
func ReadKey(secretName string, key string, data map[string]string) (string, error) {
if val, ok := data[key]; ok {
return val, nil
}
return "", errors.Errorf(`key "%s" not present in the Secret %s`, key, secretName)
}

87
k8sgo/secret_builder.go Normal file
View File

@ -0,0 +1,87 @@
package k8sgo
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type builder struct {
data map[string][]byte
dataType corev1.SecretType
labels map[string]string
name string
namespace string
ownerReferences []metav1.OwnerReference
}
func (b *builder) SetName(name string) *builder {
b.name = name
return b
}
func (b *builder) SetNamespace(namespace string) *builder {
b.namespace = namespace
return b
}
func (b *builder) SetField(key, value string) *builder {
b.data[key] = []byte(value)
return b
}
func (b *builder) SetOwnerReferences(ownerReferences []metav1.OwnerReference) *builder {
b.ownerReferences = ownerReferences
return b
}
func (b *builder) SetLabels(labels map[string]string) *builder {
newLabels := make(map[string]string, len(labels))
for k, v := range labels {
newLabels[k] = v
}
b.labels = newLabels
return b
}
func (b *builder) SetByteData(stringData map[string][]byte) *builder {
newStringDataBytes := make(map[string][]byte, len(stringData))
for k, v := range stringData {
newStringDataBytes[k] = v
}
b.data = newStringDataBytes
return b
}
func (b *builder) SetStringData(stringData map[string]string) *builder {
newStringDataBytes := make(map[string][]byte, len(stringData))
for k, v := range stringData {
newStringDataBytes[k] = []byte(v)
}
b.data = newStringDataBytes
return b
}
func (b *builder) SetDataType(dataType corev1.SecretType) *builder {
b.dataType = dataType
return b
}
func (b builder) Build() corev1.Secret {
return corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: b.name,
Namespace: b.namespace,
OwnerReferences: b.ownerReferences,
Labels: b.labels,
},
Data: b.data,
Type: b.dataType,
}
}
func Builder() *builder {
return &builder{
labels: map[string]string{},
data: map[string][]byte{},
ownerReferences: []metav1.OwnerReference{},
}
}

View File

@ -62,7 +62,7 @@ func CreateMongoStandaloneSetup(cr *opstreelabsinv1alpha1.MongoDB) error {
// CreateMongoMonitoringSecret is a method to create secret for monitoring
func CreateMongoMonitoringSecret(cr *opstreelabsinv1alpha1.MongoDB) error {
logger := logGenerator(cr.ObjectMeta.Name, cr.Namespace, "Secret")
err := CreateSecret(getMongoDBSecretParams(cr))
err := CreateSecret(getMongoDBSecretParams(cr), "password")
if err != nil {
logger.Error(err, "Cannot create mongodb monitoring secret")
return err
@ -85,7 +85,7 @@ func getMongoDBSecretParams(cr *opstreelabsinv1alpha1.MongoDB) secretsParameters
Namespace: cr.Namespace,
Labels: labels,
Annotations: generateAnnotations(),
Password: password,
Data: password,
Name: appName,
}
return params

View File

@ -33,6 +33,7 @@ type statefulSetParameters struct {
PriorityClassName string
AdditionalConfig *string
SecurityContext *corev1.PodSecurityContext
TLS bool
}
// pvcParameters is the structure for MongoDB PVC
@ -200,6 +201,11 @@ func generateStatefulSetDef(params statefulSetParameters) *appsv1.StatefulSet {
if params.ImagePullSecret != nil {
statefulset.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: *params.ImagePullSecret}}
}
if params.TLS {
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, getVolumeFromSecret(tlsCAVolumeName, params.StatefulSetMeta.Name+"-ca-certificate")...)
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, getVolumeFromSecret(tlsCertVolumeName, params.StatefulSetMeta.Name+"-server-certificate-key")...)
}
AddOwnerRefToObject(statefulset, params.OwnerDef)
return statefulset
}

239
k8sgo/tls.go Normal file
View File

@ -0,0 +1,239 @@
package k8sgo
import (
"crypto/sha256"
"fmt"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
opstreelabsinv1alpha1 "mongodb-operator/api/v1alpha1"
"strings"
)
const (
tlsCAMountPath = "/var/lib/tls/ca/"
tlsCACertName = "ca.crt"
tlsOperatorSecretMountPath = "/var/lib/tls/server/" //nolint
tlsSecretCertName = "tls.crt" //nolint
tlsSecretKeyName = "tls.key"
tlsSecretPemName = "tls.pem"
tlsCAVolumeName = "tls-ca"
tlsCertVolumeName = "tls-secret"
)
func ValidateTLSConfig(instance *opstreelabsinv1alpha1.MongoDBCluster) (bool, error) {
if !instance.Spec.Security.TLS.Enabled {
return true, nil
}
log.Info("Ensuring TLS is correctly configured")
// Ensure CA cert is configured
_, err := getCaCrt(instance)
if err != nil {
if apiErrors.IsNotFound(err) {
log.Error(err, "CA resource not found")
return false, nil
}
return false, err
}
// Ensure Secret exists
_, err = ReadStringData(instance.Namespace, instance.Spec.Security.TLS.CertificateKeySecret.Name)
if err != nil {
if apiErrors.IsNotFound(err) {
log.Error(err, "CertificateKeySecret not found")
return false, nil
}
return false, err
}
// validate whether the secret contains "tls.crt" and "tls.key", or it contains "tls.pem"
// if it contains all three, then the pem entry should be equal to the concatenation of crt and key
_, err = getPemOrConcatenatedCrtAndKey(instance, instance.Spec.Security.TLS.CertificateKeySecret.Name)
if err != nil {
return false, err
}
log.Info("Successfully validated TLS config")
return true, nil
}
func getCaCrt(instance *opstreelabsinv1alpha1.MongoDBCluster) (string, error) {
var caData map[string]string
var err error
if instance.Spec.Security.TLS.CaCertificateSecret != nil {
caData, err = ReadStringData(instance.Namespace, instance.Spec.Security.TLS.CaCertificateSecret.Name)
} else {
caData, err = ReadData(instance.Namespace, instance.Spec.Security.TLS.CaConfigMap.Name)
}
if err != nil {
return "", err
}
if cert, ok := caData[tlsCACertName]; !ok || cert == "" {
return "", errors.New("CA certificate resource should have a CA certificate in field ")
} else {
return cert, nil
}
}
// getPemOrConcatenatedCrtAndKey will get the final PEM to write to the secret.
// This is either the tls.pem entry in the given secret, or the concatenation
// of tls.crt and tls.key
// It performs a basic validation on the entries.
func getPemOrConcatenatedCrtAndKey(instance *opstreelabsinv1alpha1.MongoDBCluster, secretName string) (string, error) {
data, err := ReadStringData(instance.Namespace, secretName)
if err != nil {
return "", err
}
certKey := getCertAndKey(data, secretName)
pem := getPem(data, secretName)
if certKey == "" && pem == "" {
return "", fmt.Errorf(`neither "%s" nor the pair "%s"/"%s" were present in the TLS secret`, tlsSecretPemName, tlsSecretCertName, tlsSecretKeyName)
}
if certKey == "" {
return pem, nil
}
if pem == "" {
return certKey, nil
}
if certKey != pem {
return "", fmt.Errorf(`if all of "%s", "%s" and "%s" are present in the secret, the entry for "%s" must be equal to the concatenation of "%s" with "%s"`, tlsSecretCertName, tlsSecretKeyName, tlsSecretPemName, tlsSecretPemName, tlsSecretCertName, tlsSecretKeyName)
}
return certKey, nil
}
// getCertAndKey will fetch the certificate and key from the user-provided Secret.
func getCertAndKey(data map[string]string, secretName string) string {
cert, err := ReadKey(secretName, tlsSecretCertName, data)
if err != nil {
return ""
}
key, err := ReadKey(secretName, tlsSecretKeyName, data)
if err != nil {
return ""
}
return combineCertificateAndKey(cert, key)
}
func combineCertificateAndKey(cert, key string) string {
trimmedCert := strings.TrimRight(cert, "\n")
trimmedKey := strings.TrimRight(key, "\n")
return fmt.Sprintf("%s\n%s", trimmedCert, trimmedKey)
}
// getPem will fetch the pem from the user-provided secret
func getPem(data map[string]string, secretName string) string {
pem, err := ReadKey(secretName, tlsSecretPemName, data)
if err != nil {
return ""
}
return pem
}
// ensureTLSResources creates any required TLS resources that the MongoDBCommunity
// requires for TLS configuration.
func EnsureTLSResources(instance *opstreelabsinv1alpha1.MongoDBCluster) error {
if !instance.Spec.Security.TLS.Enabled {
return nil
}
// the TLS secret needs to be created beforehand, as both the StatefulSet and AutomationConfig
// require the contents.
log.Info("TLS is enabled, creating/updating CA secret")
if err := ensureCASecret(instance); err != nil {
return errors.Errorf("could not ensure CA secret: %s", err)
}
log.Info("TLS is enabled, creating/updating TLS secret")
if err := ensureTLSSecret(instance); err != nil {
return errors.Errorf("could not ensure TLS secret: %s", err)
}
return nil
}
// ensureCASecret will create or update the operator managed Secret containing
// the CA certficate from the user provided Secret or ConfigMap.
func ensureCASecret(instance *opstreelabsinv1alpha1.MongoDBCluster) error {
cert, err := getCaCrt(instance)
if err != nil {
return err
}
//caFileName := tlsOperatorSecretFileName(cert)
labels := map[string]string{
"app": instance.Name,
"mongodb_setup": "cluster",
"role": "cluster",
}
params := secretsParameters{
SecretsMeta: generateObjectMetaInformation(instance.Name, instance.Namespace, labels, generateAnnotations()),
OwnerDef: mongoClusterAsOwner(instance),
Namespace: instance.Namespace,
Labels: labels,
Annotations: generateAnnotations(),
Name: instance.Name + "-ca-certificate",
Data: cert,
}
return CreateSecret(params, tlsCACertName)
}
// ensureTLSSecret will create or update the operator-managed Secret containing
// the concatenated certificate and key from the user-provided Secret.
func ensureTLSSecret(instance *opstreelabsinv1alpha1.MongoDBCluster) error {
certKey, err := getPemOrConcatenatedCrtAndKey(instance, instance.Spec.Security.TLS.CertificateKeySecret.Name)
if err != nil {
return err
}
// Calculate file name from certificate and key
//fileName := tlsOperatorSecretFileName(certKey)
labels := map[string]string{
"app": instance.Name,
"mongodb_setup": "cluster",
"role": "cluster",
}
params := secretsParameters{
SecretsMeta: generateObjectMetaInformation(instance.Name, instance.Namespace, labels, generateAnnotations()),
OwnerDef: mongoClusterAsOwner(instance),
Namespace: instance.Namespace,
Labels: labels,
Annotations: generateAnnotations(),
Name: instance.Name + "-server-certificate-key",
Data: certKey,
}
return CreateSecret(params, tlsSecretCertName)
}
// tlsOperatorSecretFileName calculates the file name to use for the mounted
// certificate-key file. The name is based on the hash of the combined cert and key.
// If the certificate or key changes, the file path changes as well which will trigger
// the agent to perform a restart.
// The user-provided secret is being watched and will trigger a reconciliation
// on changes. This enables the operator to automatically handle cert rotations.
func tlsOperatorSecretFileName(certKey string) string {
hash := sha256.Sum256([]byte(certKey))
return fmt.Sprintf("%x.pem", hash)
}
func getVolumeFromSecret(volumeName, secretName string) []corev1.Volume {
permission := int32(416)
return []corev1.Volume{
{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secretName,
DefaultMode: &permission,
},
},
},
}
}