Skip to content

Commit 9afa725

Browse files
committed
feat(encryption) [3/N] Support encryption: KMS
1 parent 4e8cf7f commit 9afa725

5 files changed

Lines changed: 415 additions & 6 deletions

File tree

crates/iceberg/src/encryption/crypto.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use crate::{Error, ErrorKind, Result};
4343
/// containing `SensitiveBytes` can safely derive or implement `Debug`
4444
/// without risk of leaking key material.
4545
#[derive(Clone, PartialEq, Eq)]
46-
struct SensitiveBytes(Zeroizing<Box<[u8]>>);
46+
pub struct SensitiveBytes(Zeroizing<Box<[u8]>>);
4747

4848
impl SensitiveBytes {
4949
/// Wraps the given bytes as sensitive material.
@@ -57,13 +57,11 @@ impl SensitiveBytes {
5757
}
5858

5959
/// Returns the number of bytes.
60-
#[allow(dead_code)] // Encryption work is ongoing so currently unused
6160
pub fn len(&self) -> usize {
6261
self.0.len()
6362
}
6463

6564
/// Returns `true` if the byte slice is empty.
66-
#[allow(dead_code)] // Encryption work is ongoing so currently unused
6765
pub fn is_empty(&self) -> bool {
6866
self.0.is_empty()
6967
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
22+
use std::sync::Arc;
23+
24+
use async_trait::async_trait;
25+
26+
use crate::encryption::SensitiveBytes;
27+
use crate::{Error, ErrorKind, Result};
28+
29+
/// Result of a server-side key generation operation.
30+
///
31+
/// Returned by [`KeyManagementClient::generate_key`] when the KMS supports
32+
/// atomic key generation and wrapping.
33+
pub struct KeyGenerationResult {
34+
/// The plaintext key bytes. Zeroized on drop, redacted in Debug.
35+
pub key: SensitiveBytes,
36+
/// The wrapped (encrypted) key bytes.
37+
pub wrapped_key: Vec<u8>,
38+
}
39+
40+
/// Pluggable interface for key management systems (AWS KMS, Azure Key Vault, etc.).
41+
#[async_trait]
42+
pub trait KeyManagementClient: Send + Sync + std::fmt::Debug {
43+
/// Wrap (encrypt) a key using a wrapping key managed by the KMS.
44+
async fn wrap_key(&self, key: &[u8], wrapping_key_id: &str) -> Result<Vec<u8>>;
45+
46+
/// Unwrap (decrypt) a previously wrapped key.
47+
async fn unwrap_key(&self, wrapped_key: &[u8], wrapping_key_id: &str)
48+
-> Result<SensitiveBytes>;
49+
50+
/// Whether this KMS supports server-side key generation.
51+
///
52+
/// If `true`, callers can use [`generate_key`](Self::generate_key) for atomic
53+
/// key generation and wrapping, which is more secure than generating a key
54+
/// locally and then wrapping it.
55+
fn supports_key_generation(&self) -> bool {
56+
false
57+
}
58+
59+
/// Generate a new key and wrap it atomically on the server side.
60+
///
61+
/// This is only supported when [`supports_key_generation`](Self::supports_key_generation)
62+
/// returns `true`. The default implementation returns `FeatureUnsupported`.
63+
async fn generate_key(&self, _wrapping_key_id: &str) -> Result<KeyGenerationResult> {
64+
Err(Error::new(
65+
ErrorKind::FeatureUnsupported,
66+
"This KMS client does not support server-side key generation",
67+
))
68+
}
69+
}
70+
71+
#[async_trait]
72+
impl KeyManagementClient for Arc<dyn KeyManagementClient> {
73+
async fn wrap_key(&self, key: &[u8], wrapping_key_id: &str) -> Result<Vec<u8>> {
74+
self.as_ref().wrap_key(key, wrapping_key_id).await
75+
}
76+
77+
async fn unwrap_key(
78+
&self,
79+
wrapped_key: &[u8],
80+
wrapping_key_id: &str,
81+
) -> Result<SensitiveBytes> {
82+
self.as_ref().unwrap_key(wrapped_key, wrapping_key_id).await
83+
}
84+
85+
fn supports_key_generation(&self) -> bool {
86+
self.as_ref().supports_key_generation()
87+
}
88+
89+
async fn generate_key(&self, wrapping_key_id: &str) -> Result<KeyGenerationResult> {
90+
self.as_ref().generate_key(wrapping_key_id).await
91+
}
92+
}

0 commit comments

Comments
 (0)