Skip to content

Commit 7abb235

Browse files
author
py
committed
wip: add workload identity auth
1 parent 330310d commit 7abb235

File tree

8 files changed

+141
-38
lines changed

8 files changed

+141
-38
lines changed

crates/cli/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ async fn initialize(with_metadata: bool, context: Context<impl Environment>) ->
108108
description: "The BigQuery service key".to_string(),
109109
default_value: None,
110110
},
111+
metadata::EnvironmentVariableDefinition {
112+
name: "HASURA_BIGQUERY_WORKLOAD_IDENTITY_AUTH".to_string(),
113+
description: "The BigQuery workload identity auth URL".to_string(),
114+
default_value: None,
115+
},
111116
metadata::EnvironmentVariableDefinition {
112117
name: "HASURA_BIGQUERY_PROJECT_ID".to_string(),
113118
description: "The BigQuery project ID/name".to_string(),

crates/configuration/src/configuration.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::values::PoolSettings;
1919
pub struct Configuration {
2020
pub metadata: metadata::Metadata,
2121
pub pool_settings: PoolSettings,
22-
pub service_key: String,
22+
pub auth: (bool, String),
2323
pub project_id: String,
2424
pub dataset_id: String,
2525
// pub mutations_version: Option<metadata::mutations::MutationsVersion>,

crates/configuration/src/connection_settings.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
//! Database connection settings.
22
3-
use crate::values::{DatasetId, ProjectId, Secret, ServiceKey};
3+
use crate::values::{DatasetId, ProjectId, Secret, ServiceKey, WorkloadIdentityAuth};
44
use schemars::JsonSchema;
55
use serde::{Deserialize, Serialize};
66

77
pub const DEFAULT_SERVICE_KEY_VARIABLE: &str = "HASURA_BIGQUERY_SERVICE_KEY";
8+
pub const DEFAULT_WORKLOAD_IDENTITY_AUTH_VARIABLE: &str = "HASURA_BIGQUERY_WORKLOAD_IDENTITY_AUTH";
89
pub const DEFAULT_PROJECT_ID_VARIABLE: &str = "HASURA_BIGQUERY_PROJECT_ID";
910
pub const DEFAULT_DATASET_ID_VARIABLE: &str = "HASURA_BIGQUERY_DATASET_ID";
1011

1112
/// Database connection settings.
1213
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, JsonSchema)]
1314
#[serde(rename_all = "camelCase")]
1415
pub struct DatabaseConnectionSettings {
15-
/// Connection string for a Postgres-compatible database.
16-
pub service_key: ServiceKey,
16+
/// Connection string for a BigQuery-compatible database.
17+
pub service_key: Option<ServiceKey>,
18+
/// Connection string for a BigQuery-compatible database.
19+
pub workload_identity_auth: Option<WorkloadIdentityAuth>,
1720
/// Project ID for a BigQuery database.
1821
pub project_id: ProjectId,
1922
/// Dataset ID for a BigQuery database.
@@ -23,9 +26,12 @@ pub struct DatabaseConnectionSettings {
2326
impl DatabaseConnectionSettings {
2427
pub fn empty() -> Self {
2528
Self {
26-
service_key: ServiceKey(Secret::FromEnvironment {
29+
service_key: Some(ServiceKey(Secret::FromEnvironment {
2730
variable: DEFAULT_SERVICE_KEY_VARIABLE.into(),
28-
}),
31+
})),
32+
workload_identity_auth: Some(WorkloadIdentityAuth(Secret::FromEnvironment {
33+
variable: DEFAULT_WORKLOAD_IDENTITY_AUTH_VARIABLE.into(),
34+
})),
2935
project_id: ProjectId(Secret::FromEnvironment {
3036
variable: DEFAULT_PROJECT_ID_VARIABLE.into(),
3137
}),

crates/configuration/src/to_runtime_configuration.rs

+32-9
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,49 @@ use std::collections::BTreeMap;
66
use super::version1::ParsedConfiguration;
77
use crate::environment::Environment;
88
use crate::error::MakeRuntimeConfigurationError;
9-
use crate::values::{DatasetId, ProjectId, Secret, ServiceKey};
9+
use crate::values::{DatasetId, ProjectId, Secret, ServiceKey, WorkloadIdentityAuth};
1010
use query_engine_metadata::{self, metadata};
11-
// use crate::VersionTag;
1211

1312
/// Convert the parsed configuration metadata to internal engine metadata
1413
/// That can be used by the connector at runtime.
1514
pub fn make_runtime_configuration(
1615
parsed_config: ParsedConfiguration,
1716
environment: impl Environment,
1817
) -> Result<crate::Configuration, MakeRuntimeConfigurationError> {
19-
let service_key = match parsed_config.connection_settings.service_key {
20-
ServiceKey(Secret::Plain(key)) => Ok(key),
21-
ServiceKey(Secret::FromEnvironment { variable }) => {
22-
environment.read(&variable).map_err(|error| {
18+
let auth: (bool, String) = match parsed_config.connection_settings.workload_identity_auth {
19+
Some(WorkloadIdentityAuth(Secret::Plain(key))) => {
20+
Ok((true, key))
21+
},
22+
Some(WorkloadIdentityAuth(Secret::FromEnvironment { variable })) => {
23+
let variable_value = environment.read(&variable).map_err(|error| {
2324
MakeRuntimeConfigurationError::MissingEnvironmentVariable {
2425
file_path: super::version1::CONFIGURATION_FILENAME.into(),
2526
message: error.to_string(),
2627
}
27-
})
28+
})?;
29+
Ok((true, variable_value))
30+
},
31+
None => {
32+
match parsed_config.connection_settings.service_key {
33+
Some(ServiceKey(Secret::Plain(key))) => {
34+
Ok((false, key))
35+
},
36+
Some(ServiceKey(Secret::FromEnvironment { variable })) => {
37+
let variable_value = environment.read(&variable).map_err(|error| {
38+
MakeRuntimeConfigurationError::MissingEnvironmentVariable {
39+
file_path: super::version1::CONFIGURATION_FILENAME.into(),
40+
message: error.to_string(),
41+
}
42+
})?;
43+
Ok((false, variable_value))
44+
},
45+
None => {
46+
return Err(MakeRuntimeConfigurationError::MissingEnvironmentVariable {
47+
file_path: super::version1::CONFIGURATION_FILENAME.into(),
48+
message: "Neither Workload Identity Auth URL or Service key is provided".into(),
49+
});
50+
},
51+
}
2852
}
2953
}?;
3054

@@ -53,10 +77,9 @@ pub fn make_runtime_configuration(
5377
Ok(crate::Configuration {
5478
metadata: convert_metadata(parsed_config.metadata),
5579
pool_settings: parsed_config.pool_settings,
56-
service_key,
80+
auth,
5781
project_id,
5882
dataset_id,
59-
// mutations_version: convert_mutations_version(parsed_config.mutations_version),
6083
})
6184
}
6285

crates/configuration/src/values/connection_info.rs

+15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ impl From<&str> for ServiceKey {
1818
}
1919
}
2020

21+
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
22+
pub struct WorkloadIdentityAuth(pub Secret);
23+
24+
impl From<String> for WorkloadIdentityAuth {
25+
fn from(value: String) -> Self {
26+
Self(value.into())
27+
}
28+
}
29+
30+
impl From<&str> for WorkloadIdentityAuth {
31+
fn from(value: &str) -> Self {
32+
Self::from(value.to_string())
33+
}
34+
}
35+
2136
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
2237
pub struct ProjectId(pub Secret);
2338

crates/configuration/src/values/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ pub mod connection_info;
22
mod pool_settings;
33
mod secret;
44

5-
pub use connection_info::{DatasetId, ProjectId, ServiceKey};
5+
pub use connection_info::{DatasetId, ProjectId, ServiceKey, WorkloadIdentityAuth};
66
pub use pool_settings::PoolSettings;
77
pub use secret::Secret;

crates/configuration/src/version1.rs

+63-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::connection_settings;
44
use crate::environment::Environment;
55
use crate::error::WriteParsedConfigurationError;
6-
use crate::values::{DatasetId, PoolSettings, ProjectId, Secret, ServiceKey};
6+
use crate::values::{DatasetId, PoolSettings, ProjectId, Secret, ServiceKey, WorkloadIdentityAuth};
77

88
use super::error::ParseConfigurationError;
99
use gcp_bigquery_client::model::query_request::QueryRequest;
@@ -94,10 +94,44 @@ pub async fn configure(
9494
args: &ParsedConfiguration,
9595
environment: impl Environment,
9696
) -> anyhow::Result<ParsedConfiguration> {
97-
let service_key = match &args.connection_settings.service_key {
98-
ServiceKey(Secret::Plain(value)) => Cow::Borrowed(value),
99-
ServiceKey(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?),
97+
let bigquery_client = match &args.connection_settings.workload_identity_auth {
98+
Some(WorkloadIdentityAuth(Secret::Plain(value))) => {
99+
let url = Cow::Borrowed(value);
100+
std::env::set_var("BIG_QUERY_AUTH_URL", url.as_ref());
101+
gcp_bigquery_client::Client::with_workload_identity(false).await.unwrap()
102+
},
103+
Some(WorkloadIdentityAuth(Secret::FromEnvironment { variable })) => {
104+
let url: Cow<'_, String> = Cow::Owned(environment.read(variable)?);
105+
std::env::set_var("BIG_QUERY_AUTH_URL", url.as_ref());
106+
gcp_bigquery_client::Client::with_workload_identity(false).await.unwrap()
107+
},
108+
None => {
109+
match &args.connection_settings.service_key {
110+
Some(ServiceKey(Secret::Plain(value))) => {
111+
let service_key = Cow::Borrowed(value);
112+
let service_account_key = yup_oauth2::parse_service_account_key(service_key.as_str()).unwrap();
113+
gcp_bigquery_client::Client::from_service_account_key(service_account_key, false).await.unwrap()
114+
},
115+
Some(ServiceKey(Secret::FromEnvironment { variable })) => {
116+
let service_key: Cow<'_, String> = Cow::Owned(environment.read(variable)?);
117+
let service_account_key = yup_oauth2::parse_service_account_key(service_key.as_str()).unwrap();
118+
gcp_bigquery_client::Client::from_service_account_key(service_account_key, false).await.unwrap()
119+
},
120+
None => {
121+
return Err(anyhow::anyhow!("Neither Workload Identity Auth URL or Service key is provided"));
122+
},
123+
}
124+
}
100125
};
126+
// let service_key = match &args.connection_settings.service_key {
127+
// Some(ServiceKey(Secret::Plain(value))) => Cow::Borrowed(value),
128+
// Some(ServiceKey(Secret::FromEnvironment { variable })) => Cow::Owned(environment.read(variable)?),
129+
// };
130+
131+
// let workload_identity_auth = match &args.connection_settings.workload_identity_auth {
132+
// WorkloadIdentityAuth(Secret::Plain(value)) => Cow::Borrowed(value),
133+
// WorkloadIdentityAuth(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?),
134+
// };
101135

102136
let project_id_ = match &args.connection_settings.project_id {
103137
ProjectId(Secret::Plain(value)) => Cow::Borrowed(value),
@@ -109,19 +143,37 @@ pub async fn configure(
109143
DatasetId(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?),
110144
};
111145

112-
let service_account_key = yup_oauth2::parse_service_account_key(service_key.as_str()).unwrap();
146+
// let service_account_key = yup_oauth2::parse_service_account_key(service_key.as_str()).unwrap();
113147

114148
let project_id = project_id_.as_str();
115149
let dataset_id = dataset_id_.as_str();
116150

117151
let schema_name = format!("{project_id}.{dataset_id}");
118152
let database_name = schema_name.clone();
119153

120-
// Init BigQuery client
121-
let bigquery_client =
122-
gcp_bigquery_client::Client::from_service_account_key(service_account_key, false)
123-
.await
124-
.unwrap();
154+
// let bigquery_client = match
155+
// BIG_QUERY_AUTH_URL
156+
157+
// let big_query_auth_url = match std::env::var("HASURA_BIGQUERY_WORKLOAD_IDENTITY_AUTH") {
158+
// Ok(val) => val,
159+
// Err(_) => {
160+
// return Err(anyhow::anyhow!(
161+
// "Environment variable HASURA_BIGQUERY_WORKLOAD_IDENTITY_AUTH not set"
162+
// ))
163+
// }
164+
// };
165+
166+
// std::env::set_var("BIG_QUERY_AUTH_URL", workload_identity_auth.as_ref());
167+
168+
// if
169+
170+
// let bigquery_client_auth = gcp_bigquery_client::Client::with_workload_identity(true).await.unwrap();
171+
172+
// // Init BigQuery client
173+
// let bigquery_client =
174+
// gcp_bigquery_client::Client::from_service_account_key(service_account_key, false)
175+
// .await
176+
// .unwrap();
125177

126178
// get scalar_types
127179

@@ -221,6 +273,7 @@ pub async fn configure(
221273
version: 1,
222274
connection_settings: connection_settings::DatabaseConnectionSettings {
223275
service_key: args.connection_settings.service_key.clone(),
276+
workload_identity_auth: args.connection_settings.workload_identity_auth.clone(),
224277
project_id: args.connection_settings.project_id.clone(),
225278
dataset_id: args.connection_settings.dataset_id.clone(),
226279
},

crates/connectors/ndc-bigquery/src/state.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
use thiserror::Error;
66
use tracing::{info_span, Instrument};
77

8-
// use ndc_bigquery_configuration::PoolSettings;
9-
// use ndc_bigquery_configuration::ConfigurationError;
10-
// use super::configuration::{Configuration, ConfigurationError};
11-
// use query_engine_execution::database_info::{self, DatabaseInfo, DatabaseVersion};
128
use query_engine_execution::metrics;
139

1410
/// State for our connector.
@@ -33,14 +29,19 @@ pub async fn create_state(
3329
.instrument(info_span!("Setup metrics"))
3430
.await?;
3531

36-
let service_account_key =
37-
yup_oauth2::parse_service_account_key(configuration.service_key.clone()).unwrap();
38-
39-
// Init BigQuery client
40-
let bigquery_client =
41-
gcp_bigquery_client::Client::from_service_account_key(service_account_key, false)
42-
.await
43-
.unwrap();
32+
let bigquery_client = match &configuration.auth {
33+
(true, workload_identity_auth) => {
34+
std::env::set_var("BIG_QUERY_AUTH_URL", workload_identity_auth);
35+
gcp_bigquery_client::Client::with_workload_identity(false).await.unwrap()
36+
}
37+
(false, service_key) => {
38+
let service_account_key =
39+
yup_oauth2::parse_service_account_key(service_key.clone()).unwrap();
40+
gcp_bigquery_client::Client::from_service_account_key(service_account_key, false)
41+
.await
42+
.unwrap()
43+
}
44+
};
4445

4546
Ok(State {
4647
metrics,

0 commit comments

Comments
 (0)