From 14790f8277dfc5b1c5eda6d1632c7ff88ce0019a Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Mon, 23 Sep 2024 22:01:18 +1000 Subject: [PATCH] feat: import current status - import pki, ssh, kv, rundeck engines - deploy all roles from terraform - deploy all policies from terraform - deploy all approles from terraform --- .gitignore | 3 ++ README.md | 36 +++++++++++++- auth_approle_certmanager.tf | 14 ++++++ auth_approle_rundeck-role.tf | 9 ++++ auth_approle_sshsign-host-role.tf | 14 ++++++ auth_approle_sshsigner.tf | 17 +++++++ auth_backend_approle.tf | 7 +++ auth_backend_ldap.tf | 13 +++++ engine_kv.tf | 15 ++++++ engine_pki_int.tf | 49 +++++++++++++++++++ engine_pki_root.tf | 39 +++++++++++++++ engine_rundeck.tf | 14 ++++++ engine_ssh-host-signer.tf | 18 +++++++ engine_sshca.tf | 18 +++++++ main.tf | 31 ++++++++++++ policies.tf | 31 ++++++++++++ policies/pki_int/certmanager.hcl | 9 ++++ policies/rundeck/rundeck.hcl | 7 +++ .../ssh-host-signer/sshsign-host-policy.hcl | 3 ++ policies/ssh-host-signer/sshsigner.hcl | 3 ++ policies/sshca/sshca_signhost.hcl | 3 ++ policies/sshca/sshca_signuser.hcl | 3 ++ role_pki_int_servers_default.tf | 15 ++++++ role_pki_root_2024_servers.tf | 6 +++ role_ssh-host-signer_hostrole.tf | 11 +++++ role_sshca_signhost.tf | 12 +++++ 26 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 auth_approle_certmanager.tf create mode 100644 auth_approle_rundeck-role.tf create mode 100644 auth_approle_sshsign-host-role.tf create mode 100644 auth_approle_sshsigner.tf create mode 100644 auth_backend_approle.tf create mode 100644 auth_backend_ldap.tf create mode 100644 engine_kv.tf create mode 100644 engine_pki_int.tf create mode 100644 engine_pki_root.tf create mode 100644 engine_rundeck.tf create mode 100644 engine_ssh-host-signer.tf create mode 100644 engine_sshca.tf create mode 100644 main.tf create mode 100644 policies.tf create mode 100644 policies/pki_int/certmanager.hcl create mode 100644 policies/rundeck/rundeck.hcl create mode 100644 policies/ssh-host-signer/sshsign-host-policy.hcl create mode 100644 policies/ssh-host-signer/sshsigner.hcl create mode 100644 policies/sshca/sshca_signhost.hcl create mode 100644 policies/sshca/sshca_signuser.hcl create mode 100644 role_pki_int_servers_default.tf create mode 100644 role_pki_root_2024_servers.tf create mode 100644 role_ssh-host-signer_hostrole.tf create mode 100644 role_sshca_signhost.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64b3492 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.terraform +.terraform.lock.hcl +env diff --git a/README.md b/README.md index 90aa768..20f70ed 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,37 @@ # terraform-vault -A repository to manage the configuration of Vault secret engines, authentication modes and policies. \ No newline at end of file +A repository to manage the configuration of Vault secret engines, authentication modes and policies. + + +# Usage + +1. Initialize Terraform + +Once you have your backend block configured, you need to initialize your Terraform working directory to configure the backend: + +```bash +terraform init +``` + +This command initializes the backend and checks the connection to Consul. If everything is set up correctly, Terraform will start using Consul as its backend for storing the state. + +2. Common terraform init Errors + +If you encounter errors while running terraform init, check the following: + + Consul server is reachable: Make sure that the address is correct and that you can connect to the Consul server. + Consul token (if using ACLs): Verify that the token has the correct permissions to write to the specified path in the Consul KV store. + +3. Example Consul KV Structure + +In Consul, the state file will be stored in the KV store under the specified path: + +```bash +terraform/state +``` + +You can check the Consul KV store by accessing the Consul UI or using the consul kv command to see the stored Terraform state: + +```bash +consul kv get terraform/state +``` diff --git a/auth_approle_certmanager.tf b/auth_approle_certmanager.tf new file mode 100644 index 0000000..230fafd --- /dev/null +++ b/auth_approle_certmanager.tf @@ -0,0 +1,14 @@ +resource "vault_approle_auth_backend_role" "certmanager" { + role_name = "certmanager" + bind_secret_id = false + token_policies = ["certmanager"] + token_ttl = 30 + token_max_ttl = 30 + token_bound_cidrs = [ + "198.18.17.3/32", + "198.18.13.32/32", + "198.18.13.33/32", + "198.18.13.34/32", + "198.18.13.46/32" + ] +} diff --git a/auth_approle_rundeck-role.tf b/auth_approle_rundeck-role.tf new file mode 100644 index 0000000..daa972f --- /dev/null +++ b/auth_approle_rundeck-role.tf @@ -0,0 +1,9 @@ +resource "vault_approle_auth_backend_role" "rundeck-role" { + role_name = "rundeck-role" + bind_secret_id = true + token_policies = ["rundeck"] + token_ttl = 1 * 3600 + token_max_ttl = 4 * 3600 + token_bound_cidrs = ["198.18.13.59/32"] + secret_id_bound_cidrs = ["198.18.13.59/32"] +} diff --git a/auth_approle_sshsign-host-role.tf b/auth_approle_sshsign-host-role.tf new file mode 100644 index 0000000..34bec66 --- /dev/null +++ b/auth_approle_sshsign-host-role.tf @@ -0,0 +1,14 @@ +resource "vault_approle_auth_backend_role" "sshsign-host-role" { + role_name = "sshsign-host-role" + bind_secret_id = false + token_policies = ["sshsign-host-policy"] + token_ttl = 30 + token_max_ttl = 30 + token_bound_cidrs = [ + "198.18.17.3/32", + "198.18.13.32/32", + "198.18.13.33/32", + "198.18.13.34/32", + "198.18.13.46/32" + ] +} diff --git a/auth_approle_sshsigner.tf b/auth_approle_sshsigner.tf new file mode 100644 index 0000000..be770b6 --- /dev/null +++ b/auth_approle_sshsigner.tf @@ -0,0 +1,17 @@ +resource "vault_approle_auth_backend_role" "sshsigner" { + role_name = "sshsigner" + bind_secret_id = false + token_policies = [ + "sshsigner", + "sshca_signhost" + ] + token_ttl = 30 + token_max_ttl = 30 + token_bound_cidrs = [ + "198.18.17.3/32", + "198.18.13.32/32", + "198.18.13.33/32", + "198.18.13.34/32", + "198.18.13.46/32" + ] +} diff --git a/auth_backend_approle.tf b/auth_backend_approle.tf new file mode 100644 index 0000000..7c8412d --- /dev/null +++ b/auth_backend_approle.tf @@ -0,0 +1,7 @@ +#---------------------------- +# Enable approle auth method +#---------------------------- +resource "vault_auth_backend" "approle" { + type = "approle" + path = "approle" +} diff --git a/auth_backend_ldap.tf b/auth_backend_ldap.tf new file mode 100644 index 0000000..a49d979 --- /dev/null +++ b/auth_backend_ldap.tf @@ -0,0 +1,13 @@ +#-------------------------------- +# Enable ldap auth method +#-------------------------------- +resource "vault_ldap_auth_backend" "ldap" { + path = "ldap" + url = "ldap://ldap.query.consul" + userdn = "dc=main,dc=unkin,dc=net" + userattr = "uid" + upndomain = "main.unkin.net" + discoverdn = false + groupdn = "ou=groups,dc=main,dc=unkin,dc=net" + groupfilter = "(memberOf=ou=vault_access,ou=groups,dc=main,dc=unkin,dc=net)" +} diff --git a/engine_kv.tf b/engine_kv.tf new file mode 100644 index 0000000..5b1f11e --- /dev/null +++ b/engine_kv.tf @@ -0,0 +1,15 @@ +#-------------------------------------------------------------- +# kv +# create engine +#-------------------------------------------------------------- +resource "vault_mount" "kv" { + path = "kv" + type = "kv" + listing_visibility = "hidden" + max_lease_ttl_seconds = 0 + external_entropy_access = false + seal_wrap = false + options = { + version = "2" + } +} diff --git a/engine_pki_int.tf b/engine_pki_int.tf new file mode 100644 index 0000000..a2d5a54 --- /dev/null +++ b/engine_pki_int.tf @@ -0,0 +1,49 @@ +#-------------------------------------------------------------- +# pki_int +# create engine +# generate intermediate csa +# sign the intermediate against rootca +# set the signed intermediate cert in the pki_int engine +#-------------------------------------------------------------- +resource "vault_mount" "pki_int" { + path = "pki_int" + type = "pki" + description = "PKI Intermediate CA" + max_lease_ttl_seconds = 43800 * 3600 # 43800 hours +} + +## Generate the intermediate CSR +#resource "vault_pki_secret_backend_intermediate_cert_request" "pki_int_intermediate" { +# backend = vault_mount.pki_int.path +# common_name = "unkin.net Intermediate Authority" +# format = "pem" +# type = "internal" +#} +# +## Sign the intermediate CSR using the root CA +#resource "vault_generic_endpoint" "pki_root_sign_intermediate" { +# path = "${vault_mount.pki_root.path}/root/sign-intermediate" +# +# data_json = jsonencode({ +# csr = vault_pki_secret_backend_intermediate_cert_request.pki_int_intermediate.csr, +# format = "pem_bundle", +# ttl = "43800h", +# issuer_ref = "UNKIN_ROOTCA_2024" +# }) +#} +# +## Decode the certificate from the response +#locals { +# intermediate_signed_cert = vault_generic_endpoint.pki_root_sign_intermediate.write_data["certificate"] +#} +# +## Set the signed intermediate certificate +#resource "vault_pki_secret_backend_intermediate_set_signed" "pki_int_set_signed" { +# backend = vault_mount.pki_int.path +# certificate = local.intermediate_signed_cert +#} + +#data "vault_pki_secret_backend_issuer" "pki_int_issuer" { +# backend = vault_mount.pki_int.path +# issuer_ref = data.vault_pki_secret_backend_root_cert.root.issuer_id +#} diff --git a/engine_pki_root.tf b/engine_pki_root.tf new file mode 100644 index 0000000..576fd80 --- /dev/null +++ b/engine_pki_root.tf @@ -0,0 +1,39 @@ +#------------------------------------------- +# pki_root: +# create engine +# generate rootca certificate +# read the issuer +# configure the pki urls +#------------------------------------------- +resource "vault_mount" "pki_root" { + path = "pki_root" + type = "pki" + description = "PKI Root CA" + max_lease_ttl_seconds = 87600 * 3600 # 87600h +} + +#resource "vault_pki_secret_backend_root_cert" "pki_root_root_cert" { +# backend = vault_mount.pki_root.path +# common_name = "unkin.net" +# issuer_name = "UNKIN_ROOTCA_2024" +# ttl = 87600 * 3600 +# format = "pem" +# type = "internal" +#} +# +#output "root_certificate" { +# value = vault_pki_secret_backend_root_cert.pki_root_root_cert.certificate +# sensitive = true +#} + +data "vault_pki_secret_backend_issuer" "pki_root_issuer" { + backend = vault_mount.pki_root.path + issuer_ref = "default" +} + +resource "vault_pki_secret_backend_config_urls" "pki_root_urls" { + backend = vault_mount.pki_root.path + + issuing_certificates = ["${local.vault_addr}/v1/pki_root/ca"] + crl_distribution_points = ["${local.vault_addr}/v1/pki_root/crl"] +} diff --git a/engine_rundeck.tf b/engine_rundeck.tf new file mode 100644 index 0000000..b368c99 --- /dev/null +++ b/engine_rundeck.tf @@ -0,0 +1,14 @@ +#-------------------------------------------------------------- +# rundeck +# create engine +#-------------------------------------------------------------- +resource "vault_mount" "rundeck" { + path = "rundeck" + type = "kv" + max_lease_ttl_seconds = 0 + external_entropy_access = false + seal_wrap = false + options = { + version = "2" + } +} diff --git a/engine_ssh-host-signer.tf b/engine_ssh-host-signer.tf new file mode 100644 index 0000000..c64de19 --- /dev/null +++ b/engine_ssh-host-signer.tf @@ -0,0 +1,18 @@ +#-------------------------------------------------------------- +# ssh-host-signer +# create engine +# generate ca cert +# tune the ssh engine +#-------------------------------------------------------------- +#resource "vault_mount" "ssh_host_signer" { +# path = "ssh-host-signer" +# type = "ssh" +# description = "SSH Host Signing Engine" +# max_lease_ttl_seconds = 87600 * 3600 +#} +# +#resource "vault_ssh_secret_backend_ca" "ssh_host_signer_ca" { +# backend = vault_mount.ssh_host_signer.path +# generate_signing_key = false # change to true for new configuration +# key_type = "ssh-rsa" +#} diff --git a/engine_sshca.tf b/engine_sshca.tf new file mode 100644 index 0000000..8fdb483 --- /dev/null +++ b/engine_sshca.tf @@ -0,0 +1,18 @@ +#-------------------------------------------------------------- +# ssh +# create engine +# generate ca cert +# tune the ssh engine +#-------------------------------------------------------------- +resource "vault_mount" "sshca" { + path = "sshca" + type = "ssh" + description = "SSH CA Engine" + max_lease_ttl_seconds = 87600 * 3600 +} + +resource "vault_ssh_secret_backend_ca" "ssh_ca" { + backend = vault_mount.sshca.path + generate_signing_key = true + key_type = "ssh-rsa" +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..7b97e02 --- /dev/null +++ b/main.tf @@ -0,0 +1,31 @@ +#------------------------------------------- +# locals +#------------------------------------------- +locals { + vault_addr = "https://vault.service.consul:8200" +} + + +#----------------------------------------------------------------------------- +# Configure this provider through the environment variables: +# - VAULT_ADDR +# - VAULT_TOKEN +#----------------------------------------------------------------------------- +provider "vault" { + address = local.vault_addr +} + +#------------------------------------------------------------------------------ +# Use remote state file and encrypt it since your state files may contains +# sensitive data. +# export CONSUL_HTTP_TOKEN= +#------------------------------------------------------------------------------ +terraform { + backend "consul" { + address = "https://consul.service.consul" + path = "infra/terraform/state" + scheme = "https" + lock = true + ca_file = "/etc/pki/tls/certs/ca-bundle.crt" + } +} diff --git a/policies.tf b/policies.tf new file mode 100644 index 0000000..29700e4 --- /dev/null +++ b/policies.tf @@ -0,0 +1,31 @@ +# Define directories for different policy sets +locals { + policy_directories = { + pki_int = "policies/pki_int" + pki_root = "policies/pki_root" + rundeck = "policies/rundeck" + ssh_host_signer = "policies/ssh-host-signer" + sshca = "policies/sshca" + } +} + +# Load policy files from each directory +locals { + policy_files = flatten([ + for dir, path in local.policy_directories : [ + for policy in fileset(path, "*.hcl") : { + name = trim(replace(policy, ".hcl", ""), "/") + path = "${path}/${policy}" + } + ] + ]) +} + +# Define vault policies for all sets +resource "vault_policy" "policies" { + for_each = { for policy in local.policy_files : policy.name => policy } + + name = each.value.name + policy = file(each.value.path) +} + diff --git a/policies/pki_int/certmanager.hcl b/policies/pki_int/certmanager.hcl new file mode 100644 index 0000000..c1b38d5 --- /dev/null +++ b/policies/pki_int/certmanager.hcl @@ -0,0 +1,9 @@ +path "pki_int/issue/*" { + capabilities = ["create", "update", "read"] +} +path "pki_int/renew/*" { + capabilities = ["update"] +} +path "pki_int/cert/*" { + capabilities = ["read"] +} diff --git a/policies/rundeck/rundeck.hcl b/policies/rundeck/rundeck.hcl new file mode 100644 index 0000000..ea4c523 --- /dev/null +++ b/policies/rundeck/rundeck.hcl @@ -0,0 +1,7 @@ +path "rundeck/data/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} + +path "rundeck/metadata/*" { + capabilities = ["list"] +} diff --git a/policies/ssh-host-signer/sshsign-host-policy.hcl b/policies/ssh-host-signer/sshsign-host-policy.hcl new file mode 100644 index 0000000..5127e62 --- /dev/null +++ b/policies/ssh-host-signer/sshsign-host-policy.hcl @@ -0,0 +1,3 @@ +path "ssh-host-signer/sign/hostrole" { + capabilities = ["create", "update"] +} diff --git a/policies/ssh-host-signer/sshsigner.hcl b/policies/ssh-host-signer/sshsigner.hcl new file mode 100644 index 0000000..5127e62 --- /dev/null +++ b/policies/ssh-host-signer/sshsigner.hcl @@ -0,0 +1,3 @@ +path "ssh-host-signer/sign/hostrole" { + capabilities = ["create", "update"] +} diff --git a/policies/sshca/sshca_signhost.hcl b/policies/sshca/sshca_signhost.hcl new file mode 100644 index 0000000..58b104b --- /dev/null +++ b/policies/sshca/sshca_signhost.hcl @@ -0,0 +1,3 @@ +path "sshca/sign/host" { + capabilities = ["create", "update"] +} diff --git a/policies/sshca/sshca_signuser.hcl b/policies/sshca/sshca_signuser.hcl new file mode 100644 index 0000000..6450b2c --- /dev/null +++ b/policies/sshca/sshca_signuser.hcl @@ -0,0 +1,3 @@ +path "sshca/sign/user" { + capabilities = ["create", "update"] +} diff --git a/role_pki_int_servers_default.tf b/role_pki_int_servers_default.tf new file mode 100644 index 0000000..ce0ea8c --- /dev/null +++ b/role_pki_int_servers_default.tf @@ -0,0 +1,15 @@ +resource "vault_pki_secret_backend_role" "servers_default" { + backend = "pki_int" + name = "servers_default" + #issuer_ref = data.vault_pki_secret_backend_issuer.pki_int_issuer.default + allow_ip_sans = true + allowed_domains = ["unkin.net", "*.unkin.net", "localhost"] + allow_subdomains = true + allow_glob_domains = true + allow_bare_domains = true + enforce_hostnames = true + allow_any_name = true + max_ttl = 2160 * 3600 + key_bits = 4096 + country = ["Australia"] +} diff --git a/role_pki_root_2024_servers.tf b/role_pki_root_2024_servers.tf new file mode 100644 index 0000000..6e2975b --- /dev/null +++ b/role_pki_root_2024_servers.tf @@ -0,0 +1,6 @@ +resource "vault_pki_secret_backend_role" "pki_root_2024_servers" { + backend = vault_mount.pki_root.path + name = "2024-servers" + issuer_ref = data.vault_pki_secret_backend_issuer.pki_root_issuer.issuer_ref + allow_any_name = true +} diff --git a/role_ssh-host-signer_hostrole.tf b/role_ssh-host-signer_hostrole.tf new file mode 100644 index 0000000..71ff4db --- /dev/null +++ b/role_ssh-host-signer_hostrole.tf @@ -0,0 +1,11 @@ +resource "vault_ssh_secret_backend_role" "hostrole" { + backend = "ssh-host-signer" + name = "hostrole" + key_type = "ca" + algorithm_signer = "rsa-sha2-256" + ttl = 87600 * 3600 + allow_host_certificates = true + allowed_domains = "*" + allow_subdomains = true + allow_bare_domains = false +} diff --git a/role_sshca_signhost.tf b/role_sshca_signhost.tf new file mode 100644 index 0000000..1b4dd3b --- /dev/null +++ b/role_sshca_signhost.tf @@ -0,0 +1,12 @@ +resource "vault_ssh_secret_backend_role" "sshca_signhost" { + backend = vault_mount.sshca.path + name = "sshca_signhost" + key_type = "ca" + algorithm_signer = "rsa-sha2-256" + ttl = 87600 * 3600 + allow_host_certificates = true + allow_subdomains = true + allow_bare_domains = false + allowed_domains = "main.unkin.net,consul" +} +