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
Add modules to configure LDAP and create, update, and delete groups #140
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1cfc689
Added a module to configure the LDAP authentication method
jasonneurohr 829030f
Fixed spelling in ansible/modules/hashivault/hashivault_identity_grou…
jasonneurohr a64fd58
Updated hashivault_auth_list.py to return False for changed
jasonneurohr e253663
Updated hashivault_auth_ldap to do desired vs configured comparison a…
jasonneurohr 2d304bc
Updated wording in hashivault_auth_ldap & hashivault_identity_group
jasonneurohr File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
#!/usr/bin/env python | ||
from ansible.module_utils.hashivault import hashivault_argspec | ||
from ansible.module_utils.hashivault import hashivault_auth_client | ||
from ansible.module_utils.hashivault import hashivault_init | ||
from ansible.module_utils.hashivault import hashiwrapper | ||
from hvac.constants.ldap import DEFAULT_GROUP_FILTER | ||
import json | ||
|
||
ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} | ||
DOCUMENTATION = ''' | ||
--- | ||
module: hashivault_auth_ldap | ||
version_added: "3.17.7" | ||
short_description: Hashicorp Vault ldap configuration module | ||
description: | ||
- Module to configure the LDAP authentication method in Hashicorp Vault. | ||
options: | ||
url: | ||
description: | ||
- url for vault | ||
default: to environment variable VAULT_ADDR | ||
ca_cert: | ||
description: | ||
- "path to a PEM-encoded CA cert file to use to verify the Vault server TLS certificate" | ||
default: to environment variable VAULT_CACERT | ||
ca_path: | ||
description: | ||
- "path to a directory of PEM-encoded CA cert files to verify the Vault server TLS certificate : if ca_cert | ||
is specified, its value will take precedence" | ||
default: to environment variable VAULT_CAPATH | ||
client_cert: | ||
description: | ||
- "path to a PEM-encoded client certificate for TLS authentication to the Vault server" | ||
default: to environment variable VAULT_CLIENT_CERT | ||
client_key: | ||
description: | ||
- "path to an unencrypted PEM-encoded private key matching the client certificate" | ||
default: to environment variable VAULT_CLIENT_KEY | ||
verify: | ||
description: | ||
- "if set, do not verify presented TLS certificate before communicating with Vault server : setting this | ||
variable is not recommended except during testing" | ||
default: to environment variable VAULT_SKIP_VERIFY | ||
authtype: | ||
description: | ||
- "authentication type to use: token, userpass, github, ldap, approle" | ||
default: token | ||
token: | ||
description: | ||
- token for vault | ||
default: to environment variable VAULT_TOKEN | ||
username: | ||
description: | ||
- username to login to vault. | ||
default: to environment variable VAULT_USER | ||
password: | ||
description: | ||
- password to login to vault. | ||
default: to environment variable VAULT_PASSWORD | ||
mount_point: | ||
description: | ||
- location where this auth_method is mounted. also known as "path" | ||
ldap_url: | ||
description: | ||
- The LDAP server to connect to. Examples: ldap://ldap.myorg.com | ||
default: ldap://127.0.0.1 | ||
case_sensitive_names: | ||
description: | ||
- If set, user and group names assigned to policies within the backend will be case sensitive. Otherwise, | ||
names will be normalized to lower case. Case will still be preserved when sending the username to the LDAP | ||
server at login time; this is only for matching local user/group definitions. | ||
default: False | ||
starttls: | ||
description: | ||
- If true, issues a StartTLS command after establishing an unencrypted connection | ||
default: False | ||
tls_min_version: | ||
description: | ||
- Minimum TLS version to use. Accepted values are tls10, tls11 or tls12 | ||
default: tls12 | ||
tls_max_version: | ||
description: | ||
- Maximum TLS version to use. Accepted values are tls10, tls11 or tls12 | ||
default: tls12 | ||
insecure_tls: | ||
description: | ||
- If true, skips LDAP server SSL certificate verification | ||
default: False | ||
certificate: | ||
description: | ||
- CA certificate to use when verifying LDAP server certificate, must be x509 PEM encoded | ||
default: '' | ||
bind_dn: | ||
description: | ||
- Distinguished name of object to bind when performing user search. Example: cn=vault,ou=Users,dc=example,dc=com | ||
default: '' | ||
bind_pass: | ||
description: | ||
- Password to use along with binddn when performing user search | ||
default: None | ||
user_dn: | ||
description: | ||
- Base DN under which to perform user search. Example: ou=Users,dc=example,dc=com | ||
default: '' | ||
user_attr: | ||
description: | ||
- Attribute on user attribute object matching the username passed when authenticating. Examples: sAMAccountName, cn, uid | ||
default: cn | ||
discover_dn: | ||
description: | ||
- Use anonymous bind to discover the bind DN of a user | ||
default: False | ||
deny_null_bind: | ||
description: | ||
- This option prevents users from bypassing authentication when providing an empty password | ||
default: True | ||
upn_domain: | ||
description: | ||
- The userPrincipalDomain used to construct the UPN string for the authenticating user | ||
default: '' | ||
group_filter: | ||
description: | ||
- Go template used when constructing the group membership query. The template can access the following context variables: [UserDN, Username] | ||
default: (|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}})) | ||
group_attr: | ||
description: | ||
- LDAP attribute to follow on objects returned by groupfilter in order to enumerate user group membership | ||
default: 'cn' | ||
group_dn: | ||
description: | ||
- LDAP search base to use for group membership search | ||
default: '' | ||
|
||
''' | ||
EXAMPLES = ''' | ||
--- | ||
- hosts: localhost | ||
tasks: | ||
- hashivault_auth_ldap: | ||
user_dn: "{{ auth_ldap_userdn }}" | ||
group_dn: "{{ auth_ldap_groupdn }}" | ||
bind_dn: "{{ auth_ldap_binddn }}" | ||
ldap_url: "{{ auth_ldap_url }}" | ||
insecure_tls: "{{ auth_ldap_insecure_tls }}" | ||
group_filter: "{{ auth_ldap_groupfilter }}" | ||
upn_domain: "{{ auth_ldap_upndomain }}" | ||
token: "{{ vault_token }}" | ||
url: "{{ vault_url }}" | ||
''' | ||
|
||
def main(): | ||
argspec = hashivault_argspec() | ||
argspec['description'] = dict(required=False, type='str') | ||
argspec['mount_point'] = dict(required=False, type='str', default='ldap') | ||
argspec['ldap_url'] = dict(required=False, type='str', default='ldap://127.0.0.1') | ||
argspec['case_sensitive_names'] = dict(required=False, type='bool', default=False) | ||
argspec['starttls'] = dict(required=False, type='bool', default=False) | ||
argspec['tls_min_version'] = dict(required=False, type='str', default='tls12') | ||
argspec['tls_max_version'] = dict(required=False, type='str', default='tls12') | ||
argspec['insecure_tls'] = dict(required=False, type='bool', default=False) | ||
argspec['certificate'] = dict(required=False, type='str', default='') | ||
argspec['bind_dn'] = dict(required=False, type='str', default='') | ||
argspec['bind_pass'] = dict(required=False, type='str', default=None, no_log=True) | ||
argspec['user_attr'] = dict(required=False, type='str', default='cn') | ||
argspec['user_dn'] = dict(required=False, type='str', default='') | ||
argspec['discover_dn'] = dict(required=False, type='bool', default=False) | ||
argspec['deny_null_bind'] = dict(required=False, type='bool', default=True) | ||
argspec['upn_domain'] = dict(required=False, type='str', default='') | ||
argspec['group_filter'] = dict(required=False, type='str', default=DEFAULT_GROUP_FILTER) | ||
argspec['group_attr'] = dict(required=False, type='str', default='cn') | ||
argspec['group_dn'] = dict(required=False, type='str', default='') | ||
module = hashivault_init(argspec, supports_check_mode=True) | ||
result = hashivault_auth_ldap(module) | ||
if result.get('failed'): | ||
module.fail_json(**result) | ||
else: | ||
module.exit_json(**result) | ||
|
||
@hashiwrapper | ||
def hashivault_auth_ldap(module): | ||
params = module.params | ||
client = hashivault_auth_client(params) | ||
exists = False | ||
changed = False | ||
desired_state = dict() | ||
current_state = dict() | ||
|
||
desired_state['mount_point'] = params.get('mount_point') | ||
desired_state['url'] = params.get('ldap_url') | ||
desired_state['case_sensitive_names'] = params.get('case_sensitive_names') | ||
desired_state['starttls'] = params.get('starttls') | ||
desired_state['tls_min_version'] = params.get('tls_min_version') | ||
desired_state['tls_max_version'] = params.get('tls_max_version') | ||
desired_state['insecure_tls'] = params.get('insecure_tls') | ||
desired_state['certificate'] = params.get('certificate') | ||
desired_state['bind_dn'] = params.get('bind_dn') | ||
desired_state['bind_pass'] = params.get('bind_pass') | ||
desired_state['user_attr'] = params.get('user_attr') | ||
desired_state['user_dn'] = params.get('user_dn') | ||
desired_state['discover_dn'] = params.get('discover_dn') | ||
desired_state['deny_null_bind'] = params.get('deny_null_bind') | ||
desired_state['upn_domain'] = params.get('upn_domain') | ||
desired_state['group_filter'] = params.get('group_filter') | ||
desired_state['group_attr'] = params.get('group_attr') | ||
desired_state['group_dn'] = params.get('group_dn') | ||
|
||
auth_methods = client.sys.list_auth_methods() | ||
path = (desired_state['mount_point']) + u"/" | ||
|
||
# is auth method enabled already? | ||
if path in auth_methods['data'].keys(): | ||
exists = True | ||
|
||
# if the auth method isn't enabled | ||
if exists == False: | ||
return {'msg': 'auth method isn\'t enabled'} | ||
|
||
# if bind pass is None, remove it from desired state since we can't compare | ||
if desired_state['bind_pass'] is None: | ||
del desired_state['bind_pass'] | ||
|
||
# check current config | ||
if exists: | ||
result = client.auth.ldap.read_configuration()['data'] | ||
# some keys need to be remapped to match desired state (and HVAC implementation) | ||
current_state['discover_dn'] = result['discoverdn'] | ||
current_state['group_attr'] = result['groupattr'] | ||
current_state['user_attr'] = result['userattr'] | ||
current_state['group_dn'] = result['groupdn'] | ||
current_state['upn_domain'] = result['upndomain'] | ||
current_state['group_filter'] = result['groupfilter'] | ||
current_state['case_sensitive_names'] = result['case_sensitive_names'] | ||
current_state['certificate'] = result['certificate'] | ||
current_state['tls_max_version'] = result['tls_max_version'] | ||
current_state['tls_min_version'] = result['tls_min_version'] | ||
current_state['insecure_tls'] = result['insecure_tls'] | ||
current_state['deny_null_bind'] = result['deny_null_bind'] | ||
current_state['user_dn'] = result['userdn'] | ||
current_state['bind_dn'] = result['binddn'] | ||
#current_state['use_token_groups'] = result['use_token_groups'] # returned from Vault - not implemented in HVAC | ||
current_state['url'] = result['url'] | ||
current_state['starttls'] = result['starttls'] | ||
|
||
# check if current config matches desired config values, if they match, set changed to false to prevent action | ||
for k, v in current_state.items(): | ||
if v != desired_state[k]: | ||
changed = True | ||
|
||
# if configs dont match and checkmode is off, complete the change | ||
if changed == True and not module.check_mode: | ||
client.auth.ldap.configure(**desired_state) | ||
|
||
return {'changed': changed} | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a good change