Expose azure_get_token() scalar to mint AAD bearer tokens#170
Open
djouallah wants to merge 2 commits into
Open
Expose azure_get_token() scalar to mint AAD bearer tokens#170djouallah wants to merge 2 commits into
djouallah wants to merge 2 commits into
Conversation
djouallah
marked this pull request as ready for review
May 19, 2026 01:45
Mints a short-lived Azure AAD bearer token via the existing CreateChainedTokenCredential helper. Intended use: feed the token into a duckdb-iceberg `iceberg`-typed secret to attach an OneLake REST catalog, without coupling either extension's secret types. Three arities: azure_get_token() azure_get_token(chain) azure_get_token(chain, scope) Defaults: chain='default', scope='https://storage.azure.com/.default'. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
djouallah
force-pushed
the
add-azure-get-token-scalar
branch
from
May 19, 2026 01:47
dcf1154 to
5e7d1c6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a single scalar function
azure_get_token([chain[, scope]])that mints an Azure AAD bearer token from the same credential-chain providers duckdb-azure already understands (cli,managed_identity,env,default,workload_identity).Three arities:
Motivation
duckdb/duckdb-iceberg#499 — attaching a OneLake REST iceberg catalog fails because the iceberg extension expects an OAuth2 client-credentials flow, while OneLake wants a plain AAD bearer token (the same one duckdb-azure already mints internally for storage reads).
duckdb/duckdb-iceberg#612 was closed by @Tmonster because it pulled the Azure SDK into duckdb-iceberg. His suggestion was to keep Azure logic in duckdb-azure. This PR follows that direction without modifying duckdb-iceberg at all — duckdb-iceberg's
iceberg-typed secret already accepts a statictokenfield, so once duckdb-azure can produce one, ATTACH works untouched:Why expose a scalar, not a new secret type
A second
iceberg-typedcredential_chainsecret in duckdb-azure was the obvious alternative but has two downsides:CreateSecretFunction, scope handling, redaction wiring) for what's essentially "callGetTokenand stash the string".A plain scalar function decouples duckdb-azure from duckdb-iceberg's secret-type registration entirely. The same primitive is also the natural hook for future auto-refresh.
Security framing — this reduces token exposure compared to current practice
Without this function, the working pattern for OneLake users today is a launcher script that:
az account get-access-token --resource https://storage.azure.com/ -o tsv > %TEMP%\az_tok.txtSET VARIABLEstatement inside an init SQL file (often underC:\ProgramData\so the path doesn't leak the username — which is world-readable)duckdb -init <init.sql>That workflow lands the JWT on disk twice (the temp file and the init SQL file), and races a manual
DeleteFilebetween the two.azure_get_token()keeps the token entirely in-memory: no disk write, no init-file plaintext, no temp-file cleanup race. The token surface is narrower, not wider — the function only succeeds when a chain provider is already authenticated (e.g.az login), and anyone with that prerequisite can already mint the same token by hand.Implementation
FetchAzureBearerToken(chain, scope)in src/azure_storage_account_client.cpp — directly calls the existingstatic CreateChainedTokenCredentialhelper in the same translation unit, so no header churn for the static helper.UnaryExecutor/BinaryExecutorto handle constant/null vectors.loader.RegisterFunction.azure-identity-cppis already linked.Total: ~60 net lines across 3 files.
Out of scope
SET VARIABLE+CREATE OR REPLACE SECRET. Real auto-refresh would require either duckdb-iceberg to callazure_get_token()on every catalog request / on 401, or a duckdb mechanism to make secret values be live expressions. Both are bigger conversations. This PR is the primitive that makes either approach possible later.TYPE azuresecret. Users attaching OneLake typically have two secrets: oneazure(blob reads) and oneiceberg(catalog).Test plan
az loginSELECT length(azure_get_token('cli'))returns a JWTATTACHagainst OneLake REST catalog succeeds,SHOW TABLES+SELECT ... LIMIT 5reads rowsSELECT azure_get_token('cli')without prioraz loginraisesInvalidConfigurationExceptionwith the hint message.Happy to add a sqllogictest verifying registration (
SELECT 1 FROM duckdb_functions() WHERE function_name = 'azure_get_token'), mark the functionFunctionStability::VOLATILE, and add a README section if you want any of those before merge.