Skip to content

Commit

Permalink
feat: add vaultwarden
Browse files Browse the repository at this point in the history
  • Loading branch information
kahlstrm committed Nov 21, 2024
1 parent 935e1ed commit 8636a6d
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 17 deletions.
34 changes: 18 additions & 16 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,30 @@ module "invoicing" {
acme_account_key = module.common.acme_account_key
}


module "vaultwarden" {
source = "./modules/vaultwarden"
admin_api_key = module.keyvault.secrets["vaultwarden-api-key"]
app_service_plan_id = module.common.tikweb_app_plan_id
app_service_plan_location = local.resource_group_location
app_service_plan_resource_group_name = module.common.resource_group_name
db_password = module.common.postgres_admin_password
db_username = module.common.postgres_admin_username
db_name = "vaultwarden"
db_host = module.common.postgres_server_fqdn
location = local.resource_group_location
smtp_host = "smtp.eu.mailgun.org"
vaultwarden_smtp_from = "[email protected]"
vaultwarden_smtp_username = module.keyvault.secrets["vaultwarden-smtp-username"]
vaultwarden_smtp_password = module.keyvault.secrets["vaultwarden-smtp-password"]
dns_resource_group_name = module.dns_prod.resource_group_name
acme_account_key = module.common.acme_account_key
root_zone_name = module.dns_prod.root_zone_name
subdomain = "vaultwarden"
dkim_selector = "s1"
dkim_key = "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqMtEsg4MR4gCzUovwmok+T2MsPAKfnWl9UxVHDTXyalQ4dFzgYwHi+nRHjSucAsw5WYy8arDKsJx/jEnOBOpOJECTGg6z75jXO5E9hpKFN8oWtcV/bX1KLIKZ/XlxqEsuAIbTgVUfIvZBOLzyOP0lPKsyfQw5w/0HakJFNQ1E1Zjf+NdXMQ2FSbJB1ohcWU5uMmBQagChc6IR0Lm14+Ot+EL1ZKmVoaQ2LIoNby8/Cb/5f8knUscdkeQU2HDAmHq7V+5ZJtxQZufHnUM0XaRcQw3F7sk9A9vdxa4NKTYsYd+y9AfiEM7KAd3KuPxC2wA1sxvpIq3Y+X1tr40DgyG2wIDAQAB"

}
# module "m0" {
# source = "./modules/m0"
# resource_group_location = local.resource_group_location
Expand Down
5 changes: 4 additions & 1 deletion modules/keyvault/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ locals {
"mailgun-domain",
"mailgun-url",
"tikjob-tg-bot-token",
"tikjob-tg-ghost-hook-secret"
"tikjob-tg-ghost-hook-secret",
"vaultwarden-api-key",
"vaultwarden-smtp-username",
"vaultwarden-smtp-password",
]
}

Expand Down
56 changes: 56 additions & 0 deletions modules/vaultwarden/dns.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
locals {
fqdn = "${var.subdomain}.${var.root_zone_name}"
}

# MX records for Mailman
resource "azurerm_dns_mx_record" "list_mx" {
name = var.subdomain
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300

record {
preference = 20
exchange = "tietokilta.fi"
}
record {
preference = 21
exchange = "mail.cs.hut.fi"
}
}

# SPF record
resource "azurerm_dns_txt_record" "list_spf" {
name = var.subdomain
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300

record {
value = "v=spf1 mx include:mailgun.org ~all"
}
}

# DKIM key for Mailgun (Mailman doesn't sign emails)
resource "azurerm_dns_txt_record" "list_dkim" {
name = "${var.dkim_selector}._domainkey.${var.subdomain}"
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300

record {
value = var.dkim_key
}
}

# Reporting-only DMARC policy
resource "azurerm_dns_txt_record" "list_dmarc" {
name = "_dmarc.${var.subdomain}"
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300

record {
value = "v=DMARC1;p=none;sp=none;rua=mailto:[email protected]!10m;ruf=mailto:[email protected]!10m"
}
}
151 changes: 151 additions & 0 deletions modules/vaultwarden/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
terraform {
required_providers {
acme = {
source = "vancluever/acme"
version = "2.19.0"
}
}
}
resource "azurerm_resource_group" "rg" {
name = "vaultwarden-rg"
location = var.location
}
# Storage Account and File Share
resource "azurerm_storage_account" "storage_account" {
name = "tikvaultwardenstorage"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "GRS" # Zone redundant https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy
account_kind = "StorageV2"
access_tier = "Hot"
}

resource "azurerm_storage_share" "file_share" {
name = "vaultwarden-data"
storage_account_name = azurerm_storage_account.storage_account.name
quota = 10 # GB
}

