From 9af202e8ff0f816fc8186817646cde3d77d0f264 Mon Sep 17 00:00:00 2001 From: Gianluca Salvo Date: Tue, 19 Mar 2024 21:33:50 +0100 Subject: [PATCH] Jinja2 templating support in inventory (#101) Jinja2 templating support in inventory (#101) --------- Co-authored-by: Gianluca Salvo Co-authored-by: Jordan Borean --- changelogs/fragments/templating_support.yml | 3 ++ plugins/doc_fragments/ldap_connection.py | 13 +++++++ plugins/inventory/ldap.py | 34 ++++++++++++++++++- .../inventory_ldap/roles/test/tasks/main.yml | 17 ++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/templating_support.yml diff --git a/changelogs/fragments/templating_support.yml b/changelogs/fragments/templating_support.yml new file mode 100644 index 0000000..8707554 --- /dev/null +++ b/changelogs/fragments/templating_support.yml @@ -0,0 +1,3 @@ +minor_changes: + - >- + Added support for Jinja2 templating in ldap inventory. diff --git a/plugins/doc_fragments/ldap_connection.py b/plugins/doc_fragments/ldap_connection.py index 9300881..327c1ba 100644 --- a/plugins/doc_fragments/ldap_connection.py +++ b/plugins/doc_fragments/ldap_connection.py @@ -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 @@ -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 @@ -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 @@ -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 @@ -89,6 +93,7 @@ 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 @@ -96,6 +101,7 @@ class ModuleDocFragment: 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 @@ -103,6 +109,7 @@ class ModuleDocFragment: 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: @@ -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: @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/plugins/inventory/ldap.py b/plugins/inventory/ldap.py index c5b34c8..0a329da 100644 --- a/plugins/inventory/ldap.py +++ b/plugins/inventory/ldap.py @@ -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 @@ -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 # @@ -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) diff --git a/tests/integration/targets/inventory_ldap/roles/test/tasks/main.yml b/tests/integration/targets/inventory_ldap/roles/test/tasks/main.yml index a5ebcd4..7e0bb2e 100644 --- a/tests/integration/targets/inventory_ldap/roles/test/tasks/main.yml +++ b/tests/integration/targets/inventory_ldap/roles/test/tasks/main.yml @@ -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