Skip to content

Commit 765c12f

Browse files
committed
Add elasticsearch_user module
1 parent 5972e87 commit 765c12f

File tree

9 files changed

+284
-74
lines changed

9 files changed

+284
-74
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.cache
22
*.swp
3-
__pycache__*
3+
__pycache__*
4+
.vscode

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@ Every role is documented with all variables, please refer to the documentation f
88

99
**Please note**: If you are already using this collection before version `1.0.0`, please note that we had to rename a significant amount of variables due to naming schema changes made by Ansible. Please review the variables you have set in your playbooks and variable files.
1010

11-
## Roles Documentation
11+
## Roles documentation
1212

1313
* [Beats](docs/role-beats.md)
1414
* [Elasticsearch](docs/role-elasticsearch.md)
1515
* [Kibana](docs/role-kibana.md)
1616
* [Logstash](docs/role-logstash.md)
1717
* [Repos](docs/role-repos.md)
1818

19+
## Modules documentation
20+
21+
* [elasticsearch_role](docs/module-elasticsearch_role.md)
22+
* [elasticsearch_user](docs/module-elasticsearch_user.md)
23+
1924
## Installation
2025

2126
You can easily install the collection with the `ansible-galaxy` command.

docs/module-elasticsearch_role.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Ansible module: elasticsearch_role
2+
===
3+
4+
This module creates, updates and deletes roles from your Elasticsearch.
5+
6+
Requirements
7+
---
8+
9+
As this module uses the Elasticsearch API you will need to install the `elasticsearch` Python3 library.
10+
```
11+
pip3 install elasticsearch
12+
```
13+
14+
Module arguments
15+
---
16+
17+
* *name*: Name of your role (**Required**)
18+
* *cluster*: List of clusters
19+
* *indicies*: List of indicies
20+
* *names*: List of names (**Required**)
21+
* *privileges*: List of privileges (**Required**)
22+
* *state*: State of the role (Default: `present`)
23+
* *host*: API endpoint (**Required**)
24+
* *auth_user*: User to authenticate on the Elasticsearch API (**Required**)
25+
* *auth_pass*: Password for the given user (**Required**)
26+
* *verify_certs*: Verify certificates (Default: True)
27+
* *ca_certs*: Verify HTTPS connection by using ca certificate. Path to ca needs to be given
28+
29+
Example usage
30+
---
31+
```
32+
- name: Create elasticsearch role 'new-role'
33+
netways.elasticstack.elasticsearch_role:
34+
name: new-role
35+
cluster:
36+
- manage_own_api_key
37+
- delegate_pki
38+
indicies:
39+
- names:
40+
- default01
41+
privileges:
42+
- read
43+
- write
44+
state: present
45+
host: https://localhost:9200
46+
auth_user: elastic
47+
auth_pass: changeMe123!
48+
verify_certs: false
49+
```

docs/module-elasticsearch_user.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Ansible module: elasticsearch_user
2+
===
3+
4+
This module creates, updates and deletes users from your Elasticsearch.
5+
6+
Requirements
7+
---
8+
9+
As this module uses the Elasticsearch API you will need to install the `elasticsearch` Python3 library.
10+
```
11+
pip3 install elasticsearch
12+
```
13+
14+
Module arguments
15+
---
16+
17+
* *name*: Name of your user (**Required**)
18+
* *fullname*: Fullname of your user
19+
* *password*: Password for your user (**Required**)
20+
* *email*: Email for your user
21+
* *roles*: List of roles (**Required**)
22+
* *enabled*: Define wheter this user should be enabled (Default: `true`)
23+
* *state*: State of the role. `absent` to delete the user (Default: `present`)
24+
* *host*: API endpoint (**Required**)
25+
* *auth_user*: User to authenticate on the Elasticsearch API (**Required**)
26+
* *auth_pass*: Password for the given user (**Required**)
27+
* *verify_certs*: Verify certificates (Default: True)
28+
* *ca_certs*: Verify HTTPS connection by using ca certificate. Path to ca needs to be given
29+
30+
Example usage
31+
---
32+
```
33+
- name: Create elasticsearch user 'new-user'
34+
netways.elasticstack.elasticsearch_user:
35+
name: new-user
36+
fullname: New User
37+
password: changeMe321!
38+
39+
roles:
40+
- new-role
41+
- logstash-writer
42+
enabled: true
43+
state: present
44+
host: https://localhost:9200
45+
auth_user: elastic
46+
auth_pass: changeMe123!
47+
verify_certs: false
48+
```

