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}}"
# ENDThe 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}}"
# ENDThis 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}}"
# ENDThis 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