diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index cf21948497dd..3a6f2454ab20 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -1,5 +1,7 @@ ## Main +- [11708](https://github.com/grafana/loki/pull/11708) **btaani**: Add support for Swift TLS CA configuration + ## 0.6.0 (2024-03-19) - [12228](https://github.com/grafana/loki/pull/12228) **xperimental**: Restructure LokiStack metrics diff --git a/operator/internal/manifests/storage/configure.go b/operator/internal/manifests/storage/configure.go index b1c8a0df955a..3e790e996c8b 100644 --- a/operator/internal/manifests/storage/configure.go +++ b/operator/internal/manifests/storage/configure.go @@ -29,17 +29,23 @@ var ( // based on the object storage type. Currently supported amendments: // - All: Ensure object storage secret mounted and auth projected as env vars. // - GCS: Ensure env var GOOGLE_APPLICATION_CREDENTIALS in container -// - S3: Ensure mounting custom CA configmap if any TLSConfig given +// - S3 & Swift: Ensure mounting custom CA configmap if any TLSConfig given func ConfigureDeployment(d *appsv1.Deployment, opts Options) error { switch opts.SharedStore { - case lokiv1.ObjectStorageSecretAlibabaCloud, lokiv1.ObjectStorageSecretAzure, lokiv1.ObjectStorageSecretGCS, lokiv1.ObjectStorageSecretSwift: + case lokiv1.ObjectStorageSecretAlibabaCloud, lokiv1.ObjectStorageSecretAzure, lokiv1.ObjectStorageSecretGCS: return configureDeployment(d, opts) case lokiv1.ObjectStorageSecretS3: err := configureDeployment(d, opts) if err != nil { return err } - return configureDeploymentCA(d, opts.TLS) + return configureDeploymentCA(d, opts.TLS, lokiv1.ObjectStorageSecretS3) + case lokiv1.ObjectStorageSecretSwift: + err := configureDeployment(d, opts) + if err != nil { + return err + } + return configureDeploymentCA(d, opts.TLS, lokiv1.ObjectStorageSecretSwift) default: return nil } @@ -49,16 +55,21 @@ func ConfigureDeployment(d *appsv1.Deployment, opts Options) error { // based on the object storage type. Currently supported amendments: // - All: Ensure object storage secret mounted and auth projected as env vars. // - GCS: Ensure env var GOOGLE_APPLICATION_CREDENTIALS in container -// - S3: Ensure mounting custom CA configmap if any TLSConfig given +// - S3 & Swift: Ensure mounting custom CA configmap if any TLSConfig given func ConfigureStatefulSet(d *appsv1.StatefulSet, opts Options) error { switch opts.SharedStore { - case lokiv1.ObjectStorageSecretAlibabaCloud, lokiv1.ObjectStorageSecretAzure, lokiv1.ObjectStorageSecretGCS, lokiv1.ObjectStorageSecretSwift: + case lokiv1.ObjectStorageSecretAlibabaCloud, lokiv1.ObjectStorageSecretAzure, lokiv1.ObjectStorageSecretGCS: return configureStatefulSet(d, opts) case lokiv1.ObjectStorageSecretS3: if err := configureStatefulSet(d, opts); err != nil { return err } - return configureStatefulSetCA(d, opts.TLS) + return configureStatefulSetCA(d, opts.TLS, lokiv1.ObjectStorageSecretS3) + case lokiv1.ObjectStorageSecretSwift: + if err := configureStatefulSet(d, opts); err != nil { + return err + } + return configureStatefulSetCA(d, opts.TLS, lokiv1.ObjectStorageSecretSwift) default: return nil } @@ -75,16 +86,22 @@ func configureDeployment(d *appsv1.Deployment, opts Options) error { return nil } -// ConfigureDeploymentCA merges a S3 CA ConfigMap volume into the deployment spec. -func configureDeploymentCA(d *appsv1.Deployment, tls *TLSConfig) error { +// ConfigureDeploymentCA merges a S3 or Swift CA ConfigMap volume into the deployment spec. +func configureDeploymentCA(d *appsv1.Deployment, tls *TLSConfig, secretType lokiv1.ObjectStorageSecretType) error { if tls == nil { return nil } - p := ensureCAForS3(&d.Spec.Template.Spec, tls) + var p corev1.PodSpec + switch secretType { + case lokiv1.ObjectStorageSecretS3: + p = ensureCAForObjectStorage(&d.Spec.Template.Spec, tls, lokiv1.ObjectStorageSecretS3) + case lokiv1.ObjectStorageSecretSwift: + p = ensureCAForObjectStorage(&d.Spec.Template.Spec, tls, lokiv1.ObjectStorageSecretSwift) + } if err := mergo.Merge(&d.Spec.Template.Spec, p, mergo.WithOverride); err != nil { - return kverrors.Wrap(err, "failed to merge s3 object storage ca options ") + return kverrors.Wrap(err, "failed to merge object storage ca options ") } return nil @@ -101,16 +118,22 @@ func configureStatefulSet(s *appsv1.StatefulSet, opts Options) error { return nil } -// ConfigureStatefulSetCA merges a S3 CA ConfigMap volume into the statefulset spec. -func configureStatefulSetCA(s *appsv1.StatefulSet, tls *TLSConfig) error { +// ConfigureStatefulSetCA merges a S3 or Swift CA ConfigMap volume into the statefulset spec. +func configureStatefulSetCA(s *appsv1.StatefulSet, tls *TLSConfig, secretType lokiv1.ObjectStorageSecretType) error { if tls == nil { return nil } + var p corev1.PodSpec - p := ensureCAForS3(&s.Spec.Template.Spec, tls) + switch secretType { + case lokiv1.ObjectStorageSecretS3: + p = ensureCAForObjectStorage(&s.Spec.Template.Spec, tls, lokiv1.ObjectStorageSecretS3) + case lokiv1.ObjectStorageSecretSwift: + p = ensureCAForObjectStorage(&s.Spec.Template.Spec, tls, lokiv1.ObjectStorageSecretSwift) + } if err := mergo.Merge(&s.Spec.Template.Spec, p, mergo.WithOverride); err != nil { - return kverrors.Wrap(err, "failed to merge s3 object storage ca options ") + return kverrors.Wrap(err, "failed to merge object storage ca options ") } return nil @@ -246,7 +269,7 @@ func serverSideEncryption(opts Options) []corev1.EnvVar { } } -func ensureCAForS3(p *corev1.PodSpec, tls *TLSConfig) corev1.PodSpec { +func ensureCAForObjectStorage(p *corev1.PodSpec, tls *TLSConfig, secretType lokiv1.ObjectStorageSecretType) corev1.PodSpec { container := p.Containers[0].DeepCopy() volumes := p.Volumes @@ -267,9 +290,16 @@ func ensureCAForS3(p *corev1.PodSpec, tls *TLSConfig) corev1.PodSpec { MountPath: caDirectory, }) - container.Args = append(container.Args, - fmt.Sprintf("-s3.http.ca-file=%s", path.Join(caDirectory, tls.Key)), - ) + switch secretType { + case lokiv1.ObjectStorageSecretS3: + container.Args = append(container.Args, + fmt.Sprintf("-s3.http.ca-file=%s", path.Join(caDirectory, tls.Key)), + ) + case lokiv1.ObjectStorageSecretSwift: + container.Args = append(container.Args, + fmt.Sprintf("-swift.http.ca-file=%s", path.Join(caDirectory, tls.Key)), + ) + } return corev1.PodSpec{ Containers: []corev1.Container{ diff --git a/operator/internal/manifests/storage/configure_test.go b/operator/internal/manifests/storage/configure_test.go index f9aed80a00fd..3d82c2e73ec6 100644 --- a/operator/internal/manifests/storage/configure_test.go +++ b/operator/internal/manifests/storage/configure_test.go @@ -2505,6 +2505,102 @@ func TestConfigureDeploymentForStorageCA(t *testing.T) { }, }, }, + { + desc: "object storage Swift", + opts: Options{ + SecretName: "test", + SharedStore: lokiv1.ObjectStorageSecretSwift, + TLS: &TLSConfig{ + CA: "test", + Key: "service-ca.crt", + }, + }, + dpl: &appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "loki-querier", + }, + }, + }, + }, + }, + }, + want: &appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "loki-querier", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "test", + ReadOnly: false, + MountPath: "/etc/storage/secrets", + }, + { + Name: "storage-tls", + ReadOnly: false, + MountPath: "/etc/storage/ca", + }, + }, + Args: []string{ + "-swift.http.ca-file=/etc/storage/ca/service-ca.crt", + }, + Env: []corev1.EnvVar{ + { + Name: EnvSwiftUsername, + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + Key: KeySwiftUsername, + }, + }, + }, + { + Name: EnvSwiftPassword, + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + Key: KeySwiftPassword, + }, + }, + }, + }, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "test", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "test", + }, + }, + }, + { + Name: "storage-tls", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for _, tc := range tc { @@ -2531,7 +2627,7 @@ func TestConfigureStatefulSetForStorageCA(t *testing.T) { desc: "object storage other than S3", opts: Options{ SecretName: "test", - SharedStore: lokiv1.ObjectStorageSecretSwift, + SharedStore: lokiv1.ObjectStorageSecretAzure, TLS: &TLSConfig{ CA: "test", }, @@ -2565,24 +2661,24 @@ func TestConfigureStatefulSetForStorageCA(t *testing.T) { }, Env: []corev1.EnvVar{ { - Name: EnvSwiftUsername, + Name: EnvAzureStorageAccountName, ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: "test", }, - Key: KeySwiftUsername, + Key: KeyAzureStorageAccountName, }, }, }, { - Name: EnvSwiftPassword, + Name: EnvAzureStorageAccountKey, ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: "test", }, - Key: KeySwiftPassword, + Key: KeyAzureStorageAccountKey, }, }, }, @@ -2700,6 +2796,102 @@ func TestConfigureStatefulSetForStorageCA(t *testing.T) { }, }, }, + { + desc: "object storage Swift", + opts: Options{ + SecretName: "test", + SharedStore: lokiv1.ObjectStorageSecretSwift, + TLS: &TLSConfig{ + CA: "test", + Key: "service-ca.crt", + }, + }, + sts: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "loki-ingester", + }, + }, + }, + }, + }, + }, + want: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "loki-ingester", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "test", + ReadOnly: false, + MountPath: "/etc/storage/secrets", + }, + { + Name: "storage-tls", + ReadOnly: false, + MountPath: "/etc/storage/ca", + }, + }, + Args: []string{ + "-swift.http.ca-file=/etc/storage/ca/service-ca.crt", + }, + Env: []corev1.EnvVar{ + { + Name: EnvSwiftUsername, + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + Key: KeySwiftUsername, + }, + }, + }, + { + Name: EnvSwiftPassword, + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + Key: KeySwiftPassword, + }, + }, + }, + }, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "test", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "test", + }, + }, + }, + { + Name: "storage-tls", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for _, tc := range tc {