Skip to content

Commit

Permalink
Merge pull request #95 from near/daniyar/gcp-auth
Browse files Browse the repository at this point in the history
  • Loading branch information
itegulov authored Apr 21, 2023
2 parents efa5205 + 61fe9dc commit b3c2adf
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 180 deletions.
54 changes: 48 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mpc-recovery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ near-jsonrpc-primitives = "0.16.1"
near-primitives = "0.16.1"
near-crypto = "0.16.1"
tower-http = { version = "0.4.0", features = ["cors"] }
yup-oauth2 = "8"
122 changes: 0 additions & 122 deletions mpc-recovery/src/gcp/auth.rs

This file was deleted.

100 changes: 57 additions & 43 deletions mpc-recovery/src/gcp/mod.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,69 @@
use std::fs::File;

use hyper::client::HttpConnector;
use hyper_rustls::HttpsConnector;
use mpc_recovery_gcp::google::cloud::secretmanager::v1::{
secret_manager_service_client::SecretManagerServiceClient, AccessSecretVersionRequest,
};
use tonic::{
transport::{Certificate, Channel, ClientTlsConfig},
Request,
Request, Status,
};
use yup_oauth2::{
authenticator::{ApplicationDefaultCredentialsTypes, Authenticator},
ApplicationDefaultCredentialsAuthenticator, ApplicationDefaultCredentialsFlowOpts,
};

use self::auth::TokenManager;

mod auth;

const DOMAIN_NAME: &str = "secretmanager.googleapis.com";
const ENDPOINT: &str = "https://secretmanager.googleapis.com";
const SCOPES: [&str; 1] = ["https://www.googleapis.com/auth/cloud-platform"];
const TLS_CERTS: &[u8] = include_bytes!("../../roots.pem");

pub async fn load_secret_share(node_id: u64) -> anyhow::Result<Vec<u8>> {
// GOOGLE_APPLICATION_CREDENTIALS points to the credentials file on GCP:
// https://cloud.google.com/docs/authentication/application-default-credentials
let path = std::env::var("GOOGLE_APPLICATION_CREDENTIALS")?;
let file = File::open(path)?;
let creds = serde_json::from_reader(file)?;
let mut token_manager = TokenManager::new(creds, &SCOPES);
let token = token_manager.token().await?;

let tls_config = ClientTlsConfig::new()
.ca_certificate(Certificate::from_pem(TLS_CERTS))
.domain_name(DOMAIN_NAME);

let channel = Channel::from_static(ENDPOINT)
.tls_config(tls_config)?
.connect()
.await?;
let mut client =
SecretManagerServiceClient::with_interceptor(channel, move |mut req: Request<()>| {
req.metadata_mut()
.insert("authorization", token.parse().unwrap());
Ok(req)
});
let request = Request::new(AccessSecretVersionRequest {
name: format!(
"projects/pagoda-discovery-platform-dev/secrets/mpc-recovery-secret-share-{node_id}/versions/latest"
),
});

let response = client.access_secret_version(request).await?;
let secret_payload = response
.into_inner()
.payload
.ok_or_else(|| anyhow::anyhow!("failed to fetch secret share from GCP Secret Manager"))?;
Ok(secret_payload.data)
pub struct GcpService {
authenticator: Authenticator<HttpsConnector<HttpConnector>>,
}

impl GcpService {
pub async fn new() -> anyhow::Result<Self> {
let opts = ApplicationDefaultCredentialsFlowOpts::default();
let authenticator = match ApplicationDefaultCredentialsAuthenticator::builder(opts).await {
ApplicationDefaultCredentialsTypes::InstanceMetadata(auth) => auth.build().await?,
ApplicationDefaultCredentialsTypes::ServiceAccount(auth) => auth.build().await?,
};

Ok(Self { authenticator })
}

pub async fn load_secret(&self, name: String) -> anyhow::Result<Vec<u8>> {
let access_token = self
.authenticator
.token(&["https://www.googleapis.com/auth/cloud-platform"])
.await?;
let token = access_token
.token()
.ok_or_else(|| anyhow::anyhow!("GCP token did not have access_token field in it"))?;

let tls_config = ClientTlsConfig::new()
.ca_certificate(Certificate::from_pem(TLS_CERTS))
.domain_name(DOMAIN_NAME);

let channel = Channel::from_static(ENDPOINT)
.tls_config(tls_config)?
.connect()
.await?;
let mut client =
SecretManagerServiceClient::with_interceptor(channel, move |mut req: Request<()>| {
req.metadata_mut().insert(
"authorization",
format!("Bearer {}", token)
.parse()
.map_err(|_| Status::unauthenticated("failed to parse access token"))?,
);
Ok(req)
});

let request = Request::new(AccessSecretVersionRequest { name });
let response = client.access_secret_version(request).await?;
let secret_payload = response.into_inner().payload.ok_or_else(|| {
anyhow::anyhow!("failed to fetch secret share from GCP Secret Manager")
})?;
Ok(secret_payload.data)
}
}
Loading

0 comments on commit b3c2adf

Please sign in to comment.