# App Service (Linux Web App)
resource "azurerm_linux_web_app" "vaultwarden_app" {
name = "tik-vaultwarden-${terraform.workspace}"
location = var.location
resource_group_name = var.app_service_plan_resource_group_name
service_plan_id = var.app_service_plan_id

site_config {
ftps_state = "Disabled"
always_on = false

application_stack {
docker_registry_url = "https://docker.io"
docker_image_name = "vaultwarden/server:latest"
}
}
# Mount the Azure File Share
storage_account {
name = "vaultwarden-persistent-storage"
account_name = azurerm_storage_account.storage_account.name
access_key = azurerm_storage_account.storage_account.primary_access_key
mount_path = "/data"
share_name = azurerm_storage_share.file_share.name
type = "AzureFiles"
}

app_settings = {
WEBSITES_ENABLE_APP_SERVICE_STORAGE = "false"
WEBSITES_PORT = "80"

# Vaultwarden Environment Variables
ADMIN_TOKEN = var.admin_api_key
DOMAIN = "https://${local.fqdn}"
SIGNUPS_ALLOWED = "false"

# SMTP configuration
SMTP_SECURITY = "force_tls"
SMTP_HOST = var.smtp_host
SMTP_FROM = var.vaultwarden_smtp_from
SMTP_PORT = 465
SMTP_USERNAME = var.vaultwarden_smtp_username
SMTP_PASSWORD = var.vaultwarden_smtp_password
# Database configuration
DATABASE_URL = "postgresql://${var.db_username}:${var.db_password}@${var.db_host}:${var.db_port}/${var.db_name}"
}
}


# A record for the web app
resource "azurerm_dns_a_record" "vaultwarden_a" {
name = var.subdomain
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300
records = data.dns_a_record_set.vaultwarden_dns_fetch.addrs
}

# Azure verification key
resource "azurerm_dns_txt_record" "vaultwarden_asuid" {
name = "asuid.${var.subdomain}"
resource_group_name = var.dns_resource_group_name
zone_name = var.root_zone_name
ttl = 300

record {
value = azurerm_linux_web_app.vaultwarden_app.custom_domain_verification_id
}
}


resource "azurerm_app_service_custom_hostname_binding" "vaultwarden_hostname_binding" {
hostname = local.fqdn
app_service_name = azurerm_linux_web_app.vaultwarden_app.name
resource_group_name = var.app_service_plan_resource_group_name

# Deletion may need manual work.
# https://github.com/hashicorp/terraform-provider-azurerm/issues/11231
# TODO: Add dependencies for creation
depends_on = [
azurerm_dns_a_record.vaultwarden_a,
azurerm_dns_txt_record.vaultwarden_asuid
]
}
resource "random_password" "vaultwarden_cert_password" {
length = 48
special = false
}

resource "acme_certificate" "vaultwarden_acme_cert" {
account_key_pem = var.acme_account_key
common_name = local.fqdn
key_type = "2048" # RSA
certificate_p12_password = random_password.vaultwarden_cert_password.result

dns_challenge {
provider = "azure"
config = {
AZURE_RESOURCE_GROUP = var.dns_resource_group_name
AZURE_ZONE_NAME = var.root_zone_name
}
}
}

resource "azurerm_app_service_certificate" "vaultwarden_cert" {
name = "tik-vaultwarden-cert-${terraform.workspace}"
resource_group_name = var.app_service_plan_resource_group_name
location = var.location
pfx_blob = acme_certificate.vaultwarden_acme_cert.certificate_p12
password = acme_certificate.vaultwarden_acme_cert.certificate_p12_password
}

resource "azurerm_app_service_certificate_binding" "vaultwarden_cert_binding" {
certificate_id = azurerm_app_service_certificate.vaultwarden_cert.id
hostname_binding_id = azurerm_app_service_custom_hostname_binding.vaultwarden_hostname_binding.id
ssl_state = "SniEnabled"
}

# https://github.com/hashicorp/terraform-provider-azurerm/issues/14642#issuecomment-1084728235
# Currently, the azurerm provider doesn't give us the IP address, so we need to fetch it ourselves.
data "dns_a_record_set" "vaultwarden_dns_fetch" {
host = azurerm_linux_web_app.vaultwarden_app.default_hostname
}
89 changes: 89 additions & 0 deletions modules/vaultwarden/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
variable "admin_api_key" {
description = "Vaultwarden Admin API key used to access /admin page - minLength is 20"
type = string
sensitive = true
validation {
condition = length(var.admin_api_key) >= 20
error_message = "Admin API Key must be at least 20 characters."
}
}
variable "subdomain" {
type = string
}
variable "root_zone_name" {
type = string
}
variable "dns_resource_group_name" {
type = string
}
variable "acme_account_key" {
type = string
}
variable "dkim_selector" {
type = string
}
variable "dkim_key" {
type = string
}
variable "db_host" {
description = "Hostname or IP address of the existing PostgreSQL database"
type = string
}

variable "db_port" {
description = "Port number of the existing PostgreSQL database"
type = number
default = 5432
}

variable "db_name" {
description = "Name of the existing PostgreSQL database"
type = string
}

variable "db_username" {
description = "Username for the existing PostgreSQL database"
type = string
}

variable "db_password" {
description = "Password for the existing PostgreSQL database"
type = string
sensitive = true
}

variable "location" {
description = "Azure location"
type = string
}

variable "app_service_plan_id" {
description = "ID of the existing App Service Plan"
type = string
}

variable "app_service_plan_resource_group_name" {
description = "Resource group of the existing App Service Plan"
type = string
}

variable "app_service_plan_location" {
description = "Location of the existing App Service Plan"
type = string
}

variable "smtp_host" {
type = string
}
variable "vaultwarden_smtp_from" {
type = string
}

variable "vaultwarden_smtp_username" {
type = string
sensitive = true
}
variable "vaultwarden_smtp_password" {
type = string
sensitive = true
}

0 comments on commit 8636a6d

Please sign in to comment.