From ad9a4ccb95e193b815b60aefadfb74c52a8806ea Mon Sep 17 00:00:00 2001 From: Michael Chapman Date: Wed, 24 Jun 2026 12:07:42 -0500 Subject: [PATCH 1/2] fix: add workload_identity credential chain for azure (#320) When reading delta tables from ADLS via workload_identity (commonly in k8s), DuckDB's credential chain isn't passed through to delta-kernel's credential resolution path, causing incorrect resolution. This change passes workload_identity variables to delta-kernel's expected options so that resolve_credential_auto() correctly leverages the workload_identity path. Fixes #320 --- .../delta_scan/delta_multi_file_list.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/functions/delta_scan/delta_multi_file_list.cpp b/src/functions/delta_scan/delta_multi_file_list.cpp index 4ce9e205..5d76b6e5 100644 --- a/src/functions/delta_scan/delta_multi_file_list.cpp +++ b/src/functions/delta_scan/delta_multi_file_list.cpp @@ -18,6 +18,7 @@ #include "duckdb/parser/constraints/not_null_constraint.hpp" #include +#include #include "duckdb/planner/constraints/bound_not_null_constraint.hpp" @@ -283,7 +284,22 @@ static ffi::EngineBuilder *CreateBuilder(ClientContext &context, const string &p if (chain.find("cli") != std::string::npos) { set_option(builder, "use_azure_cli", "true"); } - // Authentication option 1b: non-cli credential chains will just "hope for the best" technically since we + // Authentication option 1b: using a workload_identity + // Explicitly forward workload identity vars so object_store selects + // WorkloadIdentityOAuthProvider instead of falling back to IMDS + if (chain.find("workload_identity") != std::string::npos) { + // federated_token_file has no DuckDB secret key analog — always read from env + const char* fed_token = getenv("AZURE_FEDERATED_TOKEN_FILE"); + if (fed_token) set_option(builder, "federated_token_file", fed_token); + // Prefer secret-sourced values; fall back to env vars if not set in the secret + const char* env_client_id = getenv("AZURE_CLIENT_ID"); + const char* env_tenant_id = getenv("AZURE_TENANT_ID"); + const string resolved_client_id = !client_id.empty() ? client_id : (env_client_id ? env_client_id : ""); + const string resolved_tenant_id = !tenant_id.empty() ? tenant_id : (env_tenant_id ? env_tenant_id : ""); + if (!resolved_client_id.empty()) set_option(builder, "azure_client_id", resolved_client_id); + if (!resolved_tenant_id.empty()) set_option(builder, "azure_tenant_id", resolved_tenant_id); + } + // Authentication option 1c: non-cli credential chains will just "hope for the best" technically since we // are using the default credential chain provider duckDB and delta-kernel-rs should find the same auth } else if (!connection_string.empty() && connection_string != "NULL") { // Authentication option 2: a connection string based on account key From d835e87b4f6649711d021141e2bc8440f7e1a01a Mon Sep 17 00:00:00 2001 From: Michael Chapman Date: Wed, 24 Jun 2026 13:12:07 -0500 Subject: [PATCH 2/2] test: add workload_identity azure auth integration test (#320) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds test/sql/cloud/azure/workload_identity_auth.test following the same pattern as cli_auth.test and spn_auth.test. The test is guarded by require-env on AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE, and AZURE_STORAGE_ACCOUNT — it will skip silently in all existing CI pipelines (Azurite, cloud SPN-based) since none provide a federated token environment. Included to document expected behavior and provide coverage if an AKS-based CI runner with workload identity is added in the future. --- .../cloud/azure/workload_identity_auth.test | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/sql/cloud/azure/workload_identity_auth.test diff --git a/test/sql/cloud/azure/workload_identity_auth.test b/test/sql/cloud/azure/workload_identity_auth.test new file mode 100644 index 00000000..4fb787df --- /dev/null +++ b/test/sql/cloud/azure/workload_identity_auth.test @@ -0,0 +1,41 @@ +# name: test/sql/cloud/azure/workload_identity_auth.test +# description: test azure delta_scan with workload_identity credential chain (common in AKS) +# group: [azure] + +require azure + +require parquet + +require delta + +require-env AZURE_CLIENT_ID + +require-env AZURE_TENANT_ID + +require-env AZURE_FEDERATED_TOKEN_FILE + +require-env AZURE_STORAGE_ACCOUNT + +statement ok +set allow_persistent_secrets=false + +statement ok +CREATE SECRET az_wi ( + TYPE AZURE, + PROVIDER CREDENTIAL_CHAIN, + CHAIN 'workload_identity', + ACCOUNT_NAME '${AZURE_STORAGE_ACCOUNT}' +) + +mode output_result + +# Run a remote DAT test +query I rowsort all_primitive_types +SELECT * +FROM delta_scan('azure://delta-testing-private/dat/all_primitive_types/delta') +---- + +query I rowsort all_primitive_types +SELECT * +FROM parquet_scan('azure://delta-testing-private/dat/all_primitive_types/expected/latest/**/*.parquet') +----