Fix various issues after config rework (#1462)

Closes #1461
Closes #1458
Closes #1415
Closes #1460
This commit is contained in:
Andrew Dryga
2023-02-23 13:57:10 -06:00
committed by GitHub
parent b7938d11b9
commit 38cceb56ac
15 changed files with 144 additions and 58 deletions

View File

@@ -157,7 +157,6 @@ defmodule FzHttp.Config.Definitions do
changeset
|> FzHttp.Validator.validate_uri(key)
|> FzHttp.Validator.normalize_url(key)
|> to_string()
end
)
@@ -684,8 +683,10 @@ defmodule FzHttp.Config.Definitions do
)
defconfig(:wireguard_private_key_path, :string,
default: "/var/firezone/private_key",
changeset: &FzHttp.Validator.validate_file(&1, &2)
default: "/var/firezone/private_key"
# We don't check if the file exists, because it is generated on
# the first boot.
# changeset: &FzHttp.Validator.validate_file(&1, &2)
)
defconfig(:wireguard_interface_name, :string, default: "wg-firezone")

View File

@@ -157,14 +157,13 @@ defmodule FzHttp.Devices.Device do
end
defp wireguard_network(field) do
cidr_string = FzHttp.Config.fetch_env!(:fz_http, :"wireguard_#{field}_network")
[inet, network] = String.split(cidr_string, "/")
network = String.to_integer(network)
"#{inet}/#{limit_cidr_range(field, network)}"
cidr = FzHttp.Config.fetch_env!(:fz_http, :"wireguard_#{field}_network")
cidr = %{cidr | netmask: limit_cidr_netmask(field, cidr.netmask)}
FzHttp.Types.CIDR.to_string(cidr)
end
defp limit_cidr_range(:ipv4, network), do: network
defp limit_cidr_range(:ipv6, network), do: max(network, 70)
defp limit_cidr_netmask(:ipv4, network), do: network
defp limit_cidr_netmask(:ipv6, network), do: max(network, 70)
defp ipv4_address do
FzHttp.Config.fetch_env!(:fz_http, :wireguard_ipv4_address)

View File

@@ -26,22 +26,33 @@ defmodule FzHttp.Release do
def create_admin_user do
boot_database_app()
reply =
if Repo.exists?(from u in User, where: u.email == ^email()) do
change_password(email(), default_password())
reset_role(email(), :admin)
if Repo.exists?(from u in User, where: u.email == ^email()) do
change_password(email(), default_password())
{:ok, user} = reset_role(email(), :admin)
# Notify the user
Logger.info("Password for user specified by ADMIN_EMAIL reset to DEFAULT_ADMIN_PASSWORD!")
{:ok, user}
else
with {:ok, user} <-
Users.create_admin_user(%{
email: email(),
password: default_password(),
password_confirmation: default_password()
}) do
# Notify the user
Logger.info(
"An admin user specified by ADMIN_EMAIL is created with a DEFAULT_ADMIN_PASSWORD!"
)
{:ok, user}
else
Users.create_admin_user(%{
email: email(),
password: default_password(),
password_confirmation: default_password()
})
{:error, changeset} ->
Logger.error("Failed to create admin user: #{inspect(changeset.errors)}")
{:error, changeset}
end
# Notify the user
Logger.info("Password for user specified by ADMIN_EMAIL reset to DEFAULT_ADMIN_PASSWORD!")
reply
end
end
def create_api_token(device \\ :stdio) do

View File

@@ -48,7 +48,8 @@ defmodule FzHttp.Validator do
scheme = uri.scheme || "https"
port = URI.default_port(scheme)
path = uri.path || "/"
put_change(changeset, field, %{uri | scheme: scheme, port: port, path: path})
uri_string = URI.to_string(%{uri | scheme: scheme, port: port, path: path})
put_change(changeset, field, uri_string)
else
:error ->
changeset

View File

