From 93ab6a38d8522a1c2acc4137b2f4c6f91ff1e212 Mon Sep 17 00:00:00 2001 From: Steve Brasier Date: Thu, 16 Jan 2025 17:47:48 +0000 Subject: [PATCH 1/5] read k3s_secret from secrets.yml --- .../terraform/compute.tf | 2 +- .../terraform/nodes.tf | 4 +- .../terraform/read-inventory-secrets.py | 45 +++++++++++++++++++ .../terraform/variables.tf | 21 +++++++-- 4 files changed, 65 insertions(+), 7 deletions(-) create mode 100755 environments/skeleton/{{cookiecutter.environment}}/terraform/read-inventory-secrets.py diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf index a90108924..baf28aaf9 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf @@ -24,7 +24,7 @@ module "compute" { key_pair = var.key_pair environment_root = var.environment_root - k3s_token = var.k3s_token + k3s_token = local.k3s_token control_address = [for n in openstack_compute_instance_v2.control["control"].network: n.fixed_ip_v4 if n.access_network][0] security_group_ids = [for o in data.openstack_networking_secgroup_v2.nonlogin: o.id] } diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf index 8ea8cabcb..c374eb2d1 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf @@ -76,7 +76,7 @@ resource "openstack_compute_instance_v2" "control" { metadata = { environment_root = var.environment_root - k3s_token = var.k3s_token + k3s_token = local.k3s_token } user_data = <<-EOF @@ -125,7 +125,7 @@ resource "openstack_compute_instance_v2" "login" { metadata = { environment_root = var.environment_root - k3s_token = var.k3s_token + k3s_token = local.k3s_token control_address = [for n in openstack_compute_instance_v2.control["control"].network: n.fixed_ip_v4 if n.access_network][0] } diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/read-inventory-secrets.py b/environments/skeleton/{{cookiecutter.environment}}/terraform/read-inventory-secrets.py new file mode 100755 index 000000000..e3de2f492 --- /dev/null +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/read-inventory-secrets.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +""" opentofu external data program to load inventory string variables from + a (possibly vault-encrypted) secrets file. + + Example usage: + + data "external" "example" { + program = [this_file] + + query = { + path = "${path.module}/../inventory/group_vars/all/secrets.yml" + } + } + + The external data resource's result attribute then contains a mapping of + variable names to values. + + NB: Only keys/values where values are strings are returned, in line with + the external program protocol. + + NB: This approach is better than e.g. templating inventory vars as the + inventory doesn't need to be valid, which is helpful when opentofu will + template out hosts/groups. +""" + +import sys, json, subprocess, yaml +input = sys.stdin.read() +secrets_path = json.loads(input)['path'] + +with open(secrets_path) as f: + header = f.readline() + if header.startswith('$ANSIBLE_VAULT'): + cmd = ['ansible-vault', 'view', secrets_path] + ansible = subprocess.run(cmd, capture_output=True, text=True) + contents = ansible.stdout + else: + contents = f.read() + +data = yaml.safe_load(contents) + +output = {} +for k, v in data.items(): + if isinstance(v, str): + output[k] = v +print(json.dumps(output)) diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf index bdffd40ce..7b0b695d3 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf @@ -140,7 +140,20 @@ variable "root_volume_size" { default = 40 } -variable "k3s_token" { - description = "K3s cluster authentication token, set automatically by Ansible" - type = string -} \ No newline at end of file +variable "inventory_secrets_path" { + description = "Path to inventory secrets.yml file. Default is standard cookiecutter location." + type = string + default = "" +} + +data "external" "inventory_secrets" { + program = ["${path.module}/read-inventory-secrets.py"] + + query = { + path = var.inventory_secrets_path == "" ? "${path.module}/../inventory/group_vars/all/secrets.yml" : var.inventory_secrets_path + } +} + +locals { + k3s_token = data.external.inventory_secrets.result["vault_k3s_token"] +} From d3d9cd8f19dea83e53035f164f0e9365f76b3b75 Mon Sep 17 00:00:00 2001 From: Steve Brasier Date: Thu, 16 Jan 2025 17:49:42 +0000 Subject: [PATCH 2/5] override secrets path for stackhpc terraform --- environments/.stackhpc/terraform/main.tf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/environments/.stackhpc/terraform/main.tf b/environments/.stackhpc/terraform/main.tf index 872003db3..6d222557a 100644 --- a/environments/.stackhpc/terraform/main.tf +++ b/environments/.stackhpc/terraform/main.tf @@ -73,7 +73,9 @@ module "cluster" { key_pair = "slurm-app-ci" cluster_image_id = data.openstack_images_image_v2.cluster.id control_node_flavor = var.control_node_flavor - k3s_token = var.k3s_token + # need to override defaults as using terraform/ as a module but secrets templated + # out to *this* environment + inventory_secrets_path = "${path.module}/../inventory/group_vars/all/secrets.yml" login_nodes = { login-0: var.other_node_flavor From 6fab7f51cbc86ce5f2d363ec56ab6a7e3711bf0f Mon Sep 17 00:00:00 2001 From: Steve Brasier Date: Thu, 16 Jan 2025 17:53:11 +0000 Subject: [PATCH 3/5] remove templating of k3s_secret to terraform dir --- ansible/roles/passwords/tasks/main.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ansible/roles/passwords/tasks/main.yml b/ansible/roles/passwords/tasks/main.yml index d67dc84ea..743a6cda8 100644 --- a/ansible/roles/passwords/tasks/main.yml +++ b/ansible/roles/passwords/tasks/main.yml @@ -6,15 +6,3 @@ dest: "{{ openhpc_passwords_output_path }}" delegate_to: localhost run_once: true - -- name: Get templated passwords from target environment -# inventory group/host vars created in a play cannot be accessed in the same play, even after meta: refresh_inventory - ansible.builtin.include_vars: - file: "{{ openhpc_passwords_output_path }}" - -- name: Template k3s token to terraform - template: - src: k3s-token.auto.tfvars.json.j2 - dest: "{{ lookup('env', 'APPLIANCES_ENVIRONMENT_ROOT') }}/terraform/k3s-token.auto.tfvars.json" - delegate_to: localhost - run_once: true From 575f8d90d07e0fa5ea18a51080f5a94e29e9682e Mon Sep 17 00:00:00 2001 From: Steve Brasier Date: Thu, 16 Jan 2025 18:02:56 +0000 Subject: [PATCH 4/5] remove k3s_secret var from stackhpc env --- environments/.stackhpc/terraform/main.tf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/environments/.stackhpc/terraform/main.tf b/environments/.stackhpc/terraform/main.tf index 6d222557a..b48fb74d8 100644 --- a/environments/.stackhpc/terraform/main.tf +++ b/environments/.stackhpc/terraform/main.tf @@ -54,10 +54,6 @@ variable "volume_backed_instances" { default = false } -variable "k3s_token" { - type = string -} - data "openstack_images_image_v2" "cluster" { name = var.cluster_image[var.os_version] most_recent = true From aa935725289e4037d9b4b671e7e796093f57d8ce Mon Sep 17 00:00:00 2001 From: Steve Brasier Date: Fri, 17 Jan 2025 10:41:40 +0000 Subject: [PATCH 5/5] clarify stackhpc override for tf secrets in stackhpc --- environments/.stackhpc/terraform/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/environments/.stackhpc/terraform/main.tf b/environments/.stackhpc/terraform/main.tf index b48fb74d8..9a295e160 100644 --- a/environments/.stackhpc/terraform/main.tf +++ b/environments/.stackhpc/terraform/main.tf @@ -69,8 +69,8 @@ module "cluster" { key_pair = "slurm-app-ci" cluster_image_id = data.openstack_images_image_v2.cluster.id control_node_flavor = var.control_node_flavor - # need to override defaults as using terraform/ as a module but secrets templated - # out to *this* environment + # have to override default, as unusually the actual module path and secrets + # are not in the same environment for stackhpc inventory_secrets_path = "${path.module}/../inventory/group_vars/all/secrets.yml" login_nodes = {