diff --git a/ansible/playbook.yml b/ansible/playbook.yml index 21d84a2be..8ef5321e4 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -10,6 +10,7 @@ autoremove: yes update_cache: true pkg: + - rsync - sudo - git - curl @@ -62,9 +63,8 @@ hosts: all tasks: - name: Copy Project - copy: - src: /vagrant - dest: /home/vagrant/fireguard + shell: | + rsync --delete -avz /vagrant/* /home/vagrant/fireguard/ - name: Compile Release become: no environment: diff --git a/apps/fg_http/lib/fg_http/devices/device.ex b/apps/fg_http/lib/fg_http/devices/device.ex index c93b60c2b..b77e71f6e 100644 --- a/apps/fg_http/lib/fg_http/devices/device.ex +++ b/apps/fg_http/lib/fg_http/devices/device.ex @@ -13,6 +13,7 @@ defmodule FgHttp.Devices.Device do field :public_key, :string field :ifname, :string field :last_ip, EctoNetwork.INET + field :last_seen_at, :utc_datetime_usec has_many :rules, Rule belongs_to :user, User diff --git a/apps/fg_http/priv/repo/migrations/20201115200531_add_last_seen_at_to_devices.exs b/apps/fg_http/priv/repo/migrations/20201115200531_add_last_seen_at_to_devices.exs new file mode 100644 index 000000000..11095e29a --- /dev/null +++ b/apps/fg_http/priv/repo/migrations/20201115200531_add_last_seen_at_to_devices.exs @@ -0,0 +1,9 @@ +defmodule FgHttp.Repo.Migrations.AddLastSeenAtToDevices do + use Ecto.Migration + + def change do + alter table(:devices) do + add :last_seen_at, :utc_datetime_usec + end + end +end diff --git a/apps/fg_vpn/lib/fg_vpn/application.ex b/apps/fg_vpn/lib/fg_vpn/application.ex index 45208531f..28a2cab6b 100644 --- a/apps/fg_vpn/lib/fg_vpn/application.ex +++ b/apps/fg_vpn/lib/fg_vpn/application.ex @@ -6,7 +6,10 @@ defmodule FgVpn.Application do use Application def start(_type, _args) do + pubkeys = ["hello", "world"] + children = [ + {FgVpn.Config, pubkeys} # Starts a worker by calling: FgVpn.Worker.start_link(arg) # {FgVpn.Worker, arg} ] diff --git a/apps/fg_vpn/lib/fg_vpn/config.ex b/apps/fg_vpn/lib/fg_vpn/config.ex new file mode 100644 index 000000000..a9cbb81d3 --- /dev/null +++ b/apps/fg_vpn/lib/fg_vpn/config.ex @@ -0,0 +1,50 @@ +defmodule FgVpn.Config do + @moduledoc """ + Maintains our own representation of the WireGuard config + """ + use Agent + + @doc """ + Receive a list of devices and start maintaining config. + """ + def start_link(pubkeys) do + Agent.start_link(fn -> pubkeys end, name: __MODULE__) + end + + def add_peer(pubkey) do + Agent.update(__MODULE__, fn pubkeys -> [pubkey | pubkeys] end) + end + + def remove_peer(pubkey) do + Agent.update(__MODULE__, fn pubkeys -> List.delete(pubkeys, pubkey) end) + end + + def list_peers do + Agent.get(__MODULE__, fn pubkeys -> pubkeys end) + end + + def write! do + File.write!(Application.get_env(:fg_vpn, :wireguard_conf_path), render()) + end + + @doc """ + Renders WireGuard config in a deterministic way. + """ + def render do + "# BEGIN FIREGUARD-MANAGED PEER LIST\n" <> + peers_to_config(list_peers()) <> + "# END FIREGUARD-MANAGED PEER LIST" + end + + defp peers_to_config(peers) do + Enum.map_join(peers, fn pubkey -> + ~s""" + # BEGIN PEER #{pubkey} + [Peer] + PublicKey = #{pubkey} + AllowedIPs = 0.0.0.0/0, ::/0 + # END PEER #{pubkey} + """ + end) + end +end diff --git a/apps/fg_vpn/lib/fg_vpn/wg_cli.ex b/apps/fg_vpn/lib/fg_vpn/wg_cli.ex index 0bc809f33..2fbe6955f 100644 --- a/apps/fg_vpn/lib/fg_vpn/wg_cli.ex +++ b/apps/fg_vpn/lib/fg_vpn/wg_cli.ex @@ -1,16 +1,27 @@ defmodule FgVpn.WGCLI do @moduledoc """ - Wraps command-line functionality of WireGuard for our purposes + Wraps command-line functionality of WireGuard for our purposes. + + Application startup: + - wg syncconf + + Consumed events: + - add device: + 1. start listening for new connections + 2. send pubkey when device connects + 3. when verification received from fg_http, add config entry + + - remove device: + 1. disconnect device if connected + 2. remove configuration entry + + Produced events: + - client connects: + 1. send IP, connection time to FgHttp + - change config + + Helpers: + - render_conf: re-renders configuration file (peer configurations specifically) + - sync_conf: calls "wg syncconf" """ - - def add_client(_public_key) do - # Add network for this device - # Generate config entry - end - - def add_client_network do - end - - def save_config do - end end diff --git a/apps/fg_vpn/test/fixtures/wg-fireguard.conf b/apps/fg_vpn/test/fixtures/wg-fireguard.conf new file mode 100644 index 000000000..40e80a698 --- /dev/null +++ b/apps/fg_vpn/test/fixtures/wg-fireguard.conf @@ -0,0 +1 @@ +# Test WireGuard config diff --git a/config/config.exs b/config/config.exs index 6576b8704..e2c70eb91 100644 --- a/config/config.exs +++ b/config/config.exs @@ -27,8 +27,11 @@ config :phoenix, :json_library, Jason config :fg_http, ecto_repos: [FgHttp.Repo] -config :fg_http, - vpn_endpoint: "localhost:51820" +config :fg_vpn, + wireguard_conf_path: + config(:fg_http, + vpn_endpoint: "localhost:51820" + ) # Configures the endpoint # These will be overridden at runtime in production by config/releases.exs diff --git a/config/dev.exs b/config/dev.exs index b4cc1d3f3..8ffec60c5 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -71,11 +71,19 @@ config :fg_http, FgHttpWeb.Endpoint, ] ] -config :fg_http, disable_signup: true - config :fg_vpn, pubkey: "JId8GN8iPmdQXOLSdcsSkaW4i60e1/rpHB/03rsaKBk=" +config :fg_vpn, + wireguard_conf_path: Path.expand("~/.wg-fireguard.conf") + +config :fg_http, + disable_signup: + (case System.get_env("DISABLE_SIGNUP") do + d when d in ["1", "yes"] -> true + _ -> false + end) + # Do not include metadata nor timestamps in development logs config :logger, :console, format: "[$level] $message\n" diff --git a/config/prod.exs b/config/prod.exs index b1ffca8db..57b57f98e 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -58,6 +58,8 @@ config :fg_http, FgHttpWeb.Endpoint, ], force_ssl: [rewrite_on: [:x_forwarded_proto], hsts: true, host: nil] +config :fg_vpn, wireguard_conf_path: "/etc/wireguard/wg-fireguard.conf" + # Do not print debug messages in production config :logger, level: :info diff --git a/config/test.exs b/config/test.exs index ef4d7e60b..a03bd1024 100644 --- a/config/test.exs +++ b/config/test.exs @@ -25,7 +25,8 @@ config :fg_http, FgHttp.Repo, DBConfig.config(db_url) config :fg_http, FgHttp.Mailer, adapter: Bamboo.TestAdapter -config :fg_http, disable_signup: false +config :fg_vpn, + wireguard_conf_path: Path.expand("#{__DIR__}/../apps/fg_vpn/test/fixtures/wg-fireguard.conf") # We don't run a server during test. If one is required, # you can enable the server option below.