diff --git a/.envrc b/.envrc index 5e9005b..740379e 100644 --- a/.envrc +++ b/.envrc @@ -2,3 +2,5 @@ if ! has nix_direnv_version || ! nix_direnv_version 2.1.1; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.1.1/direnvrc" "sha256-b6qJ4r34rbE23yWjMqbmu3ia2z4b2wIlZUksBke/ol0=" fi use flake + +# vi: ft=sh diff --git a/README.md b/README.md index 222a7f5..b30c5ba 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,11 @@ psql --host pg.monotremata.xyz ``` ```sql -CREATE DATABASE terraform_backend; CREATE USER terraform WITH ENCRYPTED PASSWORD '****'; + +CREATE DATABASE terraform_backend; GRANT ALL PRIVILEGES ON DATABASE terraform_backend TO terraform; + +CREATE DATABASE terraform_lan; +GRANT ALL PRIVILEGES ON DATABASE terraform_lan TO terraform; ``` diff --git a/flake.nix b/flake.nix index 8595f5a..b7eedfc 100644 --- a/flake.nix +++ b/flake.nix @@ -8,8 +8,16 @@ let pkgs = nixpkgs.legacyPackages.${system}; in { devShell = pkgs.mkShell { - nativeBuildInputs = - [ pkgs.bashInteractive pkgs.terraform pkgs.linode-cli pkgs.just ]; + nativeBuildInputs = [ + pkgs.bashInteractive + pkgs.terraform + pkgs.kubectl + pkgs.kubernetes-helm + pkgs.linode-cli + pkgs.just + pkgs.postgresql + pkgs.tfk8s + ]; buildInputs = [ ]; }; }); diff --git a/lan/justfile b/lan/justfile new file mode 100644 index 0000000..d1287a5 --- /dev/null +++ b/lan/justfile @@ -0,0 +1,23 @@ +pg_user := "terraform" +# pg_host := "pg.monotremata.xyz" +pg_host := "narwhal" +pg_db := "terraform_lan" +pg_port := "5432" + +passwd := `pass pg.monotremata.xyz/terraform` +# todo: I'll use this once string interpolation gets implenented in Just https://github.com/casey/just/issues/11 +# conn_str := f"postgres://{{pg_user}}:{{passwd}}@{{pg_host}}:{{pg_port}}/{{pg_db}}" + +export TF_VAR_hetzner_token := `pass hetzner.com/tokens/suricata` + +init: + terraform init -backend-config="conn_str=postgres://{{pg_user}}:{{passwd}}@{{pg_host}}:{{pg_port}}/{{pg_db}}" + +plan *ARGS: + terraform plan {{ARGS}} + +apply *ARGS: + terraform apply {{ARGS}} + +terraform *ARGS: + terraform {{ARGS}} diff --git a/lan/main.tf b/lan/main.tf new file mode 100644 index 0000000..ce66a6a --- /dev/null +++ b/lan/main.tf @@ -0,0 +1,14 @@ +terraform { + backend "pg" {} + required_providers { + } +} + +module "cert-manager" { + source = "../modules/cert-manager" + hetzner_token = var.hetzner_token + email = var.email + zone_name = var.zone_name + dns_common_name = var.dns_common_name + dns_names = var.dns_names +} diff --git a/lan/variables.tf b/lan/variables.tf new file mode 100644 index 0000000..b1e0b27 --- /dev/null +++ b/lan/variables.tf @@ -0,0 +1,33 @@ +variable "hetzner_token" { + type = string + description = "hetzner dns token" + sensitive = true +} + +variable "email" { + type = string + description = "email for letsencrypt registration" + default = "rilla@monotremata.xyz" +} + +variable "zone_name" { + type = string + description = "hetzner domain zone" + default = "monotremata.xyx" +} + +variable "dns_common_name" { + type = string + default = "monotremata.xyz" + description = "common name for the certificate" +} + +variable "dns_names" { + type = list(string) + description = "list of domains for the certificate" + default = [ + "monotremata.xyz", + "*.monotremata.xyz", + "*.suricata.monotremata.xyz", + ] +} diff --git a/modules/cert-manager/main.tf b/modules/cert-manager/main.tf new file mode 100644 index 0000000..2b1347f --- /dev/null +++ b/modules/cert-manager/main.tf @@ -0,0 +1,145 @@ +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.20.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.9.0" + } + } +} + +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } +} + +resource "helm_release" "cert-manager" { + name = "cert-manager" + chart = "cert-manager" + repository = "https://charts.jetstack.io" + namespace = "cert-manager" + create_namespace = true + version = var.cert_manager_version + set { + name = "installCRDs" + value = true + } +} + +resource "helm_release" "cert-manager-webhook-hetzner" { + name = "cert-manager-webhook-hetzner" + chart = "cert-manager-webhook-hetzner" + repository = "https://vadimkim.github.io/cert-manager-webhook-hetzner" + namespace = helm_release.cert-manager.namespace + set { + name = "groupName" + value = var.group_name + } +} + +resource "kubernetes_secret" "hetzner-token" { + metadata { + name = "hetzner-token" + namespace = helm_release.cert-manager.namespace + } + type = "Opaque" + data = { + api-key = var.hetzner_token + } +} + +#resource "kubernetes_manifest" "clusterissuer_letsencrypt_staging" { +# manifest = { +# apiVersion = "cert-manager.io/v1" +# kind = "ClusterIssuer" +# metadata = { +# name = "letsencrypt-staging" +# } +# spec = { +# acme = { +# email = var.email +# privateKeySecretRef = { +# name = "letsencrypt-staging-account-key" +# } +# server = var.letsencrypt_servers.staging +# solvers = [ +# { +# dns01 = { +# webhook = { +# config = { +# apiUrl = var.hetzner_dns_api +# secretName = kubernetes_secret.hetzner-token.metadata[0].name +# zoneName = var.zone_name +# } +# groupName = var.group_name +# solverName = "hetzner" +# } +# } +# } +# ] +# } +# } +# } +#} + +resource "kubernetes_manifest" "clusterissuer_letsencrypt" { + manifest = { + apiVersion = "cert-manager.io/v1" + kind = "ClusterIssuer" + metadata = { + name = "letsencrypt" + } + spec = { + acme = { + email = var.email + privateKeySecretRef = { + name = "letsencrypt-account-key" + } + server = var.letsencrypt_servers.prod + solvers = [ + { + dns01 = { + webhook = { + config = { + apiUrl = var.hetzner_dns_api + secretName = kubernetes_secret.hetzner-token.metadata[0].name + zoneName = var.zone_name + } + groupName = var.group_name + solverName = "hetzner" + } + } + } + ] + } + } + } +} + +resource "kubernetes_manifest" "certificate_cert_manager" { + manifest = { + apiVersion = "cert-manager.io/v1" + kind = "Certificate" + metadata = { + name = format("%s-cert", replace(var.dns_common_name, ".", "-")) + namespace = helm_release.cert-manager.namespace + } + spec = { + commonName = var.dns_common_name + dnsNames = var.dns_names + issuerRef = { + kind = "ClusterIssuer" + name = kubernetes_manifest.clusterissuer_letsencrypt.manifest.metadata.name + } + secretName = format("%s-cert", replace(var.dns_common_name, ".", "-")) + } + } +} diff --git a/modules/cert-manager/variables.tf b/modules/cert-manager/variables.tf new file mode 100644 index 0000000..ef50fc7 --- /dev/null +++ b/modules/cert-manager/variables.tf @@ -0,0 +1,55 @@ +variable "hetzner_token" { + type = string + description = "hetzner dns token" + sensitive = true +} + +variable "group_name" { + type = string + description = "group name to be used for DNS webhook" + default = "dns.hetzner.cloud" +} + +variable "zone_name" { + type = string + description = "hetzner domain zone" +} + +variable "cert_manager_version" { + type = string + description = "cert-manager version to install" + default = "v1.12.0" +} + +variable "email" { + type = string + description = "email for letsencrypt registration" +} + +variable "letsencrypt_servers" { + type = object({ + staging = string + prod = string + }) + description = "urls for the letsencrypt servers" + default = { + staging = "https://acme-staging-v02.api.letsencrypt.org/directory" + prod = "https://acme-v02.api.letsencrypt.org/directory" + } +} + +variable "hetzner_dns_api" { + type = string + description = "endpoint for the hetnzer dns api" + default = "https://dns.hetzner.com/api/v1" +} + +variable "dns_common_name" { + type = string + description = "common name for the certificate" +} + +variable "dns_names" { + type = list(string) + description = "list of domains for the certificate" +} diff --git a/justfile b/remote/justfile similarity index 99% rename from justfile rename to remote/justfile index 293bfea..c39949f 100644 --- a/justfile +++ b/remote/justfile @@ -18,7 +18,6 @@ export HETZNER_DNS_API_TOKEN := `pass hetzner.com/tokens/terraform` init: terraform init -backend-config="conn_str=postgres://{{pg_user}}:{{passwd}}@{{pg_host}}:{{pg_port}}/{{pg_db}}" - plan *ARGS: terraform plan {{ARGS}} diff --git a/main.tf b/remote/main.tf similarity index 96% rename from main.tf rename to remote/main.tf index 3a0530c..4dc4805 100644 --- a/main.tf +++ b/remote/main.tf @@ -31,7 +31,7 @@ provider "vultr" { } module "dns" { - source = "./modules/dns" + source = "../modules/dns" #nameservers = [ # "ns1.linode.com", @@ -76,5 +76,5 @@ module "dns" { } module "vps" { - source = "./modules/vps" + source = "../modules/vps" }