commonware_deployer/ec2/
authorize.rs1use crate::ec2::{
4 aws::*,
5 deployer_directory,
6 utils::{exact_cidr, get_public_ip, DEPLOYER_MAX_PORT, DEPLOYER_MIN_PORT, DEPLOYER_PROTOCOL},
7 Config, Error, CREATED_FILE_NAME, DESTROYED_FILE_NAME, MONITORING_REGION,
8};
9use std::{collections::HashSet, fs::File, path::PathBuf};
10use tracing::info;
11
12pub async fn authorize(config_path: &PathBuf, ip: Option<String>) -> Result<(), Error> {
14 let config: Config = {
16 let config_file = File::open(config_path)?;
17 serde_yaml::from_reader(config_file)?
18 };
19 let tag = &config.tag;
20 info!(tag = tag.as_str(), "loaded configuration");
21
22 let tag_directory = deployer_directory(tag);
24 if !tag_directory.exists() {
25 return Err(Error::DeploymentDoesNotExist(tag.clone()));
26 }
27 let created_file = tag_directory.join(CREATED_FILE_NAME);
28 if !created_file.exists() {
29 return Err(Error::DeploymentNotComplete(tag.clone()));
30 }
31 let destroyed_file = tag_directory.join(DESTROYED_FILE_NAME);
32 if destroyed_file.exists() {
33 return Err(Error::DeploymentAlreadyDestroyed(tag.clone()));
34 }
35
36 let new_ip = if let Some(ip_str) = ip {
38 let ip_addr: std::net::IpAddr = ip_str
40 .parse()
41 .map_err(|_| Error::InvalidIpAddress(ip_str.clone()))?;
42 let std::net::IpAddr::V4(ipv4) = ip_addr else {
43 return Err(Error::InvalidIpAddress(ip_str));
44 };
45 ipv4.to_string()
46 } else {
47 get_public_ip().await?
49 };
50 info!(
51 ip = new_ip.as_str(),
52 "adding IP to existing security groups"
53 );
54
55 let mut all_regions = HashSet::new();
57 all_regions.insert(MONITORING_REGION.to_string());
58 for instance in &config.instances {
59 all_regions.insert(instance.region.clone());
60 }
61
62 let mut changes = Vec::new();
64 for region in all_regions {
65 let ec2_client = create_ec2_client(Region::new(region.clone())).await;
66 info!(region = region.as_str(), "created EC2 client");
67
68 let security_groups = find_security_groups_by_tag(&ec2_client, tag).await?;
70 for sg in security_groups {
71 let sg_id = sg.group_id().unwrap();
73 let mut already_allowed = false;
74 for perm in sg.ip_permissions() {
75 if perm.ip_protocol() == Some(DEPLOYER_PROTOCOL)
78 && perm.from_port() == Some(DEPLOYER_MIN_PORT)
79 && perm.to_port() == Some(DEPLOYER_MAX_PORT)
80 {
81 for ip_range in perm.ip_ranges() {
82 if ip_range.cidr_ip() == Some(&exact_cidr(&new_ip)) {
83 already_allowed = true;
84 break;
85 }
86 }
87 if already_allowed {
88 break;
89 }
90 }
91 }
92
93 if already_allowed {
95 info!(sg_id, "IP already allowed");
96 continue;
97 }
98 ec2_client
99 .authorize_security_group_ingress()
100 .group_id(sg_id)
101 .ip_permissions(
102 IpPermission::builder()
103 .ip_protocol(DEPLOYER_PROTOCOL)
104 .from_port(DEPLOYER_MIN_PORT)
105 .to_port(DEPLOYER_MAX_PORT)
106 .ip_ranges(IpRange::builder().cidr_ip(exact_cidr(&new_ip)).build())
107 .build(),
108 )
109 .send()
110 .await
111 .map_err(|err| err.into_service_error())?;
112 info!(sg_id, "added ingress rule for IP");
113 changes.push(sg_id.to_string());
114 }
115 }
116 info!(?changes, "IP added to security groups");
117 Ok(())
118}