Skip to content

Commit

Permalink
Add identity server lookup base code
Browse files Browse the repository at this point in the history
Add a way to specify a custom server to lookup an AD identity on when
using module options that accept a list of identities for an attribute.
For example the microsoft.ad.group members option.

Also adds the domain_credentials option that is common to add AD based
modules to specify credentials for the extra AD servers being contacted
in case the default credentials do not work.

Migrates existing options that accept a distinguishedName to the new
lookup code to align the behaviour across the modules.
  • Loading branch information
jborean93 committed May 29, 2024
1 parent ef2a62e commit ae65779
Show file tree
Hide file tree
Showing 19 changed files with 783 additions and 258 deletions.
19 changes: 19 additions & 0 deletions changelogs/fragments/lookup-dn.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
minor_changes:
- >-
microsoft.ad AD modules - Added ``domain_credentials`` as a common module option that can be used to specify
credentials for specific AD servers.
- >-
microsoft.ad AD modules - Added ``lookup_failure_action`` on all modules that can specify a list of
distinguishedName values to control what should happen if the lookup fails.
- >-
microsoft.ad.computer - Added the ability to lookup a distinguishedName on a specific domain server for
``delegates`` and ``managed_by``.
- >-
microsoft.ad.group - Added the ability to lookup a distinguishedName on a specific domain server for
``managed_by`` and ``members``.
- >-
microsoft.ad.ou - Added the ability to lookup a distinguishedName on a specific domain server for
``managed_by``.
- >-
microsoft.ad.user - Added the ability to lookup a distinguishedName on a specific domain server for
``delegates``.
1 change: 1 addition & 0 deletions docs/docsite/extra-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
sections:
- title: Scenario Guides
toctree:
- guide_ad_module_authentication
- guide_attributes
- guide_ldap_connection
- guide_ldap_inventory
Expand Down
120 changes: 120 additions & 0 deletions docs/docsite/rst/guide_ad_module_authentication.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
.. _ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication:

****************************
AD Authentication in Modules
****************************

A key requirement of the modules used inside this collection is being able to authenticate a user to the domain controller when managing a resource. This guide will cover the different options available for this scenario.

.. note::
This guide covers authentication to a domain controller when using a module on a Windows host. See :ref:`LDAP Authentication <ansible_collections.microsoft.ad.docsite.guide_ldap_connection.authentication>` for information on how authentication is done when using plugins running on Linux.

.. contents::
:local:
:depth: 1

.. _ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication.implicit_auth:

Implicit Authentication
=======================

The first and simplest option is to use the connection user's existing credentials during authentication. This avoids having to specify a username and password in the module's parameters, but it does require that the connection method used by Ansible supports credential delegation. For example using CredSSP authentication with the ``winrm`` and ``psrp`` connection plugin, or using Kerberos delegation. Other authentication options, like NTLM, do not support credential delegation and will not work with implicit authentication.

The only way to test out if implicit authentication is available is to run the module and see if it works. If it does not work then the error will most likely contain the message ``Failed to contact the AD server``.

.. _ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication.become:

Become
======

If implicit authentication is not available, the module can be run with ``become`` that specifies the username and password to use for authentication.

.. code-block:: yaml
- name: Use become with connection credentials
microsoft.ad.user:
name: MyUser
state: present
become: true
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: '{{ ansible_user }}'
ansible_become_pass: '{{ ansible_password }}'
The ``runas`` method is used on Windows and the ``become_flags`` will specify that the credentials should be used for network authentication only. The ``ansible_become_user`` and ``ansible_become_pass`` variables specify the username and password to use for authentication. It is important that both of these variables are set to a valid username and password or else the authentication will fail.

It is also possible to use the ``SYSTEM`` account for become. This will have the module use the AD computer account for that host when authenticating with the target DC rather than an explicit username and password. The AD computer account must still have the required rights to perform the operation requested.

.. code-block:: yaml
- name: Use machine account for authentication
microsoft.ad.user:
name: MyUser
state: present
become: true
become_method: runas
become_user: SYSTEM
.. _ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication.explicit_creds:

Explicit Credentials
====================

The final option is to specify the username and password as module options. This can be done in two ways; with the ``domain_username`` and ``domain_password`` options, or with the ``domain_credentials`` option. An example of both methods is shown below.

.. code-block:: yaml
- name: Use domain_username and domain_password
microsoft.ad.user:
name: MyUser
state: present
domain_username: '{{ ansible_user }}'
domain_password: '{{ ansible_password }}'
- name: Use domain_credentials
name: MyUser
state: present
domain_credentials:
- username: '{{ ansible_user }}'
password: '{{ ansible_password }}'
.. note::
The ``domain_credentials`` option was added in version 1.6.0 of this collection.

The ``domain_credentials`` option without the ``name`` key, like in the above example, will be the credentials used for authentication with the default domain controller just like ``domain_username`` and ``domain_password``. Using both options together is not supported and will result in an error.

