Skip to content

Check for cross-VPC firewall rules before DB write#10563

Open
david-crespo wants to merge 1 commit into
mainfrom
cross-vpc-fw-rule-fix
Open

Check for cross-VPC firewall rules before DB write#10563
david-crespo wants to merge 1 commit into
mainfrom
cross-vpc-fw-rule-fix

Conversation

@david-crespo

@david-crespo david-crespo commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Improves #10561 but does not fully fix it, which would require cascading VPC renames down through all existing firewall rules.

The real problem here is that after you rename a VPC, any future updates to the firewall rules will fail if they neglect to update the VPC name in all targets and filters it appears in. This is especially a problem in the console, where you can only update one rule at a time. So even if you update the VPC name in that rule correctly, any other rules with the old name can still blow up the request. This PR does not fix this.

On top of that, the check for VPC name mismatches happens after we persist the rules to the DB. This is egregious, and it is what this PR fixes: we move the check for "cross-VPC rules" (mismatches between the VPC name and the VPC referenced in the rule) to before the DB write (technically we now do it both places to be safe).

A secondary accidental fix is that by erroring earlier, we avoid this map_err added in #10305 that turns the 400s into 500s. 500 is even worse than 400 here because it doesn't have the confusing message telling you that it's a cross-VPC issue.

nexus_networking::send_sled_agents_firewall_rules(
&self.db_datastore,
opctx,
vpc,
rules,
sleds_filter,
&self.opctx_alloc,
&self.log,
)
.await
.map_err(|e| {
Error::internal_error(&InlineErrorChain::new(&e).to_string())
})

@david-crespo david-crespo requested a review from sudomateo June 8, 2026 16:48
@david-crespo

Copy link
Copy Markdown
Contributor Author

I could see an argument that the check should go here since it's similar to this one, but it would require passing the DB model in so we could use the name.

/// Replace all firewall rules with the given rules
pub async fn vpc_update_firewall_rules(
&self,
opctx: &OpContext,
authz_vpc: &authz::Vpc,
mut rules: Vec<VpcFirewallRule>,
) -> UpdateResult<Vec<VpcFirewallRule>> {
opctx.authorize(authz::Action::Modify, authz_vpc).await?;
for r in &rules {
assert_eq!(r.vpc_id, authz_vpc.id());
}

@sudomateo sudomateo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. Extracting the logic to a shared function is the cleanest way to move the error before the DB call without trying to solve the problem entirely. The test isn't exactly the process I followed when I ran into this, but it covers the same idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants