Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/functions/delta_scan/delta_multi_file_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "duckdb/parser/constraints/not_null_constraint.hpp"

#include <regex>
#include <cstdlib>

#include "duckdb/planner/constraints/bound_not_null_constraint.hpp"

Expand Down Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions test/sql/cloud/azure/workload_identity_auth.test
Original file line number Diff line number Diff line change
@@ -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')
----