From 58c9c43bcb6af5606d5514108061645777f2595d Mon Sep 17 00:00:00 2001 From: Alicia Cozine Date: Fri, 25 Oct 2024 16:12:59 -0500 Subject: [PATCH] draft of a quarantine playbook for EDA --- group_vars/vsphere/production.yml | 2 +- group_vars/vsphere/staging.yml | 1 + playbooks/utils/isolate_vm_host.yml | 202 ++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 playbooks/utils/isolate_vm_host.yml diff --git a/group_vars/vsphere/production.yml b/group_vars/vsphere/production.yml index 02b05a6cc3..c45fbb5d7d 100644 --- a/group_vars/vsphere/production.yml +++ b/group_vars/vsphere/production.yml @@ -5,4 +5,4 @@ vcenter_cluster: "VMCluster" vcenter_username: "vmansible" vcenter_password: "{{ vault_vcenter_password }}" vm_delete_me_folder: "/Library/vm/ToBeDeleted" - +vm_quarantine_folder: "/Library/vm/Quarantine" diff --git a/group_vars/vsphere/staging.yml b/group_vars/vsphere/staging.yml index 3d8d6be898..099575bea8 100644 --- a/group_vars/vsphere/staging.yml +++ b/group_vars/vsphere/staging.yml @@ -5,3 +5,4 @@ vcenter_cluster: "VMCluster" vcenter_username: "vmansible" vcenter_password: "{{ vault_vcenter_password }}" vm_delete_me_folder: "/Library-Dev/vm/ToBeDeleted" +vm_quarantine_folder: "/Library-Dev/vm/Quarantine" diff --git a/playbooks/utils/isolate_vm_host.yml b/playbooks/utils/isolate_vm_host.yml new file mode 100644 index 0000000000..2961e41397 --- /dev/null +++ b/playbooks/utils/isolate_vm_host.yml @@ -0,0 +1,202 @@ +--- +# This playbook responds if we have a security incident on a VM, +# powers down and quarantines the VM and replaces it from a vSphere template. +# +- name: quarantine and replace the {{ replacement_vm }} VM on the {{ runtime_env | default('staging') }} vSphere + hosts: localhost + remote_user: pulsys + become: true + + vars: + slack_alerts_channel: "#infrastructure" + + vars_files: + - ../../group_vars/all/vault.yml + - ../../group_vars/vsphere/vault.yml + - ../../group_vars/vsphere/{{ runtime_env | default('staging') }}.yml + + tasks: + - name: Gather info on VM to replace + community.vmware.vmware_vm_info: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + show_allocated: true + show_folder: true + show_datacenter: true + show_mac_address: true + vm_name: "{{ replacement_vm }}" + register: old_vm_info + + - name: set the vm network to the private network if the IP starts with 172.20 + ansible.builtin.set_fact: + vm_network: "VM Network - ip4-library-servers" + when: old_vm_info.virtual_machines[0].ip_address is match("172.20.*") + + - name: set the vm network to the public network if the IP starts with 128.112 + ansible.builtin.set_fact: + vm_network: "Virtual Machine Network" + when: old_vm_info.virtual_machines[0].ip_address is match("128.112.*") + + - name: Power off old VM using UUID + community.vmware.vmware_guest_powerstate: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + uuid: "{{ old_vm_info.virtual_machines[0].uuid }}" + state: powered-off + + - name: Move old VM to the Quarantine folder + community.vmware.vmware_guest_move: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + dest_folder: "{{ vm_quarantine_folder }}" + uuid: "{{ old_vm_info.virtual_machines[0].uuid }}" + + - name: Create a new virtual machine from a template + community.vmware.vmware_guest: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + cluster: "{{ vcenter_cluster }}" + folder: "{{ old_vm_info.virtual_machines[0].folder }}" + name: "{{ replacement_vm }}" + state: present + template: "{{ vm_template | default('template_jammy_spring_2024')}}" + disk: + - size: "{{ (old_vm_info.virtual_machines[0].allocated.storage / 1024) | int }}kb" + # we are not able to use 'type: thin' with our fall 2024 templates + # type: thin + datastore: "{{ old_vm_info.virtual_machines[0].datastore_url }}" + # TODO: Add another disk from an existing VMDK + hardware: + memory_mb: "{{ old_vm_info.virtual_machines[0].allocated.memory | int | default('16384') }}" + num_cpus: "{{ old_vm_info.virtual_machines[0].allocated.cpu | int | default('2') }}" + num_cpu_cores_per_socket: "{{ vm_cpu_cores | default('1') }}" + scsi: paravirtual + version: latest # Hardware version of virtual machine + boot_firmware: "efi" + cdrom: + - controller_number: 0 + unit_number: 0 + state: present + networks: + - name: "{{ vm_network }}" + wait_for_ip_address: true + register: new_vm_deets + + - name: view new VM details + ansible.builtin.debug: + var: new_vm_deets + + - name: power down the VM so we can mess with the network settings + community.vmware.vmware_guest_powerstate: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + # new VM var does not include UUID; use moid, which is unique in each vCenter instance + moid: "{{ new_vm_deets.instance.moid }}" + state: powered-off + + - name: delete NIC with automatic mac address + community.vmware.vmware_guest_network: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + # new VM var does not include UUID; use moid, which is unique in each vCenter instance + moid: "{{ new_vm_deets.instance.moid }}" + network_name: "{{ vm_network }}" + state: absent + mac_address: "{{ new_vm_deets.instance.hw_eth0.macaddress }}" + + - name: add NIC with custom mac address + community.vmware.vmware_guest_network: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + # new VM var does not include UUID; use moid, which is unique in each vCenter instance + moid: "{{ new_vm_deets.instance.moid }}" + folder: "{{ old_vm_info.virtual_machines[0].folder }}" + network_name: "{{ vm_network }}" + device_type: "vmxnet3" + connected: true + mac_address: "{{ old_vm_info.virtual_machines[0].mac_address[0] }}" + + - name: Power the new VM on + community.vmware.vmware_guest_powerstate: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + datacenter: "{{ vcenter_datacenter }}" + folder: "{{ old_vm_info.virtual_machines[0].folder }}" + # new VM var does not include UUID; use moid, which is unique in each vCenter instance + moid: "{{ new_vm_deets.instance.moid }}" + state: powered-on + + - name: Gather details on new VM + community.vmware.vmware_vm_info: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: false + show_datacenter: true + show_mac_address: true + show_allocated: true + show_folder: true + vm_name: "{{ replacement_vm }}" + register: new_vm_info + + - name: Print out relevant details of old VM + vars: + msg: | + The VM you replaced had + an UUID of {{ old_vm_info.virtual_machines[0].uuid }} + a mac address of {{ old_vm_info.virtual_machines[0].mac_address[0] }} + in the {{ vm_network }} network + {{ old_vm_info.virtual_machines[0].allocated.cpu }} CPUs + {{ (old_vm_info.virtual_machines[0].allocated.memory | int / 1024) }} GB of memory + {{ old_vm_info.virtual_machines[0].allocated.storage | human_readable }} of disk allocated + ansible.builtin.debug: + msg: "{{ msg.split('\n') }}" + + - name: Print out relevant details of new VM + vars: + msg: | + The VM you just created has + an UUID of {{ new_vm_info.virtual_machines[0].uuid }} + a mac address of {{ new_vm_info.virtual_machines[0].mac_address[0] }} + in the {{ vm_network }} network + {{ new_vm_info.virtual_machines[0].allocated.cpu }} CPUs + {{ (new_vm_info.virtual_machines[0].allocated.memory | int / 1024) }} GB of memory + {{ new_vm_info.virtual_machines[0].allocated.storage | human_readable }} of disk allocated + ansible.builtin.debug: + msg: "{{ msg.split('\n') }}" + + - name: Remove old host from TowerDeploy1 known hosts + ansible.builtin.known_hosts: + path: /home/deploy/.ssh/known_hosts + name: "{{ replacement_vm }}.princeton.edu" + state: "absent" + delegate_to: towerdeploy1.princeton.edu + become: true + become_user: deploy + + post_tasks: + - name: send information to slack + ansible.builtin.include_tasks: + file: slack_tasks_end_of_playbook.yml