mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
Build/729/different reverse proxy (#795)
* Removes disabling SSL and adds remote_ip lib * Fix to use remote_ip when not proxy * Add trusted_proxy to config * Add proxy_forwarded prameter to config and improve logging * Fix trusted_proxy list parsing * Fix ip formatting * Expect JSON array for trusted_proxy * fix proxied-related plug loading runtime * fix typo * checkpoint * add traefik draft * add logging * woops * adding logging for debug * rollback debugging logs * docs refinement * Fix markdown lints * remove disabling proxy_forwarded option for prod * rename, improve docs and add clients config * change dev_secure to secure_cookies * Set proxy_forwarded as true by default * remove proxy_forwarded in favor of nil trusted_proxies * renaming and doc improvement * build fix * jamilbk changes Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
This commit is contained in:
@@ -8,10 +8,6 @@ EXTERNAL_URL=http://localhost:4000
|
||||
# Enable local authentication
|
||||
LOCAL_AUTH_ENABLED=true
|
||||
|
||||
# Set PROXY_FORWARDED to true if you're running this behind a proxy or using
|
||||
# GitHub codespaces
|
||||
PROXY_FORWARDED=true
|
||||
|
||||
# Generated with `jq @json < .oidc_env.json`
|
||||
# Set AUTH_OIDC to a JSON configuration string to enable
|
||||
# generic OIDC auth.
|
||||
|
||||
@@ -154,10 +154,10 @@ If the above commands indicate success, you should be good to go!
|
||||
|
||||
You can run this using Github Codespaces or your own devcontainer using Docker.
|
||||
|
||||
On GitHub Codespaces, follow the instructions above but start the server with
|
||||
PROXY_FORWARDED enabled and pass in your Codespace external url:
|
||||
On GitHub Codespaces, follow the instructions above but pass in your Codespace
|
||||
external url:
|
||||
|
||||
`PROXY_FORWARDED=true EXTERNAL_URL=[your_devcontainer_url] MIX_ENV=dev mix start`
|
||||
`EXTERNAL_URL=[your_devcontainer_url] MIX_ENV=dev mix start`
|
||||
|
||||
or using the `.env` file
|
||||
|
||||
|
||||
@@ -65,4 +65,20 @@ defmodule FzCommon.FzNet do
|
||||
def valid_hostname?(hostname) when is_binary(hostname) do
|
||||
String.match?(hostname, @host_regex)
|
||||
end
|
||||
|
||||
# IPv4
|
||||
def convert_ip({_, _, _, _} = address) when is_tuple(address) do
|
||||
address
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(".")
|
||||
end
|
||||
|
||||
# IPv6
|
||||
def convert_ip(address) when is_tuple(address) do
|
||||
address
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(":")
|
||||
end
|
||||
|
||||
def convert_ip(address) when is_binary(address), do: address
|
||||
end
|
||||
|
||||
@@ -3,12 +3,15 @@ defmodule FzHttpWeb.NotificationChannel do
|
||||
Handles dispatching realtime notifications to users' browser sessions.
|
||||
"""
|
||||
use FzHttpWeb, :channel
|
||||
import FzCommon.FzNet, only: [convert_ip: 1]
|
||||
alias FzHttp.Users
|
||||
alias FzHttpWeb.Presence
|
||||
|
||||
@token_verify_opts [max_age: 86_400]
|
||||
|
||||
@impl Phoenix.Channel
|
||||
def join("notification:session", %{"user_agent" => user_agent, "token" => token}, socket) do
|
||||
case Phoenix.Token.verify(socket, "channel auth", token, max_age: 86_400) do
|
||||
case Phoenix.Token.verify(socket, "channel auth", token, @token_verify_opts) do
|
||||
{:ok, user_id} ->
|
||||
socket =
|
||||
socket
|
||||
@@ -40,7 +43,7 @@ defmodule FzHttpWeb.NotificationChannel do
|
||||
online_at: DateTime.utc_now(),
|
||||
last_signed_in_at: user.last_signed_in_at,
|
||||
last_signed_in_method: user.last_signed_in_method,
|
||||
remote_ip: socket.assigns.remote_ip,
|
||||
remote_ip: convert_ip(socket.assigns.remote_ip),
|
||||
user_agent: socket.assigns.user_agent
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,19 @@ defmodule FzHttpWeb.UserSocket do
|
||||
use Phoenix.Socket
|
||||
|
||||
alias FzHttp.Users
|
||||
alias FzHttpWeb.HeaderHelpers
|
||||
import FzCommon.FzNet, only: [convert_ip: 1]
|
||||
|
||||
@blank_ip_error {:error, "client IP couldn't be determined!"}
|
||||
|
||||
# 4 hour channel tokens
|
||||
@token_verify_opts [max_age: 86_400]
|
||||
|
||||
require Logger
|
||||
|
||||
## Channels
|
||||
# channel "room:*", FzHttpWeb.RoomChannel
|
||||
channel "notification:session", FzHttpWeb.NotificationChannel
|
||||
channel("notification:session", FzHttpWeb.NotificationChannel)
|
||||
|
||||
# Socket params are passed from the client and can
|
||||
# be used to verify and authenticate a user. After
|
||||
@@ -21,17 +28,25 @@ defmodule FzHttpWeb.UserSocket do
|
||||
# See `Phoenix.Token` documentation for examples in
|
||||
# performing token verification on connect.
|
||||
def connect(%{"token" => token}, socket, connect_info) do
|
||||
ip = get_ip_address(connect_info)
|
||||
case get_ip_address(connect_info) do
|
||||
ip when ip in ["", nil] ->
|
||||
@blank_ip_error
|
||||
|
||||
case Phoenix.Token.verify(socket, "user auth", token, max_age: 86_400) do
|
||||
ip ->
|
||||
verify_token_and_assign_remote_ip(socket, token, convert_ip(ip))
|
||||
end
|
||||
end
|
||||
|
||||
defp verify_token_and_assign_remote_ip(socket, token, ip) do
|
||||
case Phoenix.Token.verify(socket, "user auth", token, @token_verify_opts) do
|
||||
{:ok, user_id} ->
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:current_user, Users.get_user!(user_id))
|
||||
|> assign(:remote_ip, ip)}
|
||||
|
||||
{:error, _} ->
|
||||
:error
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,36 +63,15 @@ defmodule FzHttpWeb.UserSocket do
|
||||
# def id(_socket), do: nil
|
||||
def id(socket), do: "user_socket:#{socket.assigns.current_user.id}"
|
||||
|
||||
defp get_ip_address(%{x_headers: headers_list}) when length(headers_list) > 0 do
|
||||
header =
|
||||
Enum.find(headers_list, fn {key, _val} -> key == "x-real-ip" end) ||
|
||||
Enum.find(headers_list, fn {key, _val} -> key == "x-forwarded-for" end)
|
||||
|
||||
case header do
|
||||
{_key, value} -> value
|
||||
_ -> nil
|
||||
end
|
||||
defp get_ip_address(%{x_headers: x_headers}) do
|
||||
RemoteIp.from(x_headers,
|
||||
proxies: HeaderHelpers.external_trusted_proxies(),
|
||||
clients: HeaderHelpers.clients()
|
||||
)
|
||||
end
|
||||
|
||||
# No proxy
|
||||
defp get_ip_address(%{peer_data: %{address: address}}) do
|
||||
convert_ip(address)
|
||||
|
||||
address
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(".")
|
||||
end
|
||||
|
||||
# IPv4
|
||||
defp convert_ip({_, _, _, _} = address) do
|
||||
address
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(".")
|
||||
end
|
||||
|
||||
# IPv6
|
||||
defp convert_ip(address) do
|
||||
address
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(":")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
defmodule FzHttpWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :fz_http
|
||||
alias FzHttpWeb.ProxyHeaders
|
||||
alias FzHttpWeb.HeaderHelpers
|
||||
alias FzHttpWeb.Session
|
||||
|
||||
if Application.get_env(:fz_http, FzHttpWeb.Endpoint, :proxy_forwarded) do
|
||||
plug Plug.RewriteOn, [:x_forwarded_host, :x_forwarded_port, :x_forwarded_proto]
|
||||
end
|
||||
|
||||
if Application.get_env(:fz_http, :sql_sandbox) do
|
||||
plug Phoenix.Ecto.SQL.Sandbox
|
||||
end
|
||||
@@ -21,11 +19,15 @@ defmodule FzHttpWeb.Endpoint do
|
||||
socket "/live", Phoenix.LiveView.Socket,
|
||||
websocket: [
|
||||
connect_info: [
|
||||
:peer_data,
|
||||
:x_headers,
|
||||
:uri,
|
||||
session: {Session, :options, []}
|
||||
],
|
||||
# XXX: csrf token should prevent CSWH but double check
|
||||
check_origin: false
|
||||
]
|
||||
],
|
||||
longpoll: false
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
@@ -65,6 +67,11 @@ defmodule FzHttpWeb.Endpoint do
|
||||
plug Plug.MethodOverride
|
||||
plug Plug.Head
|
||||
plug(:session)
|
||||
|
||||
if HeaderHelpers.proxied?() do
|
||||
plug ProxyHeaders
|
||||
end
|
||||
|
||||
plug FzHttpWeb.Router
|
||||
|
||||
defp session(conn, _opts) do
|
||||
|
||||
15
apps/fz_http/lib/fz_http_web/header_helpers.ex
Normal file
15
apps/fz_http/lib/fz_http_web/header_helpers.ex
Normal file
@@ -0,0 +1,15 @@
|
||||
defmodule FzHttpWeb.HeaderHelpers do
|
||||
@moduledoc """
|
||||
Helper functionalities with regards to headers
|
||||
"""
|
||||
|
||||
def external_trusted_proxies, do: conf(:external_trusted_proxies)
|
||||
|
||||
def clients, do: conf(:private_clients)
|
||||
|
||||
def proxied?, do: not (external_trusted_proxies() == false)
|
||||
|
||||
defp conf(key) when is_atom(key) do
|
||||
Application.fetch_env!(:fz_http, key)
|
||||
end
|
||||
end
|
||||
26
apps/fz_http/lib/fz_http_web/proxy_headers.ex
Normal file
26
apps/fz_http/lib/fz_http_web/proxy_headers.ex
Normal file
@@ -0,0 +1,26 @@
|
||||
defmodule FzHttpWeb.ProxyHeaders do
|
||||
@moduledoc """
|
||||
Loads proxy-related headers when it corresponds using runtime config
|
||||
"""
|
||||
import FzHttpWeb.HeaderHelpers
|
||||
@behaviour Plug
|
||||
|
||||
require Logger
|
||||
|
||||
def init(opts), do: opts
|
||||
|
||||
def call(conn, _opts) do
|
||||
conn
|
||||
|> RemoteIp.call(remote_ip_opts())
|
||||
|> Plug.RewriteOn.call(rewrite_opts())
|
||||
end
|
||||
|
||||
defp remote_ip_opts do
|
||||
RemoteIp.init(
|
||||
proxies: external_trusted_proxies(),
|
||||
clients: clients()
|
||||
)
|
||||
end
|
||||
|
||||
defp rewrite_opts, do: Plug.RewriteOn.init([:x_forwarded_proto])
|
||||
end
|
||||
@@ -91,7 +91,8 @@ defmodule FzHttp.MixProject do
|
||||
{:cidr, github: "firezone/cidr-elixir"},
|
||||
{:telemetry, "~> 1.0"},
|
||||
{:plug_cowboy, "~> 2.5"},
|
||||
{:credo, "~> 1.5", only: [:dev, :test], runtime: false}
|
||||
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
|
||||
{:remote_ip, "~> 1.0"}
|
||||
]
|
||||
end
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ config :fz_http, FzHttpWeb.Authentication,
|
||||
secret_key: "GApJ4c4a/KJLrBePgTDUk0n67AbjCvI9qdypKZEaJFXl6s9H3uRcIhTt49Fij5UO"
|
||||
|
||||
config :fz_http,
|
||||
external_trusted_proxies: [],
|
||||
private_clients: [],
|
||||
disable_vpn_on_oidc_error: true,
|
||||
auto_create_oidc_users: true,
|
||||
sandbox: true,
|
||||
@@ -112,13 +114,12 @@ config :fz_vpn,
|
||||
|
||||
config :fz_http, FzHttpWeb.Endpoint,
|
||||
render_errors: [view: FzHttpWeb.ErrorView, accepts: ~w(html json)],
|
||||
pubsub_server: FzHttp.PubSub,
|
||||
proxy_forwarded: false
|
||||
pubsub_server: FzHttp.PubSub
|
||||
|
||||
# Configures Elixir's Logger
|
||||
config :logger, :console,
|
||||
format: "$time $metadata[$level] $message\n",
|
||||
metadata: [:request_id]
|
||||
metadata: [:request_id, :remote_ip]
|
||||
|
||||
# Configures the vault
|
||||
config :fz_http, FzHttp.Vault,
|
||||
|
||||
@@ -119,6 +119,7 @@ config :phoenix, :stacktrace_depth, 20
|
||||
config :phoenix, :plug_init_mode, :runtime
|
||||
|
||||
config :fz_http,
|
||||
private_clients: ["172.28.0.0/16"],
|
||||
wireguard_allowed_ips: "172.28.0.0/16",
|
||||
cookie_secure: false,
|
||||
telemetry_module: FzCommon.MockTelemetry,
|
||||
|
||||
@@ -11,15 +11,11 @@ alias FzCommon.{CLI, FzInteger, FzString}
|
||||
external_url = System.get_env("EXTERNAL_URL", "https://localhost")
|
||||
config :fz_http, :external_url, external_url
|
||||
|
||||
# Enable Forwarded headers, e.g 'X-FORWARDED-HOST'
|
||||
proxy_forwarded = FzString.to_boolean(System.get_env("PROXY_FORWARDED") || "false")
|
||||
|
||||
%{host: host, path: path, port: port, scheme: scheme} = URI.parse(external_url)
|
||||
|
||||
config :fz_http, FzHttpWeb.Endpoint,
|
||||
url: [host: host, scheme: scheme, port: port, path: path],
|
||||
check_origin: ["//127.0.0.1", "//localhost", "//#{host}"],
|
||||
proxy_forwarded: proxy_forwarded
|
||||
check_origin: ["//127.0.0.1", "//localhost", "//#{host}"]
|
||||
|
||||
# Formerly releases.exs - Only evaluated in production
|
||||
if config_env() == :prod do
|
||||
@@ -34,6 +30,9 @@ if config_env() == :prod do
|
||||
database_parameters = Jason.decode!(System.fetch_env!("DATABASE_PARAMETERS"))
|
||||
phoenix_listen_address = System.fetch_env!("PHOENIX_LISTEN_ADDRESS")
|
||||
phoenix_port = String.to_integer(System.fetch_env!("PHOENIX_PORT"))
|
||||
external_trusted_proxies = Jason.decode!(System.fetch_env!("EXTERNAL_TRUSTED_PROXIES"))
|
||||
private_clients = Jason.decode!(System.fetch_env!("PRIVATE_CLIENTS"))
|
||||
|
||||
admin_email = System.fetch_env!("ADMIN_EMAIL")
|
||||
default_admin_password = System.fetch_env!("DEFAULT_ADMIN_PASSWORD")
|
||||
wireguard_private_key_path = System.fetch_env!("WIREGUARD_PRIVATE_KEY_PATH")
|
||||
@@ -59,6 +58,7 @@ if config_env() == :prod do
|
||||
guardian_secret_key = System.fetch_env!("GUARDIAN_SECRET_KEY")
|
||||
disable_vpn_on_oidc_error = FzString.to_boolean(System.fetch_env!("DISABLE_VPN_ON_OIDC_ERROR"))
|
||||
auto_create_oidc_users = FzString.to_boolean(System.fetch_env!("AUTO_CREATE_OIDC_USERS"))
|
||||
secure = FzString.to_boolean(System.get_env("SECURE_COOKIES", "true"))
|
||||
|
||||
allow_unprivileged_device_management =
|
||||
FzString.to_boolean(System.fetch_env!("ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT"))
|
||||
@@ -104,6 +104,7 @@ if config_env() == :prod do
|
||||
live_view_signing_salt = System.fetch_env!("LIVE_VIEW_SIGNING_SALT")
|
||||
cookie_signing_salt = System.fetch_env!("COOKIE_SIGNING_SALT")
|
||||
cookie_encryption_salt = System.fetch_env!("COOKIE_ENCRYPTION_SALT")
|
||||
cookie_secure = secure
|
||||
|
||||
# Password is not needed if using bundled PostgreSQL, so use nil if it's not set.
|
||||
database_password = System.get_env("DATABASE_PASSWORD")
|
||||
@@ -198,10 +199,13 @@ if config_env() == :prod do
|
||||
secret_key: guardian_secret_key
|
||||
|
||||
config :fz_http,
|
||||
external_trusted_proxies: external_trusted_proxies,
|
||||
private_clients: private_clients,
|
||||
disable_vpn_on_oidc_error: disable_vpn_on_oidc_error,
|
||||
auto_create_oidc_users: auto_create_oidc_users,
|
||||
cookie_signing_salt: cookie_signing_salt,
|
||||
cookie_encryption_salt: cookie_encryption_salt,
|
||||
cookie_secure: cookie_secure,
|
||||
allow_unprivileged_device_management: allow_unprivileged_device_management,
|
||||
max_devices_per_user: max_devices_per_user,
|
||||
local_auth_enabled: local_auth_enabled,
|
||||
|
||||
108
docs/docs/deploy/reverse-proxies/README.md
Normal file
108
docs/docs/deploy/reverse-proxies/README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: Custom Reverse Proxy
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
:::note
|
||||
This is an advanced configuration. The default bundled nginx proxy
|
||||
is suitable for the vast majority of use cases and is recommended for most
|
||||
users. There are important security risks if the Firezone reverse proxy is
|
||||
not set up correctly. Use only if you know what you are doing.
|
||||
:::
|
||||
|
||||
## Introduction
|
||||
|
||||
Firezone comes with a bundled [Nginx](https://www.nginx.com/) reverse-proxy,
|
||||
however, in some cases you might want to deploy your own server such as when
|
||||
using behind your own load-balancer.
|
||||
|
||||
## Requisites
|
||||
|
||||
Below you will find the requirements in order to setup firezone and the
|
||||
reverse-proxies.
|
||||
|
||||
### Firezone configuration requirements
|
||||
|
||||
* Disable the bundled Nginx by setting `default['firezone']['nginx']['enabled']`
|
||||
to `false` in the config file.
|
||||
* If you have any immediate proxies between your primary reverse proxy and the
|
||||
Firezone web app, add their IPs to
|
||||
`default['firezone']['phoenix']['external_trusted_proxies']`. Because of the
|
||||
way the [X-Forwarded-For header works](
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For),
|
||||
this is needed to parse the actual client's IP address to prevent
|
||||
spoofing.
|
||||
|
||||
:::note
|
||||
|
||||
The `external_trusted_proxies` list automatically implicitly includes the
|
||||
following private CIDR ranges, even if they're not specified in the
|
||||
configuration file:
|
||||
|
||||
* `127.0.0.0/8`
|
||||
* `10.0.0.0/8`
|
||||
* `172.16.0.0/12`
|
||||
* `1926.0.0/16`
|
||||
* `::1/128`
|
||||
* `fc00::/7`
|
||||
|
||||
This means any web requests originating from these IPs are automatically ignored
|
||||
from the `X-Forwarded-For` headers. If you're accessing Firezone from any IPs in
|
||||
this range (as seen by the Firezone web app), be sure to add them to the
|
||||
`default['firezone']['phoenix']['clients']` configuration option.
|
||||
|
||||
:::
|
||||
|
||||
Read more about the configuration options
|
||||
[here](../../../reference/configuration-file.md).
|
||||
|
||||
### Proxy requirements
|
||||
|
||||
* All your proxies need to configure the `X-Forwarded-For` header as explained
|
||||
[here](
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
|
||||
* Your proxy should also set the `X-Forwarded-Proto` to `https`.
|
||||
* Your proxy **must** terminate SSL since we enforce [secure cookies](
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies).
|
||||
* Firezone requires the use of WebSockets to establish realtime connections. We
|
||||
recommended following your proxy's specific documentation for supporting
|
||||
WebSockets as each proxy varies. In general, your proxy needs to be able to
|
||||
proxy HTTP 1.1 connections, and the Firezone web app expects the following
|
||||
headers to be set:
|
||||
* `Connection: upgrade`
|
||||
* `Upgrade: websocket`
|
||||
|
||||
## Security considerations
|
||||
|
||||
In addition to the headers above, we recommend adding the following headers for
|
||||
security purposes:
|
||||
|
||||
* `X-XSS-Protection: 1; mode=block`
|
||||
* `X-Content-Type-Options nosniff`
|
||||
* `Referrer-Policy no-referrer-when-downgrade`
|
||||
* `Content-Security-Policy: default-src 'self' ws: wss: http: https: data: blob:
|
||||
'unsafe-inline'; frame-ancestors 'self';`
|
||||
* `Permissions-Policy: interest-cohort=()`
|
||||
|
||||
Since the upstream Firezone web app expects plain HTTP traffic, any requests the
|
||||
proxy forwards is sent over HTTP and thus is **not encrypted**. In most cases,
|
||||
the reverse proxy is installed in a trusted network, and this is not an issue.
|
||||
But the connection between your trusted proxy and the Firezone web app spans
|
||||
an untrusted network (such as the Internet), you may want to leave the bundled
|
||||
`nginx` proxy enabled for SSL termination, and set up your custom
|
||||
reverse proxy to proxy to that instead.
|
||||
|
||||
## Example configurations
|
||||
|
||||
* [Apache](../reverse-proxies/apache.md)
|
||||
* [Traefik](../reverse-proxies/traefik.md)
|
||||
* [HAProxy](../reverse-proxies/haproxy.md)
|
||||
|
||||
These configurations are written to be as simple as possible. They're designed
|
||||
to function as a simple template which you can customize further to suit your
|
||||
needs.
|
||||
|
||||
If you have a working configuration for a different reverse-proxy or a different
|
||||
version of an existing one we appreciate any
|
||||
[contribution](https://github.com/firezone/firezone/) to expand the examples for
|
||||
the community.
|
||||
65
docs/docs/deploy/reverse-proxies/apache.md
Normal file
65
docs/docs/deploy/reverse-proxies/apache.md
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: Apache
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
The following are example [apache](https://httpd.apache.org/) configurations
|
||||
with and without SSL termination.
|
||||
|
||||
These expect the apache to be running on the same host as Firezone and
|
||||
`default['firezone']['phoenix']['port']` to be `13000`.
|
||||
|
||||
### Without SSL termination
|
||||
|
||||
Take into account that a previous proxy will need to terminate SSL connections.
|
||||
|
||||
`<server-name>` needs to be replaced with your domain name.
|
||||
|
||||
This configuration needs to be placed in
|
||||
`/etc/sites-available/<server-name>.conf`
|
||||
|
||||
and activated with `a2ensite <server-name>`
|
||||
|
||||
```conf
|
||||
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
|
||||
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
|
||||
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
|
||||
LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so
|
||||
<VirtualHost *:80>
|
||||
ServerName <server-name>
|
||||
ProxyPassReverse "/" "http://127.0.0.1:13000/"
|
||||
ProxyPass "/" "http://127.0.0.1:13000/"
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
||||
RewriteCond %{HTTP:Connection} upgrade [NC]
|
||||
RewriteRule ^/?(.*) "ws://127.0.0.1:13000/$1" [P,L]
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
### With SSL termination
|
||||
|
||||
This configuration should be used exactly like the previous and uses Firezone's
|
||||
generated self-signed certs to terminate SSL.
|
||||
|
||||
```conf
|
||||
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
|
||||
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
|
||||
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
|
||||
LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so
|
||||
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
|
||||
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
|
||||
Listen 443
|
||||
<VirtualHost *:443>
|
||||
ServerName <server-name>
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
ProxyPassReverse "/" "http://127.0.0.1:13000/"
|
||||
ProxyPass "/" "http://127.0.0.1:13000/"
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
||||
RewriteCond %{HTTP:Connection} upgrade [NC]
|
||||
RewriteRule ^/?(.*) "ws://127.0.0.1:13000/$1" [P,L]
|
||||
SSLEngine On
|
||||
SSLCertificateFile "/var/opt/firezone/ssl/ca/acme-test.firez.one.crt"
|
||||
SSLCertificateKeyFile "/var/opt/firezone/ssl/ca/acme-test.firez.one.key"
|
||||
</VirtualHost>
|
||||
```
|
||||
32
docs/docs/deploy/reverse-proxies/haproxy.md
Normal file
32
docs/docs/deploy/reverse-proxies/haproxy.md
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: HAProxy
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
The following is an example configuration for the
|
||||
[HAProxy](https://www.haproxy.org/) proxy. we assume
|
||||
`default['firezone']['phoenix']['port']` to be `13000` and the proxy running on
|
||||
the same host as the Firezone app.
|
||||
|
||||
There is not SSL termination in this configuration so a previous proxy will
|
||||
need to terminate the SSL connection.
|
||||
|
||||
You can also configure HAProxy to handle the SSL termination as explained
|
||||
[here](https://www.haproxy.com/blog/haproxy-ssl-termination/) but take into
|
||||
account that the `pem` file expected by `ssl crt` option needs to contain
|
||||
both the `crt` and `key` file.
|
||||
|
||||
`/etc/haproxy/haproxy.cfg`:
|
||||
|
||||
```conf
|
||||
defaults
|
||||
mode http
|
||||
|
||||
frontend app1
|
||||
bind *:80
|
||||
option forwardfor
|
||||
default_backend backend_app1
|
||||
|
||||
backend backend_app1
|
||||
server mybackendserver 127.0.0.1:13000
|
||||
```
|
||||
134
docs/docs/deploy/reverse-proxies/traefik.md
Normal file
134
docs/docs/deploy/reverse-proxies/traefik.md
Normal file
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: Traefik
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
The following are examples for configuring the [Traefik](https://traefik.io/)
|
||||
proxy.
|
||||
|
||||
As of right now Firezone can't be run as a container in production, although
|
||||
this is a [planned feature](https://github.com/firezone/firezone/issues/260).
|
||||
So, these example configurations expects Firezone to be deployed on the same
|
||||
host as the proxy.
|
||||
|
||||
In these configurations we assume `default['firezone']['phoenix']['port']` to be
|
||||
`13000`. Furthermore, for these configuration to work we need the Firezone app
|
||||
to listen in the Docker interface so you should set:
|
||||
|
||||
* `default['firezone']['phoenix']['listen_address'] = '172.17.0.1'`
|
||||
* `default['firezone']['external_trusted_proxies'] = ['172.18.0.2']`
|
||||
|
||||
In the [configuration file](../../reference/configuration-file.md).
|
||||
|
||||
## Without SSL termination
|
||||
|
||||
Take into account that a previous proxy will need to terminate SSL connections.
|
||||
|
||||
Set the following files
|
||||
|
||||
### `docker-compose.yml`
|
||||
|
||||
```conf
|
||||
ubuntu@ip-172-31-79-208:~/traefik$ cat docker-compose.yml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
reverse-proxy:
|
||||
#network_mode: "host"
|
||||
# The official v2 Traefik docker image
|
||||
image: traefik:v2.8
|
||||
# Enables the web UI and tells Traefik to listen to docker
|
||||
command:
|
||||
- "--providers.docker"
|
||||
- "--providers.file.filename=rules.yml"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.web.forwardedHeaders.insecure"
|
||||
- "--log.level=DEBUG"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
# The HTTP port
|
||||
- "80:80"
|
||||
volumes:
|
||||
# So that Traefik can listen to the Docker events
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- "./rules.yml:/rules.yml"
|
||||
```
|
||||
|
||||
### `rules.yml`
|
||||
|
||||
```conf
|
||||
ubuntu@ip-172-31-79-208:~/traefik$ cat rules.yml
|
||||
http:
|
||||
routers:
|
||||
test:
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: test
|
||||
rule: "Host(`44.200.42.78`)"
|
||||
services:
|
||||
test:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://host.docker.internal:13000"
|
||||
```
|
||||
|
||||
And then you can start the Traefik proxy with `docker compose up`
|
||||
|
||||
## With SSL termination
|
||||
|
||||
This configuration use the auto-generated Firezone self-signed certs as the
|
||||
default certificates for SSL.
|
||||
|
||||
### SSL `docker-compose.yml`
|
||||
|
||||
```conf
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
reverse-proxy:
|
||||
#network_mode: "host"
|
||||
# The official v2 Traefik docker image
|
||||
image: traefik:v2.8
|
||||
# Enables the web UI and tells Traefik to listen to docker
|
||||
command:
|
||||
- "--providers.docker"
|
||||
- "--providers.file.filename=rules.yml"
|
||||
- "--entrypoints.web.address=:443"
|
||||
- "--entrypoints.web.forwardedHeaders.insecure"
|
||||
- "--log.level=DEBUG"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
# The HTTP port
|
||||
- "443:443"
|
||||
volumes:
|
||||
# So that Traefik can listen to the Docker events
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- "./rules.yml:/rules.yml"
|
||||
- /var/opt/firezone/ssl/ca:/ssl:ro
|
||||
```
|
||||
|
||||
### SSL `rules.yml`
|
||||
|
||||
```conf
|
||||
http:
|
||||
routers:
|
||||
test:
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: test
|
||||
rule: "Host(`44.200.42.78`)"
|
||||
tls: {}
|
||||
services:
|
||||
test:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://host.docker.internal:13000"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: /ssl/ip-172-31-79-208.ec2.internal.crt
|
||||
keyFile: /ssl/ip-172-31-79-208.ec2.internal.key
|
||||
```
|
||||
@@ -120,6 +120,8 @@ Shown below is a complete listing of the configuration options available in
|
||||
| `default['firezone']['phoenix']['log_rotation']['file_maxbytes']` | Firezone web application log file size. | `104857600` |
|
||||
| `default['firezone']['phoenix']['log_rotation']['num_to_keep']` | Number of Firezone web application log files to keep. | `10` |
|
||||
| `default['firezone']['phoenix']['crash_detection']['enabled']` | Enable or disable bringing down the Firezone web application when a crash is detected. | `true` |
|
||||
| `default['firezone']['phoenix']['external_trusted_proxies']` | List of trusted reverse proxies formatted as an Array of IPs and/or CIDRs. | `[]` |
|
||||
| `default['firezone']['phoenix']['clients']` | List of private network HTTP clients, formatted an Array of IPs and/or CIDRs. | `[]` |
|
||||
| `default['firezone']['wireguard']['enabled']` | Enable or disable bundled WireGuard management. | `true` |
|
||||
| `default['firezone']['wireguard']['log_directory']` | Log directory for bundled WireGuard management. | `"#{node['firezone']['log_directory']}/wireguard"` |
|
||||
| `default['firezone']['wireguard']['log_rotation']['file_maxbytes']` | WireGuard log file max size. | `104857600` |
|
||||
@@ -141,7 +143,6 @@ Shown below is a complete listing of the configuration options available in
|
||||
| `default['firezone']['wireguard']['ipv6']['address']` | WireGuard interface IPv6 address. Must be within IPv6 address pool. | `'fd00::3:2:1'` |
|
||||
| `default['firezone']['runit']['svlogd_bin']` | Runit svlogd bin location. | `"#{node['firezone']['install_directory']}/embedded/bin/svlogd"` |
|
||||
| `default['firezone']['ssl']['directory']` | SSL directory for storing generated certs. | `'/var/opt/firezone/ssl'` |
|
||||
| `default['firezone']['ssl']['enabled']` | Enable or disable SSL for nginx. | `true` |
|
||||
| `default['firezone']['ssl']['email_address']` | Email address to use for self-signed certs and ACME protocol renewal notices. | `'you@example.com'` |
|
||||
| `default['firezone']['ssl']['acme']['enabled']` | Enable ACME for automatic SSL cert provisioning. See [here](https://docs.firezone.dev/docs/deploy/prerequisites/#create-an-ssl-certificate) for more instructions. | `false` |
|
||||
| `default['firezone']['ssl']['acme']['server']` | ACME server to use for certificate issuance/renewal. Can be any [valid acme.sh server](https://github.com/acmesh-official/acme.sh/wiki/Server) | `letsencrypt` |
|
||||
|
||||
2
mix.lock
2
mix.lock
@@ -6,6 +6,7 @@
|
||||
"cidr": {:git, "https://github.com/firezone/cidr-elixir.git", "9072aaab069bca38ef55fd901a37448861596532", []},
|
||||
"cloak": {:hex, :cloak, "1.1.2", "7e0006c2b0b98d976d4f559080fabefd81f0e0a50a3c4b621f85ceeb563e80bb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "940d5ac4fcd51b252930fd112e319ea5ae6ab540b722f3ca60a85666759b9585"},
|
||||
"cloak_ecto": {:hex, :cloak_ecto, "1.2.0", "e86a3df3bf0dc8980f70406bcb0af2858bac247d55494d40bc58a152590bd402", [:mix], [{:cloak, "~> 1.1.1", [hex: :cloak, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "8bcc677185c813fe64b786618bd6689b1707b35cd95acaae0834557b15a0c62f"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
|
||||
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
|
||||
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
|
||||
@@ -69,6 +70,7 @@
|
||||
"postgrex": {:hex, :postgrex, "0.16.3", "fac79a81a9a234b11c44235a4494d8565303fa4b9147acf57e48978a074971db", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "aeaae1d2d1322da4e5fe90d241b0a564ce03a3add09d7270fb85362166194590"},
|
||||
"posthog": {:hex, :posthog, "0.1.0", "0abe2af719c0c30fe6a24569a8947a19f0edfa63f6fed61685a219a8d5655786", [:mix], [{:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ee0426999bd35edf3dfa84141bbd3de17ae07e04d62d269fd5ee581925f1c222"},
|
||||
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
|
||||
"remote_ip": {:hex, :remote_ip, "1.0.0", "3d7fb45204a5704443f480cee9515e464997f52c35e0a60b6ece1f81484067ae", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9e9fcad4e50c43b5234bb6a9629ed6ab223f3ed07147bd35470e4ee5c8caf907"},
|
||||
"rustler_precompiled": {:hex, :rustler_precompiled, "0.5.1", "93df423bd7b14b67dcacf994443d132d300623f80756974cac4febeab40af74a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "3f8cbc8e92eef4e1a71bf441b568b868b16a3730f63f5b803c68073017e30b13"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||
"swoosh": {:hex, :swoosh, "1.7.3", "febb47c8c3ce76747eb9e3ea25ed694c815f72069127e3bb039b7724082ec670", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76abac313f95b6825baa8ceec269d597e8395950c928742fc6451d3456ca256d"},
|
||||
|
||||
@@ -135,6 +135,30 @@ default['firezone']['authentication']['oidc'] = {}
|
||||
# }
|
||||
# }
|
||||
|
||||
# ## Custom Reverse Proxy
|
||||
#
|
||||
# An array of IPs that Firezone will trust as reverse proxies.
|
||||
#
|
||||
# Read more here:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#selecting_an_ip_address
|
||||
#
|
||||
# By default the following IPs are included:
|
||||
# * IPv4: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
|
||||
# * IPv6: ::1/128, fc00::/7
|
||||
#
|
||||
# If any client requests will actually be coming from these private IPs, add them to
|
||||
# default['firezone']['phoenix']['private_clients'] below instead of here.
|
||||
#
|
||||
# If set to false Firezone will assume that it is not running behind a proxy
|
||||
default['firezone']['external_trusted_proxies'] = []
|
||||
|
||||
# An array of IPs that Firezone will assume are clients, and thus, not a trusted
|
||||
# proxy for the purpose of determining the client's IP. By default the bundled
|
||||
# See more here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#selecting_an_ip_address
|
||||
# This will supersede any proxy configured manually or by default by
|
||||
# default['firezone']['external_trusted_proxies']
|
||||
default['firezone']['phoenix']['private_clients'] = []
|
||||
|
||||
# ## Nginx
|
||||
|
||||
# These attributes control Firezone-specific portions of the Nginx
|
||||
@@ -386,9 +410,6 @@ default['firezone']['runit']['svlogd_bin'] = "#{node['firezone']['install_direct
|
||||
|
||||
default['firezone']['ssl']['directory'] = '/var/opt/firezone/ssl'
|
||||
|
||||
# Enable / disable SSL
|
||||
default['firezone']['ssl']['enabled'] = true
|
||||
|
||||
# Email to use for self signed certs and ACME cert issuance and renewal notices.
|
||||
# Defaults to default['firezone']['admin_email'] if nil.
|
||||
default['firezone']['ssl']['email_address'] = nil
|
||||
@@ -399,7 +420,6 @@ default['firezone']['ssl']['email_address'] = nil
|
||||
# 2. Port 80/tcp is accessible; this is used for domain validation.
|
||||
# 3. default['firezone']['ssl']['email_address'] is set properly. This will be used for renewal notices.
|
||||
# 4. default['firezone']['nginx']['non_ssl_port'] is set to 80
|
||||
# 5. default['firezone']['ssl']['enabled'] is set to true
|
||||
default['firezone']['ssl']['acme']['enabled'] = false
|
||||
|
||||
# Set the ACME server directory for ACME protocol SSL certificate issuance
|
||||
@@ -521,3 +541,9 @@ default['firezone']['connectivity_checks']['enabled'] = true
|
||||
# Amount of time to sleep between connectivity checks, in seconds.
|
||||
# Default: 3600 (1 hour). Minimum: 60 (1 minute). Maximum: 86400 (1 day).
|
||||
default['firezone']['connectivity_checks']['interval'] = 3_600
|
||||
|
||||
# ## Cookies settings
|
||||
|
||||
# Enable or disable the secure attributes for Firezone cookies. It's highly
|
||||
# recommended you leave this enabled unless you know what you're doing.
|
||||
default['firezone']['phoenix']['secure_cookies'] = true
|
||||
|
||||
@@ -225,6 +225,8 @@ class Firezone
|
||||
'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']),
|
||||
'EXTERNAL_URL' => attributes['external_url'] || fqdn_url,
|
||||
'ADMIN_EMAIL' => attributes['admin_email'],
|
||||
'WIREGUARD_INTERFACE_NAME' => attributes['wireguard']['interface_name'],
|
||||
@@ -244,6 +246,7 @@ class Firezone
|
||||
'WIREGUARD_IPV6_ADDRESS' => attributes['wireguard']['ipv6']['address'],
|
||||
'MAX_DEVICES_PER_USER' => attributes['max_devices_per_user'].to_s,
|
||||
'ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT' => attributes['allow_unprivileged_device_management'].to_s,
|
||||
|
||||
# Allow env var to override config
|
||||
'TELEMETRY_ENABLED' => ENV.fetch('TELEMETRY_ENABLED',
|
||||
attributes['telemetry']['enabled'] == false ? 'false' : 'true'),
|
||||
@@ -275,7 +278,10 @@ class Firezone
|
||||
'LIVE_VIEW_SIGNING_SALT' => attributes['live_view_signing_salt'],
|
||||
'COOKIE_SIGNING_SALT' => attributes['cookie_signing_salt'],
|
||||
'COOKIE_ENCRYPTION_SALT' => attributes['cookie_encryption_salt'],
|
||||
'DATABASE_ENCRYPTION_KEY' => attributes['database_encryption_key']
|
||||
'DATABASE_ENCRYPTION_KEY' => attributes['database_encryption_key'],
|
||||
|
||||
# cookies
|
||||
'SECURE_COOKIES' => attributes['phoenix']['secure_cookies'].to_s
|
||||
}
|
||||
|
||||
env.merge!('DATABASE_PASSWORD' => attributes['database']['password']) if attributes.dig('database', 'password')
|
||||
|
||||
@@ -25,8 +25,7 @@ end
|
||||
|
||||
# Enable ACME if set to enabled and user-specified certs are disabled, maintains
|
||||
# backwards compatibility during upgrades.
|
||||
if node['firezone']['ssl']['acme']['enabled'] && !node['firezone']['ssl']['certificate'] &&
|
||||
node['firezone']['ssl']['enabled']
|
||||
if node['firezone']['ssl']['acme']['enabled'] && !node['firezone']['ssl']['certificate']
|
||||
|
||||
keylength = node['firezone']['ssl']['acme']['keylength']
|
||||
server = node['firezone']['ssl']['acme']['server']
|
||||
|
||||
@@ -50,8 +50,7 @@ template 'nginx.conf' do
|
||||
mode '0600'
|
||||
variables(
|
||||
logging_enabled: node['firezone']['logging']['enabled'],
|
||||
nginx: node['firezone']['nginx'],
|
||||
ssl_enabled: node['firezone']['ssl']['enabled']
|
||||
nginx: node['firezone']['nginx']
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -30,61 +30,59 @@ include_recipe 'firezone::config'
|
||||
end
|
||||
end
|
||||
|
||||
# Unless SSL is disabled, sets up SSL certificates.
|
||||
# Sets up SSL certificates.
|
||||
# Creates a self-signed cert if none is provided.
|
||||
if node['firezone']['ssl']['enabled']
|
||||
firezone_ca_dir = File.join(node['firezone']['ssl']['directory'], 'ca')
|
||||
ssl_dhparam = File.join(firezone_ca_dir, 'dhparams.pem')
|
||||
firezone_ca_dir = File.join(node['firezone']['ssl']['directory'], 'ca')
|
||||
ssl_dhparam = File.join(firezone_ca_dir, 'dhparams.pem')
|
||||
|
||||
# Generate dhparams.pem for perfect forward secrecy
|
||||
openssl_dhparam ssl_dhparam do
|
||||
# Generate dhparams.pem for perfect forward secrecy
|
||||
openssl_dhparam ssl_dhparam do
|
||||
key_length 2048
|
||||
generator 2
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0644'
|
||||
end
|
||||
|
||||
node.default['firezone']['ssl']['ssl_dhparam'] ||= ssl_dhparam
|
||||
|
||||
if node['firezone']['ssl']['certificate']
|
||||
# A certificate has been supplied
|
||||
# Link the standard CA cert into our certs directory
|
||||
link "#{node['firezone']['ssl']['directory']}/cacert.pem" do
|
||||
to "#{node['firezone']['install_directory']}/embedded/ssl/certs/cacert.pem"
|
||||
end
|
||||
elsif node['firezone']['ssl']['acme']['enabled']
|
||||
# No certificate provided but acme enabled don't
|
||||
# auto-generate and ensure acme directory is setup
|
||||
directory "#{node['firezone']['var_directory']}/ssl/acme" do
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0600'
|
||||
end
|
||||
|
||||
# No certificate has been supplied; generate one
|
||||
else
|
||||
host = URI.parse(node['firezone']['external_url']).host
|
||||
ssl_keyfile = File.join(firezone_ca_dir, "#{host}.key")
|
||||
ssl_crtfile = File.join(firezone_ca_dir, "#{host}.crt")
|
||||
|
||||
openssl_x509_certificate ssl_crtfile do
|
||||
common_name host
|
||||
org node['firezone']['ssl']['company_name']
|
||||
org_unit node['firezone']['ssl']['organizational_unit_name']
|
||||
country node['firezone']['ssl']['country_name']
|
||||
key_length 2048
|
||||
generator 2
|
||||
expire 3650
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0644'
|
||||
end
|
||||
|
||||
node.default['firezone']['ssl']['ssl_dhparam'] ||= ssl_dhparam
|
||||
node.default['firezone']['ssl']['certificate'] ||= ssl_crtfile
|
||||
node.default['firezone']['ssl']['certificate_key'] ||= ssl_keyfile
|
||||
|
||||
if node['firezone']['ssl']['certificate']
|
||||
# A certificate has been supplied
|
||||
# Link the standard CA cert into our certs directory
|
||||
link "#{node['firezone']['ssl']['directory']}/cacert.pem" do
|
||||
to "#{node['firezone']['install_directory']}/embedded/ssl/certs/cacert.pem"
|
||||
end
|
||||
elsif node['firezone']['ssl']['acme']['enabled']
|
||||
# No certificate provided but acme enabled don't
|
||||
# auto-generate and ensure acme directory is setup
|
||||
directory "#{node['firezone']['var_directory']}/ssl/acme" do
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0600'
|
||||
end
|
||||
|
||||
# No certificate has been supplied; generate one
|
||||
else
|
||||
host = URI.parse(node['firezone']['external_url']).host
|
||||
ssl_keyfile = File.join(firezone_ca_dir, "#{host}.key")
|
||||
ssl_crtfile = File.join(firezone_ca_dir, "#{host}.crt")
|
||||
|
||||
openssl_x509_certificate ssl_crtfile do
|
||||
common_name host
|
||||
org node['firezone']['ssl']['company_name']
|
||||
org_unit node['firezone']['ssl']['organizational_unit_name']
|
||||
country node['firezone']['ssl']['country_name']
|
||||
key_length 2048
|
||||
expire 3650
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0644'
|
||||
end
|
||||
|
||||
node.default['firezone']['ssl']['certificate'] ||= ssl_crtfile
|
||||
node.default['firezone']['ssl']['certificate_key'] ||= ssl_keyfile
|
||||
|
||||
link "#{node['firezone']['ssl']['directory']}/cacert.pem" do
|
||||
to ssl_crtfile
|
||||
end
|
||||
link "#{node['firezone']['ssl']['directory']}/cacert.pem" do
|
||||
to ssl_crtfile
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,7 +94,5 @@ http {
|
||||
|
||||
include <%= @nginx['dir'] %>/conf.d/*.conf;
|
||||
include <%= @nginx['dir'] %>/sites-enabled/*;
|
||||
<% if @ssl_enabled -%>
|
||||
include <%= @nginx['dir'] %>/redirect.conf;
|
||||
<% end -%>
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ log_format cache '$remote_addr - [$time_local] "$request" $upstream_cache_status
|
||||
<% end %>
|
||||
|
||||
server {
|
||||
<% if @ssl['enabled'] -%>
|
||||
listen <%= @nginx['ssl_port'] %> default_server ssl;
|
||||
<% if @nginx['ipv6'] -%>
|
||||
listen [::]:<%= @nginx['ssl_port'] %> default_server ssl;
|
||||
@@ -35,12 +34,6 @@ server {
|
||||
ssl_protocols <%= @ssl['protocols'] %>;
|
||||
ssl_session_cache <%= @ssl['session_cache'] %>;
|
||||
ssl_session_timeout <%= @ssl['session_timeout'] %>;
|
||||
<% else -%>
|
||||
listen <%= @nginx['non_ssl_port'] %> default_server;
|
||||
<% if @nginx['ipv6'] -%>
|
||||
listen [::]:<%= @nginx['non_ssl_port'] %> default_server;
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
<% if @nginx['redirect_to_canonical'] -%>
|
||||
set $redirect_to_canonical 0;
|
||||
|
||||
Reference in New Issue
Block a user