Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

infrasys: update to AWS SDK Rust #2414

Merged
merged 1 commit into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
379 changes: 149 additions & 230 deletions tools/Cargo.lock

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions tools/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ skip = [
]

skip-tree = [
# rusoto_signature uses an older version of sha2
{ name = "rusoto_signature" },

# structopt pulls in an older version of clap
{ name = "structopt", version = "0.3.26" },

Expand Down
7 changes: 4 additions & 3 deletions tools/infrasys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ clap = "3.1"
hex = "0.4.0"
log = "0.4.14"
pubsys-config = { path = "../pubsys-config/", version = "0.1.0" }
rusoto_cloudformation = { version = "0.48.0", default-features = false, features = ["rustls"] }
rusoto_core = { version = "0.48.0", default-features = false, features = ["rustls"] }
rusoto_s3 = { version = "0.48.0", default-features = false, features = ["rustls"] }
aws-config = "0.48.0"
aws-types = "0.48.0"
aws-sdk-cloudformation = "0.18.0"
aws-sdk-s3 = "0.18.0"
serde_json = "1.0.66"
serde_yaml = "0.8.17"
sha2 = "0.10"
Expand Down
22 changes: 13 additions & 9 deletions tools/infrasys/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use aws_sdk_s3::types::SdkError;
use snafu::Snafu;
use std::io;
use std::path::PathBuf;
Expand All @@ -14,7 +15,7 @@ pub enum Error {
CreateStack {
stack_name: String,
region: String,
source: rusoto_core::RusotoError<rusoto_cloudformation::CreateStackError>,
source: SdkError<aws_sdk_cloudformation::error::CreateStackError>,
},

#[snafu(display(
Expand All @@ -40,6 +41,9 @@ pub enum Error {
))]
CreateStackTimeout { stack_name: String, region: String },

#[snafu(display("No stack data returned for CFN stack '{}' in {}", stack_name, region))]
MissingStack { stack_name: String, region: String },

#[snafu(display(
"Failed to fetch stack details for CFN stack '{}' in '{}': {}",
stack_name,
Expand All @@ -49,7 +53,7 @@ pub enum Error {
DescribeStack {
stack_name: String,
region: String,
source: rusoto_core::RusotoError<rusoto_cloudformation::DescribeStacksError>,
source: SdkError<aws_sdk_cloudformation::error::DescribeStacksError>,
},

#[snafu(display("Missing environment variable '{}'", var))]
Expand Down Expand Up @@ -117,11 +121,11 @@ pub enum Error {
source: std::num::ParseIntError,
},

#[snafu(display("Failed to parse '{}' to a valid rusoto region: {}", what, source))]
ParseRegion {
what: String,
source: rusoto_core::region::ParseRegionError,
},
#[snafu(display("Failed to find default region"))]
DefaultRegion,

#[snafu(display("Unable to parse stack status"))]
ParseStatus,

#[snafu(display(
"Failed to find field '{}' after attempting to create resource '{}'",
Expand All @@ -139,7 +143,7 @@ pub enum Error {
#[snafu(display("Failed to push object to bucket '{}': {}", bucket_name, source))]
PutObject {
bucket_name: String,
source: rusoto_core::RusotoError<rusoto_s3::PutObjectError>,
source: SdkError<aws_sdk_s3::error::PutObjectError>,
},

#[snafu(display(
Expand All @@ -149,7 +153,7 @@ pub enum Error {
))]
PutPolicy {
bucket_name: String,
source: rusoto_core::RusotoError<rusoto_s3::PutBucketPolicyError>,
source: SdkError<aws_sdk_s3::error::PutBucketPolicyError>,
},

#[snafu(display("Failed to create async runtime: {}", source))]
Expand Down
44 changes: 23 additions & 21 deletions tools/infrasys/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use async_trait::async_trait;
use aws_sdk_cloudformation::Client as CloudFormationClient;
use aws_types::region::Region;
use pubsys_config::{KMSKeyConfig, SigningKeyConfig};
use rusoto_cloudformation::{CloudFormation, CloudFormationClient, CreateStackInput};
use rusoto_core::Region;
use snafu::{OptionExt, ResultExt};
use std::fs;
use std::str::FromStr;

use super::{error, shared, Result};

