Skip to content

Commit 57e9ccd

Browse files
committed
feat: support S3 SSE-KMS with AWS-managed and customer-managed keys
Add two S3 config options alongside the existing SSE-S3 toggle: - server_side_encryption_aws_kms (SCCACHE_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS) enables SSE-KMS with the AWS-managed key (aws/s3). - server_side_encryption_kms_key_id (SCCACHE_S3_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID) enables SSE-KMS with a customer-managed KMS key. Resolution precedence in the S3 builder: customer-managed KMS key > AWS-managed KMS > SSE-S3. Existing server_side_encryption configs are unchanged.
1 parent 4fcb161 commit 57e9ccd

5 files changed

Lines changed: 91 additions & 2 deletions

File tree

docs/Configuration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ bucket = "name"
123123
endpoint = "s3-us-east-1.amazonaws.com"
124124
use_ssl = true
125125
key_prefix = "s3prefix"
126+
# SSE-S3 with an S3-managed key (AES256).
126127
server_side_encryption = false
128+
# SSE-KMS with the AWS-managed KMS key (aws/s3).
129+
server_side_encryption_aws_kms = false
130+
# SSE-KMS with a customer-managed KMS key (takes precedence when set).
131+
# server_side_encryption_kms_key_id = "arn:aws:kms:us-east-1:111:key/abc"
127132

128133
[cache.webdav]
129134
endpoint = "http://192.168.10.42:80/some/webdav.php"

docs/S3.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ If you want to use S3 storage for the sccache cache, you need to set the followi
99

1010
If your endpoint requires HTTPS/TLS, set `SCCACHE_S3_USE_SSL=true`. If you don't need a secure network layer, HTTP (`SCCACHE_S3_USE_SSL=false`) might be better for performance.
1111

