mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
feat(portal): configurable ip stack for DNS resources (#9303)
Some poorly-behaved applications (e.g. mongo) will fail to connect if they see both IPv4 and IPv6 addresses for a DNS resource, because they will try to connect to both of them and fail the whole connection setup if either one is not routable. To fix this, we need to introduce a knob to allow admins to restrict DNS resources to only A or AAAA records. <img width="750" alt="Screenshot 2025-06-02 at 10 48 39 AM" src="https://github.com/user-attachments/assets/4dbcb6ae-685f-43ee-b9e8-1502b365a294" /> <img width="1174" alt="Screenshot 2025-06-02 at 11 05 53 AM" src="https://github.com/user-attachments/assets/02d0a4b3-e6e8-4b6d-89fa-d3d999b5811e" /> --- Related: https://firezonehq.slack.com/archives/C08KPQKJZKM/p1746720923535349 Related: #9300 Fixes: #9042
This commit is contained in:
@@ -11,7 +11,8 @@ defmodule API.Client.Views.Resource do
|
||||
id: resource.id,
|
||||
type: :internet,
|
||||
gateway_groups: Views.GatewayGroup.render_many(resource.gateway_groups),
|
||||
can_be_disabled: true
|
||||
can_be_disabled: true,
|
||||
ip_stack: resource.ip_stack
|
||||
}
|
||||
end
|
||||
|
||||
@@ -27,7 +28,8 @@ defmodule API.Client.Views.Resource do
|
||||
address_description: resource.address_description,
|
||||
name: resource.name,
|
||||
gateway_groups: Views.GatewayGroup.render_many(resource.gateway_groups),
|
||||
filters: Enum.flat_map(resource.filters, &render_filter/1)
|
||||
filters: Enum.flat_map(resource.filters, &render_filter/1),
|
||||
ip_stack: resource.ip_stack
|
||||
}
|
||||
end
|
||||
|
||||
@@ -39,7 +41,8 @@ defmodule API.Client.Views.Resource do
|
||||
address_description: resource.address_description,
|
||||
name: resource.name,
|
||||
gateway_groups: Views.GatewayGroup.render_many(resource.gateway_groups),
|
||||
filters: Enum.flat_map(resource.filters, &render_filter/1)
|
||||
filters: Enum.flat_map(resource.filters, &render_filter/1),
|
||||
ip_stack: resource.ip_stack
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ defmodule API.ResourceJSON do
|
||||
name: resource.name,
|
||||
address: resource.address,
|
||||
address_description: resource.address_description,
|
||||
type: resource.type
|
||||
type: resource.type,
|
||||
ip_stack: resource.ip_stack
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,12 @@ defmodule API.Schemas.Resource do
|
||||
name: %Schema{type: :string, description: "Resource name"},
|
||||
address: %Schema{type: :string, description: "Resource address"},
|
||||
address_description: %Schema{type: :string, description: "Resource address description"},
|
||||
type: %Schema{type: :string, description: "Resource type"}
|
||||
type: %Schema{type: :string, description: "Resource type"},
|
||||
ip_stack: %Schema{
|
||||
type: :string,
|
||||
description: "IP stack type. Only supported for DNS resources.",
|
||||
enum: ["ipv4_only", "ipv6_only", "dual"]
|
||||
}
|
||||
},
|
||||
required: [:name, :type],
|
||||
example: %{
|
||||
@@ -22,7 +27,8 @@ defmodule API.Schemas.Resource do
|
||||
"name" => "Prod DB",
|
||||
"address" => "10.0.0.10",
|
||||
"address_description" => "Production Database",
|
||||
"type" => "ip"
|
||||
"type" => "ip",
|
||||
"ip_stack" => "ipv4_only"
|
||||
}
|
||||
})
|
||||
end
|
||||
@@ -90,7 +96,8 @@ defmodule API.Schemas.Resource do
|
||||
"name" => "Prod DB",
|
||||
"address" => "10.0.0.10",
|
||||
"address_description" => "Production Database",
|
||||
"type" => "ip"
|
||||
"type" => "ip",
|
||||
"ip_stack" => "ipv4_only"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource =
|
||||
Fixtures.Resources.create_resource(
|
||||
account: account,
|
||||
ip_stack: :ipv4_only,
|
||||
connections: [%{gateway_group_id: gateway_group.id}]
|
||||
)
|
||||
|
||||
@@ -287,6 +288,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert %{
|
||||
id: dns_resource.id,
|
||||
type: :dns,
|
||||
ip_stack: :ipv4_only,
|
||||
name: dns_resource.name,
|
||||
address: dns_resource.address,
|
||||
address_description: dns_resource.address_description,
|
||||
@@ -307,6 +309,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert %{
|
||||
id: cidr_resource.id,
|
||||
type: :cidr,
|
||||
ip_stack: nil,
|
||||
name: cidr_resource.name,
|
||||
address: cidr_resource.address,
|
||||
address_description: cidr_resource.address_description,
|
||||
@@ -327,6 +330,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert %{
|
||||
id: ip_resource.id,
|
||||
type: :cidr,
|
||||
ip_stack: nil,
|
||||
name: ip_resource.name,
|
||||
address: "#{ip_resource.address}/32",
|
||||
address_description: ip_resource.address_description,
|
||||
@@ -347,6 +351,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert %{
|
||||
id: internet_resource.id,
|
||||
type: :internet,
|
||||
ip_stack: nil,
|
||||
gateway_groups: [
|
||||
%{
|
||||
id: internet_gateway_group.id,
|
||||
@@ -830,6 +835,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert payload == %{
|
||||
id: resource.id,
|
||||
type: :dns,
|
||||
ip_stack: :ipv4_only,
|
||||
name: resource.name,
|
||||
address: resource.address,
|
||||
address_description: resource.address_description,
|
||||
@@ -867,6 +873,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert payload == %{
|
||||
id: resource.id,
|
||||
type: :dns,
|
||||
ip_stack: :ipv4_only,
|
||||
name: resource.name,
|
||||
address: resource.address,
|
||||
address_description: resource.address_description,
|
||||
@@ -959,6 +966,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert payload == %{
|
||||
id: resource.id,
|
||||
type: :dns,
|
||||
ip_stack: :ipv4_only,
|
||||
name: resource.name,
|
||||
address: resource.address,
|
||||
address_description: resource.address_description,
|
||||
@@ -1031,6 +1039,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert payload == %{
|
||||
id: resource.id,
|
||||
type: :dns,
|
||||
ip_stack: :ipv4_only,
|
||||
name: resource.name,
|
||||
address: resource.address,
|
||||
address_description: resource.address_description,
|
||||
|
||||
@@ -91,7 +91,7 @@ defmodule API.ResourceControllerTest do
|
||||
end
|
||||
|
||||
test "returns a single resource", %{conn: conn, account: account, actor: actor} do
|
||||
resource = Fixtures.Resources.create_resource(%{account: account})
|
||||
resource = Fixtures.Resources.create_resource(%{account: account, ip_stack: :ipv4_only})
|
||||
|
||||
conn =
|
||||
conn
|
||||
@@ -105,7 +105,8 @@ defmodule API.ResourceControllerTest do
|
||||
"address_description" => resource.address_description,
|
||||
"id" => resource.id,
|
||||
"name" => resource.name,
|
||||
"type" => Atom.to_string(resource.type)
|
||||
"type" => Atom.to_string(resource.type),
|
||||
"ip_stack" => "ipv4_only"
|
||||
}
|
||||
}
|
||||
end
|
||||
@@ -159,6 +160,7 @@ defmodule API.ResourceControllerTest do
|
||||
"address" => "google.com",
|
||||
"name" => "Google",
|
||||
"type" => "dns",
|
||||
"ip_stack" => "ipv6_only",
|
||||
"connections" => [
|
||||
%{"gateway_group_id" => gateway_group.id}
|
||||
]
|
||||
@@ -176,6 +178,7 @@ defmodule API.ResourceControllerTest do
|
||||
assert resp["data"]["address_description"] == nil
|
||||
assert resp["data"]["name"] == attrs["name"]
|
||||
assert resp["data"]["type"] == attrs["type"]
|
||||
assert resp["data"]["ip_stack"] == attrs["ip_stack"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -223,7 +226,7 @@ defmodule API.ResourceControllerTest do
|
||||
test "updates a resource", %{conn: conn, account: account, actor: actor} do
|
||||
resource = Fixtures.Resources.create_resource(%{account: account})
|
||||
|
||||
attrs = %{"name" => "Google"}
|
||||
attrs = %{"name" => "Google", "ip_stack" => "ipv6_only"}
|
||||
|
||||
conn =
|
||||
conn
|
||||
@@ -236,6 +239,7 @@ defmodule API.ResourceControllerTest do
|
||||
assert resp["data"]["address"] == resource.address
|
||||
assert resp["data"]["address_description"] == resource.address_description
|
||||
assert resp["data"]["name"] == attrs["name"]
|
||||
assert resp["data"]["ip_stack"] == attrs["ip_stack"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -261,7 +265,8 @@ defmodule API.ResourceControllerTest do
|
||||
"address_description" => resource.address_description,
|
||||
"id" => resource.id,
|
||||
"name" => resource.name,
|
||||
"type" => Atom.to_string(resource.type)
|
||||
"type" => Atom.to_string(resource.type),
|
||||
"ip_stack" => Atom.to_string(resource.ip_stack)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user