From 3eba67819640525e88577cc9dd3bfa960e631dbe Mon Sep 17 00:00:00 2001 From: Alex Plotnick Date: Mon, 31 Oct 2022 09:17:00 -0600 Subject: [PATCH 1/5] Bring in latest OPTE --- Cargo.lock | 12 ++++++------ sled-agent/Cargo.toml | 4 ++-- tools/install_opte.sh | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f69daaf4fdf..dc8cc177f73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2354,7 +2354,7 @@ dependencies = [ [[package]] name = "illumos-sys-hdrs" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" [[package]] name = "impl-trait-for-tuples" @@ -2519,7 +2519,7 @@ checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" [[package]] name = "kstat-macro" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" dependencies = [ "quote", "syn", @@ -3507,7 +3507,7 @@ dependencies = [ [[package]] name = "opte" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" dependencies = [ "cfg-if 0.1.10", "dyn-clone", @@ -3524,7 +3524,7 @@ dependencies = [ [[package]] name = "opte-api" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" dependencies = [ "cfg-if 0.1.10", "illumos-sys-hdrs", @@ -3536,7 +3536,7 @@ dependencies = [ [[package]] name = "opte-ioctl" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" dependencies = [ "libc", "libnet", @@ -3598,7 +3598,7 @@ dependencies = [ [[package]] name = "oxide-vpc" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=23fdf5856f10f23e2d26865d2d7e2d3bc537bca3#23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +source = "git+https://github.com/oxidecomputer/opte?rev=e6e197a08c086cfa4cdb2e58bf71c580f89229ac#e6e197a08c086cfa4cdb2e58bf71c580f89229ac" dependencies = [ "cfg-if 0.1.10", "illumos-sys-hdrs", diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index 97c7425fd6e..91e816c7c7e 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -25,7 +25,7 @@ libc = "0.2.135" macaddr = { version = "1.0.1", features = [ "serde_std" ] } nexus-client = { path = "../nexus-client" } omicron-common = { path = "../common" } -oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "23fdf5856f10f23e2d26865d2d7e2d3bc537bca3", features = [ "api", "std" ] } +oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "e6e197a08c086cfa4cdb2e58bf71c580f89229ac", features = [ "api", "std" ] } oximeter = { version = "0.1.0", path = "../oximeter/oximeter" } oximeter-producer = { version = "0.1.0", path = "../oximeter/producer" } p256 = "0.9.0" @@ -59,7 +59,7 @@ vsss-rs = { version = "2.0.0", default-features = false, features = ["std"] } zone = "0.1" [target.'cfg(target_os = "illumos")'.dependencies] -opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" } +opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "e6e197a08c086cfa4cdb2e58bf71c580f89229ac" } [dev-dependencies] expectorate = "1.0.5" diff --git a/tools/install_opte.sh b/tools/install_opte.sh index 55845c43526..feb3c86f2c8 100755 --- a/tools/install_opte.sh +++ b/tools/install_opte.sh @@ -122,7 +122,7 @@ function add_publisher { # `helios-netdev` provides the xde kernel driver and the `opteadm` userland tool # for interacting with it. HELIOS_NETDEV_BASE_URL="https://buildomat.eng.oxide.computer/public/file/oxidecomputer/opte/repo" -HELIOS_NETDEV_COMMIT="23fdf5856f10f23e2d26865d2d7e2d3bc537bca3" +HELIOS_NETDEV_COMMIT="e6e197a08c086cfa4cdb2e58bf71c580f89229ac" HELIOS_NETDEV_REPO_URL="$HELIOS_NETDEV_BASE_URL/$HELIOS_NETDEV_COMMIT/opte.p5p" HELIOS_NETDEV_REPO_SHA_URL="$HELIOS_NETDEV_BASE_URL/$HELIOS_NETDEV_COMMIT/opte.p5p.sha256" HELIOS_NETDEV_REPO_PATH="$XDE_DIR/$(basename "$HELIOS_NETDEV_REPO_URL")" From 1644949908487607177724395b1b9fcd20e6709a Mon Sep 17 00:00:00 2001 From: Alex Plotnick Date: Mon, 31 Oct 2022 09:30:27 -0600 Subject: [PATCH 2/5] Updates for latest OPTE --- sled-agent/src/opte/illumos/firewall_rules.rs | 10 +++++----- sled-agent/src/opte/illumos/port_manager.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sled-agent/src/opte/illumos/firewall_rules.rs b/sled-agent/src/opte/illumos/firewall_rules.rs index c3332f5d9bb..4a1cd8011b4 100644 --- a/sled-agent/src/opte/illumos/firewall_rules.rs +++ b/sled-agent/src/opte/illumos/firewall_rules.rs @@ -12,10 +12,10 @@ use omicron_common::api::external::VpcFirewallRuleAction; use omicron_common::api::external::VpcFirewallRuleDirection; use omicron_common::api::external::VpcFirewallRuleProtocol; use omicron_common::api::external::VpcFirewallRuleStatus; -use oxide_vpc::api::Action; use oxide_vpc::api::Address; use oxide_vpc::api::Direction; use oxide_vpc::api::Filters; +use oxide_vpc::api::FirewallAction; use oxide_vpc::api::FirewallRule; use oxide_vpc::api::Ipv4Cidr; use oxide_vpc::api::Ipv4PrefixLen; @@ -24,7 +24,7 @@ use oxide_vpc::api::ProtoFilter; use oxide_vpc::api::Protocol; trait FromVpcFirewallRule { - fn action(&self) -> Action; + fn action(&self) -> FirewallAction; fn direction(&self) -> Direction; fn disabled(&self) -> bool; fn hosts(&self) -> Vec
; @@ -34,10 +34,10 @@ trait FromVpcFirewallRule { } impl FromVpcFirewallRule for VpcFirewallRule { - fn action(&self) -> Action { + fn action(&self) -> FirewallAction { match self.action { - VpcFirewallRuleAction::Allow => Action::Allow, - VpcFirewallRuleAction::Deny => Action::Deny, + VpcFirewallRuleAction::Allow => FirewallAction::Allow, + VpcFirewallRuleAction::Deny => FirewallAction::Deny, } } diff --git a/sled-agent/src/opte/illumos/port_manager.rs b/sled-agent/src/opte/illumos/port_manager.rs index 9fa694f1aff..70f7e1f95f8 100644 --- a/sled-agent/src/opte/illumos/port_manager.rs +++ b/sled-agent/src/opte/illumos/port_manager.rs @@ -278,7 +278,7 @@ impl PortManager { snat, external_ips: external_ip, }), - private_mac: MacAddr::from(mac.into_array()), + guest_mac: MacAddr::from(mac.into_array()), gateway_mac: MacAddr::from(gateway.mac.into_array()), vni, phys_ip: self.inner.underlay_ip.into(), From 571399e793ae14b79ace2ab0b4c8e411c001a394 Mon Sep 17 00:00:00 2001 From: Alex Plotnick Date: Mon, 31 Oct 2022 10:07:39 -0600 Subject: [PATCH 3/5] Remove allow-rdp default firewall rule --- nexus/defaults/src/lib.rs | 10 ------- nexus/tests/integration_tests/vpc_firewall.rs | 27 ------------------- 2 files changed, 37 deletions(-) diff --git a/nexus/defaults/src/lib.rs b/nexus/defaults/src/lib.rs index c7af06cca01..8360e3aa0d3 100644 --- a/nexus/defaults/src/lib.rs +++ b/nexus/defaults/src/lib.rs @@ -66,16 +66,6 @@ lazy_static! { "action": "allow", "priority": 65534, "description": "allow inbound ICMP traffic from anywhere" - }, - { - "name": "allow-rdp", - "status": "enabled", - "direction": "inbound", - "targets": [ { "type": "vpc", "value": "default" } ], - "filters": { "ports": [ "3389" ], "protocols": [ "TCP" ] }, - "action": "allow", - "priority": 65534, - "description": "allow inbound TCP connections on port 3389 from anywhere" } ] }"#).unwrap(); diff --git a/nexus/tests/integration_tests/vpc_firewall.rs b/nexus/tests/integration_tests/vpc_firewall.rs index d8eade9c5c9..ecfb03c6b67 100644 --- a/nexus/tests/integration_tests/vpc_firewall.rs +++ b/nexus/tests/integration_tests/vpc_firewall.rs @@ -232,33 +232,6 @@ fn is_default_firewall_rules( priority: VpcFirewallRulePriority(65534), vpc_id: Uuid::new_v4(), }, - VpcFirewallRule { - identity: IdentityMetadata { - id: "dd166833-cd79-4279-beb0-186cadb982ce".parse().unwrap(), - name: "allow-rdp".parse().unwrap(), - description: - "allow inbound TCP connections on port 3389 from anywhere" - .to_string(), - time_created: "2021-11-16T00:24:06.027404Z".parse().unwrap(), - time_modified: "2021-11-16T00:24:06.027404Z".parse().unwrap(), - }, - status: VpcFirewallRuleStatus::Enabled, - direction: VpcFirewallRuleDirection::Inbound, - targets: vec![VpcFirewallRuleTarget::Vpc( - vpc_name.parse().unwrap(), - )], - filters: VpcFirewallRuleFilter { - hosts: None, - protocols: Some(vec![VpcFirewallRuleProtocol::Tcp]), - ports: Some(vec![L4PortRange { - first: L4Port::try_from(3389).unwrap(), - last: L4Port::try_from(3389).unwrap(), - }]), - }, - action: VpcFirewallRuleAction::Allow, - priority: VpcFirewallRulePriority(65534), - vpc_id: Uuid::new_v4(), - }, VpcFirewallRule { identity: IdentityMetadata { id: "4cb76726-4cb6-4bc2-8d32-71c36e3881d4".parse().unwrap(), From 1a96ebb25d522c6131ba4ca71ab0b95b1cbb8b63 Mon Sep 17 00:00:00 2001 From: Alex Plotnick Date: Mon, 31 Oct 2022 15:37:54 -0600 Subject: [PATCH 4/5] Filter VPC by VNI --- common/src/api/external/mod.rs | 18 ++++++++ nexus/src/app/vpc.rs | 33 ++++++++++---- openapi/sled-agent.json | 43 ++++++++++++++++++- sled-agent-client/src/lib.rs | 16 +++++++ sled-agent/src/opte/illumos/firewall_rules.rs | 20 ++++++--- sled-agent/src/params.rs | 2 +- 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 3d8ee960b29..ebffc14d82e 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1191,6 +1191,15 @@ impl From for IpNet { } } +impl From for IpNet { + fn from(n: IpAddr) -> IpNet { + match n { + IpAddr::V4(v4) => IpNet::from(v4), + IpAddr::V6(v6) => IpNet::from(v6), + } + } +} + impl std::fmt::Display for IpNet { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -1269,6 +1278,15 @@ impl JsonSchema for IpNet { } } +/// A `VpcAddress` represents either an explicit IP network (v4 or v6) +/// or an entire VPC (identified by its VNI). +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] +pub enum VpcAddress { + Ip(IpNet), + Vpc(Vni), +} + /// Insert another level of schema indirection in order to provide an /// additional title for a subschema. This allows generators to infer a better /// variant name for an "untagged" enum. diff --git a/nexus/src/app/vpc.rs b/nexus/src/app/vpc.rs index 121e73d05e3..50cd9edfbc4 100644 --- a/nexus/src/app/vpc.rs +++ b/nexus/src/app/vpc.rs @@ -21,6 +21,7 @@ use omicron_common::api::external::DataPageParams; use omicron_common::api::external::DeleteResult; use omicron_common::api::external::Error; use omicron_common::api::external::IdentityMetadataCreateParams; +use omicron_common::api::external::IpNet; use omicron_common::api::external::ListResultVec; use omicron_common::api::external::LookupResult; use omicron_common::api::external::LookupType; @@ -29,8 +30,9 @@ use omicron_common::api::external::RouteTarget; use omicron_common::api::external::RouterRouteCreateParams; use omicron_common::api::external::RouterRouteKind; use omicron_common::api::external::UpdateResult; +use omicron_common::api::external::Vni; +use omicron_common::api::external::VpcAddress; use omicron_common::api::external::VpcFirewallRuleUpdateParams; -use sled_agent_client::types::IpNet; use sled_agent_client::types::NetworkInterface; use futures::future::join_all; @@ -666,10 +668,10 @@ impl super::Nexus { .unwrap_or(&no_interfaces) .iter() .filter(|nic| match (net, nic.ip) { - (external::IpNet::V4(net), IpAddr::V4(ip)) => { + (IpNet::V4(net), IpAddr::V4(ip)) => { net.contains(ip) } - (external::IpNet::V6(net), IpAddr::V6(ip)) => { + (IpNet::V6(net), IpAddr::V6(ip)) => { net.contains(ip) } (_, _) => false, @@ -696,7 +698,12 @@ impl super::Nexus { .get(&name) .unwrap_or(&no_interfaces) { - host_addrs.push(IpNet::from(interface.ip)) + host_addrs.push( + VpcAddress::Ip(IpNet::from( + interface.ip, + )) + .into(), + ) } } external::VpcFirewallRuleHostFilter::Subnet( @@ -706,21 +713,31 @@ impl super::Nexus { .get(&name) .unwrap_or(&no_networks) { - host_addrs.push(IpNet::from(*subnet)); + host_addrs.push( + VpcAddress::Ip(IpNet::from(*subnet)) + .into(), + ); } } external::VpcFirewallRuleHostFilter::Ip(addr) => { - host_addrs.push(IpNet::from(*addr)) + host_addrs.push( + VpcAddress::Ip(IpNet::from(*addr)).into(), + ) } external::VpcFirewallRuleHostFilter::IpNet(net) => { - host_addrs.push(IpNet::from(*net)) + host_addrs.push(VpcAddress::Ip(*net).into()) } external::VpcFirewallRuleHostFilter::Vpc(name) => { for interface in vpc_interfaces .get(&name) .unwrap_or(&no_interfaces) { - host_addrs.push(IpNet::from(interface.ip)) + host_addrs.push( + VpcAddress::Vpc(Vni::try_from( + *interface.vni, + )?) + .into(), + ) } } } diff --git a/openapi/sled-agent.json b/openapi/sled-agent.json index 8b9bdc64d52..5477846a33d 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent.json @@ -1736,6 +1736,47 @@ } ] }, + "VpcAddress": { + "description": "A `VpcAddress` represents either an explicit IP network (v4 or v6) or an entire VPC (identified by its VNI).", + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ip" + ] + }, + "value": { + "$ref": "#/components/schemas/IpNet" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "vpc" + ] + }, + "value": { + "$ref": "#/components/schemas/Vni" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, "VpcFirewallRule": { "description": "VPC firewall rule after object name resolution has been performed by Nexus", "type": "object", @@ -1750,7 +1791,7 @@ "nullable": true, "type": "array", "items": { - "$ref": "#/components/schemas/IpNet" + "$ref": "#/components/schemas/VpcAddress" } }, "filter_ports": { diff --git a/sled-agent-client/src/lib.rs b/sled-agent-client/src/lib.rs index 9f22257d7dc..7da3a341ff6 100644 --- a/sled-agent-client/src/lib.rs +++ b/sled-agent-client/src/lib.rs @@ -206,6 +206,12 @@ impl From for types::Vni { } } +impl From for omicron_common::api::external::Vni { + fn from(s: types::Vni) -> Self { + Self::try_from(s.0 as u32).unwrap() + } +} + impl From for types::MacAddr { fn from(s: omicron_common::api::external::MacAddr) -> Self { Self::try_from(s.0.to_string()) @@ -313,6 +319,16 @@ impl From } } +impl From for types::VpcAddress { + fn from(s: omicron_common::api::external::VpcAddress) -> Self { + use omicron_common::api::external::VpcAddress::*; + match s { + Ip(net) => Self::Ip(net.into()), + Vpc(vni) => Self::Vpc(vni.into()), + } + } +} + impl From for types::VpcFirewallRuleAction { diff --git a/sled-agent/src/opte/illumos/firewall_rules.rs b/sled-agent/src/opte/illumos/firewall_rules.rs index 4a1cd8011b4..932d3c7b200 100644 --- a/sled-agent/src/opte/illumos/firewall_rules.rs +++ b/sled-agent/src/opte/illumos/firewall_rules.rs @@ -8,6 +8,7 @@ use crate::opte::Vni; use crate::params::VpcFirewallRule; use macaddr::MacAddr6; use omicron_common::api::external::IpNet; +use omicron_common::api::external::VpcAddress; use omicron_common::api::external::VpcFirewallRuleAction; use omicron_common::api::external::VpcFirewallRuleDirection; use omicron_common::api::external::VpcFirewallRuleProtocol; @@ -62,16 +63,23 @@ impl FromVpcFirewallRule for VpcFirewallRule { hosts .iter() .map(|host| match host { - IpNet::V4(net) if net.prefix() == 32 => { + VpcAddress::Ip(IpNet::V4(net)) + if net.prefix() == 32 => + { Address::Ip(net.ip().into()) } - IpNet::V4(net) => Address::Subnet(Ipv4Cidr::new( - net.ip().into(), - Ipv4PrefixLen::new(net.prefix()).unwrap(), - )), - IpNet::V6(_net) => { + VpcAddress::Ip(IpNet::V4(net)) => { + Address::Subnet(Ipv4Cidr::new( + net.ip().into(), + Ipv4PrefixLen::new(net.prefix()).unwrap(), + )) + } + VpcAddress::Ip(IpNet::V6(_net)) => { todo!("IPv6 host filters") } + VpcAddress::Vpc(vni) => { + Address::Vni(Vni::new(u32::from(*vni)).unwrap()) + } }) .collect::>() }, diff --git a/sled-agent/src/params.rs b/sled-agent/src/params.rs index 6692f1209a0..0200614085c 100644 --- a/sled-agent/src/params.rs +++ b/sled-agent/src/params.rs @@ -52,7 +52,7 @@ pub struct VpcFirewallRule { pub status: external::VpcFirewallRuleStatus, pub direction: external::VpcFirewallRuleDirection, pub targets: Vec, - pub filter_hosts: Option>, + pub filter_hosts: Option>, pub filter_ports: Option>, pub filter_protocols: Option>, pub action: external::VpcFirewallRuleAction, From 47361a5a0f8f27429dd5be8ef16c0fa0fa39dbad Mon Sep 17 00:00:00 2001 From: Alex Plotnick Date: Wed, 2 Nov 2022 14:22:24 -0600 Subject: [PATCH 5/5] =?UTF-8?q?Rename=20VpcAddress=20=E2=86=92=20HostIdent?= =?UTF-8?q?ifier,=20move=20to=20Nexus=20private=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/src/api/external/mod.rs | 9 -- common/src/api/internal/nexus.rs | 13 ++- nexus/src/app/vpc.rs | 17 ++-- openapi/sled-agent.json | 84 +++++++++---------- sled-agent-client/src/lib.rs | 8 +- sled-agent/src/opte/illumos/firewall_rules.rs | 10 +-- sled-agent/src/params.rs | 4 +- 7 files changed, 76 insertions(+), 69 deletions(-) diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index ebffc14d82e..6fd7e1db716 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1278,15 +1278,6 @@ impl JsonSchema for IpNet { } } -/// A `VpcAddress` represents either an explicit IP network (v4 or v6) -/// or an entire VPC (identified by its VNI). -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(tag = "type", content = "value", rename_all = "snake_case")] -pub enum VpcAddress { - Ip(IpNet), - Vpc(Vni), -} - /// Insert another level of schema indirection in order to provide an /// additional title for a subschema. This allows generators to infer a better /// variant name for an "untagged" enum. diff --git a/common/src/api/internal/nexus.rs b/common/src/api/internal/nexus.rs index 8ae0199705f..4e4b179cc61 100644 --- a/common/src/api/internal/nexus.rs +++ b/common/src/api/internal/nexus.rs @@ -5,7 +5,8 @@ //! APIs exposed by Nexus. use crate::api::external::{ - ByteCount, DiskState, Generation, InstanceCpuCount, InstanceState, + ByteCount, DiskState, Generation, InstanceCpuCount, InstanceState, IpNet, + Vni, }; use chrono::{DateTime, Utc}; use parse_display::Display; @@ -103,3 +104,13 @@ pub struct UpdateArtifact { pub enum UpdateArtifactKind { Zone, } + +/// A `HostIdentifier` represents either an IP host or network (v4 or v6), +/// or an entire VPC (identified by its VNI). It is used in firewall rule +/// host filters. +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] +pub enum HostIdentifier { + Ip(IpNet), + Vpc(Vni), +} diff --git a/nexus/src/app/vpc.rs b/nexus/src/app/vpc.rs index 50cd9edfbc4..508a6b9708a 100644 --- a/nexus/src/app/vpc.rs +++ b/nexus/src/app/vpc.rs @@ -31,8 +31,8 @@ use omicron_common::api::external::RouterRouteCreateParams; use omicron_common::api::external::RouterRouteKind; use omicron_common::api::external::UpdateResult; use omicron_common::api::external::Vni; -use omicron_common::api::external::VpcAddress; use omicron_common::api::external::VpcFirewallRuleUpdateParams; +use omicron_common::api::internal::nexus::HostIdentifier; use sled_agent_client::types::NetworkInterface; use futures::future::join_all; @@ -699,7 +699,7 @@ impl super::Nexus { .unwrap_or(&no_interfaces) { host_addrs.push( - VpcAddress::Ip(IpNet::from( + HostIdentifier::Ip(IpNet::from( interface.ip, )) .into(), @@ -714,18 +714,21 @@ impl super::Nexus { .unwrap_or(&no_networks) { host_addrs.push( - VpcAddress::Ip(IpNet::from(*subnet)) - .into(), + HostIdentifier::Ip(IpNet::from( + *subnet, + )) + .into(), ); } } external::VpcFirewallRuleHostFilter::Ip(addr) => { host_addrs.push( - VpcAddress::Ip(IpNet::from(*addr)).into(), + HostIdentifier::Ip(IpNet::from(*addr)) + .into(), ) } external::VpcFirewallRuleHostFilter::IpNet(net) => { - host_addrs.push(VpcAddress::Ip(*net).into()) + host_addrs.push(HostIdentifier::Ip(*net).into()) } external::VpcFirewallRuleHostFilter::Vpc(name) => { for interface in vpc_interfaces @@ -733,7 +736,7 @@ impl super::Nexus { .unwrap_or(&no_interfaces) { host_addrs.push( - VpcAddress::Vpc(Vni::try_from( + HostIdentifier::Vpc(Vni::try_from( *interface.vni, )?) .into(), diff --git a/openapi/sled-agent.json b/openapi/sled-agent.json index 5477846a33d..39b1f94795b 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent.json @@ -889,6 +889,47 @@ "format": "uint64", "minimum": 0 }, + "HostIdentifier": { + "description": "A `HostIdentifier` represents either an IP host or network (v4 or v6), or an entire VPC (identified by its VNI). It is used in firewall rule host filters.", + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ip" + ] + }, + "value": { + "$ref": "#/components/schemas/IpNet" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "vpc" + ] + }, + "value": { + "$ref": "#/components/schemas/Vni" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, "InstanceCpuCount": { "description": "The number of CPUs in an Instance", "type": "integer", @@ -1736,47 +1777,6 @@ } ] }, - "VpcAddress": { - "description": "A `VpcAddress` represents either an explicit IP network (v4 or v6) or an entire VPC (identified by its VNI).", - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ip" - ] - }, - "value": { - "$ref": "#/components/schemas/IpNet" - } - }, - "required": [ - "type", - "value" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "vpc" - ] - }, - "value": { - "$ref": "#/components/schemas/Vni" - } - }, - "required": [ - "type", - "value" - ] - } - ] - }, "VpcFirewallRule": { "description": "VPC firewall rule after object name resolution has been performed by Nexus", "type": "object", @@ -1791,7 +1791,7 @@ "nullable": true, "type": "array", "items": { - "$ref": "#/components/schemas/VpcAddress" + "$ref": "#/components/schemas/HostIdentifier" } }, "filter_ports": { diff --git a/sled-agent-client/src/lib.rs b/sled-agent-client/src/lib.rs index 7da3a341ff6..d3a3dbf04cf 100644 --- a/sled-agent-client/src/lib.rs +++ b/sled-agent-client/src/lib.rs @@ -319,9 +319,11 @@ impl From } } -impl From for types::VpcAddress { - fn from(s: omicron_common::api::external::VpcAddress) -> Self { - use omicron_common::api::external::VpcAddress::*; +impl From + for types::HostIdentifier +{ + fn from(s: omicron_common::api::internal::nexus::HostIdentifier) -> Self { + use omicron_common::api::internal::nexus::HostIdentifier::*; match s { Ip(net) => Self::Ip(net.into()), Vpc(vni) => Self::Vpc(vni.into()), diff --git a/sled-agent/src/opte/illumos/firewall_rules.rs b/sled-agent/src/opte/illumos/firewall_rules.rs index 932d3c7b200..e8fa9bde59d 100644 --- a/sled-agent/src/opte/illumos/firewall_rules.rs +++ b/sled-agent/src/opte/illumos/firewall_rules.rs @@ -8,11 +8,11 @@ use crate::opte::Vni; use crate::params::VpcFirewallRule; use macaddr::MacAddr6; use omicron_common::api::external::IpNet; -use omicron_common::api::external::VpcAddress; use omicron_common::api::external::VpcFirewallRuleAction; use omicron_common::api::external::VpcFirewallRuleDirection; use omicron_common::api::external::VpcFirewallRuleProtocol; use omicron_common::api::external::VpcFirewallRuleStatus; +use omicron_common::api::internal::nexus::HostIdentifier; use oxide_vpc::api::Address; use oxide_vpc::api::Direction; use oxide_vpc::api::Filters; @@ -63,21 +63,21 @@ impl FromVpcFirewallRule for VpcFirewallRule { hosts .iter() .map(|host| match host { - VpcAddress::Ip(IpNet::V4(net)) + HostIdentifier::Ip(IpNet::V4(net)) if net.prefix() == 32 => { Address::Ip(net.ip().into()) } - VpcAddress::Ip(IpNet::V4(net)) => { + HostIdentifier::Ip(IpNet::V4(net)) => { Address::Subnet(Ipv4Cidr::new( net.ip().into(), Ipv4PrefixLen::new(net.prefix()).unwrap(), )) } - VpcAddress::Ip(IpNet::V6(_net)) => { + HostIdentifier::Ip(IpNet::V6(_net)) => { todo!("IPv6 host filters") } - VpcAddress::Vpc(vni) => { + HostIdentifier::Vpc(vni) => { Address::Vni(Vni::new(u32::from(*vni)).unwrap()) } }) diff --git a/sled-agent/src/params.rs b/sled-agent/src/params.rs index 0200614085c..7673ae56979 100644 --- a/sled-agent/src/params.rs +++ b/sled-agent/src/params.rs @@ -8,7 +8,7 @@ use omicron_common::address::{ }; use omicron_common::api::external; use omicron_common::api::internal::nexus::{ - DiskRuntimeState, InstanceRuntimeState, + DiskRuntimeState, HostIdentifier, InstanceRuntimeState, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -52,7 +52,7 @@ pub struct VpcFirewallRule { pub status: external::VpcFirewallRuleStatus, pub direction: external::VpcFirewallRuleDirection, pub targets: Vec, - pub filter_hosts: Option>, + pub filter_hosts: Option>, pub filter_ports: Option>, pub filter_protocols: Option>, pub action: external::VpcFirewallRuleAction,