Skip to content

Commit

Permalink
First shot at spoof-prevention prevention.
Browse files Browse the repository at this point in the history
Named, for now, 'transit IPs'. Not sure what the best wayy to alter them
is but we'll see what mileage this gets us.
  • Loading branch information
FelixMcFelix committed May 29, 2024
1 parent e6fe817 commit e78c51f
Show file tree
Hide file tree
Showing 24 changed files with 153 additions and 8 deletions.
4 changes: 4 additions & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,10 @@ pub struct InstanceNetworkInterface {
/// True if this interface is the primary for the instance to which it's
/// attached.
pub primary: bool,

/// A set of additional networks that this interface may send and
/// receive traffic on.
pub transit_ips: Vec<IpNet>,
}

#[derive(
Expand Down
1 change: 1 addition & 0 deletions common/src/api/internal/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub struct NetworkInterface {
pub vni: external::Vni,
pub primary: bool,
pub slot: u8,
pub transit_ips: Vec<external::IpNet>,
}

/// An IP address and port range used for source NAT, i.e., making
Expand Down
16 changes: 16 additions & 0 deletions illumos-utils/src/opte/port_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,22 @@ impl PortManager {
}
}

// If there are any transit IPs set, allow them through.
// TODO: Currently set only in initial state.
// This, external IPs, and cfg'able state
// (DHCP?) are probably worth being managed by an RPW.
for block in &nic.transit_ips {
#[cfg(target_os = "illumos")]
hdl.allow_cidr(&port_name, super::net_to_cidr(*block));

debug!(
self.inner.log,
"Added CIDR to in/out allowlist";
"port_name" => &port_name,
"cidr" => ?block,
);
}

info!(
self.inner.log,
"Created OPTE port";
Expand Down
26 changes: 23 additions & 3 deletions nexus/db-model/src/network_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use chrono::DateTime;
use chrono::Utc;
use db_macros::Resource;
use diesel::AsChangeset;
use ipnetwork::IpNetwork;
use ipnetwork::NetworkSize;
use nexus_types::external_api::params;
use nexus_types::identity::Resource;
Expand Down Expand Up @@ -63,11 +64,13 @@ pub struct NetworkInterface {
//
// If user requests an address of either kind, give exactly that and not the other.
// If neither is specified, auto-assign one of each?
pub ip: ipnetwork::IpNetwork,
pub ip: IpNetwork,

pub slot: SqlU8,
#[diesel(column_name = is_primary)]
pub primary: bool,

pub transit_ips: Vec<IpNetwork>,
}

impl NetworkInterface {
Expand Down Expand Up @@ -101,6 +104,7 @@ impl NetworkInterface {
vni: external::Vni::try_from(0).unwrap(),
primary: self.primary,
slot: *self.slot,
transit_ips: self.transit_ips.into_iter().map(Into::into).collect(),
}
}
}
Expand All @@ -121,11 +125,13 @@ pub struct InstanceNetworkInterface {
pub subnet_id: Uuid,

pub mac: MacAddr,
pub ip: ipnetwork::IpNetwork,
pub ip: IpNetwork,

pub slot: SqlU8,
#[diesel(column_name = is_primary)]
pub primary: bool,

pub transit_ips: Vec<IpNetwork>,
}

/// Service Network Interface DB model.
Expand All @@ -144,7 +150,7 @@ pub struct ServiceNetworkInterface {
pub subnet_id: Uuid,

pub mac: MacAddr,
pub ip: ipnetwork::IpNetwork,
pub ip: IpNetwork,

pub slot: SqlU8,
#[diesel(column_name = is_primary)]
Expand Down Expand Up @@ -241,6 +247,7 @@ impl NetworkInterface {
ip: self.ip,
slot: self.slot,
primary: self.primary,
transit_ips: self.transit_ips,
}
}

Expand Down Expand Up @@ -289,6 +296,7 @@ impl From<InstanceNetworkInterface> for NetworkInterface {
ip: iface.ip,
slot: iface.slot,
primary: iface.primary,
transit_ips: iface.transit_ips,
}
}
}
Expand All @@ -312,6 +320,7 @@ impl From<ServiceNetworkInterface> for NetworkInterface {
ip: iface.ip,
slot: iface.slot,
primary: iface.primary,
transit_ips: vec![],
}
}
}
Expand Down Expand Up @@ -459,6 +468,7 @@ pub struct NetworkInterfaceUpdate {
pub time_modified: DateTime<Utc>,
#[diesel(column_name = is_primary)]
pub primary: Option<bool>,
pub transit_ips: Vec<IpNetwork>,
}

impl From<InstanceNetworkInterface> for external::InstanceNetworkInterface {
Expand All @@ -471,6 +481,11 @@ impl From<InstanceNetworkInterface> for external::InstanceNetworkInterface {
ip: iface.ip.ip(),
mac: *iface.mac,
primary: iface.primary,
transit_ips: iface
.transit_ips
.into_iter()
.map(Into::into)
.collect(),
}
}
}
Expand All @@ -483,6 +498,11 @@ impl From<params::InstanceNetworkInterfaceUpdate> for NetworkInterfaceUpdate {
description: params.identity.description,
time_modified: Utc::now(),
primary,
transit_ips: params
.transit_ips
.into_iter()
.map(Into::into)
.collect(),
}
}
}
1 change: 1 addition & 0 deletions nexus/db-model/src/omicron_zone_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ impl OmicronZoneNic {
vni: omicron_common::api::external::Vni::try_from(*self.vni)
.context("parsing VNI")?,
subnet: self.subnet.into(),
transit_ips: vec![],
})
}
}
2 changes: 2 additions & 0 deletions nexus/db-model/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ table! {
ip -> Inet,
slot -> Int2,
is_primary -> Bool,
transit_ips -> Array<Inet>,
}
}

