Skip to content

Commit

Permalink
Only apply external IP allowlist to Nexus (#5900)
Browse files Browse the repository at this point in the history
- Fixes #5892
- Modifies the application of the external services IP allowlist so that
it's only relevant for Nexus API servers, rather than all
external-facing services (DNS being the other example today). It is not
always possible to know the peer addresses for DNS servers in the case
of recursive DNS, and so the allowlist cannot directly apply to external
DNS. This works by inserting the allowlist entries as a host-filter,
which we were doing before, but only on the named VPC Firewall rule for
the Nexus VPC Subnet.
  • Loading branch information
bnaecker authored and Nieuwejaar committed Jun 15, 2024
1 parent 42fe148 commit 7a8ce1f
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
9 changes: 8 additions & 1 deletion nexus/db-fixed-data/src/vpc_firewall_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,17 @@ pub static DNS_VPC_FW_RULE: Lazy<VpcFirewallRuleUpdate> =
priority: VpcFirewallRulePriority(65534),
});

/// The name for the built-in VPC firewall rule for Nexus.
pub const NEXUS_VPC_FW_RULE_NAME: &str = "nexus-inbound";

/// Built-in VPC firewall rule for Nexus.
///
/// Note that we currently rely on this being exactly one rule to implement the
/// Nexus allowlist. See `nexus/networking/src/firewall_rules.rs` for more
/// details.
pub static NEXUS_VPC_FW_RULE: Lazy<VpcFirewallRuleUpdate> =
Lazy::new(|| VpcFirewallRuleUpdate {
name: "nexus-inbound".parse().unwrap(),
name: NEXUS_VPC_FW_RULE_NAME.parse().unwrap(),
description:
"allow inbound connections for console & api from anywhere"
.to_string(),
Expand Down
2 changes: 1 addition & 1 deletion nexus/db-model/src/allow_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl AllowList {
Self { id, time_created: now, time_modified: now, allowed_ips }
}

/// Create an `AllowedSourceIps` type from the contained address.
/// Create an `AllowedSourceIps` type from the contained addresses.
pub fn allowed_source_ips(
&self,
) -> Result<external::AllowedSourceIps, Error> {
Expand Down
37 changes: 28 additions & 9 deletions nexus/networking/src/firewall_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use nexus_db_queries::authz;
use nexus_db_queries::context::OpContext;
use nexus_db_queries::db;
use nexus_db_queries::db::fixed_data::vpc::SERVICES_VPC_ID;
use nexus_db_queries::db::fixed_data::vpc_firewall_rule::NEXUS_VPC_FW_RULE_NAME;
use nexus_db_queries::db::identity::Asset;
use nexus_db_queries::db::identity::Resource;
use nexus_db_queries::db::lookup;
Expand Down Expand Up @@ -316,15 +317,21 @@ pub async fn resolve_firewall_rules_for_sled_agent(
// `nexus_db_queries::fixed_data::vpc_firewall_rule` for those
// rules.) If those rules change to include any filter hosts, this
// logic needs to change as well.
(None, Some(allowed_ips)) => match allowed_ips {
AllowedSourceIps::Any => None,
AllowedSourceIps::List(list) => Some(
list.iter()
.copied()
.map(|ip| HostIdentifier::Ip(ip).into())
.collect(),
),
},
(None, Some(allowed_ips)) => {
if allowlist_applies_to_firewall_rule(rule) {
match allowed_ips {
AllowedSourceIps::Any => None,
AllowedSourceIps::List(list) => Some(
list.iter()
.copied()
.map(|ip| HostIdentifier::Ip(ip).into())
.collect(),
),
}
} else {
None
}
}

// No rules exist, and we don't need to add anything for the
// allowlist.
Expand Down Expand Up @@ -521,6 +528,18 @@ fn allowlist_applies_to_vpc(vpc: &db::model::Vpc) -> bool {
vpc.id() == *SERVICES_VPC_ID
}

/// Return true if the user-facing services allowlist applies to a firewall
/// rule.
///
/// Today, we only apply the allowlist to Nexus. That lives in its own VPC, and
/// has exactly one firewall rule that allows inbound TCP traffic on HTTP(s)
/// ports. If either of those things change, this will also need to change.
fn allowlist_applies_to_firewall_rule(
rule: &db::model::VpcFirewallRule,
) -> bool {
rule.name().as_str() == NEXUS_VPC_FW_RULE_NAME
}

/// Return the list of allowed IPs from the database.
async fn lookup_allowed_source_ips(
datastore: &DataStore,
Expand Down

0 comments on commit 7a8ce1f

Please sign in to comment.