@@ -10,7 +10,10 @@ defmodule FzHttpWeb.HeaderHelpers do
|> Enum.map(&to_string/1)
end
def clients, do: FzHttp.Config.fetch_env!(:fz_http, :private_clients)
def clients do
FzHttp.Config.fetch_env!(:fz_http, :private_clients)
|> Enum.map(&to_string/1)
end
def proxied?, do: external_trusted_proxies() != []

View File

@@ -0,0 +1,33 @@
defmodule FzHttp.Repo.Migrations.TrimDNSFields do
use Ecto.Migration
def change do
execute("""
UPDATE devices
SET dns = string_to_array(
trim(
both ' ' from regexp_replace(
array_to_string(dns, ','),
'\s*,\s*',
','
)
),
','
)
""")
execute("""
UPDATE configurations
SET default_client_dns = string_to_array(
trim(
both ' ' from regexp_replace(
array_to_string(default_client_dns, ','),
'\s*,\s*',
','
)
),
','
)
""")
end
end

View File

@@ -83,7 +83,8 @@ defmodule FzHttp.DevicesTest do
end
test "soft limit max network range for IPv6", %{device: device} do
FzHttp.Config.put_env_override(:wireguard_ipv6_network, "fd00::/20")
{:ok, cidr} = FzHttp.Types.CIDR.cast("fd00::/20")
FzHttp.Config.put_env_override(:wireguard_ipv6_network, cidr)
attrs = %{@device_attrs | ipv4: nil, ipv6: nil, user_id: device.user_id}
assert {:ok, _device} = Devices.create_device(attrs)
end
@@ -91,7 +92,8 @@ defmodule FzHttp.DevicesTest do
test "returns error when device IP can't be assigned due to CIDR pool exhaustion", %{
device: device
} do
FzHttp.Config.put_env_override(:wireguard_ipv4_network, "10.3.2.0/30")
{:ok, cidr} = FzHttp.Types.CIDR.cast("10.3.2.0/30")
FzHttp.Config.put_env_override(:wireguard_ipv4_network, cidr)
attrs = %{@device_attrs | ipv4: nil, ipv6: nil, user_id: device.user_id}
assert {:ok, _device} = Devices.create_device(attrs)

View File

@@ -4,8 +4,15 @@ defmodule FzHttp.RulesTest do
alias FzHttp.Rules
setup do
FzHttp.Config.put_env_override(:wireguard_ipv4_network, "100.64.0.0/10")
FzHttp.Config.put_env_override(:wireguard_ipv6_network, "fd00::0/106")
FzHttp.Config.put_env_override(:wireguard_ipv4_network, %Postgrex.INET{
address: {100, 64, 0, 0},
netmask: 10
})
FzHttp.Config.put_env_override(:wireguard_ipv6_network, %Postgrex.INET{
address: {64_768, 0, 0, 0, 0, 0, 0, 0},
netmask: 106
})
:ok
end

View File

@@ -44,11 +44,19 @@ config :fz_http, FzHttpWeb.Endpoint,
config :fz_http,
wireguard_ipv4_enabled: true,
wireguard_ipv4_network: "100.64.0.0/10",
wireguard_ipv4_address: "100.64.0.1",
wireguard_ipv4_network: %{__struct__: Postgrex.INET, address: {100, 64, 0, 0}, netmask: 10},
wireguard_ipv4_address: %{__struct__: Postgrex.INET, address: {100, 64, 0, 1}, netmask: nil},
wireguard_ipv6_enabled: true,
wireguard_ipv6_network: "fd00::/106",
wireguard_ipv6_address: "fd00::1"
wireguard_ipv6_network: %{
__struct__: Postgrex.INET,
address: {64768, 0, 0, 0, 0, 0, 0, 0},
netmask: 106
},
wireguard_ipv6_address: %{
__struct__: Postgrex.INET,
address: {64768, 0, 0, 0, 0, 0, 0, 1},
netmask: nil
}
config :fz_http,
saml_entity_id: "urn:firezone.dev:firezone-app",
@@ -57,7 +65,7 @@ config :fz_http,
config :fz_http,
external_trusted_proxies: [],
private_clients: ["172.28.0.0/16"]
private_clients: [%{__struct__: Postgrex.INET, address: {172, 28, 0, 0}, netmask: 16}]
config :fz_http,
telemetry_id: "firezone-dev",

