Skip to content

Commit b40b870

Browse files
committed
feat(config): add access_key_env and secret_key_env
1 parent da34254 commit b40b870

File tree

4 files changed

+68
-45
lines changed

4 files changed

+68
-45
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [0.2.0] - 2024-06-26
8+
## [Unreleased]
9+
10+
### Added
11+
12+
- Add `secret-key-env` and `access-key-env` options to load secrets from environment variables.
13+
14+
## [0.2.0] - 2024-06-27
915

1016
### Added
1117

@@ -16,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1622
- New `graceful-shutdown` config to enable or disable graceful shutdown for the HTTP server.
1723

1824
### Changed
25+
1926
- Disabled endpoints will return 503 (Service Unavailable) instead of 404 (Not Found).
2027

2128
## [0.1.1] - 2024-05-22
@@ -41,3 +48,5 @@ It includes basic support for QIDO-RS, WADO-RS and STOW-RS for the DIMSE backend
4148
- Implement QIDO-RS using the C-FIND protocol
4249
- Implement WADO-RS using the C-MOVE protocol
4350
- Implement STOW-RS using the C-STORE protocol
51+
52+
[0.2.0]: https://github.com/UMEssen/DICOM-RST/releases/tag/v0.2.0

src/backend/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ where
4949
let ae_config = state
5050
.config
5151
.aets
52-
.iter()
52+
.into_iter()
5353
.find(|aet_config| aet_config.aet == aet)
5454
.ok_or_else(|| (StatusCode::NOT_FOUND, format!("Unknown AET {aet}")))?;
5555