Expand Down Expand Up @@ -34,7 +33,7 @@ pub fn check_signing_key_config(signing_key_config: &SigningKeyConfig) -> Result
SigningKeyConfig::file { .. } => (),
SigningKeyConfig::kms { config, .. } => {
let config = config.as_ref().context(error::MissingConfigSnafu {
missing: "config field for a kms key",
missing: "config field for kms keys",
})?;

match (
Expand Down Expand Up @@ -89,9 +88,13 @@ impl KMSKeyConfigExt for KMSKeyConfig {
missing: "key_alias",
})?
);
let cfn_client = CloudFormationClient::new(
Region::from_str(region).context(error::ParseRegionSnafu { what: region })?,
);

let config = aws_config::from_env()
.region(Region::new(region.to_owned()))
.load()
.await;
let cfn_client = CloudFormationClient::new(&config);

let cfn_filepath = format!(
"{}/infrasys/cloudformation-templates/kms_key_setup.yml",
shared::getenv("BUILDSYS_TOOLS_DIR")?
Expand All @@ -100,20 +103,19 @@ impl KMSKeyConfigExt for KMSKeyConfig {
.context(error::FileReadSnafu { path: cfn_filepath })?;

let stack_result = cfn_client
.create_stack(CreateStackInput {
parameters: Some(vec![shared::create_parameter(
"Alias".to_string(),
self.key_alias
.as_ref()
.context(error::KeyConfigSnafu {
missing: "key_alias",
})?
.to_string(),
)]),
stack_name: stack_name.clone(),
template_body: Some(cfn_template.clone()),
..Default::default()
})
.create_stack()
.parameters(shared::create_parameter(
"Alias".to_string(),
self.key_alias
.as_ref()
.context(error::KeyConfigSnafu {
missing: "key_alias",
})?
.to_string(),
))
.stack_name(stack_name.clone())
.template_body(cfn_template.clone())
.send()
.await
.context(error::CreateStackSnafu {
stack_name: &stack_name,
Expand Down
53 changes: 42 additions & 11 deletions tools/infrasys/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ mod root;
mod s3;
mod shared;

use aws_sdk_cloudformation::Region;
use error::Result;
use log::{error, info};
use pubsys_config::{InfraConfig, RepoConfig, S3Config, SigningKeyConfig};
use sha2::{Digest, Sha512};
use shared::KeyRole;
use simplelog::{Config as LogConfig, LevelFilter, SimpleLogger};
use simplelog::{CombinedLogger, Config as LogConfig, ConfigBuilder, LevelFilter, SimpleLogger};
use snafu::{ensure, OptionExt, ResultExt};
use std::collections::HashMap;
use std::num::NonZeroUsize;
Expand Down Expand Up @@ -62,7 +63,35 @@ fn run() -> Result<()> {
// Parse and store the args passed to the program
let args = Args::from_args();

SimpleLogger::init(args.log_level, LogConfig::default()).context(error::LoggerSnafu)?;
match args.log_level {
// Set log level for AWS SDK to error to reduce verbosity.
LevelFilter::Info => {
CombinedLogger::init(vec![
SimpleLogger::new(
LevelFilter::Info,
ConfigBuilder::new()
.add_filter_ignore_str("aws_config")
.add_filter_ignore_str("aws_smithy")
.add_filter_ignore_str("tracing::span")
.build(),
),
SimpleLogger::new(
LevelFilter::Warn,
ConfigBuilder::new()
.add_filter_allow_str("aws_config")
.add_filter_allow_str("aws_smithy")
.add_filter_allow_str("tracing::span")
.build(),
),
])
.context(error::LoggerSnafu)?;
}

// Set the supplied log level across the whole crate.
_ => {
SimpleLogger::init(args.log_level, LogConfig::default()).context(error::LoggerSnafu)?
}
}

match args.subcommand {
SubCommand::CreateInfra(ref run_task_args) => {
Expand Down Expand Up @@ -124,7 +153,7 @@ async fn create_infra(toml_path: &Path, root_role_path: &Path) -> Result<()> {
// Upload root.json.
info!("Uploading root.json to S3 bucket...");
s3::upload_file(
repo_info.s3_region,
&repo_info.s3_region,
&bucket_name,
&repo_info.prefix,
root_role_path,
Expand Down Expand Up @@ -187,7 +216,7 @@ struct ValidRepoInfo<'a> {
root_key_threshold: &'a NonZeroUsize,
root_keys: &'a mut SigningKeyConfig,
root_role_url: &'a mut Option<Url>,
s3_region: &'a String,
s3_region: Region,
s3_stack_name: String,
signing_keys: &'a mut SigningKeyConfig,
stack_arn: &'a mut Option<String>,
Expand All @@ -204,20 +233,22 @@ impl<'a> ValidRepoInfo<'a> {
let s3_stack_name =
repo_config
.file_hosting_config_name
.as_ref()
.to_owned()
.context(error::MissingConfigSnafu {
missing: "file_hosting_config_name",
})?;
let s3_info = s3_info_map
.get_mut(s3_stack_name)
.get_mut(&s3_stack_name)
.context(error::MissingConfigSnafu {
missing: format!("aws.s3 config with name {}", s3_stack_name),
})?;
Ok(ValidRepoInfo {
s3_stack_name: s3_stack_name.to_string(),
s3_region: s3_info.region.as_ref().context(error::MissingConfigSnafu {
missing: format!("region for '{}' s3 config", s3_stack_name),
})?,
s3_region: Region::new(s3_info.region.as_ref().cloned().context(
error::MissingConfigSnafu {
missing: format!("region for '{}' s3 config", s3_stack_name),
},
)?),
bucket_name: &mut s3_info.bucket_name,
stack_arn: &mut s3_info.stack_arn,
vpce_id: s3_info
Expand Down Expand Up @@ -262,11 +293,11 @@ async fn create_repo_infrastructure(
// Create S3 bucket
info!("Creating S3 bucket...");
let (s3_stack_arn, bucket_name, bucket_rdn) =
s3::create_s3_bucket(repo_info.s3_region, &repo_info.s3_stack_name).await?;
s3::create_s3_bucket(&repo_info.s3_region, &repo_info.s3_stack_name).await?;

// Add Bucket Policy to newly created bucket
s3::add_bucket_policy(
repo_info.s3_region,
&repo_info.s3_region,
&bucket_name,
&repo_info.prefix,
repo_info.vpce_id,
Expand Down
39 changes: 26 additions & 13 deletions tools/infrasys/src/root.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{error, KeyRole, Result};
use aws_config::meta::region::RegionProviderChain;
use log::{trace, warn};
use pubsys_config::SigningKeyConfig;
use rusoto_core::Region;
use snafu::{ensure, OptionExt, ResultExt};
use std::collections::HashMap;
use std::fs;
Expand Down Expand Up @@ -39,6 +39,21 @@ pub fn check_root(root_role_path: &Path) -> Result<()> {
});
Ok(())
}
pub fn get_region() -> Result<String> {
let rt = tokio::runtime::Runtime::new().context(error::RuntimeSnafu)?;
rt.block_on(async { async_get_region().await })
}

async fn async_get_region() -> Result<String> {
let default_region_fallback = "us-east-1";
let default_region = RegionProviderChain::default_provider()
.or_else(default_region_fallback)
.region()
.await
.context(error::DefaultRegionSnafu)?
.to_string();
Ok(default_region)
}

/// Creates the directory where root.json will live and creates root.json itself according to details specified in root-role-path
pub fn create_root(root_role_path: &Path) -> Result<()> {
Expand All @@ -48,22 +63,20 @@ pub fn create_root(root_role_path: &Path) -> Result<()> {
thing: "root role",
})?;
fs::create_dir_all(role_dir).context(error::MkdirSnafu { path: role_dir })?;
let default_region = get_region()?;

// Initialize root
tuftool!(&default_region, "root init '{}'", root_role_path.display());
tuftool!(
Region::default().name(),
"root init '{}'",
root_role_path.display()
);
tuftool!(
Region::default().name(),
&default_region,
// TODO: expose expiration date as a configurable parameter
"root expire '{}' 'in 52 weeks'",
root_role_path.display()
);
Ok(())
}

/// Adds keys to root.json according to key type
/// Adds keys to root.json according to key type
pub fn add_keys(
signing_key_config: &mut SigningKeyConfig,
role: &KeyRole,
Expand Down Expand Up @@ -108,11 +121,11 @@ fn add_keys_kms(
num_keys: (*available_keys).len(),
}
);

let default_region = get_region()?;
match role {
KeyRole::Root => {
tuftool!(
Region::default().name(),
&default_region,
"root set-threshold '{}' root '{}' ",
filepath,
threshold.to_string()
Expand All @@ -128,19 +141,19 @@ fn add_keys_kms(
}
KeyRole::Publication => {
tuftool!(
Region::default().name(),
&default_region,
"root set-threshold '{}' snapshot '{}' ",
filepath,
threshold.to_string()
);
tuftool!(
Region::default().name(),
&default_region,
"root set-threshold '{}' targets '{}' ",
filepath,
threshold.to_string()
);
tuftool!(
Region::default().name(),
&default_region,
"root set-threshold '{}' timestamp '{}' ",
filepath,
threshold.to_string()
Expand Down
Loading