molecule/elasticsearch_test_modules/converge.yml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,15 @@
2929
register: elasticstack_password
3030
changed_when: false
3131

32-
- name: Create role
32+
- name: Create elasticsearch role 'new-role'
3333
netways.elasticstack.elasticsearch_role:
34-
name: new-role3
34+
name: new-role1
3535
cluster:
3636
- manage_own_api_key
3737
- delegate_pki
3838
indicies:
3939
- names:
4040
- foobar321
41-
- barfoo123
4241
privileges:
4342
- read
4443
- write
@@ -47,4 +46,21 @@
4746
auth_user: elastic
4847
auth_pass: "{{ elasticstack_password.stdout }}"
4948
verify_certs: false
50-
ca_certs: /etc/elasticsearch/certs/http_ca.crt
49+
#ca_certs: /etc/elasticsearch/certs/http_ca.crt
50+
51+
- name: Create elasticsearch user 'new-user'
52+
netways.elasticstack.elasticsearch_user:
53+
name: new-user1
54+
fullname: New User
55+
password: changeMe123!
56+
57+
roles:
58+
- new-role1
59+
- logstash-writer
60+
enabled: true
61+
state: present
62+
host: https://localhost:9200
63+
auth_user: elastic
64+
auth_pass: "{{ elasticstack_password.stdout }}"
65+
verify_certs: false
66+
#ca_certs: /etc/elasticsearch/certs/http_ca.crt

plugins/module_utils/api.py

Lines changed: 98 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
55
# https://www.gnu.org/licenses/gpl-3.0.txt)
66

7-
from asyncio.constants import SENDFILE_FALLBACK_READBUFFER_SIZE
7+
from difflib import restore
8+
from pickle import NONE
9+
from xml.sax.saxutils import prepare_input_source
810
from elasticsearch import Elasticsearch
911
import ssl
1012

@@ -16,16 +18,13 @@ def new_client_basic_auth(host, auth_user, auth_pass, ca_certs, verify_certs) ->
1618

1719

1820
class Role():
19-
def __init__(self, result, role_name, cluster, indicies, state, host, auth_user, auth_pass, verify_certs, ca_certs):
21+
def __init__(self, result, role_name, cluster, indicies, state, host, auth_user, auth_pass, verify_certs, ca_certs):
2022
self.role_name = role_name
2123
self.cluster = cluster
2224
self.indicies = indicies
2325
self.state = state
2426
self.result = result
2527

26-
if auth_user == "" or auth_pass == "":
27-
result['stderr'] = "'basic_auth' for authentication defined but 'auth_user' or auth_pass' is empty"
28-
return
2928
self.client = new_client_basic_auth(host=host, auth_user=auth_user, auth_pass=auth_pass, verify_certs=verify_certs, ca_certs=ca_certs)
3029

3130
self.handle()
@@ -36,39 +35,118 @@ def return_result(self) -> dict:
3635

3736

3837
def handle(self):
38+
all_roles = self.get_all()
39+
3940
if self.state == 'absent':
40-
res = self.delete()
41-
if res['found'] == True:
42-
self.result['changed'] = True
43-
self.result['msg'] = self.role_name + " has been deleted."
44-
return
41+
if self.role_name in all_roles:
42+
res = self.delete()
43+
if res['found'] == True:
44+
self.result['changed'] = True
45+
self.result['msg'] = self.role_name + " has been deleted"
46+
return
4547

4648
elif self.state == 'present':
47-
pre_role = self.get()
48-
self.result['foo1'] = pre_role.raw
49+
if self.role_name in all_roles.raw:
50+
pre_role = self.get()
51+
else:
52+
pre_role = None
53+
4954
res = self.put()
5055