View File

@@ -117,11 +117,6 @@ default['firezone']['sysvinit_id'] = 'SUP'
# Local email/password authentication is enabled by default
default['firezone']['authentication']['local']['enabled'] = true
# Automatically create users siging in from OIDC for the first time. Disable this
# and manually create them (leaving their password blank) if you wish to only
# allow existing certain existing users to sign in.
default['firezone']['authentication']['auto_create_oidc_users'] = true
# OIDC Authentication
#
# Firezone can disable a user's VPN if there's any error detected trying
@@ -135,15 +130,16 @@ default['firezone']['authentication']['disable_vpn_on_oidc_error'] = false
# Any OpenID Connect provider can be used here.
# Multiple OIDC configs can be added to the same Firezone instance.
# This is an example using Google and Okta as an SSO identity provider.
# default['firezone']['authentication']['oidc'] = {
# google: {
# default['firezone']['authentication']['oidc'] = [
# {
# discovery_document_uri: "https://accounts.google.com/.well-known/openid-configuration",
# client_id: "<GOOGLE_CLIENT_ID>",
# client_secret: "<GOOGLE_CLIENT_SECRET>",
# redirect_uri: "https://firezone.example.com/auth/oidc/google/callback/",
# response_type: "code",
# scope: "openid email profile",
# label: "Google"
# label: "Google",
# auto_create_users: true
# },
# okta: {
# discovery_document_uri: "https://<OKTA_DOMAIN>/.well-known/openid-configuration",
@@ -152,10 +148,30 @@ default['firezone']['authentication']['disable_vpn_on_oidc_error'] = false
# redirect_uri: "https://firezone.example.com/auth/oidc/okta/callback/",
# response_type: "code",
# scope: "openid email profile offline_access",
# label: "Okta"
# label: "Okta",
# auto_create_users: true
# }
# }
default['firezone']['authentication']['oidc'] = {}
# ]
default['firezone']['authentication']['oidc'] = []
# SAML Authentication providers
#
# Example adding an OKTA provider:
#
# default['firezone']['authentication']['saml'] = [
# {
# "auto_create_users": false,
# "base_url": "https://saml",
# "id": "okta",
# "label": "okta",
# "metadata": "<?xml version="1.0"?>...",
# "sign_metadata": false,
# "sign_requests": false,
# "signed_assertion_in_resp": false,
# "signed_envelopes_in_resp": false
# }
# ]
default['firezone']['authentication']['saml'] = []
# ## Custom Reverse Proxy
#

View File