5656
// TODO: Use a singleton to avoid re-creating on every request.
57-
let provider = match &ae_config.backend {
57+
let provider = match ae_config.backend {
5858
#[cfg(feature = "dimse")]
5959
BackendConfig::Dimse { .. } => {
6060
let pool = state.pools.get(&ae_config.aet).expect("pool should exist");
@@ -86,7 +86,7 @@ where
8686
},
8787
BackendConfig::S3(config) => Self {
8888
qido: None,
89-
wado: Some(Box::new(S3WadoService::new(config))),
89+
wado: Some(Box::new(S3WadoService::new(&config))),
9090
stow: None,
9191
},
9292
};

src/backend/s3/wado.rs

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
use crate::api::wado::{InstanceResponse, RetrieveError, RetrieveInstanceRequest, WadoService};
22
use crate::backend::dimse::cmove::movescu::MoveError;
33
use crate::backend::dimse::wado::DicomMultipartStream;
4-
use crate::config::{S3Config, S3Credentials, S3EndpointStyle};
4+
use crate::config::{S3Config, S3EndpointStyle};
55
use async_trait::async_trait;
66
use aws_config::retry::RetryConfig;
77
use aws_config::stalled_stream_protection::StalledStreamProtectionConfig;
88
use aws_config::timeout::TimeoutConfig;
9-
use aws_config::{AppName, Region, SdkConfig};
10-
use aws_credential_types::provider::future::ProvideCredentials as ProvideCredentialsAsync;
11-
use aws_sdk_s3::config::{
12-
BehaviorVersion, Credentials, ProvideCredentials, SharedCredentialsProvider,
13-
};
9+
use aws_config::{AppName, Region};
10+
use aws_sdk_s3::config::BehaviorVersion;
1411
use bytes::Buf;
1512
use dicom::object::FileDicomObject;
1613
use futures::StreamExt;
1714
use std::sync::Arc;
1815
use std::time::Duration;
19-
use tracing::info;
2016
use tracing::log::trace;
17+
use tracing::{info, warn};
2118

2219
use super::S3ClientExt;
2320

@@ -27,36 +24,14 @@ pub struct S3WadoService {
2724
bucket: String,
2825
}
2926

30-
impl S3Credentials {
31-
#[allow(clippy::unused_async)]
32-
async fn load(&self) -> aws_credential_types::provider::Result {
33-
Ok(Credentials::new(
34-
&self.access_key,
35-
&self.secret_key,
36-
None,
37-
None,
38-
"StaticCredentials",
39-
))
40-
}
41-
}
42-
43-
impl ProvideCredentials for S3Credentials {
44-
fn provide_credentials<'a>(&'a self) -> ProvideCredentialsAsync<'a>
45-
where
46-
Self: 'a,
47-
{
48-
ProvideCredentialsAsync::new(self.load())
49-
}
50-
}
51-
5227
impl S3WadoService {
5328
pub fn new(config: &S3Config) -> Self {
5429
info!("Using S3 endpoint {}", &config.endpoint);
5530
let mut builder = aws_sdk_s3::config::Builder::new()
5631
.endpoint_url(&config.endpoint)
5732
.region(config.region.clone().map(Region::new))
5833
.behavior_version(BehaviorVersion::latest())
59-
.force_path_style(matches!(config.endpoint_style, S3EndpointStyle::Path))
34+
.force_path_style(matches!(config.endpoint_style, S3EndpointStyle::Path))
6035
.retry_config(RetryConfig::adaptive())
6136
// Causes issues with long-running requests and high concurrency.
6237
// It's okay to stall for some time.
@@ -72,12 +47,11 @@ impl S3WadoService {
7247
.app_name(AppName::new("DICOM-RST").expect("valid app name"));
7348

7449
if let Some(credentials) = &config.credentials {
75-
let credentials_provider = S3Credentials {
76-
access_key: String::from(&credentials.access_key),
77-
secret_key: String::from(&credentials.secret_key),
78-
};
79-
builder =
80-
builder.credentials_provider(SharedCredentialsProvider::new(credentials_provider));
50+
if let Ok(resolved_secrets) = credentials.resolve() {
51+
builder = builder.credentials_provider(resolved_secrets);
52+
} else {
53+
warn!("Failed to resolve credentials. Check your environment variables.");
54+
}
8155
}
8256

8357
let sdk_config = builder.build();

src/config/mod.rs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::types::AE;
22
use crate::DEFAULT_AET;
3+
use aws_credential_types::Credentials as AwsCredentials;
34
use serde::de::Error;
45
use serde::{Deserialize, Deserializer};
56
use std::net::IpAddr;
@@ -57,7 +58,7 @@ pub struct S3Config {
5758
pub region: Option<String>,
5859
pub concurrency: usize,
5960
#[serde(default)]
60-
pub credentials: Option<S3Credentials>,
61+
pub credentials: Option<S3CredentialsConfig>,
6162
#[serde(default)]
6263
pub endpoint_style: S3EndpointStyle,
6364
}
@@ -76,10 +77,49 @@ impl Default for S3EndpointStyle {
7677
}
7778

7879
#[derive(Debug, Clone, Deserialize)]
79-
#[serde(rename_all = "kebab-case")]
80-
pub struct S3Credentials {
81-
pub secret_key: String,
82-
pub access_key: String,
80+
#[serde(untagged)]
81+
pub enum S3CredentialsConfig {
82+
#[serde(rename_all = "kebab-case")]
83+
Env {
84+
access_key_env: String,
85+
secret_key_env: String,
86+
},
87+
#[serde(rename_all = "kebab-case")]
88+
Plain {
89+
access_key: String,
90+
secret_key: String,
91+
},
92+
}
93+
94+
impl S3CredentialsConfig {
95+
pub fn resolve(&self) -> Result<AwsCredentials, std::env::VarError> {
96+
match &self {
97+
Self::Plain {
98+
access_key,
99+
secret_key,
100+
} => Ok(AwsCredentials::new(
101+
access_key,
102+
secret_key,
103+
None,
104+
None,
105+
"AppConfigProvider",
106+
)),
107+
Self::Env {
108+
access_key_env,
109+
secret_key_env,
110+
} => {
111+
let access_key = std::env::var(access_key_env)?;
112+
let secret_key = std::env::var(secret_key_env)?;
113+
Ok(AwsCredentials::new(
114+
access_key,
115+
secret_key,
116+
None,
117+
None,
118+
"EnvVarProvider",
119+
))
120+
}
121+
}
122+
}
83123
}
84124

85125
#[derive(Debug, Clone, Deserialize)]

0 commit comments

Comments
 (0)