Expand All @@ -537,6 +538,7 @@ table! {
ip -> Inet,
slot -> Int2,
is_primary -> Bool,
transit_ips -> Array<Inet>,
}
}
joinable!(instance_network_interface -> instance (instance_id));
Expand Down
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::collections::BTreeMap;
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(65, 0, 0);
pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(66, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -29,6 +29,7 @@ static KNOWN_VERSIONS: Lazy<Vec<KnownVersion>> = Lazy::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(66, "nic-spoof-allow"),
KnownVersion::new(65, "vpc-subnet-routing"),
KnownVersion::new(64, "add-view-for-v2p-mappings"),
KnownVersion::new(63, "remove-producer-base-route-column"),
Expand Down
3 changes: 3 additions & 0 deletions nexus/db-queries/src/db/datastore/network_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct NicInfo {
vni: db::model::Vni,
primary: bool,
slot: i16,
transit_ips: Vec<ipnetwork::IpNetwork>,
}

impl From<NicInfo> for omicron_common::api::internal::shared::NetworkInterface {
Expand Down Expand Up @@ -93,6 +94,7 @@ impl From<NicInfo> for omicron_common::api::internal::shared::NetworkInterface {
vni: nic.vni.0,
primary: nic.primary,
slot: u8::try_from(nic.slot).unwrap(),
transit_ips: nic.transit_ips.iter().map(|v| (*v).into()).collect(),
}
}
}
Expand Down Expand Up @@ -503,6 +505,7 @@ impl DataStore {
vpc::vni,
network_interface::is_primary,
network_interface::slot,
network_interface::transit_ips,
))
.get_results_async::<NicInfo>(
&*self.pool_connection_authorized(opctx).await?,
Expand Down
9 changes: 9 additions & 0 deletions nexus/db-queries/src/db/datastore/rack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -1417,6 +1418,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
external_ip: OmicronZoneExternalSnatIp {
id: ExternalIpUuid::new_v4(),
Expand Down Expand Up @@ -1464,6 +1466,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -1493,6 +1496,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
external_ip: OmicronZoneExternalSnatIp {
id: ExternalIpUuid::new_v4(),
Expand Down Expand Up @@ -1718,6 +1722,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -1750,6 +1755,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -1988,6 +1994,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -2093,6 +2100,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down Expand Up @@ -2125,6 +2133,7 @@ mod test {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
},
},
),
Expand Down
3 changes: 3 additions & 0 deletions nexus/reconfigurator/execution/src/external_networking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ mod tests {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
};

let dns_id = OmicronZoneUuid::new_v4();
Expand All @@ -526,6 +527,7 @@ mod tests {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
};

// Boundary NTP:
Expand Down Expand Up @@ -555,6 +557,7 @@ mod tests {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
};

Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ impl<'a> BlueprintBuilder<'a> {
vni: Vni::SERVICES_VNI,
primary: true,
slot: 0,
transit_ips: vec![],
}
};

Expand Down
2 changes: 2 additions & 0 deletions nexus/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> {
slot: 0,
subnet: (*NEXUS_OPTE_IPV4_SUBNET).into(),
vni: Vni::SERVICES_VNI,
transit_ips: vec![],
},
}),
});
Expand Down Expand Up @@ -1043,6 +1044,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> {
slot: 0,
subnet: (*DNS_OPTE_IPV4_SUBNET).into(),
vni: Vni::SERVICES_VNI,
transit_ips: vec![],
},
},
),
Expand Down
1 change: 1 addition & 0 deletions nexus/tests/integration_tests/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ pub static DEMO_INSTANCE_NIC_PUT: Lazy<params::InstanceNetworkInterfaceUpdate> =
description: Some(String::from("an updated description")),
},
primary: false,
transit_ips: vec![],
});

pub static DEMO_CERTIFICATE_NAME: Lazy<Name> =
Expand Down
3 changes: 3 additions & 0 deletions nexus/tests/integration_tests/instances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2213,6 +2213,7 @@ async fn test_instance_update_network_interfaces(
description: Some(new_description.clone()),
},
primary: false,
transit_ips: vec![],
};

// Verify we fail to update the NIC when the instance is running
Expand Down Expand Up @@ -2289,6 +2290,7 @@ async fn test_instance_update_network_interfaces(
description: None,
},
primary: true,
transit_ips: vec![],
};
let updated_primary_iface1 = NexusRequest::object_put(
client,
Expand Down Expand Up @@ -2383,6 +2385,7 @@ async fn test_instance_update_network_interfaces(
description: None,
},
primary: true,
transit_ips: vec![],
};
let new_primary_iface = NexusRequest::object_put(
client,
Expand Down
3 changes: 3 additions & 0 deletions nexus/types/src/external_api/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,9 @@ pub struct InstanceNetworkInterfaceUpdate {
// for the instance, though not the name.
#[serde(default)]
pub primary: bool,

/// TODO: describe
pub transit_ips: Vec<IpNet>,
}

// CERTIFICATES
Expand Down
Loading

0 comments on commit e78c51f

Please sign in to comment.