Skip to content

Commit e91336a

Browse files
authored
Default to checking Azure CLI authentication (#292)
* Default to checking Azure CLI authentication * add note
1 parent aaa8d6a commit e91336a

File tree

6 files changed

+56
-7
lines changed

6 files changed

+56
-7
lines changed

docs/authentication.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Note that many authentication variants are already supported natively.
4444
- Workload identity OAuth2, using a `client_id`, `tenant_id`, and `federated_token_file` passed in by the user
4545
- OAuth2, using a `client_id`, `client_secret`, and `tenant_id` passed in by the user
4646
- A SAS key passed in by the user.
47-
- Azure CLI
47+
- Azure CLI. (If you want to ensure the IMDS authentication is used below, pass [`use_azure_cli=False`][obstore.store.AzureConfigInput.use_azure_cli] to `AzureStore`.)
4848
- IMDS Managed Identity Provider.
4949

5050
(A transcription of [this underlying code](https://github.com/apache/arrow-rs/blob/a00f9f43a0530b9255e4f9940e43121deedb0cc7/object_store/src/azure/builder.rs#L942-L1019)).

docs/dev/overridden-defaults.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Overridden Defaults
2+
3+
In general, we wish to follow the upstream `object_store` as closely as possible, which should reduce the maintenance overhead here.
4+
5+
However, there are occasionally places where we want to diverge from the upstream decision making, and we document those here.
6+
7+
## Azure CLI
8+
9+
We always check for Azure CLI authentication as a fallback.
10+
11+
If we stuck with the upstream `object_store` default, you would need to pass `use_azure_cli=True` to check for Azure CLI credentials.
12+
13+
The Azure CLI is the [second-to-last Azure authentication method checked](https://github.com/apache/arrow-rs/blob/9c92a50b6d190ca9d0c74c3ccc69e348393d9246/object_store/src/azure/builder.rs#L1015-L1016) checked. So this only changes the default behavior for people relying on instance authentication. For those people, they can still pass `use_azure_cli=False`.
14+
15+
See upstream discussion [here](https://github.com/apache/arrow-rs/issues/7204).

mkdocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ nav:
6969
- Developer Docs:
7070
- Contributing: dev/DEVELOP.md
7171
- Functional API: dev/functional-api.md
72+
- Overridden Defaults: dev/overridden-defaults.md
7273
- dev/pickle.md
7374
- CHANGELOG.md
7475

obstore/python/obstore/store/_azure.pyi

+16-4
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ class AzureConfigInput(TypedDict, total=False):
138138
azure_tenant_id: str
139139
"""Tenant id used in oauth flows"""
140140
azure_use_azure_cli: bool
141-
"""Use azure cli for acquiring access token"""
141+
"""Use azure cli for acquiring access token.
142+
143+
Defaults to `True`.
144+
"""
142145
azure_use_fabric_endpoint: bool
143146
"""Use object store with url scheme account.dfs.fabric.microsoft.com"""
144147
bearer_token: str
@@ -186,7 +189,10 @@ class AzureConfigInput(TypedDict, total=False):
186189
token: str
187190
"""Bearer token"""
188191
use_azure_cli: bool
189-
"""Use azure cli for acquiring access token"""
192+
"""Use azure cli for acquiring access token.
193+
194+
Defaults to `True`.
195+
"""
190196
use_emulator: bool
191197
"""Use object store with azurite storage emulator"""
192198
use_fabric_endpoint: bool
@@ -262,7 +268,10 @@ class AzureConfigInput(TypedDict, total=False):
262268
AZURE_TENANT_ID: str
263269
"""Tenant id used in oauth flows"""
264270
AZURE_USE_AZURE_CLI: bool
265-
"""Use azure cli for acquiring access token"""
271+
"""Use azure cli for acquiring access token.
272+
273+
Defaults to `True`.
274+
"""
266275
AZURE_USE_FABRIC_ENDPOINT: bool
267276
"""Use object store with url scheme account.dfs.fabric.microsoft.com"""
268277
BEARER_TOKEN: str
@@ -310,7 +319,10 @@ class AzureConfigInput(TypedDict, total=False):
310319
TOKEN: str
311320
"""Bearer token"""
312321
USE_AZURE_CLI: bool
313-
"""Use azure cli for acquiring access token"""
322+
"""Use azure cli for acquiring access token.
323+
324+
Defaults to `True`.
325+
"""
314326
USE_EMULATOR: bool
315327
"""Use object store with azurite storage emulator"""
316328
USE_FABRIC_ENDPOINT: bool

pyo3-object_store/src/azure/store.rs

+9
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ impl PyAzureStore {
9292
kwargs: Option<PyAzureConfig>,
9393
) -> PyObjectStoreResult<Self> {
9494
let mut builder = MicrosoftAzureBuilder::from_env();
95+
builder = PyAzureConfig::OVERRIDDEN_DEFAULTS().apply_config(builder);
9596
let mut config = config.unwrap_or_default();
9697
if let Some(container) = container.clone() {
9798
// Note: we apply the bucket to the config, not directly to the builder, so they stay
@@ -255,6 +256,14 @@ impl PyAzureConfig {
255256
Self(HashMap::new())
256257
}
257258

259+
/// Default values that we opt into that differ from the upstream object_store defaults
260+
#[allow(non_snake_case)]
261+
fn OVERRIDDEN_DEFAULTS() -> Self {
262+
let mut map = HashMap::with_capacity(1);
263+
map.insert(AzureConfigKey::UseAzureCli.into(), true.into());
264+
Self(map)
265+
}
266+
258267
fn apply_config(self, mut builder: MicrosoftAzureBuilder) -> MicrosoftAzureBuilder {
259268
for (key, value) in self.0.into_iter() {
260269
builder = builder.with_config(key.0, value.0);

pyo3-object_store/src/config.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ impl AsRef<str> for PyConfigValue {
2828
impl<'py> FromPyObject<'py> for PyConfigValue {
2929
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
3030
if let Ok(val) = ob.extract::<bool>() {
31-
Ok(Self(val.to_string()))
31+
Ok(val.into())
3232
} else if let Ok(duration) = ob.extract::<Duration>() {
33-
Ok(Self(format_duration(duration).to_string()))
33+
Ok(duration.into())
3434
} else {
3535
Ok(Self(ob.extract()?))
3636
}
@@ -42,3 +42,15 @@ impl From<PyConfigValue> for String {
4242
value.0
4343
}
4444
}
45+
46+
impl From<bool> for PyConfigValue {
47+
fn from(value: bool) -> Self {
48+
Self(value.to_string())
49+
}
50+
}
51+
52+
impl From<Duration> for PyConfigValue {
53+
fn from(value: Duration) -> Self {
54+
Self(format_duration(value).to_string())
55+
}
56+
}

0 commit comments

Comments
 (0)