diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index e220f2c146275..a93f3afd03b37 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -2,6 +2,7 @@ ## Release 5.9.1 +- [12469](https://github.com/grafana/loki/pull/12469) **btaani**: Configure Loki to use virtual-host-style URLs for S3 AWS endpoints - [12181](https://github.com/grafana/loki/pull/12181) **btaani**: Improve validation of provided S3 storage configuration - [12370](https://github.com/grafana/loki/pull/12370) **periklis**: Update Loki operand to v2.9.6 - [12333](https://github.com/grafana/loki/pull/12333) **periklis**: Bump max OpenShift version to next release diff --git a/operator/internal/handlers/internal/storage/secrets.go b/operator/internal/handlers/internal/storage/secrets.go index 63b6857068a0c..6c0c116009ac1 100644 --- a/operator/internal/handlers/internal/storage/secrets.go +++ b/operator/internal/handlers/internal/storage/secrets.go @@ -403,7 +403,8 @@ func extractS3ConfigSecret(s *corev1.Secret, credentialMode lokiv1.CredentialMod roleArn = s.Data[storage.KeyAWSRoleArn] audience = s.Data[storage.KeyAWSAudience] // Optional fields - region = s.Data[storage.KeyAWSRegion] + region = s.Data[storage.KeyAWSRegion] + forcePathStyle = !strings.HasSuffix(string(endpoint), awsEndpointSuffix) ) sseCfg, err := extractS3SSEConfig(s.Data) @@ -412,9 +413,10 @@ func extractS3ConfigSecret(s *corev1.Secret, credentialMode lokiv1.CredentialMod } cfg := &storage.S3StorageConfig{ - Buckets: string(buckets), - Region: string(region), - SSE: sseCfg, + Buckets: string(buckets), + Region: string(region), + SSE: sseCfg, + ForcePathStyle: forcePathStyle, } switch credentialMode { diff --git a/operator/internal/handlers/internal/storage/secrets_test.go b/operator/internal/handlers/internal/storage/secrets_test.go index 764f87ef85689..f46a471f1b80d 100644 --- a/operator/internal/handlers/internal/storage/secrets_test.go +++ b/operator/internal/handlers/internal/storage/secrets_test.go @@ -9,6 +9,7 @@ import ( configv1 "github.com/grafana/loki/operator/apis/config/v1" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests/storage" ) func TestHashSecretData(t *testing.T) { @@ -561,6 +562,62 @@ func TestS3Extract(t *testing.T) { } } +func TestS3Extract_S3ForcePathStyle(t *testing.T) { + tt := []struct { + desc string + secret *corev1.Secret + wantOptions *storage.S3StorageConfig + }{ + { + desc: "aws s3 endpoint", + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Data: map[string][]byte{ + "endpoint": []byte("https://s3.region.amazonaws.com"), + "region": []byte("region"), + "bucketnames": []byte("this,that"), + "access_key_id": []byte("id"), + "access_key_secret": []byte("secret"), + }, + }, + wantOptions: &storage.S3StorageConfig{ + Endpoint: "https://s3.region.amazonaws.com", + Region: "region", + Buckets: "this,that", + }, + }, + { + desc: "non-aws s3 endpoint", + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Data: map[string][]byte{ + "endpoint": []byte("https://test.default.svc.cluster.local:9000"), + "region": []byte("region"), + "bucketnames": []byte("this,that"), + "access_key_id": []byte("id"), + "access_key_secret": []byte("secret"), + }, + }, + wantOptions: &storage.S3StorageConfig{ + Endpoint: "https://test.default.svc.cluster.local:9000", + Region: "region", + Buckets: "this,that", + ForcePathStyle: true, + }, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + options, err := extractS3ConfigSecret(tc.secret, lokiv1.CredentialModeStatic) + require.NoError(t, err) + require.Equal(t, tc.wantOptions, options) + }) + } +} + func TestS3Extract_WithOpenShiftTokenCCOAuth(t *testing.T) { fg := configv1.FeatureGates{ OpenShift: configv1.OpenShiftFeatureGates{ diff --git a/operator/internal/manifests/internal/config/build_test.go b/operator/internal/manifests/internal/config/build_test.go index 53650429196e0..4f057adee5b64 100644 --- a/operator/internal/manifests/internal/config/build_test.go +++ b/operator/internal/manifests/internal/config/build_test.go @@ -25,7 +25,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -245,9 +245,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -282,7 +283,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -592,9 +593,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -676,9 +678,10 @@ func TestBuild_ConfigAndRuntimeConfig_CreateLokiConfigFailed(t *testing.T) { ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -707,7 +710,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -1028,9 +1031,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -1065,7 +1069,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -1387,9 +1391,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -1424,7 +1429,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -1776,9 +1781,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -1813,7 +1819,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -2111,9 +2117,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -2151,7 +2158,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -2533,9 +2540,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -2570,7 +2578,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -2879,9 +2887,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -2916,7 +2925,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -3375,9 +3384,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -3412,7 +3422,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -3635,9 +3645,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -3672,7 +3683,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -3897,9 +3908,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -3934,7 +3946,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -4157,9 +4169,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -4194,7 +4207,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -4454,9 +4467,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, SSE: storage.S3SSEConfig{ Type: storage.SSEKMSType, @@ -4496,7 +4510,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -4753,9 +4767,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, SSE: storage.S3SSEConfig{ Type: storage.SSES3Type, @@ -4795,7 +4810,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} @@ -5011,9 +5026,10 @@ overrides: ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -5100,9 +5116,10 @@ func defaultOptions() Options { ObjectStorage: storage.Options{ SharedStore: lokiv1.ObjectStorageSecretS3, S3: &storage.S3StorageConfig{ - Endpoint: "http://test.default.svc.cluster.local.:9000", - Region: "us-east", - Buckets: "loki", + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, }, Schemas: []lokiv1.ObjectStorageSchema{ { @@ -5284,7 +5301,7 @@ chunk_store_config: common: storage: s3: - s3: http://test.default.svc.cluster.local.:9000 + endpoint: http://test.default.svc.cluster.local.:9000 bucketnames: loki region: us-east access_key_id: ${AWS_ACCESS_KEY_ID} diff --git a/operator/internal/manifests/internal/config/loki-config.yaml b/operator/internal/manifests/internal/config/loki-config.yaml index 2b29c51806cf7..3df0ac7463881 100644 --- a/operator/internal/manifests/internal/config/loki-config.yaml +++ b/operator/internal/manifests/internal/config/loki-config.yaml @@ -33,12 +33,14 @@ common: region: {{.Region}} s3forcepathstyle: false {{- else }} - s3: {{ .Endpoint }} + endpoint: {{ .Endpoint }} bucketnames: {{ .Buckets }} region: {{ .Region }} access_key_id: ${AWS_ACCESS_KEY_ID} secret_access_key: ${AWS_ACCESS_KEY_SECRET} + {{- if .ForcePathStyle }} s3forcepathstyle: true + {{- end}} {{- end }} {{- with .SSE }} {{- if .Type }} diff --git a/operator/internal/manifests/storage/options.go b/operator/internal/manifests/storage/options.go index 47779ce554793..1f8d3d904b71a 100644 --- a/operator/internal/manifests/storage/options.go +++ b/operator/internal/manifests/storage/options.go @@ -42,12 +42,13 @@ type GCSStorageConfig struct { // S3StorageConfig for S3 storage config type S3StorageConfig struct { - Endpoint string - Region string - Buckets string - Audience string - STS bool - SSE S3SSEConfig + Endpoint string + Region string + Buckets string + Audience string + STS bool + SSE S3SSEConfig + ForcePathStyle bool } type S3SSEType string