The ``domain_credentials`` option can also be used to specify server specific credentials. For example when attempting to lookup the identity of an AD object:

.. code-block:: yaml
- name: Set member with lookup on different server
microsoft.ad.group:
name: MyGroup
state: present
members:
add:
- GroupOnDefaultDC
- name: GroupOnDefaultDC2
- name: GroupOnOtherDC
server: OtherDC
- name: GroupOnThirdDC
server: ThirdDC
domain_credentials:
- username: UserForDefaultDC
password: PasswordForDefaultDC
- name: OtherDC
username: UserForOtherDC
password: PasswordForOtherDC
In the case above there are three members being added to the group:

* ``GroupOnDefaultDC`` - Will be looked up on the default domain controller using ``UserForDefaultDC`` and ``PasswordForDefaultDC``
* ``GroupOnDefaultDC2`` - Same as the above just specified as a dictionary
* ``GroupOnOtherDC`` - Will be looked up on ``OtherDC`` using ``UserForOtherDC`` and ``PasswordForOtherDC``
* ``GroupOnThirdDC`` - Will be looked up on ``ThirdDC`` using the implicit user authentication context

The value for ``server`` must correspond to a ``name`` entry in ``domain_credentials``. If the server is not specified in ``domain_credentials``, the module will default to using the ``domain_username/domain_password`` or implicit user authentication.

.. note::
The default (no ``name`` key) entry in ``domain_credentials`` is only used for lookups without an explicit server set. The ``domain_username`` and ``domain_password`` credential will be used for all connections unless there is an explicit server entry in ``domain_credentials``.
74 changes: 74 additions & 0 deletions docs/docsite/rst/guide_attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,77 @@ SDDL strings can be quite complex so building them manually is ill-advised. It i
$dn = 'CN=ObjectName,DC=domain,DC=test'
$obj = Get-ADObject -Identity $dn -Properties nTSecurityDescriptor
$obj.nTSecurityDescriptor.GetSecurityDescriptorSddlForm('All')
.. _ansible_collections.microsoft.ad.docsite.guide_attributes.dn_lookup_attributes:

DN Lookup Attributes
====================

Some attributes in Active Directory are stored as a Distinguished Name (``DN``) value that references another AD object. Some modules expose a way to lookup the DN using a more human friendly value, such as ``managed_by``. These option values must either be a string or a dictionary with the key ``name`` and optional key ``server``. The string value or the value of ``name`` is the identity to lookup while ``server`` is the domain server to lookup the identity on. The lookup identity value can be specified as a ``distinguishedName``, ``objectGUID``, ``objectSid``, ``sAMAccountName``, or ``userPrincipalName``. The below is an example of how to lookup a DN using the ``sAMAccountName`` using a string value or in the dictionary form:

.. code-block:: yaml
- name: Find managed_by using string value
microsoft.ad.group:
name: My Group
scope: global
managed_by: Domain Admins
- name: Find managed_by using dictionary value with a server
microsoft.ad.group:
name: My Group
scope: global
managed_by:
name: Domain Admins
server: OtherDC
There are also module options that can set a list of DN values for an attribute. The list values for these options are the same as the single value attributes where each DN lookup is set as a string or a dictionary with the ``name`` and optional ``server`` key.

.. code-block:: yaml
- name: Specify a list of DNs to set
microsoft.ad.computer:
identity: TheComputer
delegates:
set:
- FileShare
- name: ServerA
server: OtherDC
For list attributes with the ``add/remove/set`` subkey options, the ``lookup_failure_action`` option can also be set to ``fail`` (default), ``ignore``, or ``warn``. The ``fail`` option will fail the task if any of the lookups fail, ``ignore`` will ignore any invalid lookups, and ``warn`` will emit a warning but still continue on a lookup failure.

.. code-block:: yaml
- name: Specify a list of DNs to set - ignoring lookup failures
microsoft.ad.computer:
identity: TheComputer
delegates:
lookup_failure_action: ignore
set:
- FileShare
- MissingUser
When a ``server`` key is provided, the lookup will be done using the server value specified. It is possible to also provide explicit credentials just for that server using the ``domain_credentials`` option.

.. code-block:: yaml
- name: Set member with lookup on different server
microsoft.ad.group:
name: MyGroup
state: present
members:
add:
- GroupOnDefaultDC
- name: GroupOnDefaultDC2
- name: GroupOnOtherDC
server: OtherDC
domain_credentials:
- username: UserForDefaultDC
password: PasswordForDefaultDC
- name: OtherDC
username: UserForOtherDC
password: PasswordForOtherDC
In the above, the ``GroupOnOtherDC`` will be done with ``OtherDC`` with the username ``UserForOtherDC``.

