2019-11-02

Automating Azure Deployments with Ansible on OpenBSD: Part 2

Once you've installed Ansible and its Azure cloud modules to your OpenBSD machine and you've authenticated it with Azure, you can create an Ansible playbook to start interacting with your Azure resources.

ANSIBLE_GIT_PATH=~/ansible.git
cd "${ANSIBLE_GIT_PATH}"
bash
bash-5.0$ source hacking/env-setup
bash-5.0$ cd ~/azure-ansible-modules
bash-5.0$ pipenv shell

Create your first Ansible playbook. This playbook will print out a list of your existing resource groups, if you have any:

bash-5.0$ cat get-resource-group-facts.yml
---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: fetch resource group facts
      azure_rm_resourcegroup_facts:
      register: rgroups

    - name: print facts
      debug:
        var: rgroups

# END

You can run this playbook with the ansible-playbook tool:

(azure-ansible-modules) bash-5.0$ ansible-playbook get-resource-group-facts.yml

This works in part because you are not using Ansible in the way it's normally intended. Ansible expects to give your commands to the hosts you designate. It's a task- and command-delegating tool, and a powerful one at that. When performing cloud actions, there is no set of hosts to receive those commands — you are really asking a cloud "remote-service-platform-as-an-abstraction" endpoint to do something, not a discrete computer — so these tasks are run on the localhost and the cloud module ("azure_rm_resourcegroup_facts" in this case) comprehends that it isn't intended to make a change to a discrete piece of hardware the way that a regular Ansible module might.

Our get-resource-group-facts playbook looks nice, but it doesn't do much. Let's create a resource group:

bash-5.0$ cat rgroup-add.yml
---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: create the resource group
      azure_rm_resourcegroup:
        name: my-new-rgroup
        location: westus2

# END

To remove this group, you'd make sure this group's state is "absent":

bash-5.0$ cat rgroup-del.yml
---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: delete the resource group
      azure_rm_resourcegroup:
        name: my-new-rgroup
        location: westus2
        state: absent

# END

Ansible allows a number of ways to be able to define important values: you can put a "vars" section in your playbook to define these settings. Let's make a VM! We'll need some pre-requisites: a virtual network with a subnet, a network interface, and an OS image to use as our base:

bash-5.0$ cat vm-new.yml
---
- hosts: localhost
  gather_facts: no
  vars:
    service_prefix: my-service
    rgroup_name: "{{service_prefix}}-rgroup"
    location: westus2
    subnet_name: subnet-1
    vm_size: Standard_A1

  tasks:
    - name: create resource group
      azure_rm_resourcegroup:
        name: "{{rgroup_name}}"
        location: "{{location}}"

    - name: create virtual network
      azure_rm_virtualnetwork:
        resource_group: "{{rgroup_name}}"
        name: "{{service_prefix}}-vnet"
        address_prefixes_cidr:
            - "10.0.0.0/24"

    - name: create subnet
      azure_rm_subnet:
        resource_group: "{{rgroup_name}}"
        virtual_network_name: "{{service_prefix}}-vnet"
        name: "{{subnet_name}}"
        address_prefix_cidr: "10.0.0.0/24"

    - name: create network interface
      azure_rm_networkinterface:
        name: "{{service_prefix}}-nic"
        resource_group: "{{rgroup_name}}"
        create_with_security_group: no
        virtual_network_name: "{{service_prefix}}-vnet"
        subnet_name: "{{subnet_name}}"
        ip_configurations:
          - name: ipconfig-1
      register: network_if

    - name: create vm
      azure_rm_virtualmachine:
        name: "{{service_prefix}}-vm"
        resource_group: "{{rgroup_name}}"
        os_disk_name: "{{service_prefix}}-osdisk"
        network_interface_name: "{{service_prefix}}-nic"
        vm_size: "{{vm_size}}"
        os_type: Windows
        image:
          publisher: MicrosoftWindowsServer
          offer: WindowsServer
          sku: 2019-Datacenter-smalldisk
          version: latest
        managed_disk_type: Standard_LRS
        admin_username: MyAdminUserName
        admin_password: My_Pa$$w0rd_G0es_H3r3

    - name: print IP address
      debug:
        msg: "{{network_if.state.ip_configuration.private_ip_address}}"

# END

This will create a VM in Azure that is NOT publicly accessible on the Internet at large, which is good for a demo like this, but probably not for creating a real service. You can modify this playbook to include a public IP with a network security group and a public IP.

Another concern here is hardcoding credentials into your playbook, which in general you don't want to do. I've recently learned a nifty way to generate pseudorandom passwords and you can leverage this method to create a username and password for your VM at deployment time that you won't ever accidentally upload to Github one day.

Next time: Characters wanted.

No comments: