Skip to content

Commit

Permalink
pubsys: disallow private AMIs in public SSM params
Browse files Browse the repository at this point in the history
  • Loading branch information
cbgbt committed Dec 21, 2022
1 parent 0e50626 commit a89fb03
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 27 deletions.
79 changes: 79 additions & 0 deletions tools/Cargo.lock

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

2 changes: 1 addition & 1 deletion tools/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ confidence-threshold = 0.93
# Commented license types are allowed but not currently used
allow = [
"Apache-2.0",
# "BSD-2-Clause",
"BSD-2-Clause",
"BSD-3-Clause",
"BSL-1.0",
# "CC0-1.0",
Expand Down
6 changes: 3 additions & 3 deletions tools/pubsys-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl InfraConfig {
}

/// S3-specific TUF infrastructure configuration
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Eq, Clone)]
pub struct S3Config {
pub region: Option<String>,
#[serde(default)]
Expand All @@ -116,7 +116,7 @@ pub struct S3Config {
}

/// AWS-specific infrastructure configuration
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Eq, Clone)]
#[serde(deny_unknown_fields)]
pub struct AwsConfig {
#[serde(default)]
Expand All @@ -130,7 +130,7 @@ pub struct AwsConfig {
}

/// AWS region-specific configuration
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
#[serde(deny_unknown_fields)]
pub struct AwsRegionConfig {
pub role: Option<String>,
Expand Down
2 changes: 2 additions & 0 deletions tools/pubsys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ clap = "3.1"
coldsnap = { version = "0.4", default-features = false, features = ["aws-sdk-rust-rustls"] }
duct = "0.13.0"
futures = "0.3.5"
governor = "0.5"
http = "0.2.8"
indicatif = "0.17.1"
lazy_static = "1.4"
log = "0.4"
nonzero_ext = "0.3"
num_cpus = "1"
parse-datetime = { path = "../../sources/parse-datetime", version = "0.1.0" }
pubsys-config = { path = "../pubsys-config/", version = "0.1.0" }
Expand Down
3 changes: 2 additions & 1 deletion tools/pubsys/src/aws/ami/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The ami module owns the 'ami' subcommand and controls the process of registering and copying
//! EC2 AMIs.

pub(crate) mod public;
mod register;
mod snapshot;
pub(crate) mod wait;
Expand Down Expand Up @@ -370,7 +371,7 @@ async fn _run(args: &Args, ami_args: &AmiArgs) -> Result<HashMap<String, Image>>
/// If JSON output was requested, we serialize out a mapping of region to AMI information; this
/// struct holds the information we save about each AMI. The `ssm` subcommand uses this
/// information to populate templates representing SSM parameter names and values.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
pub(crate) struct Image {
pub(crate) id: String,
pub(crate) name: String,
Expand Down
64 changes: 64 additions & 0 deletions tools/pubsys/src/aws/ami/public.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use aws_sdk_ec2::Client as Ec2Client;
use snafu::{ensure, OptionExt, ResultExt};

/// Returns whether or not the given AMI ID refers to a public AMI.
pub(crate) async fn ami_is_public(
ec2_client: &Ec2Client,
region: &str,
ami_id: &str,
) -> Result<bool> {
let ec2_response = ec2_client
.describe_images()
.image_ids(ami_id.to_string())
.send()
.await
.context(error::DescribeImagesSnafu {
ami_id: ami_id.to_string(),
region: region.to_string(),
})?;

let returned_images = ec2_response.images().unwrap_or_default();

ensure!(
returned_images.len() <= 1,
error::TooManyImagesSnafu {
ami_id: ami_id.to_string(),
region: region.to_string(),
}
);

Ok(returned_images
.first()
.context(error::NoSuchImageSnafu {
ami_id: ami_id.to_string(),
region: region.to_string(),
})?
.public()
.unwrap_or(false))
}

mod error {
use aws_sdk_ec2::error::DescribeImagesError;
use aws_sdk_ec2::types::SdkError;
use snafu::Snafu;

#[derive(Debug, Snafu)]
#[snafu(visibility(pub(super)))]
pub(crate) enum Error {
#[snafu(display("Error describing AMI {} in {}: {}", ami_id, region, source))]
DescribeImages {
ami_id: String,
region: String,
#[snafu(source(from(SdkError<DescribeImagesError>, Box::new)))]
source: Box<SdkError<DescribeImagesError>>,
},

#[snafu(display("AMI {} not found in {}", ami_id, region))]
NoSuchImage { ami_id: String, region: String },

#[snafu(display("Multiples AMIs with ID {} found in {}", ami_id, region))]
TooManyImages { ami_id: String, region: String },
}
}
pub(crate) use error::Error;
type Result<T> = std::result::Result<T, error::Error>;
Loading

0 comments on commit a89fb03

Please sign in to comment.