diff --git a/Cargo.lock b/Cargo.lock
index 0c882e7..cb84cfc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1898,6 +1898,8 @@ dependencies = [
"reqwest",
"rust_util",
"sequoia-openpgp",
+ "serde",
+ "serde_json",
"sha-1",
"tar",
"tiny-encrypt",
@@ -2666,18 +2668,28 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.216"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.216"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -2686,14 +2698,15 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.133"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
- "ryu",
"serde",
+ "serde_core",
+ "zmij",
]
[[package]]
@@ -3873,6 +3886,12 @@ dependencies = [
"zstd",
]
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+
[[package]]
name = "zopfli"
version = "0.8.1"
diff --git a/Cargo.toml b/Cargo.toml
index 1ba8b3b..ceba3a9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,3 +29,5 @@ tar = "0.4"
flate2 = "1.0"
rust_util = "0.6"
tiny-encrypt = { version = "1.8", default-features = false }
+serde = { version = "1.0.228", features = ["serde_derive"] }
+serde_json = "1.0.149"
diff --git a/README.md b/README.md
index 3cb4197..4783a61 100644
--- a/README.md
+++ b/README.md
@@ -68,3 +68,18 @@ cd nettle
make
sudo make install
```
+
+
+
+Use STS token resolver:
+```json
+{
+ "oss_config": {
+ "endpoint": "_endpoint",
+ "sts_token_resolver": ["assume-role.ts", "ROLE_ARN"],
+ "bucket": "_bucket",
+ "path": "_path"
+ }
+}
+
+```
diff --git a/src/config_util.rs b/src/config_util.rs
index 20a9a22..05c5250 100644
--- a/src/config_util.rs
+++ b/src/config_util.rs
@@ -1,10 +1,9 @@
use chrono::Utc;
use json::JsonValue;
-use rust_util::{new_box_ioerror, XResult};
-use std::{
- fs,
- path::Path,
-};
+use rust_util::{new_box_ioerror, util_cmd, XResult};
+use serde::Deserialize;
+use std::process::Command;
+use std::{fs, path::Path};
pub const NAME: &str = env!("CARGO_PKG_NAME");
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -37,11 +36,22 @@ const ETC_OSS_BACKUPD_CONFIG: &str = "/etc/oss-backupd/config.json";
}
*/
+#[derive(Debug, Deserialize)]
+pub struct StsResolverResponse {
+ pub mode: String,
+ pub access_key_id: String,
+ pub access_key_secret: String,
+ pub sts_token: String,
+ pub expiration: String,
+}
+
#[derive(Debug, Clone)]
pub struct OSSConfig {
pub endpoint: Option,
pub access_key_id: Option,
pub access_key_secret: Option,
+ pub security_token: Option,
+ pub sts_token_resolver: Option>,
pub bucket: Option,
pub path: Option,
}
@@ -184,6 +194,12 @@ fn parse_oss_backupd_config_item(
if oc.access_key_secret.is_none() && root_oc.access_key_secret.is_some() {
oc.access_key_secret = root_oc.access_key_secret.clone();
}
+ if oc.security_token.is_none() && root_oc.security_token.is_some() {
+ oc.security_token = root_oc.security_token.clone();
+ }
+ if oc.sts_token_resolver.is_none() && root_oc.sts_token_resolver.is_some() {
+ oc.sts_token_resolver = root_oc.sts_token_resolver.clone();
+ }
if oc.bucket.is_none() && root_oc.bucket.is_some() {
oc.bucket = root_oc.bucket.clone();
}
@@ -249,13 +265,68 @@ fn parse_sub_oss_config(json: &json::JsonValue) -> Option {
}
fn parse_oss_config(oss_config: &json::JsonValue) -> OSSConfig {
- OSSConfig {
+ let mut oss_config = OSSConfig {
endpoint: get_string_value(oss_config, "endpoint"),
access_key_id: get_string_value(oss_config, "access_key_id"),
access_key_secret: get_string_value(oss_config, "access_key_secret"),
+ security_token: None,
+ sts_token_resolver: get_string_array_value(oss_config, "sts_token_resolver"),
bucket: get_string_value(oss_config, "bucket"),
path: get_string_value(oss_config, "path"),
+ };
+
+ if oss_config.sts_token_resolver.is_some()
+ && oss_config.access_key_id.is_none()
+ && oss_config.access_key_secret.is_none()
+ {
+ if let Some(sts_token_resolver) = &oss_config.sts_token_resolver {
+ if sts_token_resolver.len() > 0 {
+ let mut cmd = Command::new(&sts_token_resolver[0]);
+ for arg in sts_token_resolver.iter().skip(1) {
+ cmd.arg(arg);
+ }
+ match util_cmd::run_command_and_wait(&mut cmd) {
+ Ok(exit_status) => {
+ if exit_status.success() {
+ match cmd.output() {
+ Ok(output) => {
+ match serde_json::from_slice::(
+ output.stdout.as_slice(),
+ ) {
+ Ok(sts_resolver_response) => {
+ oss_config.access_key_id = Some(sts_resolver_response.access_key_id);
+ oss_config.access_key_secret = Some(sts_resolver_response.access_key_secret);
+ oss_config.security_token = Some(sts_resolver_response.sts_token);
+ }
+ Err(err) => {
+ failure!(
+ "Parse {:?} response failed: {}",
+ sts_token_resolver,
+ err
+ );
+ }
+ }
+ }
+ Err(err) => {
+ failure!("Execute {:?} failed: {}", sts_token_resolver, err);
+ }
+ }
+ } else {
+ failure!(
+ "Execute {:?} exit failed: {}",
+ sts_token_resolver,
+ exit_status
+ );
+ }
+ }
+ Err(err) => {
+ failure!("Execute {:?} failed: {}", sts_token_resolver, err);
+ }
+ }
+ }
+ }
}
+ oss_config
}
fn get_string_value(json: &JsonValue, key: &str) -> Option {
@@ -263,6 +334,20 @@ fn get_string_value(json: &JsonValue, key: &str) -> Option {
value.as_str().map(|s| s.to_owned())
}
+fn get_string_array_value(json: &JsonValue, key: &str) -> Option> {
+ let value = &json[key];
+ if let JsonValue::Array(array) = value {
+ let mut arr = vec![];
+ for value in array {
+ if let Some(s) = value.as_str() {
+ arr.push(s.to_owned());
+ }
+ }
+ return Some(arr);
+ }
+ return None;
+}
+
fn get_tiny_encrypt_value(json: &JsonValue) -> Option {
let tiny_encrypt = &json["tiny_encrypt"];
let config = get_string_value(tiny_encrypt, "config");
@@ -324,10 +409,11 @@ fn get_config_content(custom_oss_backupd_config: Option<&str>, verbose: bool) ->
}
};
}
- let home_dot_oss_backupd_config = &get_user_home_dir(DOT_OSS_BACKUPD_CONFIG).unwrap_or_else(|e| {
- warning!("Get user home error: {}", e);
- String::new()
- });
+ let home_dot_oss_backupd_config =
+ &get_user_home_dir(DOT_OSS_BACKUPD_CONFIG).unwrap_or_else(|e| {
+ warning!("Get user home error: {}", e);
+ String::new()
+ });
if !home_dot_oss_backupd_config.is_empty() {
let home_dot_oss_backupd_config_path = Path::new(home_dot_oss_backupd_config);
if home_dot_oss_backupd_config_path.exists() {
diff --git a/src/main.rs b/src/main.rs
index d391967..3f91a0e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@ use std::{
fs::{ self, File },
};
use std::path::PathBuf;
-use rust_util::{XResult, util_time::*, util_msg::*};
+use rust_util::{XResult, util_time::*};
use tiny_encrypt::CmdEncrypt;
use oss_util::*;
use config_util::*;