Skip to content

Commit

Permalink
Store the session tokens on the credentials file
Browse files Browse the repository at this point in the history
- Store the tokens
- Read them before requesting a new one
- Make sure to respect the expiration date comming from AWS

Closes #2
  • Loading branch information
marceloboeira committed Sep 24, 2018
1 parent 4db89c8 commit 458808c
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 34 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ clap = "2.31.2"
rusoto_core = "0.33"
rusoto_sts = "0.33"
rust-ini = "0.12"
chrono = "0.4"
111 changes: 77 additions & 34 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern crate clap;
extern crate ini;
extern crate rusoto_core;
extern crate rusoto_sts;
extern crate chrono;

use std::env;
use std::path::Path;
Expand All @@ -10,18 +11,13 @@ use std::process::{Command, Stdio};

use ini::Ini;
use clap::{Arg, App};
use rusoto_sts::{Sts, StsClient, Credentials, AssumeRoleRequest};
use rusoto_sts::{Sts, StsClient, AssumeRoleRequest};
use rusoto_core::{Region};
use chrono::prelude::*;

const AWS_DEFAULT_CONFIG_PATH: &str = ".aws/credentials";
const AWS_DEFAULT_SESSION_NAME: &str = "awsudo";

fn inject_environment_with(credentials: Credentials) {
env::set_var("AWS_ACCESS_KEY_ID", credentials.access_key_id);
env::set_var("AWS_SECRET_ACCESS_KEY", credentials.secret_access_key);
env::set_var("AWS_SESSION_TOKEN", credentials.session_token);
}

fn main() {
// CLI
//TODO Extract this to its own module/file/package...
Expand Down Expand Up @@ -61,7 +57,7 @@ fn main() {
// END CLI

// State manager
let conf = match Ini::load_from_file(config_file_path) {
let conf = match Ini::load_from_file(config_file_path.clone()) {
Err(message) => panic!(message),
Ok(value) => value
};
Expand All @@ -71,43 +67,90 @@ fn main() {
let mfa_serial = section.get("mfa_serial").unwrap();
//TODO parse region or default

//TODO use a debug flag for those
// ~~~cached token ~~
let file_aws_access_key_id = match section.get("aws_sudo_access_key_id") {
Some(value) => value,
None => "invalid"
};
let file_aws_secret_access_key = match section.get("aws_sudo_secret_access_key") {
Some(value) => value,
None => "invalid"
};
let file_aws_session_token = match section.get("aws_sudo_session_token") {
Some(value) => value,
None => "invalid"
};
let file_aws_session_expiration_date = match section.get("aws_sudo_session_expiration_date") {
Some(value) => value,
None => "1994-07-03T07:30:00.00Z"
};

let now = Utc::now();
let session_expires_at = match file_aws_session_expiration_date.parse::<DateTime<Utc>>() {
Ok(value) => value,
Err(e) => panic!("{:?}", e)
};

println!("role_arn: {:?}", role_arn);
println!("mfa_serial: {:?}", mfa_serial);
// END State Manager

//TODO Figure where to put this token request interaction...
//TODO Get the MFA token only if necessary
let mut token = String::new();
if !mfa_serial.is_empty() {
println!("Please type your MFA token for {:}: ", mfa_serial);
match io::stdin().read_line(&mut token) {
Ok(_) => {
token.pop(); //REMOVES THE \n
println!("token: {}", token);

if file_aws_access_key_id != "invalid" && now <= session_expires_at {
env::set_var("AWS_ACCESS_KEY_ID", file_aws_access_key_id);
env::set_var("AWS_SECRET_ACCESS_KEY", file_aws_secret_access_key);
env::set_var("AWS_SESSION_TOKEN", file_aws_session_token);
} else {
//TODO use a debug flag for those
println!("role_arn: {:?}", role_arn);
println!("mfa_serial: {:?}", mfa_serial);
// END State Manager

//TODO Figure where to put this token request interaction...
//TODO Get the MFA token only if necessary
let mut token = String::new();
if !mfa_serial.is_empty() {
println!("Please type your MFA token for {:}: ", mfa_serial);
match io::stdin().read_line(&mut token) {
Ok(_) => {
token.pop(); //REMOVES THE \n
println!("token: {}", token);
}
Err(error) => println!("error: {}", error),
}
Err(error) => println!("error: {}", error),
}
}

// Token Generator
//TODO Extract this to its own module/file/package...
//TODO use the default
let sts = StsClient::new(Region::EuCentral1);
match sts.assume_role(AssumeRoleRequest{
// Token Generator
//TODO Extract this to its own module/file/package...
//TODO use the default
let sts = StsClient::new(Region::EuCentral1);
match sts.assume_role(AssumeRoleRequest{
role_arn: role_arn.to_string(),
role_session_name: AWS_DEFAULT_SESSION_NAME.to_owned(),
serial_number: Some(mfa_serial.to_string()),
token_code: Some(token.to_string()),
..Default::default() }).sync() {
Err(e) => panic!("{:?}", e),
Ok(response) => inject_environment_with(response.credentials.unwrap())
};
// END Token Generator
Err(e) => panic!("{:?}", e),
Ok(response) => {
let credentials = response.credentials.unwrap();
let mut another = match Ini::load_from_file(config_file_path.clone()) {
Err(message) => panic!(message),
Ok(value) => value
};

another.with_section(Some(profile_name))
.set("aws_sudo_access_key_id", credentials.access_key_id.clone())
.set("aws_sudo_secret_access_key", credentials.secret_access_key.clone())
.set("aws_sudo_session_token", credentials.session_token.clone())
.set("aws_sudo_session_expiration_date", credentials.expiration.clone());

another.write_to_file(config_file_path.clone()).unwrap();

env::set_var("AWS_ACCESS_KEY_ID", credentials.access_key_id);
env::set_var("AWS_SECRET_ACCESS_KEY", credentials.secret_access_key);
env::set_var("AWS_SESSION_TOKEN", credentials.session_token);
}

// TODO: Persist token with State Manager
//
// TODO: Where to put the environment stuff? StateManager?
};
}

// Command runner
//TODO Extract this to its own module/file/package...
Expand Down

0 comments on commit 458808c

Please sign in to comment.