12-
Enable server-side encryption with s3 managed key (SSE-S3), set `SCCACHE_S3_SERVER_SIDE_ENCRYPTION=true`.
12+
Server-side encryption can be enabled in one of three modes. They are resolved in the following order of precedence:
13+
14+
- **SSE-KMS with a customer-managed KMS key:** set `SCCACHE_S3_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID` to the KMS key ID/ARN. This implies `aws:kms` and takes precedence over the other settings.
15+
- **SSE-KMS with the AWS-managed KMS key (`aws/s3`):** set `SCCACHE_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS=true`.
16+
- **SSE-S3 with an S3-managed key (AES256):** set `SCCACHE_S3_SERVER_SIDE_ENCRYPTION=true`.
17+
1318
More details about encryption [here](https://opendal.apache.org/docs/services/s3/#server-side-encryption) and documentation [here](https://docs.rs/opendal/latest/opendal/services/struct.S3.html#method.server_side_encryption_with_s3_key).
1419

1520
You can also define a prefix that will be prepended to the keys of all cache objects created and read within the S3 bucket, effectively creating a scope. To do that use the `SCCACHE_S3_KEY_PREFIX` environment variable. This can be useful when sharing a bucket with another application.

src/cache/cache.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,10 @@ pub fn build_single_cache(
528528
.with_endpoint(c.endpoint.clone())
529529
.with_use_ssl(c.use_ssl)
530530
.with_server_side_encryption(c.server_side_encryption)
531+
.with_server_side_encryption_aws_kms(c.server_side_encryption_aws_kms)
532+
.with_server_side_encryption_kms_key_id(
533+
c.server_side_encryption_kms_key_id.clone(),
534+
)
531535
.with_enable_virtual_host_style(c.enable_virtual_host_style)
532536
.build()
533537
.map_err(|err| anyhow!("create s3 cache failed: {err:?}"))?;

src/cache/s3.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub struct S3Cache {
2626
endpoint: Option<String>,
2727
use_ssl: Option<bool>,
2828
server_side_encryption: Option<bool>,
29+
server_side_encryption_aws_kms: Option<bool>,
30+
server_side_encryption_kms_key_id: Option<String>,
2931
enable_virtual_host_style: Option<bool>,
3032
}
3133

@@ -39,6 +41,8 @@ impl S3Cache {
3941
endpoint: None,
4042
use_ssl: None,
4143
server_side_encryption: None,
44+
server_side_encryption_aws_kms: None,
45+
server_side_encryption_kms_key_id: None,
4246
enable_virtual_host_style: None,
4347
}
4448
}
@@ -58,6 +62,20 @@ impl S3Cache {
5862
self.server_side_encryption = server_side_encryption;
5963
self
6064
}
65+
pub fn with_server_side_encryption_aws_kms(
66+
mut self,
67+
server_side_encryption_aws_kms: Option<bool>,
68+
) -> Self {
69+
self.server_side_encryption_aws_kms = server_side_encryption_aws_kms;
70+
self
71+
}
72+
pub fn with_server_side_encryption_kms_key_id(
73+
mut self,
74+
server_side_encryption_kms_key_id: Option<String>,
75+
) -> Self {
76+
self.server_side_encryption_kms_key_id = server_side_encryption_kms_key_id;
77+
self
78+
}
6179
pub fn with_enable_virtual_host_style(
6280
mut self,
6381
enable_virtual_host_style: Option<bool>,
@@ -93,7 +111,14 @@ impl S3Cache {
93111
builder = builder.endpoint(&endpoint_resolver(endpoint, self.use_ssl)?);
94112
}
95113

96-
if self.server_side_encryption.unwrap_or_default() {
114+
if let Some(kms_key_id) = &self.server_side_encryption_kms_key_id {
115+
// SSE-KMS with a customer-managed KMS key.
116+
builder = builder.server_side_encryption_with_customer_managed_kms_key(kms_key_id);
117+
} else if self.server_side_encryption_aws_kms.unwrap_or_default() {
118+
// SSE-KMS with the AWS-managed KMS key (aws/s3).
119+
builder = builder.server_side_encryption_with_aws_managed_kms_key();
120+
} else if self.server_side_encryption.unwrap_or_default() {
121+
// SSE-S3 with an S3-managed key (AES256).
97122
builder = builder.server_side_encryption_with_s3_key();
98123
}
99124

src/config.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@ pub struct S3CacheConfig {
464464
pub endpoint: Option<String>,
465465
pub use_ssl: Option<bool>,
466466
pub server_side_encryption: Option<bool>,
467+
pub server_side_encryption_aws_kms: Option<bool>,
468+
pub server_side_encryption_kms_key_id: Option<String>,
467469
pub enable_virtual_host_style: Option<bool>,
468470
#[serde(default)]
469471
pub rw_mode: CacheModeConfig,
@@ -886,6 +888,10 @@ fn config_from_env() -> Result<EnvConfig> {
886888
let no_credentials = bool_from_env_var("SCCACHE_S3_NO_CREDENTIALS")?.unwrap_or(false);
887889
let use_ssl = bool_from_env_var("SCCACHE_S3_USE_SSL")?;
888890
let server_side_encryption = bool_from_env_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION")?;
891+
let server_side_encryption_aws_kms =
892+
bool_from_env_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS")?;
893+
let server_side_encryption_kms_key_id =
894+
string_from_env_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID");
889895
let endpoint = string_from_env_var("SCCACHE_ENDPOINT");
890896
let key_prefix = key_prefix_from_env_var("SCCACHE_S3_KEY_PREFIX");
891897
let enable_virtual_host_style = bool_from_env_var("SCCACHE_S3_ENABLE_VIRTUAL_HOST_STYLE")?;
@@ -900,6 +906,8 @@ fn config_from_env() -> Result<EnvConfig> {
900906
endpoint,
901907
use_ssl,
902908
server_side_encryption,
909+
server_side_encryption_aws_kms,
910+
server_side_encryption_kms_key_id,
903911
enable_virtual_host_style,
904912
rw_mode,
905913
})
@@ -2353,6 +2361,44 @@ fn test_s3_no_credentials_valid_false() {
23532361
}
23542362
}
23552363

2364+
#[test]
2365+
#[serial(config_from_env)]
2366+
#[cfg(feature = "s3")]
2367+
fn test_s3_sse_kms_from_env() {
2368+
unsafe {
2369+
env::set_var("SCCACHE_BUCKET", "my-bucket");
2370+
env::set_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS", "true");
2371+
env::set_var(
2372+
"SCCACHE_S3_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID",
2373+
"arn:aws:kms:us-east-1:111:key/abc",
2374+
);
2375+
}
2376+
2377+
let cfg = config_from_env();
2378+
2379+
unsafe {
2380+
env::remove_var("SCCACHE_BUCKET");
2381+
env::remove_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS");
2382+
env::remove_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID");
2383+
}
2384+
2385+
let env_cfg = cfg.unwrap();
2386+
match env_cfg.cache.s3 {
2387+
Some(S3CacheConfig {
2388+
server_side_encryption_aws_kms,
2389+
ref server_side_encryption_kms_key_id,
2390+
..
2391+
}) => {
2392+
assert_eq!(server_side_encryption_aws_kms, Some(true));
2393+
assert_eq!(
2394+
server_side_encryption_kms_key_id.as_deref(),
2395+
Some("arn:aws:kms:us-east-1:111:key/abc")
2396+
);
2397+
}
2398+
None => unreachable!(),
2399+
}
2400+
}
2401+
23562402
#[test]
23572403
#[serial(config_from_env)]
23582404
#[cfg(feature = "gcs")]
@@ -2528,6 +2574,8 @@ key_prefix = "cosprefix"
25282574
key_prefix: "s3prefix".into(),
25292575
no_credentials: true,
25302576
server_side_encryption: Some(false),
2577+
server_side_encryption_aws_kms: None,
2578+
server_side_encryption_kms_key_id: None,
25312579
enable_virtual_host_style: None,
25322580
rw_mode: CacheModeConfig::ReadWrite,
25332581
}),
@@ -3025,6 +3073,8 @@ fn test_get_cache_levels_single_cache() {
30253073
endpoint: None,
30263074
use_ssl: None,
30273075
server_side_encryption: None,
3076+
server_side_encryption_aws_kms: None,
3077+
server_side_encryption_kms_key_id: None,
30283078
enable_virtual_host_style: None,
30293079
rw_mode: CacheModeConfig::ReadWrite,
30303080
}),

0 commit comments

Comments
 (0)