diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml index 7040c3d061..1fff93a202 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml @@ -136,9 +136,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml index 0f4f6e635b..2cb734bdeb 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml @@ -97,9 +97,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 6f197adcff..c64edd17e0 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -361,9 +361,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object main: type: boolean diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 5b9ac149ac..25a961b93d 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -140,9 +140,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -378,9 +379,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -1248,9 +1250,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object main: type: boolean diff --git a/deploy/crd.yaml b/deploy/crd.yaml index 64fc72478a..b4003c02f8 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -140,9 +140,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -378,9 +379,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -1248,9 +1250,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object main: type: boolean diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index cc126dccb1..a25126cfce 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -140,9 +140,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -378,9 +379,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -1248,9 +1250,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object main: type: boolean diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index 64fc72478a..b4003c02f8 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -140,9 +140,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -378,9 +379,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object lastTransition: format: date-time @@ -1248,9 +1250,10 @@ spec: - backoffMax - backoffMultiplier type: object + workloadIdentity: + type: boolean required: - bucket - - credentialsSecret type: object main: type: boolean diff --git a/go.mod b/go.mod index b9d03afbc2..25d19ed62e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/percona/percona-server-mongodb-operator -go 1.25.1 +go 1.25.5 require ( github.com/Percona-Lab/percona-version-service v0.0.0-20230216094301-f9489c81b52a @@ -20,7 +20,7 @@ require ( github.com/hashicorp/vault/api/auth/kubernetes v0.10.0 github.com/onsi/ginkgo/v2 v2.28.1 github.com/onsi/gomega v1.39.1 - github.com/percona/percona-backup-mongodb v1.8.1-0.20251104101930-05ab6d7e1004 + github.com/percona/percona-backup-mongodb v1.8.1-0.20260211104648-63ec17219d7c github.com/pkg/errors v0.9.1 github.com/robfig/cron/v3 v3.0.1 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 38cb54058b..23874d4ae0 100644 --- a/go.sum +++ b/go.sum @@ -420,6 +420,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/percona/percona-backup-mongodb v1.8.1-0.20251104101930-05ab6d7e1004 h1:Q/HeUxMI63ekZYY0TlnfF0Vp3WZ0mmx7gI9iBzehjeY= github.com/percona/percona-backup-mongodb v1.8.1-0.20251104101930-05ab6d7e1004/go.mod h1:NYc9wcoGLNXmOHwfsaed+Ej3nxv3dUViHOcCfQneJ84= +github.com/percona/percona-backup-mongodb v1.8.1-0.20260211104648-63ec17219d7c h1:DWISfU16p/4WseJ+j4Rb61MAp7CBx1Rsffbg0KCV/5A= +github.com/percona/percona-backup-mongodb v1.8.1-0.20260211104648-63ec17219d7c/go.mod h1:YZ6ek2JZEGcuR228HoRXQYjm5Icu5Fg5qX46voUfI8k= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index e1bee7ea6a..a0b47f3862 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -1286,7 +1286,8 @@ type GCSRetryer struct { type BackupStorageGCSSpec struct { Bucket string `json:"bucket"` Prefix string `json:"prefix,omitempty"` - CredentialsSecret string `json:"credentialsSecret"` + WorkloadIdentity bool `json:"workloadIdentity,omitempty"` + CredentialsSecret string `json:"credentialsSecret,omitempty"` ChunkSize int `json:"chunkSize,omitempty"` Retryer *GCSRetryer `json:"retryer,omitempty"` } diff --git a/pkg/controller/perconaservermongodbbackup/psmdb_backup_controller.go b/pkg/controller/perconaservermongodbbackup/psmdb_backup_controller.go index 86150a6d6d..d1c0db7de3 100644 --- a/pkg/controller/perconaservermongodbbackup/psmdb_backup_controller.go +++ b/pkg/controller/perconaservermongodbbackup/psmdb_backup_controller.go @@ -327,7 +327,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, EndpointURL: cr.Status.Azure.EndpointURL, Prefix: cr.Status.Azure.Prefix, Credentials: azure.Credentials{ - Key: string(azureSecret.Data[backup.AzureStorageAccountKeySecretKey]), + Key: storage.MaskedString(azureSecret.Data[backup.AzureStorageAccountKeySecretKey]), }, } return azure.New(azureConf, "", nil) @@ -344,8 +344,8 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, return nil, errors.Wrap(err, "get gcs credentials secret") } gcsConf.Credentials = gcs.Credentials{ - ClientEmail: string(gcsSecret.Data[backup.GCSClientEmailSecretKey]), - PrivateKey: string(gcsSecret.Data[backup.GCSPrivateKeySecretKey]), + ClientEmail: storage.MaskedString(gcsSecret.Data[backup.GCSClientEmailSecretKey]), + PrivateKey: storage.MaskedString(gcsSecret.Data[backup.GCSPrivateKeySecretKey]), } } @@ -369,8 +369,8 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, return nil, errors.Wrap(err, "get s3 credentials secret") } s3Conf.Credentials = s3.Credentials{ - AccessKeyID: string(s3secret.Data[backup.AWSAccessKeySecretKey]), - SecretAccessKey: string(s3secret.Data[backup.AWSSecretAccessKeySecretKey]), + AccessKeyID: storage.MaskedString(s3secret.Data[backup.AWSAccessKeySecretKey]), + SecretAccessKey: storage.MaskedString(s3secret.Data[backup.AWSSecretAccessKeySecretKey]), } } @@ -388,8 +388,8 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, } gcsConf.Credentials = gcs.Credentials{ - HMACAccessKey: string(gcsSecret.Data[backup.AWSAccessKeySecretKey]), - HMACSecret: string(gcsSecret.Data[backup.AWSSecretAccessKeySecretKey]), + HMACAccessKey: storage.MaskedString(gcsSecret.Data[backup.AWSAccessKeySecretKey]), + HMACSecret: storage.MaskedString(gcsSecret.Data[backup.AWSSecretAccessKeySecretKey]), } } @@ -401,7 +401,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, case len(cr.Status.S3.ServerSideEncryption.SSECustomerKey) != 0: s3Conf.ServerSideEncryption = &s3.AWSsse{ SseCustomerAlgorithm: cr.Status.S3.ServerSideEncryption.SSECustomerAlgorithm, - SseCustomerKey: cr.Status.S3.ServerSideEncryption.SSECustomerKey, + SseCustomerKey: storage.MaskedString(cr.Status.S3.ServerSideEncryption.SSECustomerKey), } case len(cluster.Spec.Secrets.SSE) != 0: sseSecret, err := secret(ctx, r.client, cr.Namespace, cluster.Spec.Secrets.SSE) @@ -410,7 +410,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, } s3Conf.ServerSideEncryption = &s3.AWSsse{ SseCustomerAlgorithm: cr.Status.S3.ServerSideEncryption.SSECustomerAlgorithm, - SseCustomerKey: string(sseSecret.Data[backup.SSECustomerKey]), + SseCustomerKey: storage.MaskedString(sseSecret.Data[backup.SSECustomerKey]), } default: return nil, errors.New("no SseCustomerKey specified") @@ -463,8 +463,8 @@ func (r *ReconcilePerconaServerMongoDBBackup) getPBMStorage(ctx context.Context, return nil, errors.Wrap(err, "get minio credentials secret") } minioConf.Credentials = mio.Credentials{ - AccessKeyID: string(minioSecret.Data[backup.AWSAccessKeySecretKey]), - SecretAccessKey: string(minioSecret.Data[backup.AWSSecretAccessKeySecretKey]), + AccessKeyID: storage.MaskedString(minioSecret.Data[backup.AWSAccessKeySecretKey]), + SecretAccessKey: storage.MaskedString(minioSecret.Data[backup.AWSSecretAccessKeySecretKey]), } } return mio.New(minioConf, "", nil) diff --git a/pkg/psmdb/backup/pbm.go b/pkg/psmdb/backup/pbm.go index 7d563f79d4..c798ba0cd2 100644 --- a/pkg/psmdb/backup/pbm.go +++ b/pkg/psmdb/backup/pbm.go @@ -376,8 +376,8 @@ func GetPBMStorageMinioConfig( } storageConf.Minio.Credentials = mio.Credentials{ - AccessKeyID: string(accessKey), - SecretAccessKey: string(secretAccessKey), + AccessKeyID: storage.MaskedString(accessKey), + SecretAccessKey: storage.MaskedString(secretAccessKey), } } @@ -421,7 +421,7 @@ func GetPBMStorageS3Config( case len(stg.S3.ServerSideEncryption.SSECustomerKey) != 0: storageConf.S3.ServerSideEncryption = &s3.AWSsse{ SseCustomerAlgorithm: stg.S3.ServerSideEncryption.SSECustomerAlgorithm, - SseCustomerKey: stg.S3.ServerSideEncryption.SSECustomerKey, + SseCustomerKey: storage.MaskedString(stg.S3.ServerSideEncryption.SSECustomerKey), } case len(cluster.Spec.Secrets.SSE) != 0: sseSecret, err := getSecret(ctx, k8sclient, cluster.Namespace, cluster.Spec.Secrets.SSE) @@ -430,7 +430,7 @@ func GetPBMStorageS3Config( } storageConf.S3.ServerSideEncryption = &s3.AWSsse{ SseCustomerAlgorithm: stg.S3.ServerSideEncryption.SSECustomerAlgorithm, - SseCustomerKey: string(sseSecret.Data[SSECustomerKey]), + SseCustomerKey: storage.MaskedString(sseSecret.Data[SSECustomerKey]), } default: return storageConf, errors.New("no SseCustomerKey specified") @@ -459,8 +459,8 @@ func GetPBMStorageS3Config( } } storageConf.S3.Credentials = s3.Credentials{ - AccessKeyID: string(s3secret.Data[AWSAccessKeySecretKey]), - SecretAccessKey: string(s3secret.Data[AWSSecretAccessKeySecretKey]), + AccessKeyID: storage.MaskedString(s3secret.Data[AWSAccessKeySecretKey]), + SecretAccessKey: storage.MaskedString(s3secret.Data[AWSSecretAccessKeySecretKey]), } } @@ -499,9 +499,17 @@ func GetPBMStorageGCSConfig( Bucket: stg.GCS.Bucket, Prefix: stg.GCS.Prefix, ChunkSize: stg.GCS.ChunkSize, + Credentials: gcs.Credentials{ + WorkloadIdentity: stg.GCS.WorkloadIdentity, + }, }, } + if !stg.GCS.WorkloadIdentity && stg.GCS.CredentialsSecret == "" { + msg := "either workloadIdentity must be enabled or credentialsSecret must be specified for GCS storage" + return config.StorageConf{}, errors.New(msg) + } + if stg.GCS.CredentialsSecret != "" { gcsSecret, err := getSecret(ctx, k8sclient, cluster.Namespace, stg.GCS.CredentialsSecret) if err != nil { @@ -510,16 +518,16 @@ func GetPBMStorageGCSConfig( if _, ok := gcsSecret.Data[GCSClientEmailSecretKey]; ok { storageConf.GCS.Credentials = gcs.Credentials{ - ClientEmail: string(gcsSecret.Data[GCSClientEmailSecretKey]), - PrivateKey: string(gcsSecret.Data[GCSPrivateKeySecretKey]), + ClientEmail: storage.MaskedString(gcsSecret.Data[GCSClientEmailSecretKey]), + PrivateKey: storage.MaskedString(gcsSecret.Data[GCSPrivateKeySecretKey]), } } // s3 compatibility if _, ok := gcsSecret.Data[AWSAccessKeySecretKey]; ok { storageConf.GCS.Credentials = gcs.Credentials{ - HMACAccessKey: string(gcsSecret.Data[AWSAccessKeySecretKey]), - HMACSecret: string(gcsSecret.Data[AWSSecretAccessKeySecretKey]), + HMACAccessKey: storage.MaskedString(gcsSecret.Data[AWSAccessKeySecretKey]), + HMACSecret: storage.MaskedString(gcsSecret.Data[AWSSecretAccessKeySecretKey]), } } } @@ -582,7 +590,7 @@ func GetPBMStorageAzureConfig( EndpointURL: stg.Azure.EndpointURL, Prefix: stg.Azure.Prefix, Credentials: azure.Credentials{ - Key: string(azureSecret.Data[AzureStorageAccountKeySecretKey]), + Key: storage.MaskedString(azureSecret.Data[AzureStorageAccountKeySecretKey]), }, }, }