feat: manage users
This commit is contained in:
parent
aaeea21e54
commit
f1ba54d2ad
10 changed files with 228 additions and 26 deletions
|
@ -7,6 +7,7 @@ Which is based on [Keep A Changelog](http://keepachangelog.com/)
|
|||
|
||||
### Added
|
||||
|
||||
- feat: manage user
|
||||
- feat: add variable to set major version
|
||||
- feat: add ilm policy
|
||||
- test: add support debian 12
|
||||
|
@ -17,6 +18,7 @@ Which is based on [Keep A Changelog](http://keepachangelog.com/)
|
|||
|
||||
### Changed
|
||||
|
||||
- major default version is 8
|
||||
- replace kitchen to molecule
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -16,6 +16,8 @@ Install and configure Elasticsearch
|
|||
|
||||
* `elasticsearch_major_version` - set the major version (default: `7`)
|
||||
* `elasticsearch_heap_size` - set the heap size (default: `1g`)
|
||||
* `elasticsearch_api_user` - set the admin user (default: `elastic`)
|
||||
* `elasticsearch_api_password` - set the password for api
|
||||
* `elasticsearch_config` - hash with the configuration (see [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html))
|
||||
|
||||
```
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
---
|
||||
elasticsearch_major_version: 7
|
||||
elasticsearch_major_version: 8
|
||||
elasticsearch_api_user: elastic
|
||||
elasticsearch_heap_size: 1g
|
||||
elasticsearch_config: {}
|
||||
elasticsearch_default_config:
|
||||
path.data: /var/lib/elasticsearch
|
||||
path.logs: /var/log/elasticsearch
|
||||
xpack.security.transport.ssl.enabled: false
|
||||
xpack.security.http.ssl.enabled: false
|
||||
elasticsearch_full_config: "{{ elasticsearch_default_config | combine(elasticsearch_config) }}"
|
||||
elasticsearch_index_templates: {}
|
||||
elasticsearch_ilm_policies: {}
|
||||
|
|
52
library/elasticsearch_init_password.py
Normal file
52
library/elasticsearch_init_password.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.elasticsearch_api import *
|
||||
import subprocess
|
||||
|
||||
class ElasticsearchInitPassword:
|
||||
def __init__(self, api_url, api_user, api_password):
|
||||
self.api = ElasticsearchApi(
|
||||
api_url,
|
||||
api_user,
|
||||
api_password
|
||||
)
|
||||
self.user = api_user
|
||||
self.password = api_password
|
||||
|
||||
def is_set(self):
|
||||
status_code, _ = self.api.get('_cluster/health')
|
||||
if status_code == 401:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def change(self):
|
||||
subprocess.run(
|
||||
['/usr/share/elasticsearch/bin/elasticsearch-reset-password', '-u', self.user, '-b', '-i'],
|
||||
input='{}\n{}'.format(self.password, self.password).encode()
|
||||
)
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'api_url': { 'type': 'str', 'default': 'http://127.0.0.1:9200' },
|
||||
'api_user': { 'type': 'str', 'default': None },
|
||||
'api_password': { 'type': 'str', 'default': None, 'no_log': True },
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
changed = False
|
||||
|
||||
init = ElasticsearchInitPassword(
|
||||
module.params['api_url'],
|
||||
module.params['api_user'],
|
||||
module.params['api_password'],
|
||||
)
|
||||
|
||||
if not init.is_set():
|
||||
init.change()
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
106
library/elasticsearch_user.py
Normal file
106
library/elasticsearch_user.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.elasticsearch_api import *
|
||||
|
||||
class ElasticsearchUser:
|
||||
def __init__(self, api_url, api_user, api_password, name, password, roles):
|
||||
self.api = ElasticsearchApi(
|
||||
api_url,
|
||||
api_user,
|
||||
api_password
|
||||
)
|
||||
self.api_url = api_url
|
||||
self.name = name
|
||||
self.password = password
|
||||
self.roles = roles
|
||||
self.exist = False
|
||||
self.data = {}
|
||||
|
||||
def get_data(self):
|
||||
status_code, data = self.api.get('_security/user/{}'.format(self.name))
|
||||
if status_code == 200:
|
||||
self.exist = True
|
||||
self.data = data[self.name]
|
||||
|
||||
def roles_have_changed(self):
|
||||
for role in self.roles:
|
||||
if role not in self.data['roles']:
|
||||
return True
|
||||
|
||||
for role in self.data['roles']:
|
||||
if role not in self.roles:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def password_has_changed(self):
|
||||
api = ElasticsearchApi(
|
||||
self.api_url,
|
||||
self.name,
|
||||
self.password
|
||||
)
|
||||
status_code, _ = api.get('_cluster/health')
|
||||
if status_code == 401:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def has_changed(self):
|
||||
if self.roles_have_changed():
|
||||
return True
|
||||
|
||||
if self.password_has_changed():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def create(self):
|
||||
self.api.put(
|
||||
'_security/user/{}'.format(self.name),
|
||||
{
|
||||
'password': self.password,
|
||||
'roles': self.roles
|
||||
}
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
self.api.delete('_security/user/{}'.format(self.name))
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'name': { 'type': 'str', 'required': True },
|
||||
'password': { 'type': 'str', 'required': True, 'no_log': True },
|
||||
'roles': { 'type': 'list', 'default': [] },
|
||||
'api_url': { 'type': 'str', 'default': 'http://127.0.0.1:9200' },
|
||||
'api_user': { 'type': 'str', 'default': None },
|
||||
'api_password': { 'type': 'str', 'default': None, 'no_log': True },
|
||||
'state': { 'type': 'str', 'default': 'present', 'choice': ['present', 'absent'] },
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
changed = False
|
||||
|
||||
user = ElasticsearchUser(
|
||||
module.params['api_url'],
|
||||
module.params['api_user'],
|
||||
module.params['api_password'],
|
||||
module.params['name'],
|
||||
module.params['password'],
|
||||
module.params['roles'],
|
||||
)
|
||||
user.get_data()
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
if not user.exist or user.has_changed():
|
||||
user.create()
|
||||
changed = True
|
||||
else:
|
||||
if user.exist:
|
||||
user.delete()
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -5,28 +5,25 @@ import base64
|
|||
class ElasticsearchApi:
|
||||
def __init__(self, url, user, password):
|
||||
self.url = url
|
||||
self.headers = {}
|
||||
self.basic = None
|
||||
if user and password:
|
||||
token = base64.b64encode('{}:{}',)
|
||||
self.headers = { 'Authorization': 'Basic ' + base64.b64encode({},) }
|
||||
self.basic = requests.auth.HTTPBasicAuth(user, password)
|
||||
|
||||
def get(self, path):
|
||||
r = requests.get(
|
||||
'{}/{}'.format(self.url, path),
|
||||
headers=self.headers
|
||||
auth=self.basic
|
||||
)
|
||||
|
||||
if r.status_code == 500:
|
||||
raise Exception('Server return 500 error: {}'.format(r.text))
|
||||
elif r.status_code == 401:
|
||||
raise Exception('Authentification has failed')
|
||||
|
||||
return r.status_code, r.json()
|
||||
|
||||
def put(self, path, data):
|
||||
r = requests.put(
|
||||
'{}/{}'.format(self.url, path),
|
||||
headers=self.headers,
|
||||
auth=self.basic,
|
||||
json=data
|
||||
)
|
||||
|
||||
|
|
|
@ -4,7 +4,13 @@
|
|||
roles:
|
||||
- ansible-role-elasticsearch
|
||||
vars:
|
||||
elasticsearch_password: mysecret
|
||||
elasticsearch_heap_size: 512m
|
||||
elasticsearch_users:
|
||||
toto:
|
||||
password: supers3cret
|
||||
roles:
|
||||
- viewer
|
||||
elasticsearch_index_templates:
|
||||
test:
|
||||
index_patterns:
|
||||
|
|
|
@ -11,6 +11,8 @@ platforms:
|
|||
command: /bin/systemd
|
||||
capabilities:
|
||||
- SYS_ADMIN
|
||||
published_ports:
|
||||
- 127.0.0.1:5601:5601
|
||||
lint: |
|
||||
set -e
|
||||
yamllint .
|
||||
|
|
|
@ -23,10 +23,15 @@ def test_socket(host):
|
|||
assert socket.is_listening
|
||||
|
||||
def test_java_memory(host):
|
||||
process = host.process.get(user='elasticsearch', comm='java')
|
||||
assert '-Xms512m' in process.args
|
||||
assert '-Xmx512m' in process.args
|
||||
process = host.process.filter(user='elasticsearch', comm='java')
|
||||
assert '-Xms512m' in process[1].args
|
||||
assert '-Xmx512m' in process[1].args
|
||||
|
||||
def test_elasticsearch_template(host):
|
||||
result = host.check_output('curl -v http://127.0.0.1:9200/_template/test')
|
||||
result = host.check_output('curl -v -u elastic:mysecret http://127.0.0.1:9200/_template/test')
|
||||
assert '"number_of_replicas":"1"' in result
|
||||
|
||||
def test_elasticsearch_user(host):
|
||||
result = host.check_output('curl -v -u elastic:mysecret http://127.0.0.1:9200/_security/user/toto')
|
||||
assert '"username":"toto"' in result
|
||||
assert '"roles":["viewer"]' in result
|
||||
|
|
|
@ -1,8 +1,31 @@
|
|||
---
|
||||
- name: Init elastic password
|
||||
elasticsearch_init_password:
|
||||
api_user: "{{ elasticsearch_api_user }}"
|
||||
api_password: "{{ elasticsearch_password }}"
|
||||
run_once: true
|
||||
tags: elasticsearch
|
||||
|
||||
- name: Manage users
|
||||
elasticsearch_user:
|
||||
name: "{{ item.key }}"
|
||||
password: "{{ item.value.password }}"
|
||||
roles: "{{ item.value.roles | default(omit) }}"
|
||||
api_user: "{{ elasticsearch_api_user }}"
|
||||
api_password: "{{ elasticsearch_password }}"
|
||||
state: "{{ item.value.state | default('present') }}"
|
||||
loop: "{{ elasticsearch_users | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
run_once: true
|
||||
tags: elasticsearch
|
||||
|
||||
- name: Copy ilm policies
|
||||
elasticsearch_ilm_policy:
|
||||
name: "{{ item.key }}"
|
||||
phases: "{{ item.value | default({}) }}"
|
||||
api_user: "{{ elasticsearch_api_user }}"
|
||||
api_password: "{{ elasticsearch_password }}"
|
||||
loop: "{{ elasticsearch_ilm_policies | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
|
@ -15,6 +38,10 @@
|
|||
index_patterns: "{{ item.value.index_patterns }}"
|
||||
settings: "{{ item.value.settings | default({}) }}"
|
||||
mappings: "{{ item.value.mappings | default({}) }}"
|
||||
api_user: "{{ elasticsearch_api_user }}"
|
||||
api_password: "{{ elasticsearch_password }}"
|
||||
loop: "{{ elasticsearch_index_templates | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
run_once: true
|
||||
tags: elasticsearch
|
||||
|
|
Loading…
Reference in a new issue