mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
Terraform improvements for production (#2873)
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# These are used for the dev environment.
|
||||
# This should match the versions used in the built product.
|
||||
nodejs 18.16.0
|
||||
elixir 1.15.6-otp-26
|
||||
erlang 26.1.1
|
||||
terraform 1.6.2
|
||||
elixir 1.15.7-otp-26
|
||||
erlang 26.1.2
|
||||
terraform 1.6.5
|
||||
|
||||
# Used for static analysis
|
||||
python 3.9.13
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
ARG ALPINE_VERSION="3.18.4"
|
||||
ARG ERLANG_VERSION="26.1.1"
|
||||
ARG ERLANG_DOWNLOAD_SHA256="30de56e687cef15c73ef2e2e5bc8a94d28f959656e716e0a65092af7d360af57"
|
||||
ARG ELIXIR_VERSION="1.15.6"
|
||||
ARG ELIXIR_DOWNLOAD_SHA256="385fc1958bcf9023a748acf8c42179a0c6123c89744396840bdcd661ee130177"
|
||||
ARG ALPINE_VERSION="3.19.0"
|
||||
ARG ERLANG_VERSION="26.1.2"
|
||||
ARG ERLANG_DOWNLOAD_SHA256="f1074cf3a54f1f87e66027d5abebab2fa76a0243453fa58bc5f30d0ce0313921"
|
||||
ARG ELIXIR_VERSION="1.15.7"
|
||||
ARG ELIXIR_DOWNLOAD_SHA256="78bde2786b395515ae1eaa7d26faa7edfdd6632bfcfcd75bccb6341a18e8798f"
|
||||
|
||||
FROM alpine:${ALPINE_VERSION} as base
|
||||
|
||||
|
||||
@@ -356,6 +356,31 @@ iex(web@web-xxxx.us-east1-d.c.firezone-staging.internal)3> Domain.Relays.encode_
|
||||
...
|
||||
```
|
||||
|
||||
## Connection to production Cloud SQL instance
|
||||
|
||||
Install
|
||||
[`cloud-sql-proxy`](https://cloud.google.com/sql/docs/postgres/connect-instance-auth-proxy)
|
||||
(eg. `brew install cloud-sql-proxy`) and run:
|
||||
|
||||
```bash
|
||||
cloud-sql-proxy --auto-iam-authn "firezone-prod:us-east1:firezone-prod?address=0.0.0.0&port=9000"
|
||||
```
|
||||
|
||||
Then you can connect to the PostgreSQL using `psql`:
|
||||
|
||||
```bash
|
||||
# Use your work email as username to connect
|
||||
PG_USER=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" | head -n 1)
|
||||
psql "host=localhost port=9000 sslmode=disable dbname=firezone user=${PG_USER}"
|
||||
```
|
||||
|
||||
If you have issues with credentials try refreshing the application default
|
||||
token:
|
||||
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
|
||||
## Viewing logs
|
||||
|
||||
Logs can be viewed via th [Logs Explorer](https://console.cloud.google.com/logs)
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule Domain.Auth do
|
||||
alias Domain.Auth.{Adapters, Provider}
|
||||
|
||||
@default_session_duration_hours %{
|
||||
account_admin_user: 3,
|
||||
account_admin_user: 24 * 7 - 1,
|
||||
account_user: 24 * 7
|
||||
}
|
||||
|
||||
|
||||
@@ -59,18 +59,23 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do
|
||||
{:ok, provider}
|
||||
end
|
||||
|
||||
def authorization_uri(%Provider{} = provider, redirect_uri) when is_binary(redirect_uri) do
|
||||
def authorization_uri(%Provider{} = provider, redirect_uri, params \\ %{})
|
||||
when is_binary(redirect_uri) do
|
||||
config = config_for_provider(provider)
|
||||
|
||||
verifier = PKCE.code_verifier()
|
||||
state = State.new()
|
||||
|
||||
params = %{
|
||||
access_type: :offline,
|
||||
state: state,
|
||||
code_challenge_method: PKCE.code_challenge_method(),
|
||||
code_challenge: PKCE.code_challenge(verifier)
|
||||
}
|
||||
params =
|
||||
Map.merge(
|
||||
%{
|
||||
access_type: :offline,
|
||||
state: state,
|
||||
code_challenge_method: PKCE.code_challenge_method(),
|
||||
code_challenge: PKCE.code_challenge(verifier)
|
||||
},
|
||||
params
|
||||
)
|
||||
|
||||
with {:ok, uri} <- OpenIDConnect.authorization_uri(config, redirect_uri, params) do
|
||||
{:ok, uri, {state, verifier}}
|
||||
|
||||
@@ -469,14 +469,12 @@ defmodule Domain.Gateways do
|
||||
end
|
||||
|
||||
def connect_gateway(%Gateway{} = gateway) do
|
||||
{:ok, _} =
|
||||
Presence.track(self(), "gateways:#{gateway.account_id}", gateway.id, %{
|
||||
online_at: System.system_time(:second)
|
||||
})
|
||||
meta = %{online_at: System.system_time(:second)}
|
||||
|
||||
{:ok, _} = Presence.track(self(), "gateway_groups:#{gateway.group_id}", gateway.id, %{})
|
||||
|
||||
:ok
|
||||
with {:ok, _} <- Presence.track(self(), "gateways:#{gateway.account_id}", gateway.id, meta) do
|
||||
{:ok, _} = Presence.track(self(), "gateway_groups:#{gateway.group_id}", gateway.id, %{})
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def subscribe_for_gateways_presence_in_account(%Accounts.Account{} = account) do
|
||||
|
||||
@@ -277,7 +277,13 @@ defmodule Domain.Relays do
|
||||
|> filter.()
|
||||
|> Repo.all()
|
||||
|> Enum.map(fn relay ->
|
||||
%{metas: [%{secret: stamp_secret}]} = Map.get(connected_relays, relay.id)
|
||||
%{metas: metas} = Map.get(connected_relays, relay.id)
|
||||
|
||||
%{secret: stamp_secret} =
|
||||
metas
|
||||
|> Enum.sort_by(& &1.online_at, :desc)
|
||||
|> List.first()
|
||||
|
||||
%{relay | stamp_secret: stamp_secret}
|
||||
end)
|
||||
|
||||
@@ -381,15 +387,15 @@ defmodule Domain.Relays do
|
||||
""
|
||||
end
|
||||
|
||||
{:ok, _} =
|
||||
Presence.track(self(), "relays#{scope}", relay.id, %{
|
||||
online_at: System.system_time(:second),
|
||||
secret: secret
|
||||
})
|
||||
meta = %{
|
||||
online_at: System.system_time(:second),
|
||||
secret: secret
|
||||
}
|
||||
|
||||
{:ok, _} = Presence.track(self(), "relay_groups:#{relay.group_id}", relay.id, %{})
|
||||
|
||||
:ok
|
||||
with {:ok, _} <- Presence.track(self(), "relays#{scope}", relay.id, meta) do
|
||||
{:ok, _} = Presence.track(self(), "relay_groups:#{relay.group_id}", relay.id, %{})
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def subscribe_for_relays_presence_in_account(%Accounts.Account{} = account) do
|
||||
|
||||
@@ -1950,8 +1950,8 @@ defmodule Domain.AuthTest do
|
||||
assert {:ok, %Auth.Subject{} = subject} =
|
||||
sign_in(provider, identity.provider_identifier, secret, user_agent, remote_ip)
|
||||
|
||||
three_hours = 3 * 60 * 60
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), three_hours)
|
||||
one_week = 7 * 24 * 60 * 60
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), one_week - 60 * 60)
|
||||
|
||||
actor = Fixtures.Actors.create_actor(type: :account_user, account: account)
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
@@ -1960,7 +1960,6 @@ defmodule Domain.AuthTest do
|
||||
assert {:ok, %Auth.Subject{} = subject} =
|
||||
sign_in(provider, identity.provider_identifier, secret, user_agent, remote_ip)
|
||||
|
||||
one_week = 7 * 24 * 60 * 60
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), one_week)
|
||||
end
|
||||
|
||||
@@ -2191,7 +2190,7 @@ defmodule Domain.AuthTest do
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), one_week)
|
||||
end
|
||||
|
||||
test "returned expiration duration is capped at 3 hours for account admin users", %{
|
||||
test "returned expiration duration is capped at 1 week for account admin users", %{
|
||||
bypass: bypass,
|
||||
account: account,
|
||||
provider: provider,
|
||||
@@ -2217,8 +2216,8 @@ defmodule Domain.AuthTest do
|
||||
|
||||
assert {:ok, %Auth.Subject{} = subject} = sign_in(provider, payload, user_agent, remote_ip)
|
||||
|
||||
three_hours = 3 * 60 * 60
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), three_hours)
|
||||
one_week = 7 * 24 * 60 * 60
|
||||
assert_datetime_diff(subject.expires_at, DateTime.utc_now(), one_week - 60 * 60)
|
||||
end
|
||||
|
||||
test "returns error when provider is disabled", %{
|
||||
|
||||
@@ -1060,4 +1060,13 @@ defmodule Domain.GatewaysTest do
|
||||
assert {:managed, :turn} == relay_strategy([managed_group])
|
||||
end
|
||||
end
|
||||
|
||||
describe "connect_gateway/2" do
|
||||
test "does not allow duplicate presence", %{account: account} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
|
||||
assert connect_gateway(gateway) == :ok
|
||||
assert {:error, {:already_tracked, _pid, _topic, _key}} = connect_gateway(gateway)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -521,15 +521,17 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "returns list of connected account relays", %{account: account} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
relay1 = Fixtures.Relays.create_relay(account: account)
|
||||
relay2 = Fixtures.Relays.create_relay(account: account)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
assert connect_relay(relay, stamp_secret) == :ok
|
||||
assert connect_relay(relay1, stamp_secret) == :ok
|
||||
assert connect_relay(relay2, stamp_secret) == :ok
|
||||
|
||||
assert {:ok, [connected_relay]} = list_connected_relays_for_resource(resource, :self_hosted)
|
||||
assert {:ok, connected_relays} = list_connected_relays_for_resource(resource, :self_hosted)
|
||||
|
||||
assert connected_relay.id == relay.id
|
||||
assert connected_relay.stamp_secret == stamp_secret
|
||||
assert Enum.all?(connected_relays, &(&1.stamp_secret == stamp_secret))
|
||||
assert Enum.sort(Enum.map(connected_relays, & &1.id)) == Enum.sort([relay1.id, relay2.id])
|
||||
end
|
||||
|
||||
test "returns list of connected global relays", %{account: account} do
|
||||
@@ -961,4 +963,14 @@ defmodule Domain.RelaysTest do
|
||||
assert authorize_relay(Ecto.UUID.generate()) == {:error, :invalid_token}
|
||||
end
|
||||
end
|
||||
|
||||
describe "connect_relay/2" do
|
||||
test "does not allow duplicate presence", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
assert connect_relay(relay, stamp_secret) == :ok
|
||||
assert {:error, {:already_tracked, _pid, _topic, _key}} = connect_relay(relay, stamp_secret)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -205,9 +205,14 @@ defmodule Web.AuthController do
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_to_idp(%Plug.Conn{} = conn, redirect_url, %Domain.Auth.Provider{} = provider) do
|
||||
def redirect_to_idp(
|
||||
%Plug.Conn{} = conn,
|
||||
redirect_url,
|
||||
%Domain.Auth.Provider{} = provider,
|
||||
params \\ %{}
|
||||
) do
|
||||
{:ok, authorization_url, {state, code_verifier}} =
|
||||
OpenIDConnect.authorization_uri(provider, redirect_url)
|
||||
OpenIDConnect.authorization_uri(provider, redirect_url, params)
|
||||
|
||||
key = state_cookie_key(provider.id)
|
||||
value = :erlang.term_to_binary({state, code_verifier})
|
||||
|
||||
@@ -15,7 +15,7 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Connect do
|
||||
~p"/#{provider.account_id}/settings/identity_providers/google_workspace/#{provider}/handle_callback"
|
||||
)
|
||||
|
||||
Web.AuthController.redirect_to_idp(conn, redirect_url, provider)
|
||||
Web.AuthController.redirect_to_idp(conn, redirect_url, provider, %{prompt: "consent"})
|
||||
else
|
||||
{:error, :not_found} ->
|
||||
conn
|
||||
|
||||
@@ -94,7 +94,8 @@ defmodule Web.Live.Settings.IdentityProviders.GoogleWorkspace.Connect do
|
||||
"https://www.googleapis.com/auth/admin.directory.orgunit.readonly " <>
|
||||
"https://www.googleapis.com/auth/admin.directory.group.readonly " <>
|
||||
"https://www.googleapis.com/auth/admin.directory.user.readonly",
|
||||
"state" => state
|
||||
"state" => state,
|
||||
"prompt" => "consent"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,57 @@
|
||||
# Global args to use in build commands
|
||||
ARG ALPINE_VERSION="3.18"
|
||||
ARG ALPINE_VERSION="3.19"
|
||||
ARG CARGO_CHEF_VERSION="0.1.62"
|
||||
ARG RUSTUP_VERSION="1.26.0"
|
||||
ARG RUSTUP_x86_DOWNLOAD_SHA256="7aa9e2a380a9958fc1fc426a3323209b2c86181c6816640979580f62ff7d48d4"
|
||||
ARG RUSTUP_aarch64_DOWNLOAD_SHA256="b1962dfc18e1fd47d01341e6897cace67cddfabf547ef394e8883939bd6e002e"
|
||||
ARG RUST_VERSION="1.74.1"
|
||||
|
||||
FROM alpine:${ALPINE_VERSION} as rust
|
||||
|
||||
# Important! Update this no-op ENV variable when this Dockerfile
|
||||
# is updated with the current date. It will force refresh of all
|
||||
# of the base images and things like `apk add` won't be using
|
||||
# old cached versions when the Dockerfile is built.
|
||||
ENV REFRESHED_AT=2023-12-11 \
|
||||
LANG=C.UTF-8 \
|
||||
TERM=xterm
|
||||
|
||||
RUN set -xe \
|
||||
# Upgrade Alpine and base packages
|
||||
&& apk --no-cache --update-cache --available upgrade \
|
||||
# Install required deps
|
||||
&& apk add --no-cache --update-cache \
|
||||
ca-certificates \
|
||||
gcc
|
||||
|
||||
ENV RUSTUP_HOME=/usr/local/rustup \
|
||||
CARGO_HOME=/usr/local/cargo \
|
||||
PATH=/usr/local/cargo/bin:$PATH
|
||||
|
||||
ARG RUSTUP_VERSION
|
||||
ARG RUSTUP_x86_DOWNLOAD_SHA256
|
||||
ARG RUSTUP_aarch64_DOWNLOAD_SHA256
|
||||
ARG RUST_VERSION
|
||||
RUN set -eux; \
|
||||
apkArch="$(apk --print-arch)"; \
|
||||
case "$apkArch" in \
|
||||
x86_64) rustArch='x86_64-unknown-linux-musl'; rustupSha256=${RUSTUP_x86_DOWNLOAD_SHA256} ;; \
|
||||
aarch64) rustArch='aarch64-unknown-linux-musl'; rustupSha256=${RUSTUP_aarch64_DOWNLOAD_SHA256} ;; \
|
||||
*) echo >&2 "unsupported architecture: $apkArch"; exit 1 ;; \
|
||||
esac; \
|
||||
url="https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${rustArch}/rustup-init"; \
|
||||
wget "$url"; \
|
||||
echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
|
||||
chmod +x rustup-init; \
|
||||
./rustup-init -y --no-modify-path --profile minimal --default-toolchain ${RUST_VERSION} --default-host ${rustArch}; \
|
||||
rm rustup-init; \
|
||||
chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
|
||||
rustup --version; \
|
||||
cargo --version; \
|
||||
rustc --version;
|
||||
|
||||
# This image is used to prepare Cargo Chef which is used to cache dependencies
|
||||
FROM rust:1-alpine${ALPINE_VERSION} as chef
|
||||
FROM rust as chef
|
||||
|
||||
ARG CARGO_CHEF_VERSION
|
||||
RUN set -xe \
|
||||
|
||||
101
terraform/environments/production/.terraform.lock.hcl
generated
101
terraform/environments/production/.terraform.lock.hcl
generated
@@ -1,43 +1,65 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/cyrilgdn/postgresql" {
|
||||
version = "1.21.1-beta.1"
|
||||
constraints = "1.21.1-beta.1"
|
||||
hashes = [
|
||||
"h1:fOpIaAmm9W7Ku58FQBaxQsqV1bdeIisWsbSD+RnVEFs=",
|
||||
"zh:03619b7c00b869567fe0a8cd391c0137ca4f7b6ef0173035e625d610e9a5233a",
|
||||
"zh:1a1d1aec60a58052f9292cfe6e1b780c327d70a95d7e35f80eadea1e0c19820f",
|
||||
"zh:1d559c12f6f7965fcb0e246ed2b211b0f21a6635755c6545bd3692fdb356c1e3",
|
||||
"zh:26730d86fcf64395d31bf8f3f30cd49260df947f94deaed46cbe866f9ae2b859",
|
||||
"zh:26b3ffd5a02cdd68340fe9296bf5e79b78bd0e5a4729ab9136b384476dfb31b7",
|
||||
"zh:2c57d364b3302c7e9e7bc10b0768212ff238cb8b136ba0fe47a421b0b645de8c",
|
||||
"zh:653674a2807f3b0818743ea9ac1ef885c47a7971c8025db66a410da1fc13cf5e",
|
||||
"zh:696c9f6452e182932f5de1665a91ef7dcfa60c62d5b38641088c7aaad661bf1b",
|
||||
"zh:69a284e91441785da80c7a421e0d92c34f83954ca47e793cfa9c875fd6e4d1dc",
|
||||
"zh:c5a08bfb638ed660995abc4a82f3eeaa17587c5aecb4bd5073366359494d660f",
|
||||
"zh:c6e630b1f9025bd9b9001ef88b89e530fe644dfde8ab5a572a4e9fce98384fd1",
|
||||
"zh:c7df7ce987ce7e405999cbbac2a08c1a8d08cf076c9c1a0081d533e47665dfa2",
|
||||
"zh:c9b46c3f065c923a6ea82e1b692de8541eb13f508d440222696125b2be64ad9a",
|
||||
"zh:ee7c7e74882158662733a097d100cd232c82a72fcf38d4d5c8e391389c3d0dfe",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google" {
|
||||
version = "5.2.0"
|
||||
version = "5.9.0"
|
||||
constraints = "~> 5.2"
|
||||
hashes = [
|
||||
"h1:psy0RRnGgKCsDKjdXCxQMKt4A1BlcbspWLB5UZK3A5U=",
|
||||
"zh:1d4c5b154d4764a0e3e8893193dc71ba5a4cdb2d9d9dd20f69312cc75399b038",
|
||||
"zh:26c5c6ad5edc27c643f43d950ffe982267b732723a09fef74c672ede7a7459f7",
|
||||
"zh:2b48824692ecc7fe8ae3366010a7cf8b441aa2ecb4b6e9777638952844eff19e",
|
||||
"zh:2f77cbb0528e58228117c7976e8864e7604614123c8b33d7329ffb0d084505b9",
|
||||
"zh:408e6a680c4b7235dc677b8ba6ccbda0bf07ffcbd3d13767474eea2c5177488f",
|
||||
"zh:68c2e914cf71ff490b4dbc6487900c35f702285cb0047614eccafb6ff057b748",
|
||||
"zh:849052c81c2ea4c703b22af9ae524d3f45e42c7e9a3553c1ff7a95f49fde6886",
|
||||
"zh:8f764a4ddcd5eea9f81cc72bb2fd29e2549a91b66faf8df8583c584298a26a86",
|
||||
"zh:dddc597b4af5e2dc772ec4291e39daffb4dc46f2cccde1d3a6d2cbe8d291743d",
|
||||
"zh:de9752d744bd91fd35e589fea0d8a72f983fe6fc872cfd19841758dcb8629a3b",
|
||||
"zh:ec40d112e5022e2ba408bdfab1fd2d4f30c0183db02a771fdf26cd3a8c7e9949",
|
||||
"h1:jG9wcaMKIuI8JSf8T+SjAcw5vhEpW/fnFfPjSXMbuEY=",
|
||||
"zh:19c618c257b2d9e30a0978b1282b1e418748323ae74d9c1ad63a858cb159cd86",
|
||||
"zh:2c1f18b6714062fe8eab633918b41c622423693f2a4fd747dc516f3578b8e738",
|
||||
"zh:440b31f85e2d823919639c4d248a058cd90020724a2fa543546e36611ca18df4",
|
||||
"zh:453edfad0fbd30e6d694f1b38cc9d5f0b8ec356bbce3f2919f1c4622518c46ca",
|
||||
"zh:47965b68bf9afd2f6a7412792083911d22b6a1a17f0052c9a8329b5ade47bbe9",
|
||||
"zh:5621990ad07b8cd9af6862f7a66b593b19bbdf20986d7c8cfd8948302810de51",
|
||||
"zh:74e2380a9acceb552d067697c38b4679e950fc2ba4bf47025d8917910b08df3d",
|
||||
"zh:a588be4fa16331c406a15e784d419a04e995741ed09eb2e14ec58b53f3ecd8cc",
|
||||
"zh:a60af7611f69b76ff727ee569b1ebefee82a5e5e1f1809d2df04286ee2c0aa4e",
|
||||
"zh:c15d781c9a198d343201eb1a4bc17c616ca8cb38bb33739c3e138db06022a171",
|
||||
"zh:d5c15eeb3be0e01b17ed67ab9b52137480139816edd7e90e93643be57564d2d0",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google-beta" {
|
||||
version = "5.7.0"
|
||||
version = "5.9.0"
|
||||
constraints = "~> 5.2"
|
||||
hashes = [
|
||||
"h1:Rvo7YTb0Uu3oN+2FG0NZ1hBAg1Ra8630U6vkK8OQ2IA=",
|
||||
"zh:1720258635c34406db44e3d08df9cc02e6897f804d6d558e1c73772324df7b30",
|
||||
"zh:1a385e9b3d7cda4d76b242f78086f33600c566386fde97d625f3bd39e1dcb1ff",
|
||||
"zh:26e01a0059c3d9954d0af22ccc05bb21a5b8af7f91a790311cf8ba13e10a5646",
|
||||
"zh:2acdab4240714cc31407324773280eeeb8ec9ab420404a3f3b8c0f25d73a5e00",
|
||||
"zh:4836143995c83c925b040c8bc7d3958fa6743c2179a098e783bf919e17db16ab",
|
||||
"zh:4ca384ea0153ba101af3ca97276f59e76586f935c99b444bd360a4009756af2d",
|
||||
"zh:54cc3398e8c336bd3f836954f87d3a7ae8fc4bced070baac66a244af656163d4",
|
||||
"zh:a3e5d9eacc27047ea0c3c00753da3966516dfc982dee180a3a5f4a405689447e",
|
||||
"zh:cc2052e93d0b52151a2374aa49e56de823ff11dce0570fa7c4bbbcf89467670f",
|
||||
"zh:d8dc64ade395715dbb41753bda72b1bce6348cd2011f95b1cea1b2c675770c58",
|
||||
"zh:da1fe36816881dac4acd7ab37291365c4b92584b8689c7c745c7a5b6800049c0",
|
||||
"h1:/bizlmcNQaK/mYn8+WFayo2ZUVeKkWov2QXwfNGrofY=",
|
||||
"zh:2fcb82487f8c5335646375bd98a44f22df5b01a3290317e138f638cc156da8a8",
|
||||
"zh:452959d6aa53837b613dfa8d9e9f301cc7dba6c0176e03ac0d50408f1b1c6eb5",
|
||||
"zh:49d1f65ba5a8fa5462a95c238aec17b8638b09bee28bb848b9f38d2911f7e8b7",
|
||||
"zh:528821fcbf788721f71f1e78e38b24cf47da1785521637d211f95d01f53519d2",
|
||||
"zh:54f9d5e2df07a463f23d40d04014eedad49b274280d220a81dc8f0bde5591226",
|
||||
"zh:5767e527b13f66a7098fc3059786ade0eaa39fb6d6d3199a4976ccf2b3cdf280",
|
||||
"zh:582d800aa8c5ff345ce9b5494f83d5d5684d553f5b317daf8e832aa30e708e47",
|
||||
"zh:723ef344fb8e60244a18b9a0d3a38941f89b568aa09d2c5d7f5fb2693982da61",
|
||||
"zh:b1ad47427a67f8c8a14868cd474ac8973a068b72dee4d1b828749017dc241212",
|
||||
"zh:c5b980159090c9d8b5e664c79e324c60bc4c1a5f3cfa904999f027949869eef3",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
"zh:ff5fea7d6c6b259938d1d2f008fd4d31242513e2ef592a68b0b6de7eab494a10",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -62,21 +84,22 @@ provider "registry.terraform.io/hashicorp/null" {
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.5.1"
|
||||
version = "3.6.0"
|
||||
constraints = "~> 3.5"
|
||||
hashes = [
|
||||
"h1:IL9mSatmwov+e0+++YX2V6uel+dV6bn+fC/cnGDK3Ck=",
|
||||
"zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
|
||||
"zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
|
||||
"zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
|
||||
"zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
|
||||
"zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
|
||||
"h1:I8MBeauYA8J8yheLJ8oSMWqB0kovn16dF/wKZ1QTdkk=",
|
||||
"zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d",
|
||||
"zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211",
|
||||
"zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829",
|
||||
"zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d",
|
||||
"zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
|
||||
"zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
|
||||
"zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
|
||||
"zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
|
||||
"zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
|
||||
"zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
|
||||
"zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17",
|
||||
"zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21",
|
||||
"zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839",
|
||||
"zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0",
|
||||
"zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c",
|
||||
"zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ resource "random_password" "metabase_db_password" {
|
||||
min_special = 1
|
||||
}
|
||||
|
||||
# This user can also be used to connect to the Firezone database,
|
||||
# but following SQL should be run manually using the Cloud SQL Proxy:
|
||||
#
|
||||
# GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase;
|
||||
# GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO metabase;
|
||||
#
|
||||
resource "google_sql_user" "metabase" {
|
||||
project = module.google-cloud-project.project.project_id
|
||||
|
||||
@@ -36,6 +30,34 @@ resource "google_sql_database" "metabase" {
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_select_on_all_tables_schema_to_metabase" {
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["SELECT"]
|
||||
objects = [] # ALL
|
||||
object_type = "table"
|
||||
schema = "public"
|
||||
role = google_sql_user.metabase.name
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.metabase
|
||||
]
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_execute_on_all_functions_schema_to_metabase" {
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["EXECUTE"]
|
||||
objects = [] # ALL
|
||||
object_type = "function"
|
||||
schema = "public"
|
||||
role = google_sql_user.metabase.name
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.metabase
|
||||
]
|
||||
}
|
||||
|
||||
module "metabase" {
|
||||
source = "../../modules/metabase-app"
|
||||
project_id = module.google-cloud-project.project.project_id
|
||||
|
||||
@@ -43,6 +43,45 @@ module "google-cloud-project" {
|
||||
billing_account_id = "01DFC9-3D6951-579BE1"
|
||||
}
|
||||
|
||||
# Enable audit logs for the production project
|
||||
resource "google_project_iam_audit_config" "audit" {
|
||||
project = module.google-cloud-project.project.project_id
|
||||
|
||||
service = "allServices"
|
||||
|
||||
audit_log_config {
|
||||
log_type = "ADMIN_READ"
|
||||
}
|
||||
|
||||
audit_log_config {
|
||||
log_type = "DATA_READ"
|
||||
|
||||
exempted_members = concat(
|
||||
[
|
||||
module.web.service_account.member,
|
||||
module.api.service_account.member,
|
||||
module.metabase.service_account.member,
|
||||
],
|
||||
module.gateways[*].service_account.member,
|
||||
module.relays[*].service_account.member
|
||||
)
|
||||
}
|
||||
|
||||
audit_log_config {
|
||||
log_type = "DATA_WRITE"
|
||||
|
||||
exempted_members = concat(
|
||||
[
|
||||
module.web.service_account.member,
|
||||
module.api.service_account.member,
|
||||
module.metabase.service_account.member,
|
||||
],
|
||||
module.gateways[*].service_account.member,
|
||||
module.relays[*].service_account.member
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# Grant owner access to the project
|
||||
resource "google_project_iam_binding" "project_owners" {
|
||||
project = module.google-cloud-project.project.project_id
|
||||
@@ -255,7 +294,60 @@ resource "google_sql_database" "firezone" {
|
||||
|
||||
name = "firezone"
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
}
|
||||
|
||||
# Create IAM users for the database for all project owners
|
||||
resource "google_sql_user" "iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
project = module.google-cloud-project.project.project_id
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
|
||||
type = "CLOUD_IAM_USER"
|
||||
name = each.value
|
||||
}
|
||||
|
||||
# We can't remove passwords complete because for IAM users we still need to execute those GRANT statements
|
||||
provider "postgresql" {
|
||||
scheme = "gcppostgres"
|
||||
host = "${module.google-cloud-project.project.project_id}:${local.region}:${module.google-cloud-sql.master_instance_name}"
|
||||
port = 5432
|
||||
username = google_sql_user.firezone.name
|
||||
password = random_password.firezone_db_password.result
|
||||
superuser = false
|
||||
sslmode = "disable"
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_select_on_all_tables_schema_to_iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["SELECT", "INSERT", "UPDATE", "DELETE"]
|
||||
objects = [] # ALL
|
||||
object_type = "table"
|
||||
schema = "public"
|
||||
role = each.key
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.iam_users
|
||||
]
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_execute_on_all_functions_schema_to_iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["EXECUTE"]
|
||||
objects = [] # ALL
|
||||
object_type = "function"
|
||||
schema = "public"
|
||||
role = each.key
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.iam_users
|
||||
]
|
||||
}
|
||||
|
||||
# Create bucket for client logs
|
||||
|
||||
@@ -36,10 +36,3 @@ variable "postmark_server_api_token" {
|
||||
variable "pagerduty_auth_token" {
|
||||
type = string
|
||||
}
|
||||
|
||||
# TODO: add this variable to make sure you can't accidentally run script from staging to deploy prod
|
||||
# variable "deploy_to_production" {
|
||||
# type = bool
|
||||
# description = "Whether to deploy to production or not"
|
||||
# default = false
|
||||
# }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
terraform {
|
||||
required_version = "1.6.2"
|
||||
required_version = "1.6.5"
|
||||
|
||||
required_providers {
|
||||
random = {
|
||||
@@ -26,5 +26,10 @@ terraform {
|
||||
source = "hashicorp/tls"
|
||||
version = "~> 4.0"
|
||||
}
|
||||
|
||||
postgresql = {
|
||||
source = "cyrilgdn/postgresql"
|
||||
version = "1.21.1-beta.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
127
terraform/environments/staging/.terraform.lock.hcl
generated
127
terraform/environments/staging/.terraform.lock.hcl
generated
@@ -1,43 +1,65 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/cyrilgdn/postgresql" {
|
||||
version = "1.21.1-beta.1"
|
||||
constraints = "1.21.1-beta.1"
|
||||
hashes = [
|
||||
"h1:fOpIaAmm9W7Ku58FQBaxQsqV1bdeIisWsbSD+RnVEFs=",
|
||||
"zh:03619b7c00b869567fe0a8cd391c0137ca4f7b6ef0173035e625d610e9a5233a",
|
||||
"zh:1a1d1aec60a58052f9292cfe6e1b780c327d70a95d7e35f80eadea1e0c19820f",
|
||||
"zh:1d559c12f6f7965fcb0e246ed2b211b0f21a6635755c6545bd3692fdb356c1e3",
|
||||
"zh:26730d86fcf64395d31bf8f3f30cd49260df947f94deaed46cbe866f9ae2b859",
|
||||
"zh:26b3ffd5a02cdd68340fe9296bf5e79b78bd0e5a4729ab9136b384476dfb31b7",
|
||||
"zh:2c57d364b3302c7e9e7bc10b0768212ff238cb8b136ba0fe47a421b0b645de8c",
|
||||
"zh:653674a2807f3b0818743ea9ac1ef885c47a7971c8025db66a410da1fc13cf5e",
|
||||
"zh:696c9f6452e182932f5de1665a91ef7dcfa60c62d5b38641088c7aaad661bf1b",
|
||||
"zh:69a284e91441785da80c7a421e0d92c34f83954ca47e793cfa9c875fd6e4d1dc",
|
||||
"zh:c5a08bfb638ed660995abc4a82f3eeaa17587c5aecb4bd5073366359494d660f",
|
||||
"zh:c6e630b1f9025bd9b9001ef88b89e530fe644dfde8ab5a572a4e9fce98384fd1",
|
||||
"zh:c7df7ce987ce7e405999cbbac2a08c1a8d08cf076c9c1a0081d533e47665dfa2",
|
||||
"zh:c9b46c3f065c923a6ea82e1b692de8541eb13f508d440222696125b2be64ad9a",
|
||||
"zh:ee7c7e74882158662733a097d100cd232c82a72fcf38d4d5c8e391389c3d0dfe",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google" {
|
||||
version = "5.7.0"
|
||||
version = "5.9.0"
|
||||
constraints = "~> 5.2"
|
||||
hashes = [
|
||||
"h1:dGrS2F0C3frYTdaYvev6fZDWAGBE6O7Q4DhfO/0P7r8=",
|
||||
"zh:0c0cf15cc034d5f92cc1cd5ee4615012553a674b69ee1802e46c4b87f1c339aa",
|
||||
"zh:28e64a798320866c4dc84c323b66eef94ec98043dba016cf01d6adbe2dc85de4",
|
||||
"zh:3b6e6443a9000354f93682d847737d6e9f702a77c53a492a39b200134b3e8dfd",
|
||||
"zh:3ed6af130702d9da8fc14f94b3b2c9a93917cda31d50d934dd6de0ca48044572",
|
||||
"zh:784a0feae2a48aa9a63fe6feb86ad29e8d35647fa29eb42303b799f09ee92060",
|
||||
"zh:828e0198d99b7f9e53994470d6b51012566660a560da9c8266d1eaf2b140635c",
|
||||
"zh:8dcb7537d95ec14e75ca71cfce62323682ce0fb453902dc9f890b7c524a915d3",
|
||||
"zh:a7e760dc5707603091a0c3de0d47d6f8e51d8cce523b5c90587b05f113c5e09c",
|
||||
"zh:b5c79a5e5b9bcaf0158f5f704d31cf90fb93826085151f06dfc3ef48276ed17a",
|
||||
"zh:c44a2726dcfbf7d538aa0d5abd2473108f625d1d82485a340e62dfc04043288f",
|
||||
"zh:f4da66ba04847138949a6a178b8836182f7960e9d069bfe76f1203d9af99cd22",
|
||||
"h1:jG9wcaMKIuI8JSf8T+SjAcw5vhEpW/fnFfPjSXMbuEY=",
|
||||
"zh:19c618c257b2d9e30a0978b1282b1e418748323ae74d9c1ad63a858cb159cd86",
|
||||
"zh:2c1f18b6714062fe8eab633918b41c622423693f2a4fd747dc516f3578b8e738",
|
||||
"zh:440b31f85e2d823919639c4d248a058cd90020724a2fa543546e36611ca18df4",
|
||||
"zh:453edfad0fbd30e6d694f1b38cc9d5f0b8ec356bbce3f2919f1c4622518c46ca",
|
||||
"zh:47965b68bf9afd2f6a7412792083911d22b6a1a17f0052c9a8329b5ade47bbe9",
|
||||
"zh:5621990ad07b8cd9af6862f7a66b593b19bbdf20986d7c8cfd8948302810de51",
|
||||
"zh:74e2380a9acceb552d067697c38b4679e950fc2ba4bf47025d8917910b08df3d",
|
||||
"zh:a588be4fa16331c406a15e784d419a04e995741ed09eb2e14ec58b53f3ecd8cc",
|
||||
"zh:a60af7611f69b76ff727ee569b1ebefee82a5e5e1f1809d2df04286ee2c0aa4e",
|
||||
"zh:c15d781c9a198d343201eb1a4bc17c616ca8cb38bb33739c3e138db06022a171",
|
||||
"zh:d5c15eeb3be0e01b17ed67ab9b52137480139816edd7e90e93643be57564d2d0",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google-beta" {
|
||||
version = "5.7.0"
|
||||
version = "5.9.0"
|
||||
constraints = "~> 5.2"
|
||||
hashes = [
|
||||
"h1:Rvo7YTb0Uu3oN+2FG0NZ1hBAg1Ra8630U6vkK8OQ2IA=",
|
||||
"zh:1720258635c34406db44e3d08df9cc02e6897f804d6d558e1c73772324df7b30",
|
||||
"zh:1a385e9b3d7cda4d76b242f78086f33600c566386fde97d625f3bd39e1dcb1ff",
|
||||
"zh:26e01a0059c3d9954d0af22ccc05bb21a5b8af7f91a790311cf8ba13e10a5646",
|
||||
"zh:2acdab4240714cc31407324773280eeeb8ec9ab420404a3f3b8c0f25d73a5e00",
|
||||
"zh:4836143995c83c925b040c8bc7d3958fa6743c2179a098e783bf919e17db16ab",
|
||||
"zh:4ca384ea0153ba101af3ca97276f59e76586f935c99b444bd360a4009756af2d",
|
||||
"zh:54cc3398e8c336bd3f836954f87d3a7ae8fc4bced070baac66a244af656163d4",
|
||||
"zh:a3e5d9eacc27047ea0c3c00753da3966516dfc982dee180a3a5f4a405689447e",
|
||||
"zh:cc2052e93d0b52151a2374aa49e56de823ff11dce0570fa7c4bbbcf89467670f",
|
||||
"zh:d8dc64ade395715dbb41753bda72b1bce6348cd2011f95b1cea1b2c675770c58",
|
||||
"zh:da1fe36816881dac4acd7ab37291365c4b92584b8689c7c745c7a5b6800049c0",
|
||||
"h1:/bizlmcNQaK/mYn8+WFayo2ZUVeKkWov2QXwfNGrofY=",
|
||||
"zh:2fcb82487f8c5335646375bd98a44f22df5b01a3290317e138f638cc156da8a8",
|
||||
"zh:452959d6aa53837b613dfa8d9e9f301cc7dba6c0176e03ac0d50408f1b1c6eb5",
|
||||
"zh:49d1f65ba5a8fa5462a95c238aec17b8638b09bee28bb848b9f38d2911f7e8b7",
|
||||
"zh:528821fcbf788721f71f1e78e38b24cf47da1785521637d211f95d01f53519d2",
|
||||
"zh:54f9d5e2df07a463f23d40d04014eedad49b274280d220a81dc8f0bde5591226",
|
||||
"zh:5767e527b13f66a7098fc3059786ade0eaa39fb6d6d3199a4976ccf2b3cdf280",
|
||||
"zh:582d800aa8c5ff345ce9b5494f83d5d5684d553f5b317daf8e832aa30e708e47",
|
||||
"zh:723ef344fb8e60244a18b9a0d3a38941f89b568aa09d2c5d7f5fb2693982da61",
|
||||
"zh:b1ad47427a67f8c8a14868cd474ac8973a068b72dee4d1b828749017dc241212",
|
||||
"zh:c5b980159090c9d8b5e664c79e324c60bc4c1a5f3cfa904999f027949869eef3",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
"zh:ff5fea7d6c6b259938d1d2f008fd4d31242513e2ef592a68b0b6de7eab494a10",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -62,40 +84,41 @@ provider "registry.terraform.io/hashicorp/null" {
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.5.1"
|
||||
version = "3.6.0"
|
||||
constraints = "~> 3.5"
|
||||
hashes = [
|
||||
"h1:IL9mSatmwov+e0+++YX2V6uel+dV6bn+fC/cnGDK3Ck=",
|
||||
"zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
|
||||
"zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
|
||||
"zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
|
||||
"zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
|
||||
"zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
|
||||
"h1:I8MBeauYA8J8yheLJ8oSMWqB0kovn16dF/wKZ1QTdkk=",
|
||||
"zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d",
|
||||
"zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211",
|
||||
"zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829",
|
||||
"zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d",
|
||||
"zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
|
||||
"zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
|
||||
"zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
|
||||
"zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
|
||||
"zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
|
||||
"zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
|
||||
"zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17",
|
||||
"zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21",
|
||||
"zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839",
|
||||
"zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0",
|
||||
"zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c",
|
||||
"zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/tls" {
|
||||
version = "4.0.4"
|
||||
version = "4.0.5"
|
||||
constraints = "~> 4.0"
|
||||
hashes = [
|
||||
"h1:GZcFizg5ZT2VrpwvxGBHQ/hO9r6g0vYdQqx3bFD3anY=",
|
||||
"zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55",
|
||||
"zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848",
|
||||
"zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be",
|
||||
"zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5",
|
||||
"zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe",
|
||||
"zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e",
|
||||
"zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48",
|
||||
"zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8",
|
||||
"zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60",
|
||||
"zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e",
|
||||
"zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316",
|
||||
"h1:zeG5RmggBZW/8JWIVrdaeSJa0OG62uFX5HY1eE8SjzY=",
|
||||
"zh:01cfb11cb74654c003f6d4e32bbef8f5969ee2856394a96d127da4949c65153e",
|
||||
"zh:0472ea1574026aa1e8ca82bb6df2c40cd0478e9336b7a8a64e652119a2fa4f32",
|
||||
"zh:1a8ddba2b1550c5d02003ea5d6cdda2eef6870ece86c5619f33edd699c9dc14b",
|
||||
"zh:1e3bb505c000adb12cdf60af5b08f0ed68bc3955b0d4d4a126db5ca4d429eb4a",
|
||||
"zh:6636401b2463c25e03e68a6b786acf91a311c78444b1dc4f97c539f9f78de22a",
|
||||
"zh:76858f9d8b460e7b2a338c477671d07286b0d287fd2d2e3214030ae8f61dd56e",
|
||||
"zh:a13b69fb43cb8746793b3069c4d897bb18f454290b496f19d03c3387d1c9a2dc",
|
||||
"zh:a90ca81bb9bb509063b736842250ecff0f886a91baae8de65c8430168001dad9",
|
||||
"zh:c4de401395936e41234f1956ebadbd2ed9f414e6908f27d578614aaa529870d4",
|
||||
"zh:c657e121af8fde19964482997f0de2d5173217274f6997e16389e7707ed8ece8",
|
||||
"zh:d68b07a67fbd604c38ec9733069fbf23441436fecf554de6c75c032f82e1ef19",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,12 +14,6 @@ resource "random_password" "metabase_db_password" {
|
||||
min_special = 1
|
||||
}
|
||||
|
||||
# This user can also be used to connect to the Firezone database,
|
||||
# but following SQL should be run manually using the Cloud SQL Proxy:
|
||||
#
|
||||
# GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase;
|
||||
# GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO metabase;
|
||||
#
|
||||
resource "google_sql_user" "metabase" {
|
||||
project = module.google-cloud-project.project.project_id
|
||||
|
||||
@@ -36,6 +30,34 @@ resource "google_sql_database" "metabase" {
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_select_on_all_tables_schema_to_metabase" {
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["SELECT"]
|
||||
objects = [] # ALL
|
||||
object_type = "table"
|
||||
schema = "public"
|
||||
role = google_sql_user.metabase.name
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.metabase
|
||||
]
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_execute_on_all_functions_schema_to_metabase" {
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["EXECUTE"]
|
||||
objects = [] # ALL
|
||||
object_type = "function"
|
||||
schema = "public"
|
||||
role = google_sql_user.metabase.name
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.metabase
|
||||
]
|
||||
}
|
||||
|
||||
module "metabase" {
|
||||
source = "../../modules/metabase-app"
|
||||
project_id = module.google-cloud-project.project.project_id
|
||||
|
||||
@@ -250,6 +250,60 @@ resource "google_sql_database" "firezone" {
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
}
|
||||
|
||||
# Create IAM users for the database for all project owners
|
||||
resource "google_sql_user" "iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
project = module.google-cloud-project.project.project_id
|
||||
instance = module.google-cloud-sql.master_instance_name
|
||||
|
||||
type = "CLOUD_IAM_USER"
|
||||
name = each.value
|
||||
}
|
||||
|
||||
# We can't remove passwords complete because for IAM users we still need to execute those GRANT statements
|
||||
provider "postgresql" {
|
||||
scheme = "gcppostgres"
|
||||
host = "${module.google-cloud-project.project.project_id}:${local.region}:${module.google-cloud-sql.master_instance_name}"
|
||||
port = 5432
|
||||
username = google_sql_user.web.name
|
||||
password = random_password.web_db_password.result
|
||||
superuser = false
|
||||
sslmode = "disable"
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_select_on_all_tables_schema_to_iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["SELECT", "INSERT", "UPDATE", "DELETE"]
|
||||
objects = [] # ALL
|
||||
object_type = "table"
|
||||
schema = "public"
|
||||
role = each.key
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.iam_users
|
||||
]
|
||||
}
|
||||
|
||||
resource "postgresql_grant" "grant_execute_on_all_functions_schema_to_iam_users" {
|
||||
for_each = toset(local.project_owners)
|
||||
|
||||
database = google_sql_database.firezone.name
|
||||
|
||||
privileges = ["EXECUTE"]
|
||||
objects = [] # ALL
|
||||
object_type = "function"
|
||||
schema = "public"
|
||||
role = each.key
|
||||
|
||||
depends_on = [
|
||||
google_sql_user.iam_users
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "client-logs" {
|
||||
project = module.google-cloud-project.project.project_id
|
||||
name = "${module.google-cloud-project.project.project_id}-client-logs"
|
||||
|
||||
@@ -11,3 +11,7 @@ output "demo_postgresql_connection_url" {
|
||||
sensitive = true
|
||||
value = "postgres://${google_sql_user.demo.name}:${random_password.demo_db_password.result}@${module.google-cloud-sql.master_instance_ip_address}/${google_sql_database.demo.name}"
|
||||
}
|
||||
|
||||
output "image_tag" {
|
||||
value = var.image_tag
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
terraform {
|
||||
required_version = "1.6.2"
|
||||
required_version = "1.6.5"
|
||||
|
||||
required_providers {
|
||||
random = {
|
||||
@@ -26,5 +26,10 @@ terraform {
|
||||
source = "hashicorp/tls"
|
||||
version = "~> 4.0"
|
||||
}
|
||||
|
||||
postgresql = {
|
||||
source = "cyrilgdn/postgresql"
|
||||
version = "1.21.1-beta.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ write_files:
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
Restart=always
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStop=/usr/bin/docker stop otel-collector
|
||||
ExecStopPost=/usr/bin/docker rm otel-collector
|
||||
|
||||
|
||||
@@ -83,8 +83,8 @@ write_files:
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
Restart=always
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStop=/usr/bin/docker stop otel-collector
|
||||
ExecStopPost=/usr/bin/docker rm otel-collector
|
||||
|
||||
@@ -157,6 +157,7 @@ runcmd:
|
||||
- sudo apt install docker-ce docker-ce-cli containerd.io -y
|
||||
- sudo usermod -aG docker $(whoami)
|
||||
- sudo systemctl enable docker
|
||||
- sudo echo '{"ipv6":true,"fixed-cidr-v6":"fd00::/80"}' > /etc/docker/daemon.json
|
||||
- sudo systemctl start docker
|
||||
- sudo ip6tables-restore < /etc/iptables/rules.v6
|
||||
- sudo systemctl daemon-reload
|
||||
|
||||
@@ -304,7 +304,7 @@ resource "google_monitoring_alert_policy" "sql_disk_utiliziation_policy" {
|
||||
resource "google_monitoring_alert_policy" "genservers_crash_policy" {
|
||||
project = var.project_id
|
||||
|
||||
display_name = "GenServer Crashes"
|
||||
display_name = "Errors in logs"
|
||||
combiner = "OR"
|
||||
|
||||
notification_channels = local.notification_channels
|
||||
@@ -330,6 +330,45 @@ resource "google_monitoring_alert_policy" "genservers_crash_policy" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_monitoring_alert_policy" "production_db_access_policy" {
|
||||
project = var.project_id
|
||||
|
||||
display_name = "Production DB Access"
|
||||
combiner = "OR"
|
||||
|
||||
notification_channels = [
|
||||
google_monitoring_notification_channel.slack.name
|
||||
]
|
||||
|
||||
documentation {
|
||||
content = "Somebody just accessed the production database, this notification incident will be automatically discarded in 1 hour."
|
||||
mime_type = "text/markdown"
|
||||
}
|
||||
|
||||
conditions {
|
||||
display_name = "Log match condition"
|
||||
|
||||
condition_matched_log {
|
||||
filter = <<-EOT
|
||||
protoPayload.methodName="cloudsql.instances.connect"
|
||||
protoPayload.authenticationInfo.principalEmail!="terraform-cloud@terraform-iam-387817.iam.gserviceaccount.com"
|
||||
EOT
|
||||
|
||||
label_extractors = {
|
||||
"Email" = "EXTRACT(protoPayload.authenticationInfo.principalEmail)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alert_strategy {
|
||||
auto_close = "3600s"
|
||||
|
||||
notification_rate_limit {
|
||||
period = "28800s"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_monitoring_alert_policy" "ssl_certs_expiring_policy" {
|
||||
project = var.project_id
|
||||
|
||||
|
||||
@@ -120,6 +120,11 @@ resource "google_sql_database_instance" "master" {
|
||||
name = "maintenance_work_mem"
|
||||
value = floor(var.compute_instance_memory_size * 1024 / 100 * 5)
|
||||
}
|
||||
|
||||
database_flags {
|
||||
name = "cloudsql.iam_authentication"
|
||||
value = "on"
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
|
||||
@@ -83,8 +83,8 @@ write_files:
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
Restart=always
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.87.0
|
||||
ExecStartPre=/usr/bin/docker pull otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStart=/usr/bin/docker run --rm -u 2000 --name=otel-collector --network host --volume /etc/otelcol-contrib/:/etc/otelcol-contrib/ otel/opentelemetry-collector-contrib:0.90.1
|
||||
ExecStop=/usr/bin/docker stop otel-collector
|
||||
ExecStopPost=/usr/bin/docker rm otel-collector
|
||||
|
||||
|
||||
Reference in New Issue
Block a user