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 diff --git a/environments/.stackhpc/terraform/main.tf b/environments/.stackhpc/terraform/main.tf index 872003db3..9a295e160 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 @@ -73,7 +69,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 + # 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 = { login-0: var.other_node_flavor 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"] +}