Securely joining Active Directory after deploying?

I’ve spent a few days trying to figure out how to have a node securely join our internal Active Directory servers after a MAAS deployment to a bare-metal server. So far I haven’t found a way that doesn’t involve at least one of:

  • running a separate command to pre-create the machine accounts, then going back to the web UI to deploy, or
  • putting passwords or private keys/keytabs into plain-text files, or
  • having the same one-time machine password for all machines that’s embedded into the Kickstart file for the Packer image

Does anybody have a recipe that avoids all these pitfalls?

On xcat, we have a script that does something like:

  • kinit to get service account credentials (this is when the admin doing the deploying can enter the service account password so that it doesn’t have to be stored)
  • for each machine in the specified range:
    – generate a random one-time password
    – adcli preset-computer to set the one-time password
    – put the one-time password into the kickstart file for that machine
    – run the install

I’m sure that there must be a way to handle this securely, but I’ve been having surprisingly little luck with all my Googling.

1 Like

For anyone interested, what I ended up doing via Ansible is:

Vault the service account password using:

ansible-vault encrypt_string --vault-password-file /tmp/protected_vault_password_file --stdin-name 'content'
# paste the service account password, then Ctrl-D twice

Put the output of that into the playbook as a variable:

      service_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          ...bunch of encrypted gibberish...

Using local_action on the Ansible server, pre-create the machine accounts with a one-time password using:

      local_action:
        module: ansible.builtin.command
        cmd: "adcli preset-computer --stdin-password --domain={{ domain }} --domain-ou={{ domain_ou }} --one-time-password={{ lookup('ansible.builtin.password', '{{ one_time_password_path }} chars=ascii_lowercase,ascii_uppercase length=14') }} --login-user={{ service_user }} {{ hostname_short_upper }}"
        args:
          stdin: "{{ service_password }}"

On the client machine, join the machine to the domain with the one-time password using:

      ansible.builtin.shell:
        cmd: "adcli join --domain={{ domain }} --one-time-password={{ lookup('ansible.builtin.password', '{{ one_time_password_path }}') }} --computer-name={{ hostname_short_upper }}"

There’s obviously a bunch more stuff to do with setting variables, deleting the computer account if it already exists, checking to see if the account was created successfully, etc.

2 Likes

Hi @andrew-boatrocker!

Thank you for revisiting this post with the solution that you found to your question - other users will appreciate this.

As this has been solved, I’m going to close this topic. If you have any further questions, please do feel free to make a new post.

All the best.