5156
if res.raw['role']['created'] == True:
5257
self.result['changed'] = True
53-
self.result['msg'] = self.role_name + " has been created."
58+
self.result['msg'] = self.role_name + " has been created"
5459
return
5560

56-
self.result['foo2'] = self.get().raw
57-
if pre_role.raw != self.get().raw:
58-
self.result['changed'] = True
59-
self.result['msg'] = self.role_name + " has been updated"
60-
return
61+
if pre_role != None:
62+
if pre_role.raw != self.get().raw:
63+
self.result['changed'] = True
64+
self.result['msg'] = self.role_name + " has been updated"
65+
return
6166

6267
return
6368

6469

70+
def get_all(self):
71+
return self.client.security.get_role()
72+
73+
6574
def get(self):
6675
return self.client.security.get_role(name=self.role_name)
6776

6877

69-
def put(self):
78+
def put(self):
7079
return self.client.security.put_role(name=self.role_name, cluster=self.cluster, indices=self.indicies)
7180

7281

7382
def delete(self):
74-
return self.client.security.delete_role(name=self.role_name)
83+
return self.client.security.delete_role(name=self.role_name)
84+
85+
86+
class User():
87+
def __init__(self, result, user_name, full_name, password, email, roles, enabled, state, host, auth_user, auth_pass, verify_certs, ca_certs):
88+
self.user_name = user_name
89+
self.full_name = full_name
90+
self.password = password
91+
self.email = email
92+
self.roles = roles
93+
self.enabled = enabled
94+
self.state = state
95+
self.result = result
96+
97+
self.client = new_client_basic_auth(host=host, auth_user=auth_user, auth_pass=auth_pass, ca_certs=ca_certs, verify_certs=verify_certs)
98+
99+
self.handle()
100+
101+
102+
def return_result(self) -> dict:
103+
return self.result
104+
105+
106+
def handle(self):
107+
all_users = self.get_all()
108+
109+
if self.state == 'absent':
110+
if self.user_name in all_users:
111+
res = self.delete()
112+
if res['found'] == True:
113+
self.result['changed'] = True
114+
self.result['msg'] = self.user_name + " has been deleted"
115+
return
116+
117+
elif self.state == 'present':
118+
if self.user_name in all_users.raw:
119+
pre_user = self.get()
120+
else:
121+
pre_user = None
122+
123+
res = self.put()
124+
125+
if res.raw['created'] == True:
126+
self.result['changed'] = True
127+
self.result['msg'] = self.user_name + " has been created"
128+
return
129+
130+
if pre_user != None:
131+
if pre_user.raw != self.get().raw:
132+
self.result['changed'] = True
133+
self.result['msg'] = self.user_name + " has beed updated"
134+
return
135+
136+
return
137+
138+
139+
def get_all(self):
140+
return self.client.security.get_user()
141+
142+
143+
def get(self):
144+
return self.client.security.get_user(username=self.user_name)
145+
146+
147+
def put(self):
148+
return self.client.security.put_user(username=self.user_name, password=self.password, email=self.email, full_name=self.full_name, enabled=self.enabled, roles=self.roles)
149+
150+
151+
def delete(self):
152+
return self.client.security.delete_user(username=self.user_name)

plugins/modules/elasticsearch_role.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#!/usr/bin/python
22

3+
# Copyright (c) 2024, Tobias Bauriedel <[email protected]>
4+
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
5+
# https://www.gnu.org/licenses/gpl-3.0.txt)
6+
37
from __future__ import (absolute_import, division, print_function)
48
__metaclass__ = type
59

@@ -41,10 +45,13 @@ def run_module():
4145

4246
module = AnsibleModule(
4347
argument_spec=dict(
48+
# User args
4449
name=dict(type=str, required=True),
4550
cluster=dict(type=list, required=False),
46-
indicies=dict(type=list, required=False), # indicies.{n}.name, indicies.{n}.privileges
51+
indicies=dict(type=list, required=False),
4752
state=dict(type=str, required=False, default='present'),
53+
54+
# Auth args
4855
host=dict(type=str, required=True),
4956
auth_user=dict(type=str, required=True),
5057
auth_pass=dict(type=str, required=True),

0 commit comments

Comments
 (0)