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::{debug, Logger};
7
8use mithril_common::crypto_helper::ManifestSignature;
9use mithril_common::entities::AncillaryFilesManifest;
10use mithril_common::StdResult;
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)
44 .await
45 .with_context(|| BASE_ERROR_CONTEXT)?;
46
47 Ok(AncillarySignerWithGcpKms {
48 kms_client,
49 resource_name,
50 logger,
51 })
52 }
53}
54
55#[async_trait]
56impl AncillarySigner for AncillarySignerWithGcpKms {
57 async fn compute_ancillary_manifest_signature(
58 &self,
59 manifest: &AncillaryFilesManifest,
60 ) -> StdResult<ManifestSignature> {
61 debug!(
62 self.logger,
63 ">> AncillarySignerWithGcpKms::compute_ancillary_manifest_signature"
64 );
65 let data = manifest.compute_hash();
66 let signature_response = self
67 .kms_client
68 .asymmetric_sign(
69 AsymmetricSignRequest {
70 name: self.resource_name.to_string(),
71 digest: None,
72 digest_crc32c: None,
73 data,
74 data_crc32c: None,
75 },
76 None,
77 )
78 .await
79 .with_context(|| "Failed to sign the ancillary manifest with GCP KMS".to_string())?;
80
81 ManifestSignature::from_bytes(&signature_response.signature).with_context(|| {
82 "Failed to convert the signature response from GCP KMS to a ManifestSignature"
83 .to_string()
84 })
85 }
86}