Add dynamic ansible inventory from terraform state

This commit is contained in:
Tobias Reisinger 2025-08-10 14:58:54 +02:00
parent bccc07f806
commit 70578f2a13
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
11 changed files with 84 additions and 51 deletions

23
.terraform.lock.hcl generated
View file

@ -21,6 +21,29 @@ provider "registry.opentofu.org/aminueza/minio" {
] ]
} }
provider "registry.opentofu.org/ansible/ansible" {
version = "1.2.0"
constraints = "1.2.0"
hashes = [
"h1:+FFI791dQLSgrP3ldRPckp6kKHKPByGlZnZHSKEIk9M=",
"zh:06ec85f5c8809eebd7049846d3a45e5c4d052f021fd0a93681d72da8db18f03c",
"zh:13a289fbc8ba46b4a81aae5548d0f4b7c772e60b5597493be1a2f36f1642252f",
"zh:1e345d4dd6cdff194c5878a986d00494dfe4d51e5f05a85fa37243acada4ac98",
"zh:3bfc27e99ae4d4ad073f89655e88d545a043f395581fe6d30f9d2ddea98de8bc",
"zh:45798319359ac89c70fc474a8cf11888b7f4281e591fc41892a55449740aa170",
"zh:578b8b3f58f2a368bbb1326f16a14a7ff4f701a00f1123deffd1de751f9c2e28",
"zh:6160b0e5728e7fc905e1b17671fb0df74483c477d0262a6c1e51c89d48afe71f",
"zh:98961ef4beb153d15742dafc1a0428bf45323e979f4b4a82a4ec4062205a0782",
"zh:a26d76f427058ec529436bf8fbe96bf6cd4e0a29275d7a6add0d3357517e0d43",
"zh:a70366e2e21ed51d26e7797b3679db3d812e3458e7980e906934e78599461f02",
"zh:a9829a90cd302789dc277a1be55ddaff83e702159dd4a05646cedd17b5c337b9",
"zh:beb105f90d9a9d7821f533bee8ccddc9daed7c3a59646e5b3777ba62253f84f1",
"zh:bf8db622d0cb848bc843d29187b747388d73d520ee10814424fdf79693ea15d5",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
"zh:f6c47554e1e98d71dc1ca5fbb569db198f71c13b4a1375454839b44e90a91926",
]
}
provider "registry.opentofu.org/cyrilgdn/postgresql" { provider "registry.opentofu.org/cyrilgdn/postgresql" {
version = "1.23.0" version = "1.23.0"
constraints = "~> 1.23" constraints = "~> 1.23"

3
inventory/opentofu.yml Normal file
View file

@ -0,0 +1,3 @@
plugin: cloud.terraform.terraform_provider
project_path: .
binary_path: tofu

View file

@ -1,35 +0,0 @@
all:
children:
serguzim_net:
hosts:
node001:
node003:
hosts:
local-dev:
ansible_connection: local
node001:
ansible_host: "{{ opentofu.hosts.node001.fqdn_vpn }}"
ansible_port: "{{ vault_hosts.node001.ansible_port }}"
ansible_user: "{{ vault_hosts.node001.ansible_user }}"
interactive_user: "{{ vault_hosts.node001.interactive_user }}"
host_vpn:
domain: "{{ opentofu.hosts.node001.fqdn_vpn }}"
ip: "{{ opentofu.hosts.node001.ipv4_address_vpn }}"
host_backup:
hc_uid: "{{ opentofu.healthchecksio.backup.node001.id }}"
hc_url: "{{ opentofu.healthchecksio.backup.node001.ping_url }}"
gatus_token: "{{ vault_hosts.node001.backup.gatus_token }}"
node003:
ansible_host: "{{ opentofu.hosts.node003.fqdn_vpn }}"
ansible_port: "{{ vault_hosts.node003.ansible_port }}"
ansible_user: "{{ vault_hosts.node003.ansible_user }}"
interactive_user: "{{ vault_hosts.node003.interactive_user }}"
host_vpn:
domain: "{{ opentofu.hosts.node003.fqdn_vpn }}"
ip: "{{ opentofu.hosts.node003.ipv4_address_vpn }}"
host_backup:
hc_uid: "{{ opentofu.healthchecksio.backup.node003.id }}"
hc_url: "{{ opentofu.healthchecksio.backup.node003.ping_url }}"
gatus_token: "{{ vault_hosts.node003.backup.gatus_token }}"

34
main.tf
View file

@ -1,5 +1,10 @@
terraform { terraform {
required_providers { required_providers {
ansible = {
source = "ansible/ansible"
version = "1.2.0"
}
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 5.0" version = "~> 5.0"
@ -158,3 +163,32 @@ module "services" {
services = var.services services = var.services
} }
resource "random_password" "host_backup_gatus_tokens" {
for_each = module.infrastructure.hosts
length = 32
special = false
}
resource "ansible_host" "nodes" {
for_each = module.infrastructure.hosts
name = each.value.hostname
groups = ["serguzim_net"]
variables = {
# Connection vars.
ansible_host = each.value.fqdn_vpn
ansible_port = 17
ansible_user = "ansible"
# Custom vars that we might use in roles/tasks.
host_vpn_domain = each.value.fqdn_vpn
host_vpn_ip = each.value.ipv4_address_vpn
host_backup_hc_uid = module.infrastructure.healthchecksio.backup[each.key].id
host_backup_hc_url = module.infrastructure.healthchecksio.backup[each.key].ping_url
host_backup_gatus_token = random_password.host_backup_gatus_tokens[each.key].result
}
}

View file

@ -2,13 +2,17 @@
- name: Change password - name: Change password
hosts: all hosts: all
become: true become: true
vars_prompt:
- name: name
prompt: User
private: false
- name: password
prompt: Password
encrypt: sha512_crypt
confirm: true
salt_size: 7
tasks: tasks:
- name: Get new password
ansible.builtin.pause:
prompt: Enter the new password
echo: false
register: new_user_password
- name: Change password - name: Change password
ansible.builtin.user: ansible.builtin.user:
name: "{{ interactive_user }}" name: "{{ user }}"
password: "{{ new_user_password.user_input | password_hash('sha512') }}" password: "{{ password }}"

View file

@ -31,13 +31,15 @@ class FilterModule(object):
}) })
return result return result
def vault_hosts_backup_to_gatus(self, hosts): def vault_hosts_backup_to_gatus(self, hostvars):
result = [] result = []
for name, host_data in hosts.items(): for name, host_data in hostvars.items():
if not host_data.get("host_backup_gatus_token"):
continue
result.append({ result.append({
"name": f"backup@{name}", "name": f"backup@{name}",
"group": "8-backups", "group": "8-backups",
"token": host_data["backup"]["gatus_token"], "token": host_data["host_backup_gatus_token"],
"alerts": self.default_alerts, "alerts": self.default_alerts,
}) })
return result return result

View file

@ -9,8 +9,8 @@ backup_msg_success: "Backup successful"
backup_curl_base: 'curl -L -m 10 --retry 5' backup_curl_base: 'curl -L -m 10 --retry 5'
backup_hc_curl_base: '{{ backup_curl_base }} -X POST -H "Content-Type: text/plain"' backup_hc_curl_base: '{{ backup_curl_base }} -X POST -H "Content-Type: text/plain"'
backup_gatus_curl_base: '{{ backup_curl_base }} -X POST -H "Authorization: Bearer {{ host_backup.gatus_token }}"' backup_gatus_curl_base: '{{ backup_curl_base }} -X POST -H "Authorization: Bearer {{ host_backup_gatus_token }}"'
backup_hc_url: '{{ host_backup.hc_url }}' backup_hc_url: '{{ host_backup_hc_url }}'
backup_gatus_url: 'https://status.serguzim.me/api/v1/endpoints/8-backups_backup@{{ ansible_facts.hostname }}/external' backup_gatus_url: 'https://status.serguzim.me/api/v1/endpoints/8-backups_backup@{{ ansible_facts.hostname }}/external'
backup_hc_command_start: '{{ backup_hc_curl_base }} --data "{{ backup_msg_start }}" {{ backup_hc_url }}/start' backup_hc_command_start: '{{ backup_hc_curl_base }} --data "{{ backup_msg_start }}" {{ backup_hc_url }}/start'

View file

@ -10,7 +10,7 @@
import /etc/caddy/snippets import /etc/caddy/snippets
http://{{ host_vpn.domain }} { http://{{ host_vpn_domain }} {
import vpn_only import vpn_only
metrics metrics

View file

@ -3,7 +3,7 @@ gatus_svc:
domain: "{{ all_services | service_get_domain(role_name) }}" domain: "{{ all_services | service_get_domain(role_name) }}"
port: 8080 port: 8080
gatus_external_endpoints_backups: "{{ vault_hosts | vault_hosts_backup_to_gatus() }}" gatus_external_endpoints_backups: "{{ hostvars | vault_hosts_backup_to_gatus() }}"
gatus_endpoints_hosts: "{{ opentofu.hosts | hosts_to_gatus() }}" gatus_endpoints_hosts: "{{ opentofu.hosts | hosts_to_gatus() }}"
gatus_endpoints_services: "{{ all_services | services_to_gatus() }}" gatus_endpoints_services: "{{ all_services | services_to_gatus() }}"

View file

@ -1,2 +1,4 @@
collections: collections:
- name: prometheus.prometheus - name: prometheus.prometheus
- name: cloud.terraform
version: 4.0.0

View file

@ -102,9 +102,9 @@ if __name__ == '__main__':
services = {} services = {}
with open('./hosts.auto.tfvars', 'r') as file: with open('./hosts.auto.tfvars', 'r') as file:
hosts = hcl2.load(file)["hosts"][0] hosts = hcl2.load(file)["hosts"]
with open('./services.auto.tfvars', 'r') as file: with open('./services.auto.tfvars', 'r') as file:
services = hcl2.load(file)["services"][0] services = hcl2.load(file)["services"]
keys = {} keys = {}
keys["db_key"] = service_key_find("postgresql", services, hosts) keys["db_key"] = service_key_find("postgresql", services, hosts)