Re: [PATCH v1 6/6] terraform: Use the alternate ssh port for Ansible control
Chuck Lever <[email protected]> Thu, 2 Oct 2025 16:25:34 -0400
| Newsgroups | dev.linux.lists.kdevops |
|---|---|
| Message-ID | <[email protected]> |
On 10/2/25 4:21 PM, Chuck Lever wrote: > From: Chuck Lever <[email protected]> > > When provisioning guestfs instances, make use of the Ansible ssh Ooops. Copy-pasta : should be "When provisioning terraform guests," > port setting, in case it is set to something other than port 22. > > Generated-by: Claude AI > Signed-off-by: Chuck Lever <[email protected]> > --- > .../templates/aws/terraform.tfvars.j2 | 1 + > .../templates/azure/terraform.tfvars.j2 | 1 + > .../templates/gce/terraform.tfvars.j2 | 1 + > .../templates/lambdalabs/terraform.tfvars.j2 | 1 + > .../templates/oci/terraform.tfvars.j2 | 1 + > .../templates/openstack/terraform.tfvars.j2 | 1 + > .../roles/terraform/templates/ssh_config.j2 | 2 +- > scripts/update_ssh_config_lambdalabs.py | 18 ++++++-- > terraform/aws/main.tf | 5 ++- > terraform/azure/main.tf | 9 +++- > terraform/gce/main.tf | 23 +++++++++- > terraform/lambdalabs/main.tf | 43 +++++++++++++++++- > terraform/oci/main.tf | 11 ++++- > terraform/openstack/main.tf | 11 ++++- > terraform/scripts/cloud-init.sh | 44 ++++++++++++++++++- > terraform/shared.tf | 6 +++ > 16 files changed, 162 insertions(+), 16 deletions(-) > > diff --git a/playbooks/roles/gen_tfvars/templates/aws/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/aws/terraform.tfvars.j2 > index 4b20667f0686..fc9c94441ded 100644 > --- a/playbooks/roles/gen_tfvars/templates/aws/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/aws/terraform.tfvars.j2 > @@ -18,6 +18,7 @@ aws_ebs_volume_throughput = {{ terraform_aws_ebs_volume_throughput }} > ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > > ssh_config_update = "{{ kdevops_terraform_ssh_config_update | lower }}" > ssh_config_use_strict_settings = "{{ kdevops_terraform_ssh_config_update_strict | lower }}" > diff --git a/playbooks/roles/gen_tfvars/templates/azure/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/azure/terraform.tfvars.j2 > index 7ce0f6170e22..9c3ac0a0f7f6 100644 > --- a/playbooks/roles/gen_tfvars/templates/azure/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/azure/terraform.tfvars.j2 > @@ -13,6 +13,7 @@ azure_managed_disks_tier = "{{ terraform_azure_managed_disks_tier }}" > ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > > ssh_config_update = "{{ kdevops_terraform_ssh_config_update | lower }}" > ssh_config_use_strict_settings = "{{ kdevops_terraform_ssh_config_update_strict | lower }}" > diff --git a/playbooks/roles/gen_tfvars/templates/gce/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/gce/terraform.tfvars.j2 > index c6093aeff634..950e12b786fb 100644 > --- a/playbooks/roles/gen_tfvars/templates/gce/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/gce/terraform.tfvars.j2 > @@ -20,6 +20,7 @@ gce_disk_throughput = {{ terraform_gce_disk_throughput }} > ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > > ssh_config_update = "{{ kdevops_terraform_ssh_config_update | lower }}" > ssh_config_use_strict_settings = "{{ kdevops_terraform_ssh_config_update_strict | lower }}" > diff --git a/playbooks/roles/gen_tfvars/templates/lambdalabs/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/lambdalabs/terraform.tfvars.j2 > index 4fd8cad634aa..a4ba26fc1d7e 100644 > --- a/playbooks/roles/gen_tfvars/templates/lambdalabs/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/lambdalabs/terraform.tfvars.j2 > @@ -7,6 +7,7 @@ ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_privkey_file = "{{ kdevops_terraform_ssh_config_privkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > # Use unique SSH config file per directory to avoid conflicts > ssh_config_name = "{{ kdevops_ssh_config_prefix }}{{ topdir_path_sha256sum[:8] }}" > > diff --git a/playbooks/roles/gen_tfvars/templates/oci/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/oci/terraform.tfvars.j2 > index 0839bfacfb24..5f3ceed19b9a 100644 > --- a/playbooks/roles/gen_tfvars/templates/oci/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/oci/terraform.tfvars.j2 > @@ -25,6 +25,7 @@ oci_sparse_volume_device_file_name = "{{ terraform_oci_sparse_volume_device_file > ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > > ssh_config_update = "{{ kdevops_terraform_ssh_config_update | lower }}" > ssh_config_use_strict_settings = "{{ kdevops_terraform_ssh_config_update_strict | lower }}" > diff --git a/playbooks/roles/gen_tfvars/templates/openstack/terraform.tfvars.j2 b/playbooks/roles/gen_tfvars/templates/openstack/terraform.tfvars.j2 > index 3df0e3a4da24..a50468072e59 100644 > --- a/playbooks/roles/gen_tfvars/templates/openstack/terraform.tfvars.j2 > +++ b/playbooks/roles/gen_tfvars/templates/openstack/terraform.tfvars.j2 > @@ -7,6 +7,7 @@ ssh_pubkey_name = "{{ terraform_openstack_ssh_pubkey_name }}" > ssh_config_pubkey_file = "{{ kdevops_terraform_ssh_config_pubkey_file }}" > ssh_config_user = "{{ kdevops_terraform_ssh_config_user }}" > ssh_config = "{{ sshconfig }}" > +ssh_config_port = {{ ansible_cfg_ssh_port }} > > ssh_config_update = "{{ kdevops_terraform_ssh_config_update | lower }}" > ssh_config_use_strict_settings = "{{ kdevops_terraform_ssh_config_update_strict | lower }}" > diff --git a/playbooks/roles/terraform/templates/ssh_config.j2 b/playbooks/roles/terraform/templates/ssh_config.j2 > index 5e8adf0253a1..ba62a2209d4c 100644 > --- a/playbooks/roles/terraform/templates/ssh_config.j2 > +++ b/playbooks/roles/terraform/templates/ssh_config.j2 > @@ -1,7 +1,7 @@ > Host {{ item.key }} {{ item.value }} > HostName {{ item.value }} > User {{ kdevops_terraform_ssh_config_user }} > - Port 22 > + Port {{ ansible_cfg_ssh_port }} > IdentityFile {{ kdevops_terraform_ssh_config_privkey_file }} > {% if ssh_config_kexalgorithms %} > KexAlgorithms {{ ssh_config_kexalgorithms }} > diff --git a/scripts/update_ssh_config_lambdalabs.py b/scripts/update_ssh_config_lambdalabs.py > index 5b9ab0aa82e6..265f85c2315b 100755 > --- a/scripts/update_ssh_config_lambdalabs.py > +++ b/scripts/update_ssh_config_lambdalabs.py > @@ -11,7 +11,7 @@ from pathlib import Path > > > def update_ssh_config( > - action, hostname, ip_address, username, config_file, ssh_key, provider_name > + action, hostname, ip_address, username, config_file, ssh_key, provider_name, port=22 > ): > """ > Update SSH configuration file with Lambda Labs instance details. > @@ -24,6 +24,7 @@ def update_ssh_config( > config_file: SSH config file path > ssh_key: Path to SSH private key > provider_name: Provider name for comments > + port: SSH port number (default: 22) > """ > config_file = os.path.expanduser(config_file) > ssh_key = os.path.expanduser(ssh_key) > @@ -33,7 +34,7 @@ def update_ssh_config( > Host {hostname} {ip_address} > \tHostName {ip_address} > \tUser {username} > -\tPort 22 > +\tPort {port} > \tIdentityFile {ssh_key} > \tUserKnownHostsFile /dev/null > \tStrictHostKeyChecking no > @@ -90,7 +91,7 @@ def main(): > """Main entry point.""" > if len(sys.argv) < 7: > print( > - f"Usage: {sys.argv[0]} <action> <hostname> <ip_address> <username> <config_file> <ssh_key> [provider_name]" > + f"Usage: {sys.argv[0]} <action> <hostname> <ip_address> <username> <config_file> <ssh_key> [provider_name] [port]" > ) > print(" action: 'update' or 'remove'") > print(" hostname: Instance hostname") > @@ -99,6 +100,7 @@ def main(): > print(" config_file: SSH config file path") > print(" ssh_key: Path to SSH private key") > print(" provider_name: Optional provider name (default: 'Lambda Labs')") > + print(" port: Optional SSH port (default: 22)") > sys.exit(1) > > action = sys.argv[1] > @@ -108,9 +110,17 @@ def main(): > config_file = sys.argv[5] > ssh_key = sys.argv[6] > provider_name = sys.argv[7] if len(sys.argv) > 7 else "Lambda Labs" > + port = int(sys.argv[8]) if len(sys.argv) > 8 else 22 > > update_ssh_config( > - action, hostname, ip_address, username, config_file, ssh_key, provider_name > + action, > + hostname, > + ip_address, > + username, > + config_file, > + ssh_key, > + provider_name, > + port, > ) > > > diff --git a/terraform/aws/main.tf b/terraform/aws/main.tf > index 949b2febcf0a..0de2e53710cb 100644 > --- a/terraform/aws/main.tf > +++ b/terraform/aws/main.tf > @@ -39,8 +39,8 @@ resource "aws_security_group" "kdevops_sec_group" { > cidr_blocks = [ > "0.0.0.0/0", > ] > - from_port = 22 > - to_port = 22 > + from_port = var.ssh_config_port > + to_port = var.ssh_config_port > protocol = "tcp" > } > > @@ -82,6 +82,7 @@ data "template_file" "script_user_data" { > user_data_log_dir = var.user_data_log_dir > user_data_enabled = var.user_data_enabled > ssh_config_user = var.ssh_config_user > + ssh_config_port = var.ssh_config_port > new_hostname = element(var.kdevops_nodes, count.index), > } > } > diff --git a/terraform/azure/main.tf b/terraform/azure/main.tf > index 8dcead78b5fd..eb609933f2ad 100644 > --- a/terraform/azure/main.tf > +++ b/terraform/azure/main.tf > @@ -43,7 +43,7 @@ resource "azurerm_network_security_group" "kdevops_sg" { > access = "Allow" > protocol = "Tcp" > source_port_range = "*" > - destination_port_range = "22" > + destination_port_range = tostring(var.ssh_config_port) > source_address_prefix = "*" > destination_address_prefix = "*" > } > @@ -89,6 +89,13 @@ resource "azurerm_linux_virtual_machine" "kdevops_vm" { > size = var.azure_vmsize > admin_username = var.ssh_config_user > disable_password_authentication = true > + custom_data = base64encode(templatefile("${path.module}/../scripts/cloud-init.sh", { > + user_data_log_dir = "/var/log/kdevops" > + user_data_enabled = "yes" > + ssh_config_user = var.ssh_config_user > + ssh_config_port = var.ssh_config_port > + new_hostname = element(var.kdevops_nodes, count.index) > + })) > > os_disk { > # Note: yes using the names like the ones below is better however it also > diff --git a/terraform/gce/main.tf b/terraform/gce/main.tf > index 816f43098e88..254ecb6a6803 100644 > --- a/terraform/gce/main.tf > +++ b/terraform/gce/main.tf > @@ -3,6 +3,19 @@ data "google_compute_image" "kdevops_image" { > family = var.gce_image_family > } > > +resource "google_compute_firewall" "kdevops_ssh" { > + name = "kdevops-allow-ssh" > + network = "default" > + > + allow { > + protocol = "tcp" > + ports = [tostring(var.ssh_config_port)] > + } > + > + source_ranges = ["0.0.0.0/0"] > + target_tags = ["kdevops-ssh"] > +} > + > resource "google_compute_instance" "kdevops_instance" { > count = local.kdevops_num_boxes > name = element(var.kdevops_nodes, count.index) > @@ -33,7 +46,15 @@ resource "google_compute_instance" "kdevops_instance" { > ssh-keys = format("%s:%s", var.ssh_config_user, file(var.ssh_config_pubkey_file)) > } > > - metadata_startup_script = "echo hi > /test.txt" > + metadata_startup_script = templatefile("${path.module}/../scripts/cloud-init.sh", { > + user_data_log_dir = "/var/log/kdevops" > + user_data_enabled = "yes" > + ssh_config_user = var.ssh_config_user > + ssh_config_port = var.ssh_config_port > + new_hostname = element(var.kdevops_nodes, count.index) > + }) > + > + tags = ["kdevops-ssh"] > } > > module "kdevops_compute_disks" { > diff --git a/terraform/lambdalabs/main.tf b/terraform/lambdalabs/main.tf > index a78866c7c8c2..1d736f0c503a 100644 > --- a/terraform/lambdalabs/main.tf > +++ b/terraform/lambdalabs/main.tf > @@ -88,7 +88,7 @@ resource "null_resource" "ansible_update_ssh_config_hosts" { > for_each = var.ssh_config_update ? toset(var.kdevops_nodes) : [] > > provisioner "local-exec" { > - command = "python3 ${path.module}/../../scripts/update_ssh_config_lambdalabs.py update ${each.key} ${lambdalabs_instance.kdevops[each.key].ip} ${local.ssh_user} ${var.ssh_config_name} ${var.ssh_config_privkey_file} 'Lambda Labs'" > + command = "python3 ${path.module}/../../scripts/update_ssh_config_lambdalabs.py update ${each.key} ${lambdalabs_instance.kdevops[each.key].ip} ${local.ssh_user} ${var.ssh_config_name} ${var.ssh_config_privkey_file} 'Lambda Labs' ${var.ssh_config_port}" > } > > triggers = { > @@ -113,6 +113,43 @@ resource "null_resource" "remove_ssh_config" { > } > } > > +# Configure SSH port if not using default port 22 > +resource "null_resource" "configure_ssh_port" { > + for_each = var.ssh_config_port != 22 ? toset(var.kdevops_nodes) : [] > + > + connection { > + type = "ssh" > + host = lambdalabs_instance.kdevops[each.key].ip > + user = local.ssh_user > + port = 22 > + private_key = file(pathexpand(var.ssh_config_privkey_file)) > + } > + > + provisioner "remote-exec" { > + inline = [ > + "echo 'Waiting for system to be ready...'", > + "sudo cloud-init status --wait || true", > + "echo 'Configuring SSH to listen on port ${var.ssh_config_port}'", > + "sudo sed -i '/^[#[:space:]]*Port/d' /etc/ssh/sshd_config", > + "echo 'Port ${var.ssh_config_port}' | sudo tee -a /etc/ssh/sshd_config", > + "if [ -d /etc/selinux ] && sudo sestatus 2>/dev/null | grep -q 'SELinux status.*enabled'; then if ! command -v semanage >/dev/null 2>&1; then sudo yum install -y policycoreutils-python-utils 2>&1 || sudo dnf install -y policycoreutils-python-utils 2>&1 || true; fi; if command -v semanage >/dev/null 2>&1; then sudo semanage port -a -t ssh_port_t -p tcp ${var.ssh_config_port} 2>&1 || sudo semanage port -m -t ssh_port_t -p tcp ${var.ssh_config_port} 2>&1 || true; fi; fi", > + "if command -v firewall-cmd >/dev/null 2>&1 && sudo systemctl is-enabled firewalld >/dev/null 2>&1; then sudo firewall-cmd --permanent --add-port=${var.ssh_config_port}/tcp && sudo firewall-cmd --reload; fi", > + "if command -v ufw >/dev/null 2>&1 && sudo systemctl is-active ufw >/dev/null 2>&1; then sudo ufw allow ${var.ssh_config_port}/tcp; fi", > + "sudo systemctl restart sshd", > + "echo 'SSH port configuration completed'" > + ] > + } > + > + depends_on = [ > + lambdalabs_instance.kdevops, > + null_resource.ansible_update_ssh_config_hosts > + ] > + > + triggers = { > + instance_id = lambdalabs_instance.kdevops[each.key].id > + } > +} > + > # Ansible provisioning > resource "null_resource" "ansible_provision" { > for_each = toset(var.kdevops_nodes) > @@ -121,6 +158,7 @@ resource "null_resource" "ansible_provision" { > type = "ssh" > host = lambdalabs_instance.kdevops[each.key].ip > user = local.ssh_user > + port = var.ssh_config_port > private_key = file(pathexpand(var.ssh_config_privkey_file)) > } > > @@ -145,7 +183,8 @@ resource "null_resource" "ansible_provision" { > > depends_on = [ > lambdalabs_instance.kdevops, > - null_resource.ansible_update_ssh_config_hosts > + null_resource.ansible_update_ssh_config_hosts, > + null_resource.configure_ssh_port > ] > > triggers = { > diff --git a/terraform/oci/main.tf b/terraform/oci/main.tf > index 15660aa02614..399a05621ee3 100644 > --- a/terraform/oci/main.tf > +++ b/terraform/oci/main.tf > @@ -35,6 +35,13 @@ resource "oci_core_instance" "kdevops_instance" { > > metadata = { > ssh_authorized_keys = file(var.ssh_config_pubkey_file) > + user_data = base64encode(templatefile("${path.module}/../scripts/cloud-init.sh", { > + user_data_log_dir = "/var/log/kdevops" > + user_data_enabled = "yes" > + ssh_config_user = var.ssh_config_user > + ssh_config_port = var.ssh_config_port > + new_hostname = element(var.kdevops_nodes, count.index) > + })) > } > > preemptible_instance_config { > @@ -155,8 +162,8 @@ resource "oci_core_security_list" "kdevops_security_list" { > source_type = "CIDR_BLOCK" > stateless = false > tcp_options { > - min = 22 > - max = 22 > + min = var.ssh_config_port > + max = var.ssh_config_port > } > } > ingress_security_rules { > diff --git a/terraform/openstack/main.tf b/terraform/openstack/main.tf > index 6e31e2f07dd5..c9037ca734f9 100644 > --- a/terraform/openstack/main.tf > +++ b/terraform/openstack/main.tf > @@ -19,8 +19,8 @@ resource "openstack_compute_secgroup_v2" "kdevops_security_group" { > > # SSH > rule { > - from_port = 22 > - to_port = 22 > + from_port = var.ssh_config_port > + to_port = var.ssh_config_port > ip_protocol = "tcp" > cidr = "0.0.0.0/0" > } > @@ -62,6 +62,13 @@ resource "openstack_compute_instance_v2" "kdevops_instances" { > flavor_name = var.flavor_name > key_pair = var.ssh_pubkey_name > security_groups = [openstack_compute_secgroup_v2.kdevops_security_group.name] > + user_data = templatefile("${path.module}/../scripts/cloud-init.sh", { > + user_data_log_dir = "/var/log/kdevops" > + user_data_enabled = "yes" > + ssh_config_user = var.ssh_config_user > + ssh_config_port = var.ssh_config_port > + new_hostname = element(var.kdevops_nodes, count.index) > + }) > network { > name = var.public_network_name > } > diff --git a/terraform/scripts/cloud-init.sh b/terraform/scripts/cloud-init.sh > index 926afe99faf3..86c8a67ec13a 100755 > --- a/terraform/scripts/cloud-init.sh > +++ b/terraform/scripts/cloud-init.sh > @@ -49,7 +49,49 @@ if [ "$USERDATA_ENABLED" != "yes" ]; then > fi > > run_cmd_admin echo "cloud-init: kdevops script user data processing enabled" > -run_cmd_admin echo "Nothing to do..." > + > +# Configure SSH port if not using default port 22 > +SSH_PORT="${ssh_config_port}" > +if [ "$SSH_PORT" != "22" ]; then > + run_cmd_admin echo "Configuring SSH to listen on port $SSH_PORT" > + > + # Update sshd_config to use alternate port > + run_cmd_admin sed -i '/^[#[:space:]]*Port/d' /etc/ssh/sshd_config > + echo "Port $SSH_PORT" | run_cmd_admin tee -a /etc/ssh/sshd_config > /dev/null > + > + # Configure SELinux if present > + if [ -d /etc/selinux ] && sestatus 2>/dev/null | grep -q "SELinux status.*enabled"; then > + # Install semanage if not available (RHEL/CentOS/Rocky/AlmaLinux) > + if ! command -v semanage >/dev/null 2>&1; then > + run_cmd_admin yum install -y policycoreutils-python-utils 2>&1 || run_cmd_admin dnf install -y policycoreutils-python-utils 2>&1 || true > + fi > + > + # Try to add the port first, if it fails (already exists), modify it > + if command -v semanage >/dev/null 2>&1; then > + run_cmd_admin semanage port -a -t ssh_port_t -p tcp $SSH_PORT 2>&1 || run_cmd_admin semanage port -m -t ssh_port_t -p tcp $SSH_PORT 2>&1 || true > + run_cmd_admin echo "SELinux port configuration completed" > + else > + run_cmd_admin echo "WARNING: semanage not available, SELinux may block port $SSH_PORT" > + fi > + fi > + > + # Configure firewalld if present and enabled > + if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-enabled firewalld >/dev/null 2>&1; then > + run_cmd_admin firewall-cmd --permanent --add-port=$SSH_PORT/tcp > + run_cmd_admin firewall-cmd --reload > + fi > + > + # Configure ufw if present and active > + if command -v ufw >/dev/null 2>&1 && systemctl is-active ufw >/dev/null 2>&1; then > + run_cmd_admin ufw allow $SSH_PORT/tcp > + fi > + > + # Restart sshd to apply changes > + run_cmd_admin systemctl restart sshd > + run_cmd_admin echo "SSH port configuration completed" > +else > + run_cmd_admin echo "Using default SSH port 22, no configuration needed" > +fi > > # Add more functionality below if you see fit. Be sure to use a variable > # to allow to easily enable / disable each mechanism. > diff --git a/terraform/shared.tf b/terraform/shared.tf > index 88e87a27378d..488becd0f797 100644 > --- a/terraform/shared.tf > +++ b/terraform/shared.tf > @@ -44,6 +44,12 @@ variable "ssh_config_kexalgorithms" { > default = "" > } > > +variable "ssh_config_port" { > + description = "SSH port to use for remote connections and firewall rules" > + type = number > + default = 22 > +} > + > variable "private_net_enabled" { > description = "Is the private network enabled?" > default = "false" -- Chuck Lever