@@ -212,8 +212,8 @@ class Firezone
# NOTE: All these variables must be Strings
env = {
'EGRESS_INTERFACE' => attributes['egress_interface'],
'NFT_PATH' => "#{attributes['install_directory']}/embedded/sbin/nft",
'GATEWAY_EGRESS_INTERFACE' => attributes['egress_interface'],
'GATEWAY_NFT_PATH' => "#{attributes['install_directory']}/embedded/sbin/nft",
'MIX_ENV' => 'prod',
'DATABASE_NAME' => attributes['database']['name'],
'DATABASE_USER' => attributes['database']['user'],
@@ -224,16 +224,17 @@ class Firezone
'DATABASE_SSL_OPTS' => attributes['database']['ssl_opts'].to_json,
'DATABASE_PARAMETERS' => attributes['database']['parameters'].to_json,
'PHOENIX_LISTEN_ADDRESS' => attributes['phoenix']['listen_address'].to_s,
'PHOENIX_PORT' => attributes['phoenix']['port'].to_s,
'EXTERNAL_TRUSTED_PROXIES' => Chef::JSONCompat.to_json(attributes['phoenix']['external_trusted_proxies']),
'PRIVATE_CLIENTS' => Chef::JSONCompat.to_json(attributes['phoenix']['private_clients']),
'PHOENIX_HTTP_PORT' => attributes['phoenix']['port'].to_s,
'PHOENIX_EXTERNAL_TRUSTED_PROXIES' =>
Chef::JSONCompat.to_json(attributes['phoenix']['external_trusted_proxies']),
'PHOENIX_PRIVATE_CLIENTS' => Chef::JSONCompat.to_json(attributes['phoenix']['private_clients']),
'EXTERNAL_URL' => attributes['external_url'] || fqdn_url,
'ADMIN_EMAIL' => attributes['admin_email'],
'DEFAULT_ADMIN_EMAIL' => attributes['admin_email'],
'WIREGUARD_INTERFACE_NAME' => attributes['wireguard']['interface_name'],
'WIREGUARD_PORT' => attributes['wireguard']['port'].to_s,
'WIREGUARD_MTU' => attributes['wireguard']['mtu'].to_s,
'WIREGUARD_ENDPOINT' => attributes['wireguard']['endpoint'].to_s,
'WIREGUARD_DNS' => attributes['wireguard']['dns'].to_s,
'DEFAULT_CLIENT_ENDPOINT' => attributes['wireguard']['endpoint'].to_s,
'DEFAULT_CLIENT_DNS' => attributes['wireguard']['dns'].to_s,
'WIREGUARD_ALLOWED_IPS' => attributes['wireguard']['allowed_ips'].to_s,
'WIREGUARD_PERSISTENT_KEEPALIVE' => attributes['wireguard']['persistent_keepalive'].to_s,
'WIREGUARD_IPV4_ENABLED' => attributes['wireguard']['ipv4']['enabled'].to_s,
@@ -256,8 +257,8 @@ class Firezone
'CONNECTIVITY_CHECKS_INTERVAL' => attributes['connectivity_checks']['interval'].to_s,
# Outbound Emails
'OUTBOUND_EMAIL_PROVIDER' => attributes['outbound_email']['provider'],
'OUTBOUND_EMAIL_CONFIGS' => attributes['outbound_email']['configs'].to_json,
'OUTBOUND_EMAIL_ADAPTER' => attributes['outbound_email']['provider'],
'OUTBOUND_EMAIL_ADAPTER_OPTS' => attributes['outbound_email']['configs'].to_json,
'OUTBOUND_EMAIL_FROM' => attributes['outbound_email']['from'],
# XXX: Remove this in the future when we're fairly sure that users won't upgrade across
@@ -271,10 +272,11 @@ class Firezone
'LOCAL_AUTH_ENABLED' => attributes['authentication']['local']['enabled'].to_s,
'DISABLE_VPN_ON_OIDC_ERROR' => attributes['authentication']['disable_vpn_on_oidc_error'].to_s,
'AUTO_CREATE_OIDC_USERS' => attributes['authentication']['auto_create_oidc_users'].to_s,
# OpenID Connect auth settings are serialized to json for consumption by fz_http
'AUTH_OIDC_JSON' => attributes['authentication']['oidc'].to_json,
'OPENID_CONNECT_PROVIDERS' => attributes['authentication']['oidc'].to_json,
# SAML auth settings are serialized to json for consumption by fz_http
'SAML_IDENTITY_PROVIDERS' => attributes['authentication']['saml'].to_json,
# secrets
'GUARDIAN_SECRET_KEY' => attributes['guardian_secret_key'],

View File

@@ -1,3 +1,4 @@
#!/bin/sh
set -e
source "$(dirname -- "$0")/bootstrap"
exec ./firezone eval FzHttp.Release.create_api_token

View File

@@ -1,3 +1,4 @@
#!/bin/sh
set -e
source "$(dirname -- "$0")/bootstrap"
exec ./firezone eval FzHttp.Release.create_admin_user

View File

@@ -1,3 +1,4 @@
#!/bin/sh
set -e
source "$(dirname -- "$0")/bootstrap"
exec ./firezone eval FzHttp.Release.migrate

View File

@@ -1,5 +1,5 @@
#!/bin/sh
set -e
source "$(dirname -- "$0")/bootstrap"
./firezone eval FzHttp.Release.migrate