Skip to content

Commit

Permalink
Add possibility to specify credentials for S3 explicitly
Browse files Browse the repository at this point in the history
  • Loading branch information
Saruniks committed Jun 20, 2024
1 parent 3b5634a commit d5f4f48
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ endpoint = "s3-us-east-1.amazonaws.com"
use_ssl = true
key_prefix = "s3prefix"
server_side_encryption = false
access_key_id = "aws_access_key_id"
secret_access_key = "aws_secret_access_key"

[cache.webdav]
endpoint = "http://192.168.10.42:80/some/webdav.php"
Expand Down Expand Up @@ -150,6 +152,8 @@ configuration variables
* `SCCACHE_REGION` s3 region, required if using AWS S3
* `SCCACHE_S3_USE_SSL` s3 endpoint requires TLS, set this to `true`
* `SCCACHE_S3_KEY_PREFIX` s3 key prefix (optional)
* `SCCACHE_AWS_ACCESS_KEY_ID` AWS access key (optional). If not specified, sccache will attempt to load credentials from other sources (see [S3 credentials](S3.md#credentials))
* `SCCACHE_AWS_SECRET_ACCESS_KEY` AWS secret key (optional). If not specified, sccache will attempt to load credentials from other sources (see [S3 credentials](S3.md#credentials))

The endpoint used then becomes `${SCCACHE_BUCKET}.s3-{SCCACHE_REGION}.amazonaws.com`.
If you are not using the default endpoint and `SCCACHE_REGION` is undefined, it
Expand Down
4 changes: 3 additions & 1 deletion docs/S3.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ Cloudflare R2 is an S3-compatible object storage and works with the same configu

## Credentials

Sccache is able to load credentials from various sources. Including:
You can specify credentials using environment variables (`SCCACHE_AWS_ACCESS_KEY_ID` and `SCCACHE_AWS_SECRET_ACCESS_KEY`) or [file configuration](Configuration.md#file) (`access_key_id` and `secret_access_key`).

If credentials are not specified, sccache will attempt to load credentials from various other sources, including:

- Static: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
- Profile: `~/.aws/credentials` and `~/.aws/config`. The AWS_PROFILE environment variable can be used to select a specific profile if multiple profiles are available.
Expand Down
2 changes: 2 additions & 0 deletions src/cache/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,8 @@ pub fn storage_from_config(
c.endpoint.as_deref(),
c.use_ssl,
c.server_side_encryption,
c.access_key_id.as_deref(),
c.secret_access_key.as_deref(),
)
.map_err(|err| anyhow!("create s3 cache failed: {err:?}"))?;

Expand Down
11 changes: 11 additions & 0 deletions src/cache/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::errors::*;
pub struct S3Cache;

impl S3Cache {
#[allow(clippy::too_many_arguments)]
pub fn build(
bucket: &str,
region: Option<&str>,
Expand All @@ -29,12 +30,22 @@ impl S3Cache {
endpoint: Option<&str>,
use_ssl: Option<bool>,
server_side_encryption: Option<bool>,
access_key_id: Option<&str>,
secret_access_key: Option<&str>,
) -> Result<Operator> {
let mut builder = S3::default();
builder.http_client(set_user_agent());
builder.bucket(bucket);
builder.root(key_prefix);

if let Some(access_key_id) = access_key_id {
builder.access_key_id(access_key_id);
}

if let Some(secret_access_key) = secret_access_key {
builder.secret_access_key(secret_access_key);
}

if let Some(region) = region {
builder.region(region);
}
Expand Down
42 changes: 37 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ pub struct S3CacheConfig {
pub endpoint: Option<String>,
pub use_ssl: Option<bool>,
pub server_side_encryption: Option<bool>,
pub access_key_id: Option<String>,
pub secret_access_key: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -640,6 +642,8 @@ fn config_from_env() -> Result<EnvConfig> {
let server_side_encryption = bool_from_env_var("SCCACHE_S3_SERVER_SIDE_ENCRYPTION")?;
let endpoint = env::var("SCCACHE_ENDPOINT").ok();
let key_prefix = key_prefix_from_env_var("SCCACHE_S3_KEY_PREFIX");
let access_key_id = env::var("SCCACHE_AWS_ACCESS_KEY_ID").ok();
let secret_access_key = env::var("SCCACHE_AWS_SECRET_ACCESS_KEY").ok();

Some(S3CacheConfig {
bucket,
Expand All @@ -649,14 +653,18 @@ fn config_from_env() -> Result<EnvConfig> {
endpoint,
use_ssl,
server_side_encryption,
access_key_id,
secret_access_key,
})
} else {
None
};

if s3.as_ref().map(|s3| s3.no_credentials).unwrap_or_default()
&& (env::var_os("AWS_ACCESS_KEY_ID").is_some()
|| env::var_os("AWS_SECRET_ACCESS_KEY").is_some())
|| env::var_os("AWS_SECRET_ACCESS_KEY").is_some()
|| env::var_os("SCCACHE_AWS_ACCESS_KEY_ID").is_some()
|| env::var_os("SCCACHE_AWS_SECRET_ACCESS_KEY").is_some())
{
bail!("If setting S3 credentials, SCCACHE_S3_NO_CREDENTIALS must not be set.");
}
Expand Down Expand Up @@ -1309,7 +1317,27 @@ fn config_overrides() {

#[test]
#[serial]
fn test_s3_no_credentials_conflict() {
fn test_s3_no_credentials_conflict_0() {
env::set_var("SCCACHE_S3_NO_CREDENTIALS", "true");
env::set_var("SCCACHE_BUCKET", "my-bucket");
env::set_var("SCCACHE_AWS_ACCESS_KEY_ID", "aws-access-key-id");
env::set_var("SCCACHE_AWS_SECRET_ACCESS_KEY", "aws-secret-access-key");

let error = config_from_env().unwrap_err();
assert_eq!(
"If setting S3 credentials, SCCACHE_S3_NO_CREDENTIALS must not be set.",
error.to_string()
);

env::remove_var("SCCACHE_S3_NO_CREDENTIALS");
env::remove_var("SCCACHE_BUCKET");
env::remove_var("SCCACHE_AWS_ACCESS_KEY_ID");
env::remove_var("SCCACHE_AWS_SECRET_ACCESS_KEY");
}

#[test]
#[serial]
fn test_s3_no_credentials_conflict_1() {
env::set_var("SCCACHE_S3_NO_CREDENTIALS", "true");
env::set_var("SCCACHE_BUCKET", "my-bucket");
env::set_var("AWS_ACCESS_KEY_ID", "aws-access-key-id");
Expand Down Expand Up @@ -1479,8 +1507,10 @@ region = "us-east-2"
endpoint = "s3-us-east-1.amazonaws.com"
use_ssl = true
key_prefix = "s3prefix"
no_credentials = true
no_credentials = false
server_side_encryption = false
access_key_id = "some_access_key_id"
secret_access_key = "some_secret_access_key"
[cache.webdav]
endpoint = "http://127.0.0.1:8080"
Expand Down Expand Up @@ -1543,8 +1573,10 @@ no_credentials = true
endpoint: Some("s3-us-east-1.amazonaws.com".to_owned()),
use_ssl: Some(true),
key_prefix: "s3prefix".into(),
no_credentials: true,
server_side_encryption: Some(false)
no_credentials: false,
server_side_encryption: Some(false),
access_key_id: Some("some_access_key_id".to_owned()),
secret_access_key: Some("some_secret_access_key".to_owned()),
}),
webdav: Some(WebdavCacheConfig {
endpoint: "http://127.0.0.1:8080".to_string(),
Expand Down

0 comments on commit d5f4f48

Please sign in to comment.