Skip to content

Commit f06f1ee

Browse files
authored
Add static bearer tooken auth for GCS (#721)
1 parent 6516460 commit f06f1ee

File tree

7 files changed

+46
-5
lines changed

7 files changed

+46
-5
lines changed

docs/docs/icechunk-python/storage.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ Icechunk can be used with [Google Cloud Storage](https://cloud.google.com/storag
175175
)
176176
```
177177

178+
=== "Bearer Token"
179+
180+
With this option, you provide a bearer token to use for the object store. This is useful for short lived workflows where expiration is not relevant or when the bearer token will not expire [See the API](./reference.md#icechunk.gcs_storage)
181+
182+
```python
183+
icechunk.gcs_storage(
184+
bucket="icechunk-test",
185+
prefix="quickstart-demo-1",
186+
bearer_token="my-bearer-token"
187+
)
188+
```
189+
178190
=== "Refreshable Credentials"
179191

180192
With this option, you provide a callback function that will be called to obtain GCS credentials when needed. This is useful for workloads that depend on retrieving short-lived credentials from GCS or similar authority, allowing for credentials to be refreshed as needed without interrupting any workflows. This works at a lower level than the other methods, and accepts a bearer token and expiration time. These are the same credentials that are created for you when specifying the service account file, key, or ADC. [See the API](./reference.md#icechunk.gcs_storage)

icechunk-python/python/icechunk/_icechunk_python.pyi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,14 @@ class GcsStaticCredentials:
539539
class ApplicationCredentials:
540540
def __init__(self, path: str) -> None: ...
541541

542+
class BearerToken:
543+
def __init__(self, token: str) -> None: ...
544+
542545
AnyGcsStaticCredential = (
543546
GcsStaticCredentials.ServiceAccount
544547
| GcsStaticCredentials.ServiceAccountKey
545548
| GcsStaticCredentials.ApplicationCredentials
549+
| GcsStaticCredentials.BearerToken
546550
)
547551

548552
class GcsCredentials:

icechunk-python/python/icechunk/credentials.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
GcsStaticCredentials.ServiceAccount
2525
| GcsStaticCredentials.ServiceAccountKey
2626
| GcsStaticCredentials.ApplicationCredentials
27+
| GcsStaticCredentials.BearerToken
2728
)
2829

2930
AnyGcsCredential = (
@@ -181,6 +182,7 @@ def gcs_static_credentials(
181182
service_account_file: str | None = None,
182183
service_account_key: str | None = None,
183184
application_credentials: str | None = None,
185+
bearer_token: str | None = None,
184186
) -> AnyGcsStaticCredential:
185187
"""Create static credentials Google Cloud Storage object store."""
186188
if service_account_file is not None:
@@ -189,6 +191,8 @@ def gcs_static_credentials(
189191
return GcsStaticCredentials.ServiceAccountKey(service_account_key)
190192
if application_credentials is not None:
191193
return GcsStaticCredentials.ApplicationCredentials(application_credentials)
194+
if bearer_token is not None:
195+
return GcsStaticCredentials.BearerToken(bearer_token)
192196
raise ValueError("Conflicting arguments to gcs_static_credentials function")
193197

194198

@@ -209,6 +213,7 @@ def gcs_credentials(
209213
service_account_file: str | None = None,
210214
service_account_key: str | None = None,
211215
application_credentials: str | None = None,
216+
bearer_token: str | None = None,
212217
from_env: bool | None = None,
213218
get_credentials: Callable[[], GcsBearerCredential] | None = None,
214219
) -> AnyGcsCredential:
@@ -220,19 +225,22 @@ def gcs_credentials(
220225
service_account_file is None
221226
and service_account_key is None
222227
and application_credentials is None
228+
and bearer_token is None
223229
):
224230
return gcs_from_env_credentials()
225231

226232
if (
227233
service_account_file is not None
228234
or service_account_key is not None
229235
or application_credentials is not None
236+
or bearer_token is not None
230237
) and (from_env is None or not from_env):
231238
return GcsCredentials.Static(
232239
gcs_static_credentials(
233240
service_account_file=service_account_file,
234241
service_account_key=service_account_key,
235242
application_credentials=application_credentials,
243+
bearer_token=bearer_token,
236244
)
237245
)
238246

icechunk-python/python/icechunk/storage.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ def gcs_storage(
186186
service_account_file: str | None = None,
187187
service_account_key: str | None = None,
188188
application_credentials: str | None = None,
189+
bearer_token: str | None = None,
189190
from_env: bool | None = None,
190191
config: dict[str, str] | None = None,
191192
) -> Storage:
@@ -199,11 +200,14 @@ def gcs_storage(
199200
The prefix within the bucket that is the root directory of the repository
200201
from_env: bool | None
201202
Fetch credentials from the operative system environment
203+
bearer_token: str | None
204+
The bearer token to use for the object store
202205
"""
203206
credentials = gcs_credentials(
204207
service_account_file=service_account_file,
205208
service_account_key=service_account_key,
206209
application_credentials=application_credentials,
210+
bearer_token=bearer_token,
207211
from_env=from_env,
208212
)
209213
return Storage.new_gcs(

icechunk-python/src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ pub enum PyGcsStaticCredentials {
214214
ServiceAccount(String),
215215
ServiceAccountKey(String),
216216
ApplicationCredentials(String),
217+
BearerToken(String),
217218
}
218219

219220
impl From<PyGcsStaticCredentials> for GcsStaticCredentials {
@@ -228,6 +229,12 @@ impl From<PyGcsStaticCredentials> for GcsStaticCredentials {
228229
PyGcsStaticCredentials::ApplicationCredentials(path) => {
229230
GcsStaticCredentials::ApplicationCredentials(path.into())
230231
}
232+
PyGcsStaticCredentials::BearerToken(token) => {
233+
GcsStaticCredentials::BearerToken(GcsBearerCredential {
234+
bearer: token,
235+
expires_after: None,
236+
})
237+
}
231238
}
232239
}
233240
}

icechunk/src/config.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ pub enum GcsStaticCredentials {
389389
ServiceAccount(PathBuf),
390390
ServiceAccountKey(String),
391391
ApplicationCredentials(PathBuf),
392+
BearerToken(GcsBearerCredential),
392393
}
393394

394395
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
@@ -399,9 +400,9 @@ pub struct GcsBearerCredential {
399400
pub expires_after: Option<DateTime<Utc>>,
400401
}
401402

402-
impl From<GcsBearerCredential> for GcpCredential {
403-
fn from(value: GcsBearerCredential) -> Self {
404-
GcpCredential { bearer: value.bearer }
403+
impl From<&GcsBearerCredential> for GcpCredential {
404+
fn from(value: &GcsBearerCredential) -> Self {
405+
GcpCredential { bearer: value.bearer.clone() }
405406
}
406407
}
407408

icechunk/src/storage/object_store.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use object_store::{
2121
memory::InMemory,
2222
path::Path as ObjectPath,
2323
Attribute, AttributeValue, Attributes, CredentialProvider, GetOptions, ObjectMeta,
24-
ObjectStore, PutMode, PutOptions, PutPayload, UpdateVersion,
24+
ObjectStore, PutMode, PutOptions, PutPayload, StaticCredentialProvider,
25+
UpdateVersion,
2526
};
2627
use serde::{Deserialize, Serialize};
2728
use std::{
@@ -899,6 +900,10 @@ impl ObjectStoreBackend for GcsObjectStoreBackend {
899900
})?;
900901
builder.with_application_credentials(path)
901902
}
903+
Some(GcsCredentials::Static(GcsStaticCredentials::BearerToken(token))) => {
904+
let provider = StaticCredentialProvider::new(GcpCredential::from(token));
905+
builder.with_credentials(Arc::new(provider))
906+
}
902907
Some(GcsCredentials::Refreshable(fetcher)) => {
903908
let credential_provider =
904909
GcsRefreshableCredentialProvider::new(Arc::clone(fetcher));
@@ -971,7 +976,7 @@ impl CredentialProvider for GcsRefreshableCredentialProvider {
971976
let creds = self.get_or_update_credentials().await.map_err(|e| {
972977
object_store::Error::Generic { store: "gcp", source: Box::new(e) }
973978
})?;
974-
Ok(Arc::new(creds.into()))
979+
Ok(Arc::new(GcpCredential::from(&creds)))
975980
}
976981
}
977982

0 commit comments

Comments
 (0)