diff --git a/tools/pubsys/src/aws/ami/mod.rs b/tools/pubsys/src/aws/ami/mod.rs index 1e67734e327..1ff662bf384 100644 --- a/tools/pubsys/src/aws/ami/mod.rs +++ b/tools/pubsys/src/aws/ami/mod.rs @@ -111,11 +111,11 @@ async fn _run(args: &Args, ami_args: &AmiArgs) -> Result })?; // Build EBS client for snapshot management, and EC2 client for registration - let ebs_client = build_client::(&base_region, &aws).context(error::Client { + let ebs_client = build_client::(&base_region, &base_region, &aws).context(error::Client { client_type: "EBS", region: base_region.name(), })?; - let ec2_client = build_client::(&base_region, &aws).context(error::Client { + let ec2_client = build_client::(&base_region, &base_region, &aws).context(error::Client { client_type: "EC2", region: base_region.name(), })?; @@ -172,6 +172,7 @@ async fn _run(args: &Args, ami_args: &AmiArgs) -> Result wait_for_ami( &image_id, &base_region, + &base_region, "available", successes_required, &aws, @@ -187,7 +188,7 @@ async fn _run(args: &Args, ami_args: &AmiArgs) -> Result // live until the future is resolved. let mut ec2_clients = HashMap::with_capacity(regions.len()); for region in regions.iter() { - let ec2_client = build_client::(®ion, &aws).context(error::Client { + let ec2_client = build_client::(®ion, &base_region, &aws).context(error::Client { client_type: "EC2", region: base_region.name(), })?; diff --git a/tools/pubsys/src/aws/ami/wait.rs b/tools/pubsys/src/aws/ami/wait.rs index c1570e8701c..752142c5673 100644 --- a/tools/pubsys/src/aws/ami/wait.rs +++ b/tools/pubsys/src/aws/ami/wait.rs @@ -12,6 +12,7 @@ use std::time::Duration; pub(crate) async fn wait_for_ami( id: &str, region: &Region, + sts_region: &Region, state: &str, successes_required: u8, aws: &AwsConfig, @@ -49,7 +50,7 @@ pub(crate) async fn wait_for_ami( }; // Use a new client each time so we have more confidence that different endpoints can see // the new AMI. - let ec2_client = build_client::(®ion, &aws).context(error::Client { + let ec2_client = build_client::(®ion, &sts_region, &aws).context(error::Client { client_type: "EC2", region: region.name(), })?; diff --git a/tools/pubsys/src/aws/client.rs b/tools/pubsys/src/aws/client.rs index 489806219a0..d73a76ebc7d 100644 --- a/tools/pubsys/src/aws/client.rs +++ b/tools/pubsys/src/aws/client.rs @@ -38,10 +38,14 @@ impl NewWith for Ec2Client { } /// Create a rusoto client of the given type using the given region and configuration. -pub(crate) fn build_client(region: &Region, aws: &AwsConfig) -> Result { +pub(crate) fn build_client( + region: &Region, + sts_region: &Region, + aws: &AwsConfig, +) -> Result { let maybe_regional_role = aws.region.get(region.name()).and_then(|r| r.role.clone()); let assume_roles = aws.role.iter().chain(maybe_regional_role.iter()).cloned(); - let provider = build_provider(®ion, assume_roles.clone(), base_provider(&aws.profile)?)?; + let provider = build_provider(&sts_region, assume_roles.clone(), base_provider(&aws.profile)?)?; Ok(T::new_with( rusoto_core::HttpClient::new().context(error::HttpClient)?, provider, @@ -61,8 +65,13 @@ impl ProvideAwsCredentials for CredentialsProvider { } /// Chains credentials providers to assume the given roles in order. +/// The region given should be the one in which you want to talk to STS to get temporary +/// credentials, not the region in which you want to talk to a service endpoint like EC2. This is +/// needed because you may be assuming a role in an opt-in region from an account that has not +/// opted-in to that region, and you need to get session credentials from an STS endpoint in a +/// region to which you have access in the base account. fn build_provider

( - region: &Region, + sts_region: &Region, assume_roles: impl Iterator, base_provider: P, ) -> Result @@ -74,7 +83,7 @@ where let sts = StsClient::new_with( HttpClient::new().context(error::HttpClient)?, provider, - region.clone(), + sts_region.clone(), ); let expiring_provider = StsAssumeRoleSessionCredentialsProvider::new( sts, diff --git a/tools/pubsys/src/aws/publish_ami/mod.rs b/tools/pubsys/src/aws/publish_ami/mod.rs index 7b92224a2a3..94dea6fe43b 100644 --- a/tools/pubsys/src/aws/publish_ami/mod.rs +++ b/tools/pubsys/src/aws/publish_ami/mod.rs @@ -90,6 +90,9 @@ pub(crate) async fn run(args: &Args, publish_args: &PublishArgs) -> Result<()> { } else { aws.regions.clone().into() }; + ensure!(!regions.is_empty(), error::MissingConfig { missing: "aws.regions" }); + let base_region = region_from_string(®ions[0], &aws).context(error::ParseRegion)?; + // Check that the requested regions are a subset of the regions we *could* publish from the AMI // input JSON. let requested_regions = HashSet::from_iter(regions.iter()); @@ -121,7 +124,7 @@ pub(crate) async fn run(args: &Args, publish_args: &PublishArgs) -> Result<()> { // live until the future is resolved. let mut ec2_clients = HashMap::with_capacity(amis.len()); for region in amis.keys() { - let ec2_client = build_client::(®ion, &aws).context(error::Client { + let ec2_client = build_client::(®ion, &base_region, &aws).context(error::Client { client_type: "EC2", region: region.name(), })?;