The documentation for the module option will identify if the option supports the lookup behaviour or whether a DN value must be explicitly provided.
2 changes: 1 addition & 1 deletion docs/docsite/rst/guide_ldap_connection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LDAP Connection guide
This guide covers information about communicating with an LDAP server, like Microsoft Active Directory, from the Ansible host. Unlike Windows hosts, there are no builtin mechanisms to communicate and authenticate with an LDAP server, so the plugins that run on the Ansible host require some extra configuration to get working.

.. note::
This guide covers LDAP communication from the Ansible host. This does not apply to the modules that run on the remote Windows hosts.
This guide covers LDAP communication from the Ansible host. This does not apply to the modules that run on the remote Windows hosts. See :ref:`AD Authentication in Modules <ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication>` for information on how modules authentication can be configured.

.. contents::
:local:
Expand Down
24 changes: 24 additions & 0 deletions docs/docsite/rst/guide_migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,30 @@ Migrated to :ref:`microsoft.ad.group <ansible_collections.microsoft.ad.group_mod

The functionality of this module has been merged with ``microsoft.ad.group``. Use the ``members`` option to ``add``, ``remove``, or ``set`` to add, remove, or set group members respectively.

One change is ``win_domain_group_membership`` could specify the server to lookup the member using the ``SERVER\member-name`` format. This member format is not supported in ``microsoft.ad.group`` but since v1.6.0 of this collection the same can be achieved by using a dictionary as the member value. For example:

.. code-block:: yaml
- name: Add a domain user/group from another Domain in the multi-domain forest to a domain group
community.windows.win_domain_group_membership:
name: GroupinDomainAAA
domain_server: DomainAAA.cloud
members:
- DomainBBB.cloud\UserInDomainBBB
state: present
- name: Add a domain user/group from another Domain in the multi-domain forest to a domain group
microsoft.ad.group:
name: GroupinDomainAAA
domain_server: DomainAAA.cloud
members:
add:
- name: UserInDomainBBB
server: DomainBBB.cloud
state: present
See :ref:`DN Lookup Attributes <ansible_collections.microsoft.ad.docsite.guide_attributes.dn_lookup_attributes>` for more information.

.. _ansible_collections.microsoft.ad.docsite.guide_migration.migrated_modules.win_domain_object_info:

Module ``win_domain_object_info``
Expand Down
44 changes: 44 additions & 0 deletions plugins/doc_fragments/ad_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,48 @@ class ModuleDocFragment:
- The display name of the AD object to set.
- This is the value of the C(displayName) LDAP attribute.
type: str
domain_credentials:
description:
- Specifies the credentials that should be used when using the server
specified by I(name).
- To specify credentials for the default domain server, use an entry
without the I(name) key or use the I(domain_username) and
I(domain_password) option.
- This can be set under the R(play's module defaults,module_defaults_groups)
under the C(group/microsoft.ad.domain) group.
- See R(AD authentication in modules,ansible_collections.microsoft.ad.docsite.guide_ad_module_authentication)
for more information.
default: []
type: list
elements: dict
suboptions:
name:
description:
- The name of the server these credentials are for.
- This value should correspond to the value used in other options that
specify a custom server to use, for example an option that references
an AD identity located on a different AD server.
- This key can be omitted in one entry to specify the default
credentials to use when a server is not specified instead of using
I(domain_username) and I(domain_password).
type: str
username:
description:
- The username to use when connecting to the server specified by
I(name).
type: str
required: true
password:
description:
- The password to use when connecting to the server specified by
I(name).
type: str
required: true
domain_password:
description:
- The password for I(domain_username).
- The I(domain_credentials) sub entry without a I(name) key can also be
used to specify the credentials for the default domain authentication.
- This can be set under the R(play's module defaults,module_defaults_groups)
under the C(group/microsoft.ad.domain) group.
type: str
Expand All @@ -87,6 +126,9 @@ class ModuleDocFragment:
- Specified the Active Directory Domain Services instance to connect to.
- Can be in the form of an FQDN or NetBIOS name.
- If not specified then the value is based on the default domain of the computer running PowerShell.
- Custom credentials can be specified under a I(domain_credentials) entry
without a I(name) key or through I(domain_username) and
I(domain_password).
- This can be set under the R(play's module defaults,module_defaults_groups)
under the C(group/microsoft.ad.domain) group.
type: str
Expand All @@ -96,6 +138,8 @@ class ModuleDocFragment:
- If this is not set then the user that is used for authentication will be the connection user.
- Ansible will be unable to use the connection user unless auth is Kerberos with credential delegation or CredSSP,
or become is used on the task.
- The I(domain_credentials) sub entry without a I(name) key can also be
used to specify the credentials for the default domain authentication.
- This can be set under the R(play's module defaults,module_defaults_groups)
under the C(group/microsoft.ad.domain) group.
type: str
Expand Down
Loading

0 comments on commit ae65779

Please sign in to comment.