Compare commits

..

2 commits

Author SHA1 Message Date
a812baa242 fix 2020-03-27 21:48:09 +01:00
bebe621f3e feat: manage users 2020-03-08 18:35:44 +01:00
22 changed files with 214 additions and 764 deletions

View file

@ -1,18 +0,0 @@
---
on: [push]
jobs:
lint:
runs-on: docker
container:
image: code.waks.be/nishiki/molecule:docker
steps:
- uses: actions/checkout@v3
- run: ansible-lint .
- run: yamllint .
molecule:
runs-on: docker
container:
image: code.waks.be/nishiki/molecule:docker
steps:
- uses: actions/checkout@v3
- run: molecule test

View file

@ -1,10 +0,0 @@
---
image: nishiki/molecule:docker
before_script:
- molecule --version
molecule:
stage: test
script:
- molecule test

View file

@ -4,9 +4,9 @@ extends: default
ignore: | ignore: |
.kitchen/* .kitchen/*
vendor/ vendor/
.forgejo/
rules: rules:
line-length: line-length:
max: 120 max: 120
level: warning level: warning
truthy: false

View file

@ -5,31 +5,9 @@ Which is based on [Keep A Changelog](http://keepachangelog.com/)
## [Unreleased] ## [Unreleased]
### Added
- feat: add variable to set master
- feat: manage user
- feat: manage role
- feat: add variable to set major version
- feat: add ilm policy
- test: add support debian 12
### Removed
- test: remove support debian 10
- test: remove support debian 11
### Changed ### Changed
- major default version is 8
- replace kitchen to molecule - replace kitchen to molecule
- replace apt_key to get_url
- test: use personal docker registry
### Fixed
- no_log only api_password for elasticsearch_template module
- add full python3 support
## v1.1.0 - 2019-11-21 ## v1.1.0 - 2019-11-21

View file

@ -1,83 +1,43 @@
# Ansible role: Elasticsearch # Ansible role: Elasticsearch
[![Version](https://img.shields.io/badge/latest_version-1.1.0-green.svg)](https://code.waks.be/nishiki/ansible-role-elasticsearch/releases) [![Version](https://img.shields.io/badge/latest_version-1.1.0-green.svg)](https://git.yaegashi.fr/nishiki/ansible-role-elasticsearch/releases)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://code.waks.be/nishiki/ansible-role-elasticsearch/src/branch/main/LICENSE) [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://git.yaegashi.fr/nishiki/ansible-role-elasticsearch/src/branch/master/LICENSE)
[![Build](https://code.waks.be/nishiki/ansible-role-elasticsearch/actions/workflows/molecule.yml/badge.svg?branch=main)](https://code.waks.be/nishiki/ansible-role-elasticsearch/actions?workflow=molecule.yml)
Install and configure Elasticsearch Install and configure Elasticsearch
## Requirements ## Requirements
- Ansible >= 2.9 * Ansible >= 2.7
- Debian * Debian Stretch and Buster
- Bookworm
## Role variables ## Role variables
- `elasticsearch_major_version` - set the major version (default: `7`) * `elasticsearch_heap_size` - set the heap size (default: `1g`)
- `elasticsearch_master` - set if the node is master (default: `true`) * `elasticsearch_config` - hash with the configuration (see [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html))
- `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))
```yaml ```
path.data: /var/lib/elasticsearch path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch path.logs: /var/log/elasticsearch
``` ```
- `elasticsearch_ssl_key`: - string contain ssl private key if `xpack.security.transport.ssl.key` is defined in elasticsearch_config * `elasticsearch_index_templates` - hash with the index templates configuration
- `elasticsearch_ssl_certificate`: - string contain ssl certificate if `xpack.security.transport.certificate.key` is defined in elasticsearch_config
- `elasticsearch_roles` - hash with the roles to managed
```yaml ```
myrole: logstash:
cluster: index_patterns:
- all - 'logstash-*'
indices: settings:
- names: ["logstash*"] index:
privileges: number_of_replicas: 3
- create mappings:
- write metric:
type: short
date:
type: date
format: YYYY-MM-dd
``` ```
- `elasticsearch_users` - hash with the users to managed * `elasticsearch_users` - hash to manage users
```yaml
toto:
password: supers3cret
roles:
- viewer
kibana_system:
password: supertest2
```
- `elasticsearch_index_templates` - hash with the index templates configuration
```yaml
logstash:
index_patterns:
- "logstash-*"
settings:
index:
number_of_replicas: 3
mappings:
metric:
type: short
date:
type: date
format: YYYY-MM-dd
```
- `elasticsearch_ilm_policies` - hash with the ilm policies configuration
```yaml
autoclean:
delete:
min_age: 30d
actions:
delete: {}
```
## How to use ## How to use
@ -91,10 +51,10 @@ autoclean:
### Test with molecule and docker ### Test with molecule and docker
- install [docker](https://docs.docker.com/engine/installation/) * install [docker](https://docs.docker.com/engine/installation/)
- install `python3` and `python3-pip` * install `python3` and `python3-pip`
- install molecule and dependencies `pip3 install molecule 'molecule[docker]' ansible-lint testinfra yamllint` * install molecule and dependencies `pip3 install molecule 'molecule[docker]' ansible-lint testinfra yamllint`
- run `molecule test` * run `molecule test`
## License ## License

View file

@ -1,16 +1,11 @@
--- ---
elasticsearch_major_version: 8
elasticsearch_master: true
elasticsearch_api_user: elastic
elasticsearch_heap_size: 1g elasticsearch_heap_size: 1g
elasticsearch_api_user: elastic
elasticsearch_api_password: null
elasticsearch_config: {} elasticsearch_config: {}
elasticsearch_default_config: elasticsearch_default_config:
path.data: /var/lib/elasticsearch path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch path.logs: /var/log/elasticsearch
xpack.security.transport.ssl.enabled: false elasticsearch_full_config: '{{ elasticsearch_default_config|combine(elasticsearch_config) }}'
xpack.security.http.ssl.enabled: false
elasticsearch_full_config: "{{ elasticsearch_default_config | combine(elasticsearch_config) }}"
elasticsearch_index_templates: {} elasticsearch_index_templates: {}
elasticsearch_ilm_policies: {}
elasticsearch_roles: {}
elasticsearch_users: {} elasticsearch_users: {}

View file

@ -1,5 +1,5 @@
--- ---
- name: Restart elasticsearch - name: restart elasticsearch
ansible.builtin.service: systemd:
name: elasticsearch name: elasticsearch
state: restarted state: restarted

View file

@ -1,75 +0,0 @@
#!/usr/bin/python
from ansible.module_utils.basic import *
from ansible.module_utils.elasticsearch_api import *
class ElasticsearchILMPolicy:
def __init__(self, api, name):
self.api = api
self.name = name
def get_data(self):
status_code, data = self.api.get('_ilm/policy/{}'.format(self.name))
if status_code == 200:
return data[self.name]
else:
return {}
def create(self, phases):
self.api.put(
'_ilm/policy/{}'.format(self.name),
{ 'policy': { 'phases': phases } }
)
def dict_has_changed(self, new_data, old_data):
for option, value in new_data.items():
if not option in old_data:
if value:
return True
elif type(value) is dict:
if self.dict_has_changed(value, old_data[option]):
return True
elif type(value) is list:
if not type(data[option]) is list:
return True
if old_data[option].sort() != value.sort():
return True
elif str(old_data[option]) != str(value):
return True
return False
def has_changed(self, phases):
old_data = self.get_data()
if not old_data or self.dict_has_changed(phases, old_data['policy']['phases']):
self.create(phases)
return True
return False
def main():
fields = {
'name': { 'type': 'str', 'required': True },
'phases': { 'type': 'dict', '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 },
}
module = AnsibleModule(argument_spec=fields)
api = ElasticsearchApi(
module.params['api_url'],
module.params['api_user'],
module.params['api_password']
)
ilm = ElasticsearchILMPolicy(api, module.params['name'])
changed = ilm.has_changed(module.params['phases'])
module.exit_json(changed=changed)
if __name__ == '__main__':
main()

View file

@ -1,52 +0,0 @@
#!/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()

View file

@ -1,126 +0,0 @@
#!/usr/bin/python
from ansible.module_utils.basic import *
from ansible.module_utils.elasticsearch_api import *
class ElasticsearchRole:
def __init__(self, api_url, api_user, api_password, name, cluster, indices):
self.api = ElasticsearchApi(
api_url,
api_user,
api_password
)
self.api_url = api_url
self.name = name
self.cluster = cluster
self.indices = indices
self.exist = False
self.data = {}
def get_data(self):
status_code, data = self.api.get('_security/role/{}'.format(self.name))
if status_code == 200:
self.exist = True
self.data = data[self.name]
def array_has_changed(self, list1, list2):
for item in list1:
if item not in list2:
return True
for item in list2:
if item not in list1:
return True
return False
def cluster_has_changed(self):
return self.array_has_changed(self.cluster, self.data['cluster'])
def same_indice(self, indice1, indice2):
if self.array_has_changed(indice1['names'], indice2['names']):
return False
if self.array_has_changed(indice1['privileges'], indice2['privileges']):
return False
return True
def indices_have_changed(self):
for indice1 in self.indices:
exist = False
for indice2 in self.data['indices']:
if self.same_indice(indice1, indice2):
exist = True
break
if not exist:
return True
for indice1 in self.data['indices']:
exist = False
for indice2 in self.indices:
if self.same_indice(indice1, indice2):
exist = True
break
if not exist:
return True
return False
def has_changed(self):
if self.cluster_has_changed():
return True
if self.indices_have_changed():
return True
return False
def create(self):
self.api.put(
'_security/role/{}'.format(self.name),
{
'cluster': self.cluster,
'indices': self.indices
}
)
def delete(self):
self.api.delete('_security/role/{}'.format(self.name))
def main():
fields = {
'name': { 'type': 'str', 'required': True },
'indices': { 'type': 'list', 'default': [] },
'cluster': { '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
role = ElasticsearchRole(
module.params['api_url'],
module.params['api_user'],
module.params['api_password'],
module.params['name'],
module.params['cluster'],
module.params['indices'],
)
role.get_data()
if module.params['state'] == 'present':
if not role.exist or role.has_changed():
role.create()
changed = True
elif user.exist:
role.delete()
changed = True
module.exit_json(changed=changed)
if __name__ == '__main__':
main()

View file

@ -77,7 +77,7 @@ def main():
'mappings': { 'type': 'dict', 'default': {} }, 'mappings': { 'type': 'dict', 'default': {} },
'api_url': { 'type': 'str', 'default': 'http://127.0.0.1:9200' }, 'api_url': { 'type': 'str', 'default': 'http://127.0.0.1:9200' },
'api_user': { 'type': 'str', 'default': None }, 'api_user': { 'type': 'str', 'default': None },
'api_password': { 'type': 'str', 'default': None, 'no_log': True }, 'api_password': { 'type': 'str', 'default': None },
} }
module = AnsibleModule(argument_spec=fields) module = AnsibleModule(argument_spec=fields)
changed = False changed = False

View file

@ -4,131 +4,90 @@ from ansible.module_utils.basic import *
from ansible.module_utils.elasticsearch_api import * from ansible.module_utils.elasticsearch_api import *
class ElasticsearchUser: class ElasticsearchUser:
def __init__(self, api_url, api_user, api_password, name, password, roles): def __init__(self, api, name):
self.api = ElasticsearchApi( self.api = api
api_url, self.name = name
api_user, self.exist = False
api_password self.data = {}
)
self.api_url = api_url
self.name = name
self.password = password
self.roles = roles
self.exist = False
self.data = {}
def is_builtin(self): def get_data(self):
users = [ status_code, data = self.api.get('_security/user/{}'.format(self.name))
'apm_system', if status_code == 200:
'beats_system', self.exist = True
'elastic', self.data = data[self.name]
'kibana',
'kibana_system',
'logstash_system',
'remote_monitoring_user'
]
if self.name in users:
return True
return False def has_changed(self, roles):
if roles.sort() != self.data['roles'].sort():
return True
def get_data(self): return False
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): def password_has_changed(self, password):
for role in self.roles: return not self.api.check_password(self.name, password)
if role not in self.data['roles']:
return True
for role in self.data['roles']: def change_password(self, password):
if role not in self.roles: self.api.put(
return True '_security/user/{}/_password'.format(self.name),
{ 'password': password }
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 change_password(self):
self.api.post(
'_security/user/{}/_password'.format(self.name),
{
'password': self.password
}
)
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()
def create(self, options):
self.api.put(
'_security/user/{}'.format(self.name),
options
)
def main():
fields = {
'name': { 'type': 'str', 'required': True },
'password': { 'type': 'str', 'required': 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 },
'state': { 'type': 'str', 'default': 'present', 'required': True, 'choice': ['absent', 'present'] },
}
module = AnsibleModule(argument_spec=fields)
changed = False
special_users = [
'elastic', 'kibana', 'logstash_system',
'beats_system', 'apm_system', 'remote_monitoring_user'
]
if user.is_builtin(): options = {
if user.password_has_changed(): 'roles': module.params['roles'],
user.change_password() 'password': module.params['password'],
changed = True }
else:
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) api = ElasticsearchApi(
module.params['api_url'],
module.params['api_user'],
module.params['api_password']
)
user = ElasticsearchUser(
api,
module.params['name'],
)
user.get_data()
if not module.params['name'] in special_users:
if module.params['state'] == 'absent':
if user.exist:
user.delete()
changed = True
module.exit_json(changed=changed)
if not user.exist or user.has_changed(module.params['roles']):
user.create(options)
changed = True
if user.password_has_changed(module.params['password']):
user.change_password(module.params['password'])
changed = True
module.exit_json(changed=changed)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -1,17 +1,17 @@
--- ---
galaxy_info: galaxy_info:
role_name: elasticsearch role_name: elasticsearch
namespace: nishiki
author: Adrien Waksberg author: Adrien Waksberg
company: Adrien Waksberg company: Adrien Waksberg
description: Install and configure elasticsearch description: Install and configure elasticsearch
license: Apache2 license: Apache2
min_ansible_version: "2.9" min_ansible_version: 2.7
platforms: platforms:
- name: Debian - name: Debian
versions: versions:
- bookworm - stretch
- buster
galaxy_tags: galaxy_tags:
- database - database

View file

@ -5,39 +5,38 @@ import base64
class ElasticsearchApi: class ElasticsearchApi:
def __init__(self, url, user, password): def __init__(self, url, user, password):
self.url = url self.url = url
self.basic = None self.headers = {}
if user and password: if user and password:
self.basic = requests.auth.HTTPBasicAuth(user, password) token = base64.b64encode('{}:{}'.format(user, password))
self.headers = { 'Authorization': 'Basic {}'.format(token) }
def check_password(self, user, password):
token = base64.b64encode('{}:{}'.format(user, password))
headers = { 'Authorization': 'Basic {}'.format(token) }
r = requests.get(self.url, headers=headers)
if r.status_code != 401:
return True
return False
def get(self, path): def get(self, path):
r = requests.get( r = requests.get(
'{}/{}'.format(self.url, path), '{}/{}'.format(self.url, path),
auth=self.basic headers=self.headers
) )
if r.status_code == 500:
raise Exception('Server return 500 error: {}'.format(r.text))
return r.status_code, r.json()
def post(self, path, data):
r = requests.post(
'{}/{}'.format(self.url, path),
auth=self.basic,
json=data
)
if r.status_code == 500: if r.status_code == 500:
raise Exception('Server return 500 error: {}'.format(r.text)) raise Exception('Server return 500 error: {}'.format(r.text))
elif r.status_code == 401: elif r.status_code == 401:
raise Exception('Authentification has failed') raise Exception('Authentification has failed')
elif r.status_code != 200:
raise Exception('Server return an unknown error: {}'.format(r.text)) return r.status_code, r.json()
def put(self, path, data): def put(self, path, data):
r = requests.put( r = requests.put(
'{}/{}'.format(self.url, path), '{}/{}'.format(self.url, path),
auth=self.basic, headers=self.headers,
json=data json=data
) )

View file

@ -4,78 +4,8 @@
roles: roles:
- ansible-role-elasticsearch - ansible-role-elasticsearch
vars: vars:
elasticsearch_password: mysecret elasticsearch_api_password: secret
elasticsearch_heap_size: 512m elasticsearch_heap_size: 512m
elasticsearch_config:
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.certificate: /etc/elasticsearch/certificate.pem
xpack.security.transport.ssl.key: /etc/elasticsearch/key.pem
elasticsearch_ssl_certificate: |
-----BEGIN CERTIFICATE-----
MIIDOzCCAiMCFF0yQzyw+sBIqfYykFNGS9xImVk2MA0GCSqGSIb3DQEBCwUAMFkx
CzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxDjAMBgNVBAcMBVBhcmlzMRMw
EQYDVQQKDApFbnRyZXByaXNlMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAgFw0yMzEx
MTMxNTAwMzJaGA8yMTIzMTAyMDE1MDAzMlowWTELMAkGA1UEBhMCRlIxDzANBgNV
BAgMBkZyYW5jZTEOMAwGA1UEBwwFUGFyaXMxEzARBgNVBAoMCkVudHJlcHJpc2Ux
FDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAoM8v9Gp+nLULI6XjFiXgQzz1wjsCSAyBgPOApaA5QcMTeTVrCphGQX0A
3wfT4rs1bBrVphbM9FpV85QzL6fmw3SOSPh6SdSJE+pd7V0mFX1/foeJJcIJnQfU
3k5eUfDBwgsU4ad/oxyP/GLs4ZPyjeh7L8oOcejeY37T7IX2y3af7TyfIS7hDof8
DOFjhv0/FB9nexpdh7toGlbjjHljg0BNupWog2Nr1W55/4UCMOnX+iUrgUpU3a7j
e6TgFgBYMel4KCH9MNdJ5+pPs4Nt8cVkX4FfZSJnfnLlVYHw8mTpTtw1gSsjuDxS
bKrDd5i3+2xLr7GCyd9SnEBwiDZ13QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA2
rKOA7EAgJrGPkZMT1s9k0ABMX7FU5QHwHPNA3pxjpFSHGRnX9nV+/qSgQugo3Qs8
s+eEa7i37G8fgCN6XrSd+jhcWjKbMQOa1FwxBEQg+giUeWXZBei71hx0naBIJ8On
Mm6mctHQDlEymRvCxzyo/280tCE+gI6pF4JCf5D8pcJVcavkubp/saMhhiK6E3pH
KM/lbUoO6Ly4dRhIf5SFAHOxth6lsAGMIFwZr0+tYBNln2vvHuexbIrj7I9GFcme
PGIV+cLQEoYhuz+2C9V/FRQwm5p3bNbd9hSYJ93Vi6n9/25OzsCmM4YGbrPnixWe
EOT8/oluROEiuHHikq5/
-----END CERTIFICATE-----
elasticsearch_ssl_key: |
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgzy/0an6ctQsj
peMWJeBDPPXCOwJIDIGA84CloDlBwxN5NWsKmEZBfQDfB9PiuzVsGtWmFsz0WlXz
lDMvp+bDdI5I+HpJ1IkT6l3tXSYVfX9+h4klwgmdB9TeTl5R8MHCCxThp3+jHI/8
Yuzhk/KN6Hsvyg5x6N5jftPshfbLdp/tPJ8hLuEOh/wM4WOG/T8UH2d7Gl2Hu2ga
VuOMeWODQE26laiDY2vVbnn/hQIw6df6JSuBSlTdruN7pOAWAFgx6XgoIf0w10nn
6k+zg23xxWRfgV9lImd+cuVVgfDyZOlO3DWBKyO4PFJsqsN3mLf7bEuvsYLJ31Kc
QHCINnXdAgMBAAECggEABG86OBAAvlMKw9ik/r0cJlaFw22rpi98GcF9RHP66DqY
LKFBuqjQ1Sj8j2nwmKHHexvxVNNvovRjxuQJFlEXvr+V1eLOQn9zKUKvBObq8DBG
Bgf4SvuDFtq6rsez96f/O9ng4UkkbqvQt6nFtQHGsE2fKgX1KIR+r3k1oGHgWKN5
Sd71E6yr0/4q3m8TleV9PrC4kghQ5j8sntXurdfhlRM9w4wNMb5M9F8ebgxErd7i
6ncVoKdpe18cubU+9wUxW5MxrasheHmfwdgjIQyU69srsERhxRZ4mhBl7n7UCCDK
1MZ5tKph+fV4t3P/xHXW1HGhMj4UgRTLjnr6e5yOGQKBgQDjQonV85cga1SeLh4Y
8NXLKHZHL56VmS7jOQ4V6GEEWqz/2IGi1GZjKv1KOY14M+GnRPD+0LTWex8ubELL
r/0tvlx3kiuPyEMsSnIrVlaiVr1yWPLdrVaerfO8hD3WykpwH5enHOdhaoezN314
4X3Xj0+V8zZ7I1mzA0T1bPmCBQKBgQC1JVV67qoPg6X7g54j9HK4fWzRAT0cGXV7
60x78JQdcDSP4yqwDHqvryRDMP38xwSbvyegERQcbZjLbl1YY5T6ZL2ovu1OemC7
6lSOSwOCD89QVsrYV52mY1qmOsuNgLIwJ1PJVY5IeFmfCpR9IFeIhdPhj2VtsAqC
M4T1hCAz+QKBgQCSIIq4g7S9J8Z1H3pC1zjhNNc41qnFz4WSnXEtLQqU3ik3KWPR
63kact4DCBarH9EM2QuNDW36K5jVJM+eYT8OVsTmLZrNDRwEMqpOq2lxYQzXpdIk
L/zuczOyF+YbYl+S0P2WesNcpD81QYzwWS2tmXy3EngJnaVjscp5dOTKcQKBgFAJ
r+xCWdfDBmrMK+qdDrdfi94JWxP4V8WqIMA+e2NKeZ7985WX3fmUPESH+CFhWjLq
0jpScX1iG3n/SLVOQrwkGPzfZ4EeZ3GAR14b3O/xxlssDjJq/BhRm/MI1XmvXIwU
RFwYNmbk7kxsY1GqIaML5qOqNVmyx+Hhm6TTfVsZAoGBALubBpgAoT+lKHw6fC6D
7TSCcxFd5tYHHw4RUmK85RcTrbjC7LksAd01T54tdM7nZRlijgJUNsYzDfv/SuSp
F3OGK/Tmx3MW5O+lq5O+2oRmUSfcIUgnrjgUeevj6Rgt1qx33WEoKBM2rVBIBqOn
ZKrzDBkVG/H+H0hwiV219PLE
-----END PRIVATE KEY-----
elasticsearch_roles:
myrole:
cluster:
- all
indices:
- names: ["logstash*"]
privileges:
- create
- write
elasticsearch_users:
toto:
password: supers3cret
roles:
- viewer
kibana_system:
password: supertest2
elasticsearch_index_templates: elasticsearch_index_templates:
test: test:
index_patterns: index_patterns:
@ -86,8 +16,3 @@
mappings: mappings:
metrics: metrics:
type: short type: short
pre_tasks:
- name: update apt cache
ansible.builtin.apt:
update_cache: true

View file

@ -2,18 +2,17 @@
driver: driver:
name: docker name: docker
platforms: platforms:
- name: debian12 - name: debian10
image: code.waks.be/nishiki/molecule:debian12 image: nishiki/debian10:molecule
privileged: true privileged: true
volumes: volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw - /sys/fs/cgroup:/sys/fs/cgroup:ro
cgroupns_mode: host
command: /bin/systemd command: /bin/systemd
capabilities: capabilities:
- SYS_ADMIN - SYS_ADMIN
lint: | lint: |
set -e set -e
yamllint . yamllint .
ansible-lint . ansible-lint
verifier: verifier:
name: testinfra name: testinfra

View file

@ -2,55 +2,31 @@ import os
import testinfra.utils.ansible_runner import testinfra.utils.ansible_runner
def test_packages(host): def test_packages(host):
package = host.package('elasticsearch') package = host.package('elasticsearch')
assert package.is_installed assert package.is_installed
def test_config_file(host): def test_config_file(host):
config = host.file('/etc/elasticsearch/elasticsearch.yml') config = host.file('/etc/elasticsearch/elasticsearch.yml')
assert config.user == 'root' assert config.user == 'root'
assert config.group == 'elasticsearch' assert config.group == 'elasticsearch'
assert config.mode == 0o640 assert config.mode == 0o640
assert config.contains('path.data: /var/lib/elasticsearch') assert config.contains('path.data: /var/lib/elasticsearch')
def test_ssl_key_file(host):
config = host.file('/etc/elasticsearch/key.pem')
assert config.user == 'root'
assert config.group == 'elasticsearch'
assert config.mode == 0o640
assert config.contains('-----BEGIN PRIVATE KEY-----')
def test_ssl_certificate_file(host):
config = host.file('/etc/elasticsearch/certificate.pem')
assert config.user == 'root'
assert config.group == 'elasticsearch'
assert config.mode == 0o640
assert config.contains('-----BEGIN CERTIFICATE-----')
def test_service(host): def test_service(host):
service = host.service('elasticsearch') service = host.service('elasticsearch')
assert service.is_running assert service.is_running
assert service.is_enabled assert service.is_enabled
def test_socket(host): def test_socket(host):
for port in [9200, 9300]: for port in [9200, 9300]:
socket = host.socket('tcp://127.0.0.1:%d' % (port)) socket = host.socket('tcp://127.0.0.1:%d' % (port))
assert socket.is_listening assert socket.is_listening
def test_java_memory(host): def test_java_memory(host):
process = host.process.filter(user='elasticsearch', comm='java') process = host.process.get(user='elasticsearch', comm='java')
assert '-Xms512m' in process[1].args assert '-Xms512m' in process.args
assert '-Xmx512m' in process[1].args assert '-Xmx512m' in process.args
def test_elasticsearch_template(host): def test_elasticsearch_template(host):
result = host.check_output('curl -v -u elastic:mysecret http://127.0.0.1:9200/_template/test') result = host.check_output('curl -v http://127.0.0.1:9200/_template/test')
assert '"number_of_replicas":"1"' in result assert '"number_of_replicas":"1"' in result
def test_elasticsearch_role(host):
result = host.check_output('curl -v -u elastic:mysecret http://127.0.0.1:9200/_security/role/myrole')
assert '"names":["logstash*"]' in result
assert '"privileges":["create","write"]' 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

View file

@ -1,43 +1,21 @@
--- ---
- name: Set heap size - name: set heap size
ansible.builtin.lineinfile: lineinfile:
path: /etc/elasticsearch/jvm.options path: /etc/elasticsearch/jvm.options
regexp: "^-{{ item }}" regexp: '^-{{ item }}'
line: "-{{ item }}{{ elasticsearch_heap_size }}" line: '-{{ item }}{{ elasticsearch_heap_size }}'
loop: loop:
- Xms - Xms
- Xmx - Xmx
notify: Restart elasticsearch notify: restart elasticsearch
tags: elasticsearch tags: elasticsearch
- name: Copy SSL certificate - name: copy config file
ansible.builtin.copy: copy:
content: "{{ elasticsearch_ssl_certificate }}" content: '{{ elasticsearch_full_config|to_nice_yaml }}'
dest: "{{ elasticsearch_full_config['xpack.security.transport.ssl.certificate'] }}"
owner: root
group: elasticsearch
mode: "0640"
when: "'xpack.security.transport.ssl.certificate' in elasticsearch_full_config"
notify: Restart elasticsearch
tags: elasticsearch
- name: Copy SSL key
ansible.builtin.copy:
content: "{{ elasticsearch_ssl_key }}"
dest: "{{ elasticsearch_full_config['xpack.security.transport.ssl.key'] }}"
owner: root
group: elasticsearch
mode: "0640"
when: "'xpack.security.transport.ssl.key' in elasticsearch_full_config"
notify: Restart elasticsearch
tags: elasticsearch
- name: Copy config file
ansible.builtin.copy:
content: "{{ elasticsearch_full_config | to_yaml }}"
dest: /etc/elasticsearch/elasticsearch.yml dest: /etc/elasticsearch/elasticsearch.yml
owner: root owner: root
group: elasticsearch group: elasticsearch
mode: "0640" mode: 0640
notify: Restart elasticsearch notify: restart elasticsearch
tags: elasticsearch tags: elasticsearch

View file

@ -1,61 +1,26 @@
--- ---
- name: Init elastic password - name: manage users
elasticsearch_init_password:
api_user: "{{ elasticsearch_api_user }}"
api_password: "{{ elasticsearch_password }}"
run_once: true
tags: elasticsearch
- name: Manage roles
elasticsearch_role:
name: "{{ item.key }}"
cluster: "{{ item.value.cluster | default(omit) }}"
indices: "{{ item.value.indices | default(omit) }}"
api_user: "{{ elasticsearch_api_user }}"
api_password: "{{ elasticsearch_password }}"
state: "{{ item.value.state | default('present') }}"
loop: "{{ elasticsearch_roles | dict2items }}"
loop_control:
label: "{{ item.key }}"
run_once: true
tags: elasticsearch
- name: Manage users
elasticsearch_user: elasticsearch_user:
name: "{{ item.key }}" name: '{{ item.key }}'
password: "{{ item.value.password }}" password: '{{ item.value.password }}'
roles: "{{ item.value.roles | default(omit) }}" api_user: '{{ elasticsearch_api_user }}'
api_user: "{{ elasticsearch_api_user }}" api_password: '{{ elasticsearch_api_password }}'
api_password: "{{ elasticsearch_password }}" loop: '{{ elasticsearch_users|dict2items }}'
state: "{{ item.value.state | default('present') }}" when: |
loop: "{{ elasticsearch_users | dict2items }}" 'xpack.security.enabled' in elasticsearch_full_config and
loop_control: elasticsearch_full_config['xpack.security.enabled'] == True
label: "{{ item.key }}"
run_once: true run_once: true
tags: elasticsearch tags: elasticsearch
- name: Copy ilm policies - name: copy index templates
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 }}"
run_once: true
tags: elasticsearch
- name: Copy index templates
elasticsearch_template: elasticsearch_template:
name: "{{ item.key }}" name: '{{ item.key }}'
index_patterns: "{{ item.value.index_patterns }}" index_patterns: '{{ item.value.index_patterns }}'
settings: "{{ item.value.settings | default({}) }}" settings: '{{ item.value.settings|default({}) }}'
mappings: "{{ item.value.mappings | default({}) }}" mappings: '{{ item.value.mappings|default({}) }}'
api_user: "{{ elasticsearch_api_user }}" api_user: '{{ elasticsearch_api_user }}'
api_password: "{{ elasticsearch_password }}" api_password: '{{ elasticsearch_api_password }}'
loop: "{{ elasticsearch_index_templates | dict2items }}" no_log: true
loop_control: loop: '{{ elasticsearch_index_templates|dict2items }}'
label: "{{ item.key }}"
run_once: true run_once: true
tags: elasticsearch tags: elasticsearch

View file

@ -1,10 +1,5 @@
--- ---
- name: Import pacakge tasks - import_tasks: packages.yml
ansible.builtin.import_tasks: packages.yml - import_tasks: config.yml
- name: Import config tasks - import_tasks: service.yml
ansible.builtin.import_tasks: config.yml - import_tasks: data.yml
- name: Import service tasks
ansible.builtin.import_tasks: service.yml
- name: Import data tasks
ansible.builtin.import_tasks: data.yml
when: elasticsearch_master

View file

@ -1,31 +1,33 @@
--- ---
- name: Install dependencies packages - name: install dependencies packages
ansible.builtin.package: apt:
name: name: '{{ packages }}'
vars:
packages:
- apt-transport-https - apt-transport-https
- python3-requests - python-requests
retries: 2
register: result
until: result is succeeded
tags: elasticsearch tags: elasticsearch
- name: Add repository key - name: add repository key
ansible.builtin.get_url: apt_key:
url: https://artifacts.elastic.co/GPG-KEY-elasticsearch url: https://artifacts.elastic.co/GPG-KEY-elasticsearch
dest: /etc/apt/keyrings/elastic.asc retries: 2
owner: root register: result
group: root until: result is succeeded
mode: 0644
checksum: sha256:db52809c5f6b27f9c2bed45cb43e398c659275f3d35305653c6750a0db90f5eb
tags: elasticsearch tags: elasticsearch
- name: Add repository - name: add repository
ansible.builtin.apt_repository: apt_repository:
repo: > repo: deb https://artifacts.elastic.co/packages/7.x/apt stable main
deb [signed-by=/etc/apt/keyrings/elastic.asc]
https://artifacts.elastic.co/packages/{{ elasticsearch_major_version }}.x/apt stable main
filename: elastic
tags: elasticsearch tags: elasticsearch
- name: Install package - name: install package
ansible.builtin.package: apt:
name: name: elasticsearch
- elasticsearch retries: 2
register: result
until: result is succeeded
tags: elasticsearch tags: elasticsearch

View file

@ -1,13 +1,13 @@
--- ---
- name: Enable and start service - name: enable and start service
ansible.builtin.service: systemd:
name: elasticsearch name: elasticsearch
state: started state: started
enabled: true enabled: true
tags: elasticsearch tags: elasticsearch
- name: Wait for api is available - name: wait for api is available
ansible.builtin.wait_for: wait_for:
port: 9200 port: 9200
timeout: 10 timeout: 10
tags: elasticsearch tags: elasticsearch