iceberg/encryption/kms/client.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Key management client trait for encryption key operations.
19//!
20//! Mirrors the Java `KeyManagementClient` interface from the Apache Iceberg spec.
21
22use async_trait::async_trait;
23
24use crate::Result;
25use crate::encryption::SensitiveBytes;
26
27/// Result of a server-side key generation operation.
28///
29/// Returned by [`KeyManagementClient::generate_key`] when the KMS supports
30/// atomic key generation and wrapping.
31pub struct GeneratedKey {
32 key: SensitiveBytes,
33 wrapped_key: Vec<u8>,
34}
35
36impl GeneratedKey {
37 /// Creates a new `GeneratedKey` from plaintext key bytes and wrapped key bytes.
38 pub fn new(key: SensitiveBytes, wrapped_key: Vec<u8>) -> Self {
39 Self { key, wrapped_key }
40 }
41
42 /// Returns the plaintext key bytes. Zeroized on drop, redacted in Debug.
43 pub fn key(&self) -> &SensitiveBytes {
44 &self.key
45 }
46
47 /// Returns the wrapped (encrypted) key bytes.
48 pub fn wrapped_key(&self) -> &[u8] {
49 &self.wrapped_key
50 }
51}
52
53/// Pluggable interface for key management systems (AWS KMS, Azure Key Vault, etc.).
54#[async_trait]
55pub trait KeyManagementClient: Send + Sync + std::fmt::Debug {
56 /// Wrap (encrypt) a key using a wrapping key managed by the KMS.
57 async fn wrap_key(&self, key: &[u8], wrapping_key_id: &str) -> Result<Vec<u8>>;
58
59 /// Unwrap (decrypt) a previously wrapped key.
60 async fn unwrap_key(&self, wrapped_key: &[u8], wrapping_key_id: &str)
61 -> Result<SensitiveBytes>;
62
63 /// Whether this KMS supports server-side key generation.
64 ///
65 /// If `true`, callers can use [`generate_key`](Self::generate_key) for atomic
66 /// key generation and wrapping, which is more secure than generating a key
67 /// locally and then wrapping it.
68 fn supports_key_generation(&self) -> bool;
69
70 /// Generate a new key and wrap it atomically on the server side.
71 ///
72 /// This is only supported when [`supports_key_generation`](Self::supports_key_generation)
73 /// returns `true`.
74 async fn generate_key(&self, wrapping_key_id: &str) -> Result<GeneratedKey>;
75}
76
77#[async_trait]
78impl<T: AsRef<dyn KeyManagementClient> + Send + Sync + std::fmt::Debug> KeyManagementClient for T {
79 async fn wrap_key(&self, key: &[u8], wrapping_key_id: &str) -> Result<Vec<u8>> {
80 self.as_ref().wrap_key(key, wrapping_key_id).await
81 }
82
83 async fn unwrap_key(
84 &self,
85 wrapped_key: &[u8],
86 wrapping_key_id: &str,
87 ) -> Result<SensitiveBytes> {
88 self.as_ref().unwrap_key(wrapped_key, wrapping_key_id).await
89 }
90
91 fn supports_key_generation(&self) -> bool {
92 self.as_ref().supports_key_generation()
93 }
94
95 async fn generate_key(&self, wrapping_key_id: &str) -> Result<GeneratedKey> {
96 self.as_ref().generate_key(wrapping_key_id).await
97 }
98}