tf-ansible-workflow

Terraform/Ansible Workflow for Libvirt
git clone https://git.in0rdr.ch/tf-ansible-workflow.git
Log | Files | Refs | Pull requests |Archive

commit 91b1843fc82adff5ff6a94bb95453b852d584636
parent cf45ef05a01665e2663c18c3efb4a4bb8d6fcb5c
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date:   Sun, 14 Nov 2021 15:30:34 +0100

remove Proxmox workflow

Diffstat:
MReadme.md | 6++----
Dproxmox/Readme.md | 154-------------------------------------------------------------------------------
Dproxmox/ansible/defaults/all.yml | 47-----------------------------------------------
Dproxmox/ansible/dhcp-static-hosts.yml | 11-----------
Dproxmox/ansible/get-ips.yml | 26--------------------------
Dproxmox/ansible/playbook.yml | 139-------------------------------------------------------------------------------
Dproxmox/ansible/templates/config.j2 | 15---------------
Dproxmox/ansible/templates/dnsmasq.j2 | 5-----
Dproxmox/ansible/update-known-hosts.yml | 24------------------------
Dproxmox/ansible/vars/Archlinux.yml | 8--------
Dproxmox/ansible/vars/Debian.yml | 10----------
Dproxmox/ansible/vars/RedHat.yml | 10----------
Dproxmox/ansible/vars/Suse.yml | 10----------
Dproxmox/terraform/outputs.tf | 25-------------------------
Dproxmox/terraform/templates/inventory.tpl | 11-----------
Dproxmox/terraform/templates/qemu-config.yml.tpl | 8--------
Dproxmox/terraform/terraform.tfvars.example | 11-----------
Dproxmox/terraform/variables.tf | 47-----------------------------------------------
Dproxmox/terraform/vms.tf | 67-------------------------------------------------------------------
19 files changed, 2 insertions(+), 632 deletions(-)

