Automating Azure Deployments with Ansible on OpenBSD: Part 3
Way back when, you'd have to keep your password somewhere in plain text because you needed it in an important script you needed to run. Maybe you chmoded and chowned it so that people couldn't get to it, but at the end of the day it always just worked without you having to think about it; so much so that you forgot it was there and then you accidentally checked that script into source control and uploaded it to the world and you didn't realize it until, like, at best, an hour later. There's a better way.
In general when I'm uploading VM images to Azure, I've already configured a remote management user. OpenBSD makes this trivial by allowing you to add a user during autoinstall(8):
Setup a user = remoteadmin Full name for user = remoteadmin Password for user = ************* Public ssh key for user remoteadmin = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILool4pwv0BHb25YZjzq36Wl4GgqRvdFfKuDHvcSm89I
My Ansible host has this SSH key, so it can manage any VM that is created from this image. Remember to create /etc/doas.conf if you need to elevate your permissions!
Azure VM deployments require a username and (usually) a password or else the deployment won't pass the validation step. (Microsoft really doesn't want you proverbially locking your keys in the car with your baby inside it.) I don't want to define another superuser for my VMs, but since I'm forced to do so, I am going to make it something no one is ever going to be able to use, not even me.
To accomplish this, I end up needing to randomly generate a username and a password — credentials I'm never going to use — just to make Azure happy. I discovered a neat way to make this happen:
bash-5.0$ cat credentials-new-fromshell.yml --- - hosts: localhost gather_facts: no tasks: - name: generate username run_once: yes local_action: shell: head -10 /dev/urandom | strings | tr -cd '[:lower:]' | tr -d 'aeiou' | fold -w12 | head -1 register: username - name: generate password run_once: yes local_action: shell: head -30 /dev/urandom | strings | tr -cd '[:punct:]''[:alnum:]' | tr -d "\\\//\#\'\"\`\$\[\]\{\}" | fold -w72 | head -1 register: password - name: print username debug: msg: "{{username.stdout}}" - name: print password debug: msg: "{{password.stdout}}" # END
The run_once part is also critical: if you deploy multiple VMs, you want to make sure they all get the same username and password values you generated.
This works, but it feels sloppy. You'd think that a machine management platform would have a builtin solution to the problem of generating passwords. Fortunately, Ansible can handle this with the password plugin, but it isn't nearly as well known as it should be:
bash-5.0$ cat credentials-new-frombuiltin.yml --- - hosts: localhost gather_facts: no tasks: - name: generate credential run_once: yes set_fact: username: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters')|lower }}" password: "{{ lookup('password', '/dev/null length=64 chars=ascii_letters,digits,punctuation') }}" - name: print credential debug: msg: "username: {{username}} password: {{password}}" # END
This is how I recommend you generate your random usernames and passwords. So to put this into an example:
bash-5.0$ cat vm-randomusername-new.yml --- - hosts: localhost gather_facts: no vars: service_prefix: my-service rgroup_name: "{{service_prefix}}-rgroup" location: westus2 vm_size: Standard_A1 tasks: - name: generate credential run_once: yes set_fact: username: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters')|lower }}" password: "{{ lookup('password', '/dev/null length=64 chars=ascii_letters,digits,punctuation') }}" # (vnet, network interface resources go here) - name: create vm azure_rm_virtualmachine: name: "{{service_prefix}}-ubuntu1" resource_group: "{{rgroup_name}}" location: "{{location}}" vm_size: "{{vm_size}}" admin_username: "{{username}}" admin_password: "{{password}}" os_type: Linux image: publisher: Canonical offer: UbuntuServer sku: 18.04-LTS version: latest os_disk_name: "{{service_prefix}}-osdisk" managed_disk_type: Standard_LRS network_interface_names: "{{service_prefix}}-nic" started: no state: present - name: print credential debug: msg: "username: {{username}} password: {{password}}" # END
This is the last problem I needed to solve in order to completely automate my OpenBSD VM deployment pipeline. I can provision a VM with a PowerShell script and an autoinstall(8) config file. I can set it up with an Ansible playbook and a bevy of assigned roles. I can upload the .VHD file with a wrapper script around blobxfer and now, finally, I can create an Azure image and deploy VMs with an Ansible playbook using Azure management modules.
Life is good.
No comments:
Post a Comment