diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 067f2dc99..b216a97f9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -234,7 +234,7 @@ jobs:
- opensuse15-x64
if: startsWith(github.ref, 'refs/tags/')
steps:
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
with:
name: firezone-${{ matrix.platform }}
path: ./
diff --git a/.tool-versions b/.tool-versions
index 678c1ae3b..de849c898 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,6 +1,6 @@
# These are used for the dev environment.
# This should match the versions used in the built product.
nodejs 14.18.3
-elixir 1.13.2-otp-24
-erlang 24.2.1
+elixir ref:v1.13.4
+erlang 25.0-rc3
ruby 2.7.5
diff --git a/apps/fz_common/lib/fz_crypto.ex b/apps/fz_common/lib/fz_crypto.ex
index a67da3a31..db9cc362b 100644
--- a/apps/fz_common/lib/fz_crypto.ex
+++ b/apps/fz_common/lib/fz_crypto.ex
@@ -3,17 +3,28 @@ defmodule FzCommon.FzCrypto do
Utilities for working with crypto functions
"""
+ @wg_psk_length 32
+
+ def psk do
+ rand_base64(@wg_psk_length)
+ end
+
def rand_string(length \\ 16) do
- rand_base64(length)
+ rand_base64(length, :url)
|> binary_part(0, length)
end
def rand_token(length \\ 8) do
- rand_base64(length)
+ rand_base64(length, :url)
+ end
+
+ defp rand_base64(length, :url) do
+ :crypto.strong_rand_bytes(length)
+ |> Base.url_encode64()
end
defp rand_base64(length) do
:crypto.strong_rand_bytes(length)
- |> Base.url_encode64()
+ |> Base.encode64()
end
end
diff --git a/apps/fz_http/lib/fz_http/devices.ex b/apps/fz_http/lib/fz_http/devices.ex
index 5322d62c8..2fdf4f663 100644
--- a/apps/fz_http/lib/fz_http/devices.ex
+++ b/apps/fz_http/lib/fz_http/devices.ex
@@ -4,7 +4,7 @@ defmodule FzHttp.Devices do
"""
import Ecto.Query, warn: false
- alias FzCommon.NameGenerator
+ alias FzCommon.{FzCrypto, NameGenerator}
alias FzHttp.{Devices.Device, Repo, Sites, Telemetry, Users, Users.User}
def list_devices do
@@ -93,13 +93,23 @@ defmodule FzHttp.Devices do
|> Enum.map(fn device ->
%{
public_key: device.public_key,
- inet: inet(device)
+ inet: inet(device),
+ preshared_key: device.preshared_key
}
end)
end
def new_device(attrs \\ %{}) do
- change_device(%Device{}, Map.merge(%{"name" => NameGenerator.generate()}, attrs))
+ change_device(
+ %Device{},
+ Map.merge(
+ %{
+ "name" => NameGenerator.generate(),
+ "preshared_key" => FzCrypto.psk()
+ },
+ attrs
+ )
+ )
end
def allowed_ips(device), do: config(device, :allowed_ips)
@@ -142,6 +152,7 @@ defmodule FzHttp.Devices do
#{dns_config(device)}
[Peer]
+ #{psk_config(device)}
PublicKey = #{server_public_key}
#{allowed_ips_config(device)}
Endpoint = #{endpoint(device)}:#{wireguard_port}
@@ -149,6 +160,14 @@ defmodule FzHttp.Devices do
"""
end
+ defp psk_config(device) do
+ if device.preshared_key do
+ "PresharedKey = #{device.preshared_key}"
+ else
+ ""
+ end
+ end
+
defp mtu_config(device) do
m = mtu(device)
diff --git a/apps/fz_http/lib/fz_http/devices/device.ex b/apps/fz_http/lib/fz_http/devices/device.ex
index 5136f70c8..67f9f2093 100644
--- a/apps/fz_http/lib/fz_http/devices/device.ex
+++ b/apps/fz_http/lib/fz_http/devices/device.ex
@@ -24,6 +24,7 @@ defmodule FzHttp.Devices.Device do
field :uuid, Ecto.UUID, autogenerate: true
field :name, :string
field :public_key, :string
+ field :preshared_key, FzHttp.Encrypted.Binary
field :use_site_allowed_ips, :boolean, read_after_writes: true, default: true
field :use_site_dns, :boolean, read_after_writes: true, default: true
field :use_site_endpoint, :boolean, read_after_writes: true, default: true
@@ -83,6 +84,7 @@ defmodule FzHttp.Devices.Device do
:user_id,
:name,
:public_key,
+ :preshared_key,
:key_regenerated_at
])
end
diff --git a/apps/fz_http/lib/fz_http/events.ex b/apps/fz_http/lib/fz_http/events.ex
index 6eecd7a2b..0808b2692 100644
--- a/apps/fz_http/lib/fz_http/events.ex
+++ b/apps/fz_http/lib/fz_http/events.ex
@@ -11,8 +11,8 @@ defmodule FzHttp.Events do
GenServer.call(vpn_pid(), {:set_config, Devices.to_peer_list()})
end
- def delete_device(device_pubkey) when is_binary(device_pubkey) do
- GenServer.call(vpn_pid(), {:remove_peer, device_pubkey})
+ def delete_device(public_key) when is_binary(public_key) do
+ GenServer.call(vpn_pid(), {:remove_peer, public_key})
end
def delete_device(device) when is_struct(device) do
diff --git a/apps/fz_http/lib/fz_http_web/live/device_live/new_form_component.html.heex b/apps/fz_http/lib/fz_http_web/live/device_live/new_form_component.html.heex
index dba10d274..c113130fc 100644
--- a/apps/fz_http/lib/fz_http_web/live/device_live/new_form_component.html.heex
+++ b/apps/fz_http/lib/fz_http_web/live/device_live/new_form_component.html.heex
@@ -53,6 +53,7 @@
<.form let={f} for={@changeset} id="create-device" phx-change="change" phx-target={@myself} phx-submit="save">
<%= hidden_input f, :public_key, id: "device-public-key", phx_hook: "GenerateKeyPair" %>
+ <%= hidden_input f, :preshared_key %>
<%= if @changeset.action do %>
diff --git a/apps/fz_http/lib/fz_http_web/mock_events.ex b/apps/fz_http/lib/fz_http_web/mock_events.ex
index 3295bebf2..4f5d47ff2 100644
--- a/apps/fz_http/lib/fz_http_web/mock_events.ex
+++ b/apps/fz_http/lib/fz_http_web/mock_events.ex
@@ -7,8 +7,8 @@ defmodule FzHttpWeb.MockEvents do
inside FzHttp and use that for the tests.
"""
- def delete_device(pubkey) do
- {:ok, pubkey}
+ def delete_device(public_key) do
+ {:ok, public_key}
end
def update_device(_device) do
diff --git a/apps/fz_http/lib/fz_http_web/templates/shared/device_details.html.heex b/apps/fz_http/lib/fz_http_web/templates/shared/device_details.html.heex
index e5610d18f..ab0ae713d 100644
--- a/apps/fz_http/lib/fz_http_web/templates/shared/device_details.html.heex
+++ b/apps/fz_http/lib/fz_http_web/templates/shared/device_details.html.heex
@@ -62,5 +62,10 @@
Public key |
<%= @device.public_key %> |
+
+
+ | Preshared Key |
+ <%= @device.preshared_key %> |
+
diff --git a/apps/fz_http/mix.exs b/apps/fz_http/mix.exs
index 984b1f630..e7c6b225d 100644
--- a/apps/fz_http/mix.exs
+++ b/apps/fz_http/mix.exs
@@ -43,7 +43,8 @@ defmodule FzHttp.MixProject do
:runtime_tools,
:ueberauth_okta,
:ueberauth_identity
- ]
+ ],
+ registered: [:fz_http_server]
]
end
diff --git a/apps/fz_http/priv/repo/migrations/20220412144151_add_psk_to_devices.exs b/apps/fz_http/priv/repo/migrations/20220412144151_add_psk_to_devices.exs
new file mode 100644
index 000000000..eee9fccf1
--- /dev/null
+++ b/apps/fz_http/priv/repo/migrations/20220412144151_add_psk_to_devices.exs
@@ -0,0 +1,9 @@
+defmodule FzHttp.Repo.Migrations.AddPskToDevices do
+ use Ecto.Migration
+
+ def change do
+ alter table(:devices) do
+ add :preshared_key, :bytea
+ end
+ end
+end
diff --git a/apps/fz_http/priv/repo/seeds.exs b/apps/fz_http/priv/repo/seeds.exs
index 8058ae73c..0b2f36538 100644
--- a/apps/fz_http/priv/repo/seeds.exs
+++ b/apps/fz_http/priv/repo/seeds.exs
@@ -23,6 +23,7 @@ alias FzHttp.{Devices, ConnectivityChecks, Rules, Users}
Devices.create_device(%{
user_id: user.id,
name: "Factory Device",
+ preshared_key: "27eCDMVvVFfMVS5Rfnn9n7as4M6MemGY/oghmdrwX2E=",
public_key: "3Fo+SNnDJ6hi8qzPt3nWLwgjCVwvpjHL35qJeatKwEc=",
remote_ip: %Postgrex.INET{address: {127, 0, 0, 1}}
})
diff --git a/apps/fz_http/test/fz_http/devices_test.exs b/apps/fz_http/test/fz_http/devices_test.exs
index 2bbee584e..ecdf3fcf1 100644
--- a/apps/fz_http/test/fz_http/devices_test.exs
+++ b/apps/fz_http/test/fz_http/devices_test.exs
@@ -70,6 +70,10 @@ defmodule FzHttp.DevicesTest do
assert device.ipv6 == %Postgrex.INET{address: {64_768, 0, 0, 0, 0, 3, 2, 2}, netmask: 128}
end
+ test "generates preshared_key" do
+ assert String.length(Devices.new_device().changes.preshared_key) == 44
+ end
+
@tag ipv4_network: "10.3.2.0/30"
test "sets error when ipv4 address pool is exhausted", %{user: user} do
restore_env(:wireguard_ipv4_network, "10.3.2.0/30", &on_exit/1)
@@ -380,6 +384,7 @@ defmodule FzHttp.DevicesTest do
test "renders all peers", %{device: device} do
assert Devices.to_peer_list() |> List.first() == %{
+ preshared_key: nil,
public_key: device.public_key,
inet: "#{device.ipv4}/32,#{device.ipv6}/128"
}
diff --git a/apps/fz_http/test/fz_http/events_test.exs b/apps/fz_http/test/fz_http/events_test.exs
index a12f38f9e..fb3c17321 100644
--- a/apps/fz_http/test/fz_http/events_test.exs
+++ b/apps/fz_http/test/fz_http/events_test.exs
@@ -21,7 +21,10 @@ defmodule FzHttp.EventsTest do
assert :ok == Events.update_device(device)
assert :sys.get_state(Events.vpn_pid()) == %{
- device.public_key => "#{device.ipv4}/32,#{device.ipv6}/128"
+ device.public_key => %{
+ allowed_ips: "#{device.ipv4}/32,#{device.ipv6}/128",
+ preshared_key: nil
+ }
}
end
end
@@ -33,7 +36,10 @@ defmodule FzHttp.EventsTest do
assert :ok = Events.update_device(device)
assert :sys.get_state(Events.vpn_pid()) == %{
- device.public_key => "#{device.ipv4}/32,#{device.ipv6}/128"
+ device.public_key => %{
+ allowed_ips: "#{device.ipv4}/32,#{device.ipv6}/128",
+ preshared_key: nil
+ }
}
end
end
@@ -68,7 +74,9 @@ defmodule FzHttp.EventsTest do
:ok = Events.set_config()
assert :sys.get_state(Events.vpn_pid()) ==
- Map.new(Devices.to_peer_list(), fn peer -> {peer.public_key, peer.inet} end)
+ Map.new(Devices.to_peer_list(), fn peer ->
+ {peer.public_key, %{allowed_ips: peer.inet, preshared_key: peer.preshared_key}}
+ end)
end
end
diff --git a/apps/fz_vpn/lib/fz_vpn/cli/live.ex b/apps/fz_vpn/lib/fz_vpn/cli/live.ex
index acbd7cd19..b297a4c61 100644
--- a/apps/fz_vpn/lib/fz_vpn/cli/live.ex
+++ b/apps/fz_vpn/lib/fz_vpn/cli/live.ex
@@ -8,6 +8,7 @@ defmodule FzVpn.CLI.Live do
See FzVpn.Server for higher-level functionality.
"""
+ alias FzVpn.Config
import FzCommon.CLI
require Logger
@@ -19,12 +20,9 @@ defmodule FzVpn.CLI.Live do
:ok = GenServer.call(:global.whereis_name(:fz_wall_server), :teardown)
end
- def set_peer(pubkey, inet) do
- set("peer #{pubkey} allowed-ips #{inet}")
- end
-
- def remove_peer(pubkey) do
- set("peer #{pubkey} remove")
+ def remove_peer(public_key) do
+ set("peer #{public_key} remove")
+ Config.delete_psk(public_key)
end
def set(config_str) do
diff --git a/apps/fz_vpn/lib/fz_vpn/cli/sandbox.ex b/apps/fz_vpn/lib/fz_vpn/cli/sandbox.ex
index 17161594e..0c9e9b326 100644
--- a/apps/fz_vpn/lib/fz_vpn/cli/sandbox.ex
+++ b/apps/fz_vpn/lib/fz_vpn/cli/sandbox.ex
@@ -1,8 +1,10 @@
defmodule FzVpn.CLI.Sandbox do
@moduledoc """
- Sandbox CLI environment for WireGuard CLI operations.
+ Sandbox CLI environment for WireGuard CLI operations used in
+ dev and test modes.
"""
+ alias FzVpn.Config
require Logger
@wg_show """
@@ -44,16 +46,13 @@ defmodule FzVpn.CLI.Sandbox do
|> Enum.map(fn line ->
String.replace_leading(line, "peer: ", "")
end)
- |> Enum.each(fn pubkey ->
- remove_peer(pubkey)
+ |> Enum.each(fn public_key ->
+ remove_peer(public_key)
end)
end
- def remove_peer(_pubkey) do
- @default_returned
- end
-
- def set_peer(_pubkey, _allowed_ips) do
+ def remove_peer(public_key) do
+ Config.delete_psk(public_key)
@default_returned
end
diff --git a/apps/fz_vpn/lib/fz_vpn/config.ex b/apps/fz_vpn/lib/fz_vpn/config.ex
index 0b5740918..5106b1bf2 100644
--- a/apps/fz_vpn/lib/fz_vpn/config.ex
+++ b/apps/fz_vpn/lib/fz_vpn/config.ex
@@ -3,13 +3,57 @@ defmodule FzVpn.Config do
Functions for managing the WireGuard configuration.
"""
+ require Logger
+
# Render peers list into server config
def render(config) do
Enum.join(
- for {public_key, allowed_ips} <- config do
- "peer #{public_key} allowed-ips #{allowed_ips}"
+ for {public_key, %{allowed_ips: allowed_ips, preshared_key: preshared_key}} <- config do
+ if is_nil(preshared_key) do
+ "peer #{public_key} allowed-ips #{allowed_ips}"
+ else
+ write_psk(public_key, preshared_key)
+
+ "peer #{public_key} allowed-ips #{allowed_ips} preshared-key #{psk_filepath(public_key)}"
+ end
end,
" "
)
end
+
+ def write_psk(public_key, preshared_key) do
+ # Sets proper file mode before key is written
+ File.touch!(psk_filepath(public_key))
+ File.chmod!(psk_filepath(public_key), 0o660)
+ File.write!(psk_filepath(public_key), preshared_key)
+ end
+
+ def delete_psk(public_key) do
+ case File.rm(psk_filepath(public_key)) do
+ :ok ->
+ :ok
+
+ _ ->
+ Logger.warn("""
+ public_key #{public_key} at path #{psk_filepath(public_key)} \
+ seems to have already been removed.
+ """)
+ end
+ end
+
+ def psk_filepath(nil), do: raise("Error! public_key unexpectedly nil")
+
+ def psk_filepath(public_key) do
+ "#{psk_dir()}/#{psk_filename(public_key)}"
+ end
+
+ defp psk_dir do
+ Application.fetch_env!(:fz_vpn, :wireguard_psk_dir)
+ end
+
+ defp psk_filename(public_key) do
+ :crypto.hash(:sha256, public_key)
+ |> Base.encode16()
+ |> String.downcase()
+ end
end
diff --git a/apps/fz_vpn/lib/fz_vpn/server.ex b/apps/fz_vpn/lib/fz_vpn/server.ex
index e7fbd09a9..2003c3ee3 100644
--- a/apps/fz_vpn/lib/fz_vpn/server.ex
+++ b/apps/fz_vpn/lib/fz_vpn/server.ex
@@ -24,10 +24,10 @@ defmodule FzVpn.Server do
end
@impl GenServer
- def handle_call({:remove_peer, pubkey}, _from, config) do
- cli().remove_peer(pubkey)
- new_config = Map.delete(config, pubkey)
- {:reply, {:ok, pubkey}, new_config}
+ def handle_call({:remove_peer, public_key}, _from, config) do
+ cli().remove_peer(public_key)
+ new_config = Map.delete(config, public_key)
+ {:reply, {:ok, public_key}, new_config}
end
@impl GenServer
@@ -47,14 +47,14 @@ defmodule FzVpn.Server do
end
defp delete_old_peers(old_config, new_config) do
- for pubkey <- Map.keys(old_config) -- Map.keys(new_config) do
- cli().remove_peer(pubkey)
+ for public_key <- Map.keys(old_config) -- Map.keys(new_config) do
+ cli().remove_peer(public_key)
end
end
defp update_changed_peers(old_config, new_config) do
new_config
- |> Enum.filter(fn {pubkey, inet} -> Map.get(old_config, pubkey) != inet end)
+ |> Enum.filter(fn {public_key, settings} -> Map.get(old_config, public_key) != settings end)
|> Config.render()
|> cli().set()
end
@@ -64,6 +64,8 @@ defmodule FzVpn.Server do
end
defp peers_to_config(peers) do
- Map.new(peers, fn peer -> {peer.public_key, peer.inet} end)
+ Map.new(peers, fn peer ->
+ {peer.public_key, %{allowed_ips: peer.inet, preshared_key: peer.preshared_key}}
+ end)
end
end
diff --git a/apps/fz_vpn/mix.exs b/apps/fz_vpn/mix.exs
index a6c659cfe..d9a5ed03e 100644
--- a/apps/fz_vpn/mix.exs
+++ b/apps/fz_vpn/mix.exs
@@ -41,6 +41,7 @@ defmodule FzVpn.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
+ {:fz_http, in_umbrella: true},
{:fz_common, in_umbrella: true},
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
{:excoveralls, "~> 0.13", only: :test}
diff --git a/apps/fz_vpn/test/fz_vpn/config_test.exs b/apps/fz_vpn/test/fz_vpn/config_test.exs
index f1d7d0c3e..2f8375374 100644
--- a/apps/fz_vpn/test/fz_vpn/config_test.exs
+++ b/apps/fz_vpn/test/fz_vpn/config_test.exs
@@ -2,7 +2,8 @@ defmodule FzVpn.ConfigTest do
use ExUnit.Case, async: true
alias FzVpn.Config
- @populated_config "peer test-pubkey allowed-ips test-ipv4/32,test-ipv6/128"
+ @psk_config "peer test-pubkey allowed-ips test-ipv4/32,test-ipv6/128 preshared-key /tmp/0abdc3fcda5d110c7ce3626dd2a261d9c0d33f3ee643ef9a46fe2f7aee0ee5e3"
+ @no_psk_config "peer test-pubkey allowed-ips test-ipv4/32,test-ipv6/128"
describe "render" do
test "renders default config" do
@@ -11,10 +12,20 @@ defmodule FzVpn.ConfigTest do
assert Config.render(config) == ""
end
- test "renders populated config" do
- config = %{"test-pubkey" => "test-ipv4/32,test-ipv6/128"}
+ test "renders psk config" do
+ config = %{
+ "test-pubkey" => %{allowed_ips: "test-ipv4/32,test-ipv6/128", preshared_key: "foobar"}
+ }
- assert Config.render(config) == @populated_config
+ assert Config.render(config) == @psk_config
+ end
+
+ test "renders no-psk config" do
+ config = %{
+ "test-pubkey" => %{allowed_ips: "test-ipv4/32,test-ipv6/128", preshared_key: nil}
+ }
+
+ assert Config.render(config) == @no_psk_config
end
end
end
diff --git a/apps/fz_vpn/test/fz_vpn/server_test.exs b/apps/fz_vpn/test/fz_vpn/server_test.exs
index b48b23cba..d130cacb0 100644
--- a/apps/fz_vpn/test/fz_vpn/server_test.exs
+++ b/apps/fz_vpn/test/fz_vpn/server_test.exs
@@ -3,13 +3,13 @@ defmodule FzVpn.ServerTest do
import FzVpn.CLI
@single_peer [
- %{public_key: "test-pubkey", inet: "127.0.0.1/32,::1/128"}
+ %{public_key: "test-pubkey", preshared_key: "foobar", inet: "127.0.0.1/32,::1/128"}
]
@many_peers [
- %{public_key: "key1", inet: "0.0.0.0/32,::1/128"},
- %{public_key: "key2", inet: "127.0.0.1/32,::1/128"},
- %{public_key: "key3", inet: "127.0.0.1/32,::1/128"},
- %{public_key: "key4", inet: "127.0.0.1/32,::1/128"}
+ %{public_key: "key1", preshared_key: "foobar", inet: "0.0.0.0/32,::1/128"},
+ %{public_key: "key2", preshared_key: "foobar", inet: "127.0.0.1/32,::1/128"},
+ %{public_key: "key3", preshared_key: "foobar", inet: "127.0.0.1/32,::1/128"},
+ %{public_key: "key4", preshared_key: "foobar", inet: "127.0.0.1/32,::1/128"}
]
describe "state" do
@@ -31,17 +31,20 @@ defmodule FzVpn.ServerTest do
@tag stubbed_config: @many_peers
test "calcs diff and sets only the diff", %{test_pid: test_pid} do
- new_peers = [%{public_key: "key5", inet: "1.1.1.1/32,::2/128"}]
+ new_peers = [%{public_key: "key5", inet: "1.1.1.1/32,::2/128", preshared_key: "foobar"}]
assert :sys.get_state(test_pid) == %{
- "key1" => "0.0.0.0/32,::1/128",
- "key2" => "127.0.0.1/32,::1/128",
- "key3" => "127.0.0.1/32,::1/128",
- "key4" => "127.0.0.1/32,::1/128"
+ "key1" => %{allowed_ips: "0.0.0.0/32,::1/128", preshared_key: "foobar"},
+ "key2" => %{allowed_ips: "127.0.0.1/32,::1/128", preshared_key: "foobar"},
+ "key3" => %{allowed_ips: "127.0.0.1/32,::1/128", preshared_key: "foobar"},
+ "key4" => %{allowed_ips: "127.0.0.1/32,::1/128", preshared_key: "foobar"}
}
GenServer.call(test_pid, {:set_config, new_peers})
- assert :sys.get_state(test_pid) == %{"key5" => "1.1.1.1/32,::2/128"}
+
+ assert :sys.get_state(test_pid) == %{
+ "key5" => %{allowed_ips: "1.1.1.1/32,::2/128", preshared_key: "foobar"}
+ }
end
end
end
diff --git a/apps/fz_wall/mix.exs b/apps/fz_wall/mix.exs
index 4d67e3cb6..81d2a0eb3 100644
--- a/apps/fz_wall/mix.exs
+++ b/apps/fz_wall/mix.exs
@@ -41,6 +41,7 @@ defmodule FzWall.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
+ {:fz_http, in_umbrella: true},
{:fz_common, in_umbrella: true},
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
{:excoveralls, "~> 0.13", only: :test}
diff --git a/config/config.exs b/config/config.exs
index 15541ea58..509d3ac9a 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -86,6 +86,7 @@ config :hammer,
# This will be changed per-env
config :fz_vpn,
+ wireguard_psk_dir: "/tmp",
wireguard_public_key: "cB2yQeCxHO/qCH8APoM2D2Anf4Yd7sRLyfS7su71K3M=",
wireguard_interface_name: "wg-firezone",
wireguard_port: "51820",
diff --git a/config/releases.exs b/config/releases.exs
index 1cf0a3244..9f0c5b63d 100644
--- a/config/releases.exs
+++ b/config/releases.exs
@@ -23,6 +23,7 @@ nft_path = System.fetch_env!("NFT_PATH")
wg_path = System.fetch_env!("WG_PATH")
egress_interface = System.fetch_env!("EGRESS_INTERFACE")
wireguard_public_key = System.fetch_env!("WIREGUARD_PUBLIC_KEY")
+wireguard_psk_dir = System.fetch_env!("WIREGUARD_PSK_DIR")
wireguard_dns = System.fetch_env!("WIREGUARD_DNS")
wireguard_allowed_ips = System.fetch_env!("WIREGUARD_ALLOWED_IPS")
wireguard_persistent_keepalive = System.fetch_env!("WIREGUARD_PERSISTENT_KEEPALIVE")
@@ -141,6 +142,7 @@ config :fz_wall,
cli: FzWall.CLI.Live
config :fz_vpn,
+ wireguard_psk_dir: wireguard_psk_dir,
wireguard_public_key: wireguard_public_key,
wireguard_interface_name: wireguard_interface_name,
wireguard_port: wireguard_port,
diff --git a/docs/docs/reference/configuration-file.md b/docs/docs/reference/configuration-file.md
index 8d5a313e4..2b835a604 100644
--- a/docs/docs/reference/configuration-file.md
+++ b/docs/docs/reference/configuration-file.md
@@ -32,6 +32,15 @@ Shown below is a complete listing of the configuration options available in
| `default['enterprise']['name']` | Name used by the Chef 'enterprise' cookbook. | `'firezone'` |
| `default['firezone']['install_path']` | Install path used by Chef 'enterprise' cookbook. Should be set to the same as the `install_directory` above. | `node['firezone']['install_directory']` |
| `default['firezone']['sysvinit_id']` | An identifier used in `/etc/inittab`. Must be a unique sequence of 1-4 characters. | `'SUP'` |
+| `default['firezone']['authentication']['local']['enabled'] = true` | Enable or disable local email/password authentication. | `true` |
+| `default['firezone']['authentication']['okta']['enabled'] = false` | Enable or disable Okta SSO authentication. | `false` |
+| `default['firezone']['authentication']['okta']['client_id'] = nil` | OAuth Client ID for Okta SSO authentication. | `nil` |
+| `default['firezone']['authentication']['okta']['client_secret'] = nil` | OAuth Client Secret for Okta SSO authentication. | `nil` |
+| `default['firezone']['authentication']['okta']['site'] = 'https://your-domain.okta.com'` | Okta site to redirect to after successful authentication. | `'https://your-domain.okta.com'` |
+| `default['firezone']['authentication']['google']['enabled'] = false` | Enable or disable Google SSO authentication. | `false` |
+| `default['firezone']['authentication']['google']['client_id'] = nil` | OAuth Client ID for Google SSO authentication. | `nil` |
+| `default['firezone']['authentication']['google']['client_secret'] = nil` | OAuth Client Secret for Google SSO authentication. | `nil` |
+| `default['firezone']['authentication']['google']['redirect_uri'] = nil` | Google redirect URI for Google SSO authentication. | `nil` |
| `default['firezone']['nginx']['enabled']` | Enable or disable the bundled nginx server. | `true` |
| `default['firezone']['nginx']['force_ssl']` | Force nginx to SSL mode only. | `true` |
| `default['firezone']['nginx']['non_ssl_port']` | HTTP listen port. | `80` |
diff --git a/mix.lock b/mix.lock
index dfa0f6c8c..788fbf212 100644
--- a/mix.lock
+++ b/mix.lock
@@ -31,7 +31,7 @@
"hammer": {:hex, :hammer, "6.0.0", "72ec6fff10e9d63856968988a22ee04c4d6d5248071ddccfbda50aa6c455c1d7", [:mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "d8e1ec2e534c4aae508b906759e077c3c1eb3e2b9425235d4b7bbab0b016210a"},
"hammer_plug": {:hex, :hammer_plug, "2.1.1", "eb5390380eff6600e24e93edfe6a34d39f35280cbdd1caa0995b58bb8489f00d", [:make, :mix], [{:hammer, "~> 6.0", [hex: :hammer, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0fbc3e8b1aacecb7affea65c85c349fdbd00ff28a74bbe6ca30c9f4c76d71e4b"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
- "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
+ "httpoison": {:hex, :httpoison, "1.8.1", "df030d96de89dad2e9983f92b0c506a642d4b1f4a819c96ff77d12796189c63e", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "35156a6d678d6d516b9229e208942c405cf21232edd632327ecfaf4fd03e79e0"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
@@ -51,8 +51,8 @@
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.1.0", "0b499df05aad27160d697a9362f0e89fa0e24d3c7a9065c2bd9d38b4d1416c09", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c0a98a2cefa63433657983a2a594c7dee5927e4391e0f1bfd3a151d1def33fc"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
- "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.7", "05a42377075868a678d446361effba80cefef19ab98941c01a7a4c7560b29121", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "25eaf41028eb351b90d4f69671874643a09944098fefd0d01d442f40a6091b6f"},
- "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
+ "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.9", "36b5aa812bc3ccd64c9630f6b3234d9ea21105493237e927aae19d0ba758f0db", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f7ebc3e0ba0c5f6b6996ed6c901ddbfdaba59a6d09b569e7cb2f2f7d693b4455"},
+ "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"},
"plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
diff --git a/omnibus/cookbooks/firezone/libraries/config.rb b/omnibus/cookbooks/firezone/libraries/config.rb
index f3f2e3f7e..f866d2914 100644
--- a/omnibus/cookbooks/firezone/libraries/config.rb
+++ b/omnibus/cookbooks/firezone/libraries/config.rb
@@ -235,6 +235,7 @@ class Firezone
'WIREGUARD_ALLOWED_IPS' => attributes['wireguard']['allowed_ips'].to_s,
'WIREGUARD_PERSISTENT_KEEPALIVE' => attributes['wireguard']['persistent_keepalive'].to_s,
'WIREGUARD_PUBLIC_KEY' => attributes['wireguard_public_key'],
+ 'WIREGUARD_PSK_DIR' => "#{attributes['var_directory']}/cache/psks",
'WIREGUARD_IPV4_ENABLED' => attributes['wireguard']['ipv4']['enabled'].to_s,
'WIREGUARD_IPV4_NETWORK' => attributes['wireguard']['ipv4']['network'],
'WIREGUARD_IPV4_ADDRESS' => attributes['wireguard']['ipv4']['address'],
diff --git a/omnibus/cookbooks/firezone/recipes/config.rb b/omnibus/cookbooks/firezone/recipes/config.rb
index 4fd738ed7..3e99f2c97 100644
--- a/omnibus/cookbooks/firezone/recipes/config.rb
+++ b/omnibus/cookbooks/firezone/recipes/config.rb
@@ -109,3 +109,9 @@ file "#{node['firezone']['var_directory']}/cache/wg_private_key" do
content node['firezone']['wireguard_private_key']
action :create_if_missing
end
+
+directory "#{node['firezone']['var_directory']}/cache/psks" do
+ owner 'root'
+ group node['firezone']['group']
+ mode '0770'
+end
diff --git a/scripts/install.sh b/scripts/install.sh
index a6cbd0c8f..5bda967e1 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -68,7 +68,7 @@ wireguardCheck() {
kernelCheck() {
major=`uname -r | cut -d'.' -f1`
if [ "$major" -lt "5" ]; then
- echo "Kernel is not supported `uname -r`"
+ echo "Kernel version `uname -r ` is not supported. Please upgrade to 5.0 or higher."
exit
fi
}