tfmodules/hpc/ovh/credentials.tf

85 lines
2.9 KiB
HCL

// Consumer and management credentials are generated here, never injected by
// the backend. The consumer password opens SSH on the head node only (the
// single entry point); the management keypair opens every node. The Vault
// layout follows the existing contract:
// secret/{provider}/{cloud_account}/{requester_unique_id}/{username} password + head node access
// secret/{provider}/{cloud_account}/{requester_unique_id}/admin ssh keypair + admin username
// Only the Vault path of the consumer entry is exposed as an output.
resource "random_bytes" "munge_key" {
length = 128
}
resource "tls_private_key" "admin" {
algorithm = "ED25519"
}
// Regenerated whenever the rotation marker changes; the special set avoids
// shell quoting issues in the password application command.
resource "random_password" "consumer" {
length = 24
special = true
override_special = "-_=+"
keepers = {
rotation = var.credentials_version
}
}
// Applies the consumer password on the head node, on day 0 and on every
// rotation. The password never travels through user data, so a rotation
// never touches the instances: this resource is replaced (triggered by the
// rotation marker), re-runs chpasswd over SSH with the management key, and
// the Vault entry below is updated in the same apply.
// null_resource instead of terraform_data: the tofu-controller runner ships a
// Terraform older than 1.4, which has no terraform_data built-in.
resource "null_resource" "consumer_password" {
// Re-applied on rotation AND whenever the head node is recreated: a fresh
// instance boots without the consumer password (it never travels through
// user data).
triggers = {
rotation = var.credentials_version
head_node = ovh_cloud_project_instance.head.id
}
connection {
type = "ssh"
host = local.head_public_ip
user = var.admin_username
private_key = tls_private_key.admin.private_key_openssh
timeout = "15m"
}
provisioner "remote-exec" {
inline = [
"cloud-init status --wait > /dev/null || true",
"echo '${var.username}:${random_password.consumer.result}' | sudo chpasswd",
]
}
depends_on = [ovh_cloud_project_instance.head]
}
resource "vault_kv_secret_v2" "consumer" {
mount = "secret"
name = "ovh/${var.cloud_account}/${var.requester_unique_id}/${var.username}"
data_json = jsonencode({
username = var.username
password = random_password.consumer.result
host = local.head_public_ip
port = 22
})
depends_on = [null_resource.consumer_password]
}
resource "vault_kv_secret_v2" "admin" {
mount = "secret"
name = "ovh/${var.cloud_account}/${var.requester_unique_id}/admin"
data_json = jsonencode({
username = var.admin_username
ssh_private_key = tls_private_key.admin.private_key_openssh
ssh_public_key = trimspace(tls_private_key.admin.public_key_openssh)
})
}