From 68e46024e2bb0b238ad74df87c99bee909873050 Mon Sep 17 00:00:00 2001 From: Armando Ruocco Date: Tue, 16 Dec 2025 17:46:28 +0100 Subject: [PATCH 1/7] feat: Add support for DefaultAzureCredential authentication mechanism This commit adds support for the DefaultAzureCredential authentication mechanism in Azure Blob Storage. Users can now use the `useDefaultAzureCredentials` option to enable Azure's default credential chain, which automatically discovers and uses available credentials in the following order Signed-off-by: Armando Ruocco --- go.mod | 2 +- go.sum | 4 +- internal/cnpgi/operator/specs/secrets.go | 17 +- internal/cnpgi/operator/specs/secrets_test.go | 227 ++++++++++++++++++ internal/cnpgi/operator/specs/suite_test.go | 32 +++ web/docs/object_stores.md | 27 +++ 6 files changed, 299 insertions(+), 10 deletions(-) create mode 100644 internal/cnpgi/operator/specs/secrets_test.go create mode 100644 internal/cnpgi/operator/specs/suite_test.go diff --git a/go.mod b/go.mod index cc368024..6b11108e 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.25.5 require ( github.com/cert-manager/cert-manager v1.19.2 github.com/cloudnative-pg/api v1.28.0 - github.com/cloudnative-pg/barman-cloud v0.4.1-0.20251230211524-20b7e0e10b0f + github.com/cloudnative-pg/barman-cloud v0.4.1-0.20260108104508-ced266c145f5 github.com/cloudnative-pg/cloudnative-pg v1.28.0 github.com/cloudnative-pg/cnpg-i v0.3.1 github.com/cloudnative-pg/cnpg-i-machinery v0.4.2 diff --git a/go.sum b/go.sum index 709f14ef..22d8a0b6 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudnative-pg/api v1.28.0 h1:xElzHliO0eKkVQafkfMhDJo0aIRCmB1ItEt+SGh6B58= github.com/cloudnative-pg/api v1.28.0/go.mod h1:puXJBOsEaJd8JLgvCtxgl2TO/ZANap/z7bPepKRUgrk= -github.com/cloudnative-pg/barman-cloud v0.4.1-0.20251230211524-20b7e0e10b0f h1:4/PwIQOwQSTIxuncGRn3pX2V9CRwl7zJNXOVWOMSCCU= -github.com/cloudnative-pg/barman-cloud v0.4.1-0.20251230211524-20b7e0e10b0f/go.mod h1:qD0NtJOllNQbRB0MaleuHsZjFYaXtXfdg0HbFTbuHn0= +github.com/cloudnative-pg/barman-cloud v0.4.1-0.20260108104508-ced266c145f5 h1:wPB7VTNgTv6t9sl4QYOBakmVTqHnOdKUht7Q3aL+uns= +github.com/cloudnative-pg/barman-cloud v0.4.1-0.20260108104508-ced266c145f5/go.mod h1:qD0NtJOllNQbRB0MaleuHsZjFYaXtXfdg0HbFTbuHn0= github.com/cloudnative-pg/cloudnative-pg v1.28.0 h1:vkv0a0ewDSfJOPJrsyUr4uczsxheReAWf/k171V0Dm0= github.com/cloudnative-pg/cloudnative-pg v1.28.0/go.mod h1:209fkRR6m0vXUVQ9Q498eAPQqN2UlXECbXXtpGsZz3I= github.com/cloudnative-pg/cnpg-i v0.3.1 h1:fKj8NoToWI11HUL2UWYJBpkVzmaTvbs3kDMo7wQF8RU= diff --git a/internal/cnpgi/operator/specs/secrets.go b/internal/cnpgi/operator/specs/secrets.go index c1fd2684..e0aca1f7 100644 --- a/internal/cnpgi/operator/specs/secrets.go +++ b/internal/cnpgi/operator/specs/secrets.go @@ -37,13 +37,16 @@ func CollectSecretNamesFromCredentials(barmanCredentials *barmanapi.BarmanCreden ) } if barmanCredentials.Azure != nil { - references = append( - references, - barmanCredentials.Azure.ConnectionString, - barmanCredentials.Azure.StorageAccount, - barmanCredentials.Azure.StorageKey, - barmanCredentials.Azure.StorageSasToken, - ) + // When using default Azure credentials, no secrets are required + if !barmanCredentials.Azure.UseDefaultAzureCredentials { + references = append( + references, + barmanCredentials.Azure.ConnectionString, + barmanCredentials.Azure.StorageAccount, + barmanCredentials.Azure.StorageKey, + barmanCredentials.Azure.StorageSasToken, + ) + } } if barmanCredentials.Google != nil { references = append( diff --git a/internal/cnpgi/operator/specs/secrets_test.go b/internal/cnpgi/operator/specs/secrets_test.go new file mode 100644 index 00000000..d6fa706b --- /dev/null +++ b/internal/cnpgi/operator/specs/secrets_test.go @@ -0,0 +1,227 @@ +/* +Copyright © contributors to CloudNativePG, established as +CloudNativePG a Series of LF Projects, LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package specs + +import ( + barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api" + machineryapi "github.com/cloudnative-pg/machinery/pkg/api" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("CollectSecretNamesFromCredentials", func() { + Context("when collecting secrets from AWS credentials", func() { + It("should return secret names from S3 credentials", func() { + credentials := &barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + AccessKeyIDReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "access-key-id", + }, + SecretAccessKeyReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "secret-access-key", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("aws-secret")) + }) + + It("should handle nil AWS credentials", func() { + credentials := &barmanapi.BarmanCredentials{} + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(BeEmpty()) + }) + }) + + Context("when collecting secrets from Azure credentials", func() { + It("should return secret names when using explicit credentials", func() { + credentials := &barmanapi.BarmanCredentials{ + Azure: &barmanapi.AzureCredentials{ + ConnectionString: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-secret", + }, + Key: "connection-string", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("azure-secret")) + }) + + It("should return empty list when using UseDefaultAzureCredentials", func() { + credentials := &barmanapi.BarmanCredentials{ + Azure: &barmanapi.AzureCredentials{ + UseDefaultAzureCredentials: true, + ConnectionString: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-secret", + }, + Key: "connection-string", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(BeEmpty()) + }) + + It("should return empty list when using InheritFromAzureAD", func() { + credentials := &barmanapi.BarmanCredentials{ + Azure: &barmanapi.AzureCredentials{ + InheritFromAzureAD: true, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(BeEmpty()) + }) + + It("should return secret names for storage account and key", func() { + credentials := &barmanapi.BarmanCredentials{ + Azure: &barmanapi.AzureCredentials{ + StorageAccount: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-storage", + }, + Key: "account-name", + }, + StorageKey: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-storage", + }, + Key: "account-key", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("azure-storage")) + }) + }) + + Context("when collecting secrets from Google credentials", func() { + It("should return secret names from Google credentials", func() { + credentials := &barmanapi.BarmanCredentials{ + Google: &barmanapi.GoogleCredentials{ + ApplicationCredentials: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "google-secret", + }, + Key: "credentials.json", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("google-secret")) + }) + }) + + Context("when collecting secrets from multiple cloud providers", func() { + It("should return secret names from all providers", func() { + credentials := &barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + AccessKeyIDReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "access-key-id", + }, + }, + Azure: &barmanapi.AzureCredentials{ + ConnectionString: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-secret", + }, + Key: "connection-string", + }, + }, + Google: &barmanapi.GoogleCredentials{ + ApplicationCredentials: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "google-secret", + }, + Key: "credentials.json", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElements("aws-secret", "azure-secret", "google-secret")) + }) + + It("should skip Azure secrets when using UseDefaultAzureCredentials with other providers", func() { + credentials := &barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + AccessKeyIDReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "access-key-id", + }, + }, + Azure: &barmanapi.AzureCredentials{ + UseDefaultAzureCredentials: true, + ConnectionString: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "azure-secret", + }, + Key: "connection-string", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("aws-secret")) + Expect(secrets).NotTo(ContainElement("azure-secret")) + }) + }) + + Context("when handling nil references", func() { + It("should skip nil secret references", func() { + credentials := &barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + AccessKeyIDReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "access-key-id", + }, + SecretAccessKeyReference: nil, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(ContainElement("aws-secret")) + Expect(len(secrets)).To(Equal(1)) + }) + }) +}) diff --git a/internal/cnpgi/operator/specs/suite_test.go b/internal/cnpgi/operator/specs/suite_test.go new file mode 100644 index 00000000..1dc0ae18 --- /dev/null +++ b/internal/cnpgi/operator/specs/suite_test.go @@ -0,0 +1,32 @@ +/* +Copyright © contributors to CloudNativePG, established as +CloudNativePG a Series of LF Projects, LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package specs + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestSpecs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Specs Suite") +} diff --git a/web/docs/object_stores.md b/web/docs/object_stores.md index f1714c93..4582530a 100644 --- a/web/docs/object_stores.md +++ b/web/docs/object_stores.md @@ -252,6 +252,33 @@ spec: [...] ``` +### Default Azure Credentials + +The `useDefaultAzureCredentials` option enables the default Azure credentials +flow, which uses [`DefaultAzureCredential`](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential) +to automatically discover and use available credentials in the following order: + +1. **Environment Variables** — `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, and `AZURE_TENANT_ID` for Service Principal authentication +2. **Managed Identity** — Uses the managed identity assigned to the pod +3. **Azure CLI** — Uses credentials from the Azure CLI if available +4. **Azure PowerShell** — Uses credentials from Azure PowerShell if available + +This is particularly useful when running on Azure Kubernetes Service (AKS) with +[Workload Identity](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview): + +```yaml +apiVersion: barmancloud.cnpg.io/v1 +kind: ObjectStore +metadata: + name: azure-store +spec: + configuration: + destinationPath: "" + azureCredentials: + useDefaultAzureCredentials: true + [...] +``` + ### Access Key, SAS Token, or Connection String Store credentials in a Kubernetes secret: From 8e8a6c7ca485fd1a1561ea3fe5b05a334b9341f5 Mon Sep 17 00:00:00 2001 From: Armando Ruocco Date: Mon, 22 Dec 2025 17:59:32 +0100 Subject: [PATCH 2/7] fix: manifests Signed-off-by: Armando Ruocco --- config/crd/bases/barmancloud.cnpg.io_objectstores.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml index a141948e..6abbd752 100644 --- a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml +++ b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml @@ -108,6 +108,11 @@ spec: - key - name type: object + useDefaultAzureCredentials: + description: |- + Use the default Azure authentication flow, which includes DefaultAzureCredential. + This allows authentication using environment variables and managed identities. + type: boolean type: object data: description: |- From 0dcb8d812246adc5a83158739a3b8684a2ec45de Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Mon, 29 Dec 2025 15:39:16 +0100 Subject: [PATCH 3/7] docs: inheritFromAzureAD for managed identities (review #681) (#698) Make explicit in docs that the inheritFromAzureAD option enables the usage of Azure Managed Identity authentication mechanism. Signed-off-by: Gabriele Fedi --- web/docs/object_stores.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/web/docs/object_stores.md b/web/docs/object_stores.md index 4582530a..c17f8597 100644 --- a/web/docs/object_stores.md +++ b/web/docs/object_stores.md @@ -232,12 +232,16 @@ Barman Cloud supports the following authentication methods: - [Connection String](https://learn.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string) - Storage Account Name + [Access Key](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage) - Storage Account Name + [SAS Token](https://learn.microsoft.com/en-us/azure/storage/blobs/sas-service-create) -- [Azure AD Workload Identity](https://azure.github.io/azure-workload-identity/docs/introduction.html) +- [Azure AD Managed Identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) +- [Default Azure Credentials](https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet) -### Azure AD Workload Identity +### Azure AD Managed Identity -This method avoids storing credentials in Kubernetes via the -`.spec.configuration.inheritFromAzureAD` option: +This method avoids storing credentials in Kubernetes by enabling the +usage of [Azure Managed Identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) authentication mechanism. +This can be enabled by setting the `inheritFromAzureAD` option to `true`. +Managed Identitity can be configured for the AKS Cluster by following +the [Azure documentation](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity?pivots=system-assigned). ```yaml apiVersion: barmancloud.cnpg.io/v1 @@ -263,8 +267,11 @@ to automatically discover and use available credentials in the following order: 3. **Azure CLI** — Uses credentials from the Azure CLI if available 4. **Azure PowerShell** — Uses credentials from Azure PowerShell if available -This is particularly useful when running on Azure Kubernetes Service (AKS) with -[Workload Identity](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview): +This approach is particularly useful for getting started with development and testing; it allows +the SDK to attempt multiple authentication mechanisms seamlessly across different environments. +However, this is not recommended for production. Please refer to the +[official Azure guidance](https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#usage-guidance-for-defaultazurecredential) +for a comprehensive understanding of `DefaultAzureCredential`. ```yaml apiVersion: barmancloud.cnpg.io/v1 From b9d7a82ec9a98da34057e045260d07a46a84a0e3 Mon Sep 17 00:00:00 2001 From: Marco Nenciarini Date: Mon, 29 Dec 2025 16:45:27 +0100 Subject: [PATCH 4/7] chore: implement Gabriele's suggestion Signed-off-by: Marco Nenciarini --- internal/cnpgi/operator/specs/secrets.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/cnpgi/operator/specs/secrets.go b/internal/cnpgi/operator/specs/secrets.go index e0aca1f7..89811ad2 100644 --- a/internal/cnpgi/operator/specs/secrets.go +++ b/internal/cnpgi/operator/specs/secrets.go @@ -37,8 +37,9 @@ func CollectSecretNamesFromCredentials(barmanCredentials *barmanapi.BarmanCreden ) } if barmanCredentials.Azure != nil { - // When using default Azure credentials, no secrets are required - if !barmanCredentials.Azure.UseDefaultAzureCredentials { + // When using default Azure credentials or managed identity, no secrets are required + if !barmanCredentials.Azure.UseDefaultAzureCredentials && + !barmanCredentials.Azure.InheritFromAzureAD { references = append( references, barmanCredentials.Azure.ConnectionString, From 325e0092a5b0f083cb203f1390fe308c77e925de Mon Sep 17 00:00:00 2001 From: Marco Nenciarini Date: Mon, 29 Dec 2025 18:12:50 +0100 Subject: [PATCH 5/7] chore: fix spellcheck Signed-off-by: Marco Nenciarini --- .wordlist.txt | 4 ++++ web/docs/object_stores.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.wordlist.txt b/.wordlist.txt index 246e6676..3e59b458 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1,3 +1,4 @@ +AKS AccessDenied AdditionalContainerArgs Akamai @@ -5,6 +6,7 @@ Azurite BarmanObjectStore BarmanObjectStoreConfiguration BarmanObjectStores +CLI CNCF CRD CloudNativePG @@ -38,6 +40,7 @@ PITR PoR PostgreSQL Postgres +PowerShell README RPO RTO @@ -45,6 +48,7 @@ RecoveryWindow ResourceRequirements RetentionPolicy SAS +SDK SFO SPDX SPDX diff --git a/web/docs/object_stores.md b/web/docs/object_stores.md index c17f8597..065eee7f 100644 --- a/web/docs/object_stores.md +++ b/web/docs/object_stores.md @@ -240,7 +240,7 @@ Barman Cloud supports the following authentication methods: This method avoids storing credentials in Kubernetes by enabling the usage of [Azure Managed Identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) authentication mechanism. This can be enabled by setting the `inheritFromAzureAD` option to `true`. -Managed Identitity can be configured for the AKS Cluster by following +Managed Identity can be configured for the AKS Cluster by following the [Azure documentation](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity?pivots=system-assigned). ```yaml From 39f030ae12bfc3fa749df1370ca316fb23acf0a2 Mon Sep 17 00:00:00 2001 From: Marco Nenciarini Date: Tue, 30 Dec 2025 23:41:06 +0100 Subject: [PATCH 6/7] docs: improve consistency of Azure authentication methods Signed-off-by: Marco Nenciarini --- web/docs/object_stores.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/docs/object_stores.md b/web/docs/object_stores.md index 065eee7f..4ccedac8 100644 --- a/web/docs/object_stores.md +++ b/web/docs/object_stores.md @@ -230,9 +230,9 @@ is Microsoft’s cloud-based object storage solution. Barman Cloud supports the following authentication methods: - [Connection String](https://learn.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string) -- Storage Account Name + [Access Key](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage) -- Storage Account Name + [SAS Token](https://learn.microsoft.com/en-us/azure/storage/blobs/sas-service-create) -- [Azure AD Managed Identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) +- Storage Account Name + [Storage Account Access Key](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage) +- Storage Account Name + [Storage Account SAS Token](https://learn.microsoft.com/en-us/azure/storage/blobs/sas-service-create) +- [Azure AD Managed Identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) - [Default Azure Credentials](https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet) ### Azure AD Managed Identity From 407c851eb063e646c1830add789f9fcd64ce5a97 Mon Sep 17 00:00:00 2001 From: Marco Nenciarini Date: Tue, 30 Dec 2025 23:49:23 +0100 Subject: [PATCH 7/7] chore: regenerate manifest with useDefaultAzureCredentials field Signed-off-by: Marco Nenciarini --- manifest.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/manifest.yaml b/manifest.yaml index 95ed059a..b4f98a7c 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -107,6 +107,11 @@ spec: - key - name type: object + useDefaultAzureCredentials: + description: |- + Use the default Azure authentication flow, which includes DefaultAzureCredential. + This allows authentication using environment variables and managed identities. + type: boolean type: object data: description: |-