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

Jinja2 templating support in inventory #101

Merged
merged 7 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/templating_support.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- >-
Added support for Jinja2 templating in ldap inventory.
13 changes: 13 additions & 0 deletions plugins/doc_fragments/ldap_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ModuleDocFragment:
installed.
- See R(LDAP authentication,ansible_collections.microsoft.ad.docsite.guide_ldap_connection.authentication)
for more information.
- This option can be set using a Jinja2 template value.
choices:
- simple
- certificate
Expand All @@ -47,6 +48,7 @@ class ModuleDocFragment:
certificate validation.
- If omitted, the default CA store used for validation is dependent on
the current Python settings.
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_CA_CERT
Expand All @@ -60,6 +62,7 @@ class ModuleDocFragment:
hostname checks performed by TLS.
- See R(Certificate validation,ansible_collections.microsoft.ad.docsite.guide_ldap_connection.cert_validation)
for more information.
- This option can be set using a Jinja2 template value.
choices:
- always
- ignore
Expand All @@ -80,6 +83,7 @@ class ModuleDocFragment:
- Use I(certificate_key) if the certificate specified does not contain the
key.
- Use I(certificate_password) if the key is encrypted with a password.
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_CERTIFICATE
Expand All @@ -89,20 +93,23 @@ class ModuleDocFragment:
- The value can either be a path to a file containing the key in the PEM or
DER encoded form, or it can be the string of a PEM encoded key.
- Use I(certificate_password) if the key is encrypted with a password.
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_CERTIFICATE_KEY
certificate_password:
description:
- The password used to decrypt the certificate key specified by
I(certificate) or I(certificate_key).
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_CERTIFICATE_PASSWORD
connection_timeout:
description:
- The timeout in seconds to wait until the connection is established before
failing.
- This option can be set using a Jinja2 template value.
default: 5
type: int
env:
Expand All @@ -117,6 +124,7 @@ class ModuleDocFragment:
- If using C(auth_protocol=simple) over LDAP without TLS then this must be
set to C(False). As no encryption is used, all traffic will be in
plaintext and should be avoided.
- This option can be set using a Jinja2 template value.
default: true
type: bool
env:
Expand All @@ -129,6 +137,7 @@ class ModuleDocFragment:
- If I(auth_protocol) is C(negotiate), C(kerberos), or C(ntlm) and no
password is specified, it will attempt to use the local cached credential
specified by I(username) if available.
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_PASSWORD
Expand All @@ -137,6 +146,7 @@ class ModuleDocFragment:
- The LDAP port to use for the connection.
- Port 389 is used for LDAP and port 686 is used for LDAPS.
- Defaults to port C(636) if C(tls_mode=ldaps) otherwise C(389).
- This option can be set using a Jinja2 template value.
type: int
env:
- name: MICROSOFT_AD_LDAP_PORT
Expand All @@ -147,6 +157,7 @@ class ModuleDocFragment:
C(default_realm) setting and with an SRV DNS lookup.
- See R(Server lookup,ansible_collections.microsoft.ad.docsite.guide_ldap_connection.server_lookup)
for more information.
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_SERVER
Expand All @@ -159,6 +170,7 @@ class ModuleDocFragment:
operation before the authentication bind.
- It is recommended to use C(ldaps) over C(start_tls) if TLS is going to be
used.
- This option can be set using a Jinja2 template value.
choices:
- ldaps
- start_tls
Expand All @@ -173,6 +185,7 @@ class ModuleDocFragment:
- If I(auth_protocol) is C(negotiate), C(kerberos), or C(ntlm) and no
username is specified, it will attempt to use the local cached credential
if available, for example one retrieved by C(kinit).
- This option can be set using a Jinja2 template value.
type: str
env:
- name: MICROSOFT_AD_LDAP_USERNAME
Expand Down
34 changes: 33 additions & 1 deletion plugins/inventory/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
information.
- This plugin is a tech preview and the module options are subject to change
based on feedback received.
- Unless specified otherwise in the option description, the value specified in
the config file is used as is. Only the LDAP connection options allow using
a Jinja2 template.
extends_documentation_fragment:
- constructed
- microsoft.ad.ldap_connection
Expand Down Expand Up @@ -125,6 +128,11 @@
tls_mode: ldaps
ca_cert: /home/user/certs/ldap.pem

# The username and password can be retrieved using a template with a lookup.
# Other connection options can also be set this way, the option description
# tells you whether it can be set to a template.
username: '{{ lookup("ansible.builtin.env", "LDAP_USERNAME") }}'
password: '{{ lookup("ansible.builtin.env", "LDAP_PASSWORD") }}'

##############################################
# Search Options #
Expand Down Expand Up @@ -311,8 +319,32 @@ def parse(
custom_attributes["inventory_hostname"] = {
"inventory_hostname": inventory_hostname
}

connection_options = self.get_options()

# These options are in ../doc_fragments/ldap_connection.py
template_fields = {
'auth_protocol',
'ca_cert',
'cert_validation',
'certificate',
'certificate_key',
'certificate_password',
'connection_timeout',
'encrypt',
'password',
'port',
'server',
'tls_mode',
'username',
}
for option_name, option_value in connection_options.items():
if option_name in template_fields and self.templar.is_template(option_value):
self.display.vvv(f"Templating option {option_name}")
connection_options[option_name] = self.templar.template(
variable=option_value,
disable_lookups=False,
)

laps_decryptor = LAPSDecryptor(**connection_options)
with create_ldap_connection(**connection_options) as client:
schema = LDAPSchema.load_schema(client)
Expand Down
17 changes: 17 additions & 0 deletions tests/integration/targets/inventory_ldap/roles/test/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,23 @@
assert:
that: *default-assertion

- import_tasks: invoke.yml
vars:
scenario: LDAP through lookup templates
inventory:
plugin: microsoft.ad.ldap
server: !unsafe '{{ lookup("ansible.builtin.env", "LDAP_SERVER") }}'
username: !unsafe '{{ lookup("ansible.builtin.env", "LDAP_USERNAME") }}'
password: !unsafe '{{ lookup("ansible.builtin.env", "LDAP_PASSWORD") }}'
environment:
LDAP_SERVER: '{{ ldap_server }}'
LDAP_USERNAME: '{{ ldap_user }}'
LDAP_PASSWORD: '{{ ldap_pass }}'

- name: assert LDAP through lookup templates
assert:
that: *default-assertion

- import_tasks: invoke.yml
vars:
scenario: LDAPS
Expand Down