diff --git a/Readme.md b/Readme.md @@ -1,7 +1,6 @@ -# Terraform/Ansible Workflow for Proxmox and Libvirt +# Terraform/Ansible Workflow for Libvirt This repository describes a workflow which helps me to (re)create multiple similar VMs for testing purposes. -Refer to the sub-folder Readmes fore more information: +Refer to the sub-folder Readme fore more information: * [./libvirt](./libvirt/Readme.md) -* [./proxmox](./proxmox/Readme.md) -\ No newline at end of file diff --git a/proxmox/Readme.md b/proxmox/Readme.md @@ -1,154 +0,0 @@ -# Terraform/Ansible Workflow on Proxmox VE (PVE) - -This repository describes a workflow which helps me to (re)create multiple similar VMs for testing purposes. - -## 1 Preparation -### 1.1 PVE Varibles -Define authentication variables for the [PVE API](https://github.com/Telmate/proxmox-api-go). The Terraform provider relies on the PVE API which requires you to defined the following environment variables: -``` -export PM_USER=test@pve -export PM_PASS="secret" -export PM_API_URL="https://pve.cloud.org/api2/json" -#export TF_LOG=DEBUG -``` - -### 1.2 Unicast MAC Addresses and Terraform Variables -Generate a unicast MAC foreach VM. For instance, use a bash script to do so: -``` -#!/bin/sh -# source: https://serverfault.com/a/299563 -function macaddr() { - echo $RANDOM | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' -} -``` - -Use environment variables or create a new file `./terraform/terraform.tfvars` to specify the details for the VMs (see also `./terraform/variables.tf`). Among other variables, insert the mac addresses from above: -``` -# terraform.tfvars -hosts = ["host0"] -macaddr = { - host0 = "02:a2:1d:38:31:1c" -} -``` - -## 2 Run Terraform - -Run Terraform: -``` -terraform plan -terraform apply -``` - -* Terraform automatically recreates the Ansible inventory and the mapping of Qemu VM id to hostnames (see next section), whenever one of the hosts is added or removed (i.e., the Terraform `id` is changed). -* Terraform writes the SSH private key into the file `./ssh/id_rsa`. - -## 3 Terraform Outputs - -If the Ansible inventory or the mapping of Qemu VM id to hostname needs to be updated manually, the values can be retrieved from the Terraform output any time: -``` -terraform output -raw inventory > ../ansible/inventory -terraform output -raw qemu_config > ../ansible/qemu-config.yml - -# inspect the name of the key file, see instructions below -terraform output ssh_private_keyfile -``` - -## 4 Ansible - -### 4.1 Preconditions and Preparations -Ansible depends on the following files written by Terraform, see section "2 Run Terraform" and "3 Terraform Outputs": -1. `./ansible/inventory`: The Ansible inventory containing a local connection and one group of remote hosts -2. `./ansible/qemu-config.yml`: The mapping of Qemu VM ids to hostnames - -Adjust variables in `./ansible/group_vars/all.yml`: -* `ssh_identity_file`: Relative path name to the SSH privat key (output of `terraform output ssh_private_keyfile`) -* Set `ssh_proxy_jump` and `ansible_user` if necessary -* Ensure `pve_api` points to your compiled PVE API binary -* Define `additional_users` as needed - -### 4.2 Run Ansible to Build the SSH Config - -The Ansible playbook runst the following tasks: -1. Retrieve the IP of the VMs via Qemu guest agent -2. Write the IP to the file `./ansible/qemu-config.yml` -3. Build the `./ssh/ssh_config` based on the information in the previous step -4. Build an optional `./dnsmasq.conf` to enable static ip in dnsmasqs built-in dhcp subsystem -5. Add additional users `additional_users` - -It is necessary to run ansible, because the IP address of the hosts cannot be retrieved by Terraform (the PVE provider is not mature enough yet). Therefore, we need to retrieve the IP addresses of the hosts via the Qemu guest agents running in the VMs. This process is automated and it will amend the IPs to the file `./ansible/qemu-config.yml`. Furthermore, the playbook will set the hostname and restart networking inside the VMs, such that the hostnames are published to the DNS server and all hosts are known/addressable by name. - -Run the playbook: -``` -# build ssh config from qemu-config.yml -ansible-playbook playbook.yml -i inventory -l local -# if required, build a dnsmasq snippet for static ip allocation (dhcp) -# the snippet is written to the file './dnsmasq.conf' -ansible-playbook dhcp-static-hosts.yml -i inventory -l local -# set hostname, restart networking, modify users and keys -ansible-playbook playbook.yml -i inventory -l qemu -``` - -If you choose an unprivileged `ansible_user` to reach the VMs, you may need to specfiy a privileged user to run some of the tasks. Specifically, restarting the network and modifying users requires more privileges. Further, you might not want to touch all hosts and limit the execution to a specific host: -``` -# set hostname, restart networking, modify users and keys as privileged user on "myhost" -ansible-playbook playbook.yml -i inventory -l myhost -e ansible_user=root -``` - -### 4.3 Update Known Hosts - -To prepare the local host for consecutive SSH connections, you might want to update you local `./ssh/known_hosts` file as follows: -``` -# update known hosts locally and confirm -ansible-playbook update-known-hosts.yml -i inventory -``` - -Alternatively, use the following commands: -``` -cd ansible - -# remove previous hosts from known hosts -for ip in $(cat qemu-config.yml | grep ip4 | awk '{print $2}'); do ssh-keygen -R $ip; done - -# update known hosts and confirm -for host in $(cat qemu-config.yml | grep fqdn | awk '{print $3}'); do ssh -F ../ssh/config $host exit; done -``` - -## 5 Troubleshooting, Tips & Tricks - -### 5.1 Delete and Recreate Hosts -You can either taint the Terraform resources or delete them via PVE API. To taint resources: -``` -terraform taint proxmox_vm_qemu.host[\"mysql0\"] -Resource instance proxmox_vm_qemu.host["mysql0"] has been marked as tainted. -``` - -Afterwards, re-apply to restore the Terraform state: -``` -terraform apply -``` - -To delete some of the the infrastructure directly via API (this might confuse your Terraform state): -``` -~/gocode/src/github.com/Telmate/proxmox-api-go/proxmox-api-go destroy 116 -terraform refresh -``` - -To only recreate parts of the infrastructure, choose an appropriate Terraform `target`: -``` -terraform apply -target="proxmox_vm_qemu.host[\"mysql0\"]" -target="proxmox_vm_qemu.host[\"mysql1\"]" -``` - - -### 5.2 Retrive private key without running Terraform -If needed, retrieve the SSH key (again) without re-applying changes: -``` -terraform output -raw ssh_private_key > ../ssh/id_rsa -``` - -Terraform takes care of writing this private key file the first time you run `terraform apply`, however, you might want to retrieve the key again without re-running Terraform. - ---- -## Dependencies -* PVE API: https://github.com/Telmate/proxmox-api-go -* Terraform provider for Proxmox: https://github.com/Telmate/terraform-provider-proxmox - diff --git a/proxmox/ansible/defaults/all.yml b/proxmox/ansible/defaults/all.yml @@ -1,47 +0,0 @@ ---- - -# path to proxmox api binary -# this default is used if not otherwise specified -pve_api: 'proxmox-api-go' - -# ssh configuraiton to reach the VMs -# this is only an example, each line -# needs to enabled explicitly in group_vars -ansible_user: root -ssh_identity_file: '../ssh/id_rsa' -ssh_proxy_jump: proxyhost -ssh_include_config: '~/.ssh/config' - -# allow sudo/wheel users to execute any command without password -ssh_passwordless_login: no -# example of adding additional users -# additional_users: -# - name: user1 -# # comma seperated list of additional groups -# additional_groups: 'wheel' -# # mutually exclusive with reuse_ssh_key below -# generate_ssh_key: yes -# # mutually exclusive with generate_ssh_key above -# # lets you reuse an existing ssh key -# #ssh_key: '{{ ssh_identity_file }}' -# # adds this key as authorized key -# #authorized_key: '~/.ssh/id_rsa.pub' - -# The cloud-init config template has manage_etc_hosts enabled by default. -# This will overwrite the state of /etc/hosts at each reboot. The default -# cloud-init configuratin resolves {{ ansible_hostname }} to 127.0.0.1. -# This is not desirable in all cases, since sometimes you want it to resolve -# the public IP (not localhost). -# -# There is an option cicustom which could be used to change this behavior -# at an earlier stage (e.g. with Terraform): -# https://pve.proxmox.com/wiki/Cloud-Init_Support#_custom_cloud_init_configuration -# -# However, this parameter is not yet included in Telmate/terraform-provider-proxmox. -# Also, tests showed that reading the 'user' config as described in the above -# link did not really change the behavior of manage_etc_hosts (/etc/hosts was -# still modified at each reboot). Thus, this option will disable the line that -# resolves {{ ansible_hostname }} to 127.0.0.1 in all relevant files. The file -# /etc/hosts will still be overwritten at each reboot, but without the line resolving -# {{ ansible_hostname }} to 127.0.0.1. Choose 'yes' to enable this temporary fix. -cloud_init_disable_localhost_resolver: no diff --git a/proxmox/ansible/dhcp-static-hosts.yml b/proxmox/ansible/dhcp-static-hosts.yml @@ -1,11 +0,0 @@ ---- - -# create dnsmasq config for static ip addresses -- hosts: local - vars: - qemu_config: "{{ lookup('file', 'qemu-config.yml') | from_yaml }}" - tasks: - - name: create dnsmasq config snippet with ip mac mapping - template: - src: 'templates/dnsmasq.j2' - dest: './dnsmasq.conf' diff --git a/proxmox/ansible/get-ips.yml b/proxmox/ansible/get-ips.yml @@ -1,26 +0,0 @@ ---- - -- name: remove vm config from global qemu config - set_fact: - qemu_config: '{{ qemu_config | difference([item]) }}' - -- name: get qemu network interfaces from Proxmox api - command: '{{ pve_api }} getNetworkInterfaces {{ item.id }}' - register: network_interfaces - check_mode: no - -- name: extract public interface - set_fact: network_interfaces_list='{{ network_interfaces.stdout | from_json }}' - -#- debug: var=network_interfaces_list - -- name: extract ip4 from public/second interface - set_fact: ip4_addr='{{ network_interfaces_list[1]["IPAddresses"][0] }}' - -- name: combine ip4 address with vm config item - set_fact: - item_with_ip: '{{ item | combine({"ip4": ip4_addr}) }}' - -- name: append item to global qemu config - set_fact: - qemu_config: '{{ qemu_config + [item_with_ip] }}' diff --git a/proxmox/ansible/playbook.yml b/proxmox/ansible/playbook.yml @@ -1,139 +0,0 @@ ---- - -# Local tasks to generate ssh config -# Input/requires: './qemu-config.yml' -- hosts: local - vars: - qemu_config: "{{ lookup('file', 'qemu-config.yml') | from_yaml }}" - tasks: - - name: get ips for inventory hostnames - include_tasks: 'get-ips.yml' - loop_control: - index_var: i - loop: '{{ qemu_config }}' - - - name: copy ip4 adress to qemu config file - copy: - content: '{{ qemu_config | to_nice_yaml }}' - dest: 'qemu-config.yml' - - - name: create ssh config - template: - src: 'templates/config.j2' - dest: '../ssh/config' - -# remote tasks to set hostname, add users and keys -- hosts: qemu - tasks: - - name: include os specific vars - include_vars: '{{ item }}' - with_first_found: - - '{{ ansible_distribution }}_{{ ansible_distribution_major_version }}.yml' - - '{{ ansible_os_family }}.yml' - - - name: remote user information message - debug: - msg: 'Running tasks on remote host as user "{{ ansible_user }}"' - - - name: set hostname - command: 'hostnamectl set-hostname {{ inventory_hostname }}' - register: hostname_update - become: yes - - - name: restart network to register hostname with dns server - service: - name: network - state: restarted - when: hostname_update.changed - ignore_errors: yes - become: yes - - - name: restart NetworkManager to register hostname with dns server - service: - name: NetworkManager - state: restarted - when: hostname_update.changed - ignore_errors: yes - become: yes - - - name: set ssh private key - copy: - src: '{{ ssh_identity_file }}' - dest: '{{ ansible_env.HOME }}/.ssh/id_rsa' - owner: '{{ ansible_user }}' - group: '{{ ansible_user }}' - mode: '0600' - - - block: - - name: add additional users - user: - name: '{{ item.name }}' - shell: /bin/bash - groups: '{{ item.additional_groups }}' - append: yes - loop: '{{ additional_users }}' - become: yes - - - name: generate additional users ssh keys - user: - name: '{{ item.name }}' - generate_ssh_key: '{{ item.generate_ssh_key }}' - loop: '{{ additional_users }}' - when: item.generate_ssh_key | default(false, true) and not item.ssh_key | default(false, true) - become: yes - - - name: ensure ssh directory for additional users exists - file: - path: '/home/{{ item.name }}/.ssh' - state: directory - mode: '0700' - loop: '{{ additional_users }}' - become: yes - - - name: set additional users ssh keys from existing key - copy: - src: '{{ item.ssh_key }}' - dest: '/home/{{ item.name }}/.ssh/id_rsa' - owner: '{{ item.name }}' - group: '{{ item.name }}' - mode: '0600' - loop: '{{ additional_users }}' - when: item.ssh_key | default(false, true) and not item.generate_ssh_key | default(false, true) - become: yes - - - name: set authorized key for user - authorized_key: - user: '{{ item.name }}' - state: present - key: '{{ lookup("file", item.authorized_key) }}' - loop: '{{ additional_users }}' - when: item.authorized_key | default(false, true) - become: yes - when: additional_users | default(false, true) - # endblock add additional users - - - name: set passwordless login - lineinfile: - path: /etc/sudoers - state: present - regexp: '^%{{ sudo_group }}' - line: '%{{ sudo_group }} ALL=(ALL) NOPASSWD: ALL' - validate: 'visudo -cf %s' - when: ssh_passwordless_login | default(false, true) - become: yes - - - block: - - name: disable ipv4 localhost resolver - replace: - path: '{{ item.file }}' - regexp: '^127\.0\.0\.1 {{ item.fqdn }}(.*)$' - replace: '#127.0.0.1 {{ item.fqdn }}\1' - loop: '{{ host_files }}' - - - name: disable ipv6 localhost resolver - replace: - path: '{{ item.file }}' - regexp: '^::1 {{ item.fqdn }}(.*)$' - replace: '#::1 {{ item.fqdn }}\1' - loop: '{{ host_files }}' - when: cloud_init_disable_localhost_resolver diff --git a/proxmox/ansible/templates/config.j2 b/proxmox/ansible/templates/config.j2 @@ -1,15 +0,0 @@ -{% if ssh_include_config | default(false, true) %} -Include {{ ssh_include_config }} -{% endif %} - -{% for host in qemu_config %} -Host {{ host.fqdn }} - HostName {{ host.ip4 }} - User {{ ansible_user }} -{% if ssh_proxy_jump | default(false, true) %} - ProxyJump {{ ssh_proxy_jump }} -{% endif %} -{% if ssh_identity_file | default(false, true) %} - IdentityFile {{ ssh_identity_file }} -{% endif %} -{% endfor %} diff --git a/proxmox/ansible/templates/dnsmasq.j2 b/proxmox/ansible/templates/dnsmasq.j2 @@ -1,5 +0,0 @@ -# Ansible generated dnsmasq.conf snippet -{% for host in qemu_config %} -# pve host {{ host.id }} -dhcp-host={{ host.macaddr }},{{ host.ip4 }} -{% endfor %} diff --git a/proxmox/ansible/update-known-hosts.yml b/proxmox/ansible/update-known-hosts.yml @@ -1,24 +0,0 @@ ---- - -# Local tasks to update known ssh hosts -# -# Remove: -# for ip in $(cat qemu-config.yml | grep ip4 | awk '{print $2}'); do ssh-keygen -R $ip; done -# -# Add: -# for host in $(cat qemu-config.yml | grep fqdn | awk '{print $3}'); do ssh -F ../ssh/config $host exit; done -# -# Requires './qemu-config.yml' with ipv4 addresses -- hosts: local - vars: - qemu_config: "{{ lookup('file', 'qemu-config.yml') | from_yaml }}" - tasks: - - name: remove the host from local known hosts - known_hosts: - path: '{{ ansible_env.HOME }}/.ssh/known_hosts' - name: '{{ item.ip4 }}' - state: absent - loop: '{{ qemu_config }}' - - - name: update known host locally - shell: 'for host in $(cat qemu-config.yml | grep fqdn | awk "{print $3}"); do ssh -F ../ssh/config $host exit; done' diff --git a/proxmox/ansible/vars/Archlinux.yml b/proxmox/ansible/vars/Archlinux.yml @@ -1,8 +0,0 @@ ---- - -# group of sudo users -sudo_group: wheel - -host_files: - - file: '/etc/hosts' - fqdn: '{{ ansible_hostname }}' diff --git a/proxmox/ansible/vars/Debian.yml b/proxmox/ansible/vars/Debian.yml @@ -1,10 +0,0 @@ ---- - -# group of sudo users -sudo_group: sudo - -host_files: - - file: '/etc/cloud/templates/hosts.debian.tmpl' - fqdn: '\{\{fqdn\}\}' - - file: '/etc/hosts' - fqdn: '{{ ansible_hostname }}' diff --git a/proxmox/ansible/vars/RedHat.yml b/proxmox/ansible/vars/RedHat.yml @@ -1,10 +0,0 @@ ---- - -# group of sudo users -sudo_group: wheel - -host_files: - - file: '/etc/cloud/templates/hosts.redhat.tmpl' - fqdn: '\{\{fqdn\}\}' - - file: '/etc/hosts' - fqdn: '{{ ansible_hostname }}' diff --git a/proxmox/ansible/vars/Suse.yml b/proxmox/ansible/vars/Suse.yml @@ -1,10 +0,0 @@ ---- - -# group of sudo users -sudo_group: wheel - -host_files: - - file: '/etc/cloud/templates/hosts.suse.tmpl' - fqdn: '\{\{fqdn\}\}' - - file: '/etc/hosts' - fqdn: '{{ ansible_hostname }}' diff --git a/proxmox/terraform/outputs.tf b/proxmox/terraform/outputs.tf @@ -1,25 +0,0 @@ -output "inventory" { - value = "${templatefile("${path.module}/templates/inventory.tpl", { hosts = proxmox_vm_qemu.host })}" -} - -output "qemu_config" { - value = "${templatefile("${path.module}/templates/qemu-config.yml.tpl", { hosts = proxmox_vm_qemu.host })}" -} - -output "ssh_private_key" { - value = "${tls_private_key.id_rsa.private_key_pem}" - sensitive = true -} - -output "ssh_private_keyfile" { - value = "${local_file.ssh_private_key.filename}" -} - -output "ssh_public_key" { - value = "${tls_private_key.id_rsa.public_key_openssh}" - sensitive = true -} - -output "ssh_public_keyfile" { - value = "${local_file.ssh_public_key.filename}" -} diff --git a/proxmox/terraform/templates/inventory.tpl b/proxmox/terraform/templates/inventory.tpl @@ -1,10 +0,0 @@ -[local] -localhost ansible_connection=local - -[qemu] -%{ for host in hosts ~} -${host.name} -%{ endfor ~} - -[qemu:vars] -ansible_ssh_common_args='-F ../ssh/config' -\ No newline at end of file diff --git a/proxmox/terraform/templates/qemu-config.yml.tpl b/proxmox/terraform/templates/qemu-config.yml.tpl @@ -1,7 +0,0 @@ ---- - -%{ for host in hosts ~} -- fqdn: ${host.name} - macaddr: ${tolist(host.network)[0]["macaddr"]} - id: ${split("/",host.id)[2]} -%{ endfor ~} -\ No newline at end of file diff --git a/proxmox/terraform/terraform.tfvars.example b/proxmox/terraform/terraform.tfvars.example @@ -1,11 +0,0 @@ -hosts = ["host0"] -macaddr = { - bastion0 = "02:ea:8e:e2:1e:25" -} -pool = "pool-name" -cores = 1 -sockets = 1 -memory = 2048 -disk = 30 -target_node = "cloudname" -clone = "CentOS7-GenericCloud" diff --git a/proxmox/terraform/variables.tf b/proxmox/terraform/variables.tf @@ -1,47 +0,0 @@ -variable "hosts" { - type = list - default = ["node0", "node1"] -} - -variable "macaddr" { - type = map - default = { - node0 = "02:e6:df:96:00:d6" - node1 = "02:98:f7:29:3a:82" - } -} - -variable "pool" { - type = string - default = "pool-name" -} - -variable "cores" { - type = number - default = 1 -} - -variable "sockets" { - type = number - default = 1 -} - -variable "memory" { - type = number - default = 2048 -} - -variable "disk" { - type = number - default = 30 -} - -variable "target_node" { - type = string - default = "node-name" -} - -variable "clone" { - type = string - default = "CentOS7-GenericCloud" -} diff --git a/proxmox/terraform/vms.tf b/proxmox/terraform/vms.tf @@ -1,67 +0,0 @@ -resource "proxmox_vm_qemu" "host" { - # create each host - for_each = toset(var.hosts) - - name = each.value - - cores = var.cores - sockets = var.sockets - memory = var.memory - - bootdisk = "scsi0" - scsihw = "virtio-scsi-pci" - disk { - id = 0 - size = var.disk - type = "scsi" - storage = "local-lvm" - storage_type = "lvm" - } - - network { - id = 0 - model = "virtio" - bridge = "vmbr0" - macaddr = var.macaddr[each.value] - } - - target_node = var.target_node - pool = var.pool - clone = var.clone - agent = 1 - - os_type = "cloud-init" - ipconfig0 = "ip=dhcp" - ciuser = "root" - cipassword = "root" - sshkeys = tls_private_key.id_rsa.public_key_openssh -} - -resource "null_resource" "update_inventory" { - triggers = { - # when a host id changes - host_ids = "${join(" ", values(proxmox_vm_qemu.host)[*].id)}" - } - provisioner "local-exec" { - # recreate ansible inventory - command = "echo '${templatefile("${path.module}/templates/inventory.tpl", { hosts = proxmox_vm_qemu.host })}' > ../ansible/inventory" - } - provisioner "local-exec" { - # recreate mapping of qemu VM id to hostnames - command = "echo '${templatefile("${path.module}/templates/qemu-config.yml.tpl", { hosts = proxmox_vm_qemu.host })}' > ../ansible/qemu-config.yml" - } -} - -# ssh private key -resource "tls_private_key" "id_rsa" { - algorithm = "RSA" -} -resource "local_file" "ssh_private_key" { - sensitive_content = tls_private_key.id_rsa.private_key_pem - filename = "${path.module}/../ssh/id_rsa" - file_permission = "0600" -} -resource "local_file" "ssh_public_key" { - sensitive_content = tls_private_key.id_rsa.public_key_openssh - filename = "${path.module}/../ssh/id_rsa.pub" -}