Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win_group_membership failing if user/group specified is already a member of the group #40649

Closed
kxseven opened this issue May 24, 2018 · 8 comments
Labels
affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. module This issue/PR relates to a module. support:community This issue/PR relates to code supported by the Ansible community. windows Windows community

Comments

@kxseven
Copy link

kxseven commented May 24, 2018

SUMMARY
  • When using the win_group_membership module the invocation fails if user/group specified is already a member of the group
  • This happens when the user/group has been added manually and then Ansible is run (Ansible did not add member to group)
  • This also happens when Ansible is invoked multiple times; Ansible added the user/group as a member on 1st run but on 2nd and future runs it will fail
  • Tested with Ansible v2.4.3 and v2.5.3
ISSUE TYPE
  • Bug Report
COMPONENT NAME

win_group_membership.ps1

(Ref: https://devdocs.io/ansible~2.4/win_group_membership_module)

ANSIBLE VERSION
ansible 2.5.3
  config file = /opt/ansible-workspace/ansible.cfg
  configured module search path = [u'/home/ec2-user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, May  3 2017, 07:55:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-14)]

ansible 2.4.3.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/xxxxxxxxxx/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
CONFIGURATION
ANSIBLE_FORCE_COLOR(/opt/ansible-workspace/ansible.cfg) = True
ANSIBLE_NOCOWS(/opt/ansible-workspace/ansible.cfg) = True
ANSIBLE_PIPELINING(/opt/ansible-workspace/ansible.cfg) = False
ANSIBLE_SSH_ARGS(/opt/ansible-workspace/ansible.cfg) = -F ssh.cfg
ANSIBLE_SSH_CONTROL_PATH(/opt/ansible-workspace/ansible.cfg) = ~/.ssh/mux-%r@%h:%p
COMMAND_WARNINGS(/opt/ansible-workspace/ansible.cfg) = False
DEFAULT_GATHER_SUBSET(/opt/ansible-workspace/ansible.cfg) = network,hardware
DEFAULT_LOCAL_TMP(/opt/ansible-workspace/ansible.cfg) = /opt/ansible-workspace/.ansible/tmp/ansible-local-19063fQoa4E
DEFAULT_LOG_PATH(/opt/ansible-workspace/ansible.cfg) = /opt/ansible-workspace/log/ansible.log
DEFAULT_MANAGED_STR(/opt/ansible-workspace/ansible.cfg) = This file is managed by Ansible: modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
DEFAULT_ROLES_PATH(/opt/ansible-workspace/ansible.cfg) = [u'/opt/ansible-workspace/roles-galaxy', u'/opt/ansible-workspace/roles-common', u'/opt/ansible-workspace/roles-acia']
DEFAULT_TIMEOUT(/opt/ansible-workspace/ansible.cfg) = 15
DEPRECATION_WARNINGS(/opt/ansible-workspace/ansible.cfg) = False
DISPLAY_ARGS_TO_STDOUT(/opt/ansible-workspace/ansible.cfg) = False
DISPLAY_SKIPPED_HOSTS(/opt/ansible-workspace/ansible.cfg) = False
HOST_KEY_CHECKING(/opt/ansible-workspace/ansible.cfg) = False
RETRY_FILES_ENABLED(/opt/ansible-workspace/ansible.cfg) = False
SYSTEM_WARNINGS(/opt/ansible-workspace/ansible.cfg) = True
OS / ENVIRONMENT
  • Tested with Ansible from Ubuntu Linux (Ansible v2.4) and RedHat Linux (Ansible v2.5) to a Windows VM
  • Target Environment: Windows ansible -m setup servername123 (some info redacted)
servername123 | SUCCESS => {
    "ansible_facts": {
        "ansible_architecture": "64-bit", 
        "ansible_bios_date": "08/24/2006", 
        "ansible_bios_version": "4.2.amazon", 
        "ansible_distribution": "Microsoft Windows Server 2012 R2 Standard", 
        "ansible_distribution_major_version": "6", 
        "ansible_distribution_version": "6.3.9600.0", 
        "ansible_domain": "acme.Net", 
        "ansible_env": {
            "ALLUSERSPROFILE": "C:\\ProgramData", 
            "APPDATA": "C:\\Users\\acmadmin\\AppData\\Roaming", 
            "COMPUTERNAME": "SERVERNAME123", 
            "ComSpec": "C:\\Windows\\system32\\cmd.exe", 
            "CommonProgramFiles": "C:\\Program Files\\Common Files", 
            "CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files", 
            "CommonProgramW6432": "C:\\Program Files\\Common Files", 
            "FP_NO_HOST_CHECK": "NO", 
            "LOCALAPPDATA": "C:\\Users\\acmadmin\\AppData\\Local", 
            "NUMBER_OF_PROCESSORS": "2", 
            "OS": "Windows_NT", 
            "PATHEXT": ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL", 
            "PATROL_HOME": "C:\\PROGRA~1\\BMCSOF~1\\Patrol3", 
            "PATROL_TEMP": "C:\\PROGRA~1\\BMCSOF~1\\Patrol3\\tmp", 
            "PROCESSOR_ARCHITECTURE": "AMD64", 
            "PROCESSOR_IDENTIFIER": "Intel64 Family 6 Model 79 Stepping 1, GenuineIntel", 
            "PROCESSOR_LEVEL": "6", 
            "PROCESSOR_REVISION": "4f01", 
            "PROMPT": "$P$G", 
            "PSExecutionPolicyPreference": "Unrestricted", 
            "PSModulePath": "C:\\Users\\acmadmin\\Documents\\WindowsPowerShell\\Modules;C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\;C:\\Program Files (x86)\\AWS Tools\\PowerShell", 
            "ProgramData": "C:\\ProgramData", 
            "ProgramFiles": "C:\\Program Files", 
            "ProgramFiles(x86)": "C:\\Program Files (x86)", 
            "ProgramW6432": "C:\\Program Files", 
            "SystemDrive": "C:", 
            "SystemRoot": "C:\\Windows", 
            "USERDOMAIN": "SERVERNAME123", 
            "USERPROFILE": "C:\\Users\\acmadmin", 
            "windir": "C:\\Windows"
        }, 
        "ansible_fqdn": "SERVERNAME123.acme.Net", 
        "ansible_hostname": "SERVERNAME123", 
        "ansible_kernel": "6.3.9600.0", 
        "ansible_lastboot": "2018-05-23 14:25:28Z", 
        "ansible_nodename": "SERVERNAME123.acme.Net", 
        "ansible_os_family": "Windows", 
        "ansible_os_name": "Microsoft Windows Server 2012 R2 Standard", 
        "ansible_owner_name": "EC2", 
        "ansible_powershell_version": 4, 
        "ansible_reboot_pending": true, 
        "ansible_swaptotal_mb": 0, 
        "ansible_system": "Win32NT", 
        "ansible_windows_domain": "acme.Net", 
        "ansible_windows_domain_member": true, 
        "ansible_windows_domain_role": "Member server", 
        "gather_subset": [
            "all"
        ], 
        "module_setup": true
    }, 
    "changed": false
}
STEPS TO REPRODUCE
win_group_membership:
    name: "Administrators"
    members: "{{ windows_domain_name }}\\{{ ansible_hostname|upper }}"
    state: present
EXPECTED RESULTS
  • Multiple runs should succeed without failing if the user/group is already a member
ACTUAL RESULTS

The Ansible task fails with a fatal error

fatal: [servername123]: FAILED! => {"added": [], "changed": false, "msg": "Exception calling \"Add\" with \"1\" argument(s): \"The specified account name is already a member of the group.\r\n\"", "name": "Administrators"}
@kxseven
Copy link
Author

kxseven commented May 24, 2018

In the event that anyone has a similar issue and needs a workaround until this is fixed - I use the following snippet instead

- name: Add new Role Group to Local Admins via PowerShell
  raw: "powershell.exe -ExecutionPolicy Unrestricted -command \"& { ([adsi]'WinNT://./administrators').Add('WinNT://{{ windows_domain_name }}/{{ ansible_hostname|upper }},group'); }\""

@ansibot ansibot added affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. needs_triage Needs a first human triage before being processed. support:core This issue/PR relates to code supported by the Ansible Engineering Team. labels May 24, 2018
@samdoran
Copy link
Contributor

!component =lib/ansible/modules/windows/win_group_membership.ps1

@samdoran samdoran removed the needs_triage Needs a first human triage before being processed. label May 24, 2018
@ansibot
Copy link
Contributor

ansibot commented May 24, 2018

@ansibot ansibot added module This issue/PR relates to a module. support:community This issue/PR relates to code supported by the Ansible community. windows Windows community and removed support:core This issue/PR relates to code supported by the Ansible Engineering Team. labels May 24, 2018
@andrewsaraceni
Copy link
Contributor

andrewsaraceni commented May 24, 2018

Hey @kxseven, I suspect the problem you're seeing is actually what was previously identified in #39358, where the module fails to add/remove members of a group where the system hostname is part of the member name. This should only occur in domain user/group scenarios, as local groups cannot be added to another local group, and local users the same name as the hostname cannot be created. In general, the module should work without issue for any other user or group you try that doesn't contain the hostname within its name.

The initial solution proposed by @phobos786 I don't believe covered this particular case, since your domain group is an exact match of the hostname, rather than the hostname being a subset of the group name.

My testing shows changing line 136 of the module, which is used to identify local objects, to the following fixes this:

if ($split_adspath -match "^$env:COMPUTERNAME$" -and $split_adspath[-1] -notmatch $env:COMPUTERNAME) {
    ...
}

This covers both preventing against an accidental substring match, while also allowing for domain users and groups to have a name that can exactly match the hostname. i.e. Anything other than the final ADsPath item once split must match the hostname exactly to be considered local.

I'll see if I can put in a quick PR later to address this, since a couple of folks have encountered it.

@jborean93
Copy link
Contributor

After looking at this I think the best and proper option to go forward with is to not compare against strings but against the SID's of the objects. We can easily get the SIDs of the accounts in a group with

$group_members = $Group.psbase.Invoke("Members") | ForEach-Object {
    $bytes = ([ADSI]$_).InvokeGet("objectSID")
    $sid = New-Object -TypeName Security.Principal.SecurityIdentifier -ArgumentList $bytes, 0
    $sid
}

This returns an array of SecurityIdentifier objects that are members of that group. From there we can compare the members that we want to add/remove/set from the Ansible args and act accordingly. This was we don't need to worry about checking domain, account names but the unique identifier for each account.

@andrewsaraceni
Copy link
Contributor

Hey @jborean93, that's a good idea, and would definitely simplify a lot of the code, as most of the work could probably be offloaded to the SID ModuleUtils you wrote.

The only concern I can think of in doing this would be the change in return values. I'm guessing it would still make sense to return either ADsPath or the result of Convert-FromSID? This way, we could compare on SID, and still return values for members, added and removed that are at least somewhat friendly to view.

Either of these options would mean return values for local accounts would no longer match across hosts (without some parsing), as computer name would be included in the path. However, to maintain purely identical results to what we have now would require much of the logic that exists today.

If this sounds like a good path to pursue, I may be able to work on something for this in the coming weeks.

@jborean93
Copy link
Contributor

I think that’s a good plan, having the hostname isn’t the end of the world, you can always split by \ if you just want the account. Definitely a +1 to returning the account name and not the SID, the SIDs should just be for internal comparison.

@jborean93
Copy link
Contributor

Was able to replicate this locally by creating an AD account with the server's hostname set as the username. When applying #40725 the issue is no longer there.

@ansible ansible locked and limited conversation to collaborators Jun 27, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. module This issue/PR relates to a module. support:community This issue/PR relates to code supported by the Ansible community. windows Windows community
Projects
None yet
Development

No branches or pull requests

5 participants