1

My company uses Ansible (which I am a novice at) and we have a playbook and a related role for joining new Linux machines to AD. Our admin accounts have their passwords rolled three times a day, and we can't set them ourselves. The Ansible playbook works so long as there is not a ' (single quote) in the password. There may be other characters that cause it to break, but I know that ' does it for sure.

Here are the relevant bits of the scripts:

cat setup-ad.yml

---
- hosts: "{{ hosts }}"

  vars_prompt:
  - name: "username"
    prompt: "Enter admin account"
    private: no

  - name: "password"
    prompt: "Enter Password"
    unsafe: yes
    private: yes

  vars:
    domain: "{{ 'mycompany.com' }}"
    passwd: "{{ password | regex_escape() }}"

  roles:
  - join-ad

grep -B2 -A3 'passwd' ./roles/join-ad/tasks/main.yml

  - name: join to active directory
    command: net ads join MYCOMPANY.COM -U {{ username }}@MYCOMPANY.COM%'{{ passwd }}' createcomputer=Restricted/Servers/Unix --request-timeout=120 --no-dns-updates
    no_log: false
    when: ansible_distribution_major_version >= 6

  - name: join to active directory
    command: net ads join MYCOMPANY.COM -U {{ username }}@MYCOMPANY.COM%'{{ passwd }}' createcomputer=Restricted/Servers/Unix --request-timeout=120
    no_log: false
    when: ansible_distribution_major_version <= 5

The error we get is:

TASK [join-ad : join to active directory] ************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ValueError: No closing quotation
fatal: [newserver.mycompany.com]: FAILED! => {"changed": false, "module_stderr": "Shared connection to newserver.mycompany.com closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n  File \"/root/.ansible/tmp/ansible-tmp-1590785720.2-224244797633747/AnsiballZ_command.py\", line 102, in <module>\r\n    _ansiballz_main()\r\n  File \"/root/.ansible/tmp/ansible-tmp-1590785720.2-224244797633747/AnsiballZ_command.py\", line 94, in _ansiballz_main\r\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n  File \"/root/.ansible/tmp/ansible-tmp-1590785720.2-224244797633747/AnsiballZ_command.py\", line 40, in invoke_module\r\n    runpy.run_module(mod_name='ansible.modules.commands.command', init_globals=None, run_name='__main__', alter_sys=True)\r\n  File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\r\n    fname, loader, pkg_name)\r\n  File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\r\n    mod_name, mod_fname, mod_loader, pkg_name)\r\n  File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\r\n    exec code in run_globals\r\n  File \"/tmp/ansible_command_payload_4D4oFT/ansible_command_payload.zip/ansible/modules/commands/command.py\", line 344, in <module>\r\n  File \"/tmp/ansible_command_payload_4D4oFT/ansible_command_payload.zip/ansible/modules/commands/command.py\", line 263, in main\r\n  File \"/usr/lib64/python2.7/shlex.py\", line 279, in split\r\n    return list(lex)\r\n  File \"/usr/lib64/python2.7/shlex.py\", line 269, in next\r\n    token = self.get_token()\r\n  File \"/usr/lib64/python2.7/shlex.py\", line 96, in get_token\r\n    raw = self.read_token()\r\n  File \"/usr/lib64/python2.7/shlex.py\", line 172, in read_token\r\n    raise ValueError, \"No closing quotation\"\r\nValueError: No closing quotation\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP *******************************************************************************************************
newserver.mycompany.com : ok=9    changed=0    unreachable=0    failed=1    skipped=2    rescued=0    ignored=0

Okay, so the issue is that at some point the ' is being interpreted as the beginning of a quoted series of characters, rather than as simply part of the password. My problem is I don't know how to get Ansible? Python? YAML? Jinja? to treat the string of characters the user inputs as nothing more than a string of characters. Is "string literal" the correct term here?

If I ssh to the target server and run the net ads join command manually, and let it prompt for my password, it will work even with a ' in it, so at the very least I know it's not the Samba command that's the issue.

The things I've tried (which haven't helped) are:

  • Add 'hard quotes' around {{ passwd }}
  • Add unsafe: yes to the password definition
  • Add passwd: "{{ password | regex_escape() }}" to escape metacharacters
  • Lots of internet searching on Stack and Google

Any and all help would be appreciated.

Linoob
  • 113
  • 3
  • @Vladimir Botka thank you! Replacing `passwd: "{{ password | regex_escape() }}"` with `passwd: "{{ password | quote }}"`, and surrounding the whole command line with `"`'s while removing the interior `'`'s like you suggested solved it for me! If you add your suggestions as an answer I will mark it as the chosen solution. – Linoob Jun 01 '20 at 18:03

1 Answers1

0

This might be what you're looking for

- command: "net ads join MYCOMPANY.COM
            -U {{ username }}@MYCOMPANY.COM%{{ passwd|quote }}
            createcomputer=Restricted/Servers/Unix --request-timeout=120"

See YAML gotcha and String filters.

Vladimir Botka
  • 3,791
  • 6
  • 17