I thought I’d give Ansible another shot now it’s owned by RedHat (IBM). As kickstart is a bit limiting.

It seems a bit more robust these days, there’s less need to shell out to do the simplest tasks - probably due to the growing number of builtin modules.

Inventories seem to have matured as has Vault, which is now very simple to use - especially if you use it inline. For example, to encrypt your ssh/su/grub password you can use the following in inventory.yaml:

      ansible_ssh_user: testuser
      ansible_ssh_pass: !vault |
      ansible_become_pass: !vault |
    grub_password: !vault |

The strings are generated using:

ansible-vault encrypt_string 'password123' --name 'ansible_ssh_pass'

Then to run the playbook and get it to prompt for your vault password you call:

ansible-playbook -i inventory.yml playbook.yml --ask-vault-pass

If you don’t want to enter your password you can be naughty and store the plaintext in a file and tell Ansible where to find it via ansible.cfg:

  vault_password_file = .vault_pass

Don’t forget to add .vault_pass to .gitignore so you don’t end up checking your plaintext password into version control.

Also to prevent your passwords being exposed as variables in verbose mode, be sure to set no_log: true, for example here we use the expect module to set the grub password (which asks twice for the password) passing in the decrypted grub_password variable, and then notifying a handler that runs grub2-mkconfig:

- name: Set grub password
    command: grub2-setpassword
      Enter password: "{{ grub_password }}"
      Confirm password: "{{ grub_password }}"
    creates: /boot/grub2/user.cfg
  notify: grub2-mkconfig
  no_log: true

I did still find there are a few things you have to shell out to do, for instance line_in_file and replace still seem to append to the string to the file every time you run it in certain cases, mainly due to the syntax of the files you’re trying to edit. In the case of trying to ensure audit=1 is part of GRUB_CMDLINE_LINUX in /etc/default/grub, to prevent it ending up as GRUB_CMDLINE_LINUX="blah audit=1 audit=1" on the second iteration, I had to shell out to grep to check if it was already there or not:

- name: Grub audit check
  ansible.builtin.command: grep audit=1 /boot/grub2/grubenv
  register: audit_check
  failed_when: "audit_check.rc == 2"
  changed_when: False

- name: Enable auditd
    path: /etc/default/grub
    regexp: '^(GRUB_CMDLINE_LINUX=".*)"$'
    replace: '\1 audit=1"'
  when: audit_check.stdout == ""
  notify: grub2-mkconfig

I’ve found ansible-lint to be quite handy, although some test cases are still broken from years ago e.g. checking for an empty string is perfectly valid python, however ansible-lint will return an error 602, so we can add stupid policies to ignore via the .ansible-lint rc file:

# .ansible-lint
    - '602' # ansible bug, it is valid python
    - '403' # we want to update to latest packages

Speaking of linting, I’ve also been using shellcheck, black and pylint a lot more recently, and have come to the conclusion that my shell scripting is better than my python!

I should be getting FTTP soon, at the moment 1000/220 is available as FTTPoD but should be generally available soon. I’m trying to figure out how to get the cabling from the ONT to the router and onto my LAN, as I doubt Openreach will move the entry point from the duct at the front door where my FTTC/ADSL comes in to somewhere near a wall port. I’ve bought some flat CAT6 but am not too happy with running it ten metres around the lounge to a wall port. I wonder about running it up the outside guttering, through the eaves and into the loft where the switch/patchpanel is but I’d still have to run some underground across the house from the front door to the gutter in some conduit. I can’t see how I’d run it within the walls as there’s lintels, solid floors etc in the way.