mithril_aggregator/services/snapshotter/ancillary_signer/
with_gcp_kms.rs1use anyhow::Context;
2use async_trait::async_trait;
3use gcloud_kms::client::google_cloud_auth::credentials::CredentialsFile;
4use gcloud_kms::client::{Client as GcpKmsClient, ClientConfig};
5use gcloud_kms::grpc::kms::v1::AsymmetricSignRequest;
6use slog::{Logger, debug};
7
8use mithril_cardano_node_internal_database::entities::AncillaryFilesManifest;
9use mithril_common::StdResult;
10use mithril_common::crypto_helper::ManifestSignature;
11
12use crate::services::ancillary_signer::{AncillarySigner, GcpCryptoKeyVersionResourceName};
13
14pub struct AncillarySignerWithGcpKms {
17 kms_client: GcpKmsClient,
18 resource_name: GcpCryptoKeyVersionResourceName,
19 logger: Logger,
20}
21
22impl AncillarySignerWithGcpKms {
23 pub async fn new(
25 resource_name: GcpCryptoKeyVersionResourceName,
26 credentials_json_env_var: String,
27 logger: Logger,
28 ) -> StdResult<Self> {
29 const BASE_ERROR_CONTEXT: &str =
30 "Failed to create Google Cloud KMS client for Ancillary manifest signing";
31 let unparsed_credentials_json = std::env::var(&credentials_json_env_var)
32 .with_context(|| {
33 format!("Environment variable `{credentials_json_env_var}` must be set",)
34 })
35 .with_context(|| BASE_ERROR_CONTEXT)?;
36 let credentials_file = CredentialsFile::new_from_str(&unparsed_credentials_json)
37 .await
38 .with_context(|| BASE_ERROR_CONTEXT)?;
39 let config = ClientConfig::default()
40 .with_credentials(credentials_file)
41 .await
42 .with_context(|| BASE_ERROR_CONTEXT)?;
43 let kms_client = GcpKmsClient::new(config).await.with_context(|| BASE_ERROR_CONTEXT)?;
44
45 Ok(AncillarySignerWithGcpKms {
46 kms_client,
47 resource_name,
48 logger,
49 })
50 }
51}
52
53#[async_trait]
54impl AncillarySigner for AncillarySignerWithGcpKms {
55 async fn compute_ancillary_manifest_signature(
56 &self,
57 manifest: &AncillaryFilesManifest,
58 ) -> StdResult<ManifestSignature> {
59 debug!(
60 self.logger,
61 ">> AncillarySignerWithGcpKms::compute_ancillary_manifest_signature"
62 );
63 let data = manifest.compute_hash();
64 let signature_response = self
65 .kms_client
66 .asymmetric_sign(
67 AsymmetricSignRequest {
68 name: self.resource_name.to_string(),
69 digest: None,
70 digest_crc32c: None,
71 data,
72 data_crc32c: None,
73 },
74 None,
75 )
76 .await
77 .with_context(|| "Failed to sign the ancillary manifest with GCP KMS".to_string())?;
78
79 ManifestSignature::from_bytes(&signature_response.signature).with_context(|| {
80 "Failed to convert the signature response from GCP KMS to a ManifestSignature"
81 .to_string()
82 })
83 }
84}