feature: the router has a two-level CA with an optional offline root, issuing CAs for P2S, site-to-site and general use, templates, published certificates and CRLs and an ACME server, site-to-site connections authenticate with certificates, and setup installs Caddy from Ubuntu or Caddy's repository.
Release / release (push) Successful in 13s

This commit is contained in:
slawek committed 2026-10-25 22:05:39 +01:00
1 parent fe45272f7c
commit 8d3469d10a
37 files changed
+2499 -921

No files matched your search

+4 -6
View File
@@ -3,7 +3,7 @@ data "http" "repo_gpg_key" {
}
locals {
supply_pki = var.ca_cert_file != ""
supply_pki = var.root_cert_file != ""
cloud_init_vars = {
hostname = var.name
@@ -27,7 +27,7 @@ locals {
psk = var.psk
}
}
p2s = { enabled = var.p2s_enabled, address_pool = var.p2s_address_pool, ca_name = "VPN Router CA" }
p2s = { enabled = var.p2s_enabled, address_pool = var.p2s_address_pool }
wireguard = { enabled = var.wireguard_enabled, address = var.wireguard_address, listen_port = var.wireguard_listen_port }
}
}
@@ -102,10 +102,8 @@ resource "azurerm_linux_virtual_machine" "router" {
custom_data = base64encode(
local.supply_pki
? templatefile("${path.module}/../cloud-init-with-pki.yaml.tpl", merge(local.cloud_init_vars, {
label = split(".", var.local_fqdn)[0]
ca_cert = file(var.ca_cert_file)
server_cert = file(var.server_cert_file)
server_key = file(var.server_key_file)
root_cert = file(var.root_cert_file)
root_key = var.root_key_file != "" ? file(var.root_key_file) : ""
}))
: templatefile("${path.module}/../cloud-init.yaml.tpl", local.cloud_init_vars)
)
+4 -10
View File
@@ -100,20 +100,14 @@ variable "p2s_address_pool" {
default = ""
}
variable "ca_cert_file" {
description = "Path to an existing CA certificate PEM to supply instead of letting the package generate one. Leave empty to auto-generate."
variable "root_cert_file" {
description = "Path to an existing root CA certificate PEM to supply instead of letting the package create one. Leave empty to create one."
type = string
default = ""
}
variable "server_cert_file" {
description = "Path to an existing server certificate PEM, paired with ca_cert_file."
type = string
default = ""
}
variable "server_key_file" {
description = "Path to an existing server private key PEM, paired with ca_cert_file."
variable "root_key_file" {
description = "Path to the private key PEM of root_cert_file. Leave empty to keep the root offline: the issuing CAs then wait for certificates signed elsewhere."
type = string
default = ""
sensitive = true
+11 -13
View File
@@ -1,12 +1,13 @@
#cloud-config
#
# Example: install and configure vpn-router during first boot, supplying an
# existing CA and server certificate instead of letting the package generate
# one. See cloud-init.yaml.tpl for the variant that generates its own CA.
# existing root CA instead of letting the package create one. See
# cloud-init.yaml.tpl for the variant that creates its own.
#
# Template variables are Terraform templatefile() placeholders. Adapt or drop
# them for whatever renders this file. <label> is the first component of the
# FQDN, for example "router" in router.example.com.
# them for whatever renders this file. With root_key empty the root stays
# offline: the router's issuing CAs wait for their certificates, signed with
# the root elsewhere and imported with vpn-router-ca ca import.
hostname: ${hostname}
fqdn: ${fqdn}
@@ -28,21 +29,18 @@ write_files:
content: |
${jsonencode(config)}
- path: /etc/vpn-router/pki/ca_cert.pem
- path: /etc/vpn-router/pki/root/cert.pem
permissions: '0644'
owner: root:root
content: |
${indent(6, trimspace(ca_cert))}
- path: /etc/vpn-router/pki/${label}_cert.pem
permissions: '0644'
owner: root:root
content: |
${indent(6, trimspace(server_cert))}
- path: /etc/vpn-router/pki/${label}_key.pem
${indent(6, trimspace(root_cert))}
%{ if root_key != "" ~}
- path: /etc/vpn-router/pki/root/key.pem
permissions: '0600'
owner: root:root
content: |
${indent(6, trimspace(server_key))}
${indent(6, trimspace(root_key))}
%{ endif ~}
package_update: true
+3 -3
View File
@@ -10,9 +10,9 @@
# Template variables are Terraform templatefile() placeholders. Adapt or drop
# them for whatever renders this file.
#
# This variant lets the package generate its own CA on first boot. See
# cloud-init-with-pki.yaml.tpl for the variant that supplies existing PKI
# material instead.
# This variant lets the package create its own CAs on first boot. See
# cloud-init-with-pki.yaml.tpl for the variant that supplies an existing root
# CA instead.
hostname: ${hostname}
fqdn: ${fqdn}
+4 -6
View File
@@ -3,7 +3,7 @@ data "http" "repo_gpg_key" {
}
locals {
supply_pki = var.ca_cert_file != ""
supply_pki = var.root_cert_file != ""
cloud_init_vars = {
hostname = var.name
@@ -27,16 +27,14 @@ locals {
psk = var.psk
}
}
p2s = { enabled = var.p2s_enabled, address_pool = var.p2s_address_pool, ca_name = "VPN Router CA" }
p2s = { enabled = var.p2s_enabled, address_pool = var.p2s_address_pool }
wireguard = { enabled = var.wireguard_enabled, address = var.wireguard_address, listen_port = var.wireguard_listen_port }
}
}
cloud_init_rendered = local.supply_pki ? templatefile("${path.module}/../cloud-init-with-pki.yaml.tpl", merge(local.cloud_init_vars, {
label = split(".", var.local_fqdn)[0]
ca_cert = file(var.ca_cert_file)
server_cert = file(var.server_cert_file)
server_key = file(var.server_key_file)
root_cert = file(var.root_cert_file)
root_key = var.root_key_file != "" ? file(var.root_key_file) : ""
})) : templatefile("${path.module}/../cloud-init.yaml.tpl", local.cloud_init_vars)
}
+4 -10
View File
@@ -97,20 +97,14 @@ variable "p2s_address_pool" {
default = ""
}
variable "ca_cert_file" {
description = "Path to an existing CA certificate PEM to supply instead of letting the package generate one. Leave empty to auto-generate."
variable "root_cert_file" {
description = "Path to an existing root CA certificate PEM to supply instead of letting the package create one. Leave empty to create one."
type = string
default = ""
}
variable "server_cert_file" {
description = "Path to an existing server certificate PEM, paired with ca_cert_file."
type = string
default = ""
}
variable "server_key_file" {
description = "Path to an existing server private key PEM, paired with ca_cert_file."
variable "root_key_file" {
description = "Path to the private key PEM of root_cert_file. Leave empty to keep the root offline: the issuing CAs then wait for certificates signed elsewhere."
type = string
default = ""
sensitive = true
+5 -3
View File
@@ -26,7 +26,7 @@ REMOTE_CIDRS="${REMOTE_CIDRS:-[\"192.168.0.0/24\"]}"
PSK="${PSK:-change-me}"
P2S_ENABLED="${P2S_ENABLED:-false}"
P2S_ADDRESS_POOL="${P2S_ADDRESS_POOL:-172.16.0.0/24}"
P2S_CA_NAME="${P2S_CA_NAME:-VPN Router CA}"
PKI_ROOT_NAME="${PKI_ROOT_NAME:-VPN Router Root CA}"
WG_ENABLED="${WG_ENABLED:-false}"
WG_ADDRESS="${WG_ADDRESS:-}"
WG_LISTEN_PORT="${WG_LISTEN_PORT:-51820}"
@@ -66,8 +66,10 @@ cat > /etc/vpn-router/vpn-router.json <<EOF
},
"p2s": {
"enabled": ${P2S_ENABLED},
"address_pool": "${P2S_ADDRESS_POOL}",
"ca_name": "${P2S_CA_NAME}"
"address_pool": "${P2S_ADDRESS_POOL}"
},
"pki": {
"root_name": "${PKI_ROOT_NAME}"
},
"wireguard": {
"enabled": ${WG_ENABLED},