diff --git a/ansible/es7.yml b/ansible/es7.yml new file mode 100644 index 0000000000000000000000000000000000000000..93d64d6f797ed47c6e3aae82e1c36e816b0c6f8f --- /dev/null +++ b/ansible/es7.yml @@ -0,0 +1,5 @@ +--- +- hosts: es7 + become: yes + roles: + - role: es7 diff --git a/ansible/roles/es7/README.md b/ansible/roles/es7/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d7c922b359138798f5afb14d4b52d7f64b1341ad --- /dev/null +++ b/ansible/roles/es7/README.md @@ -0,0 +1,515 @@ +# ansible-elasticsearch +[](https://devops-ci.elastic.co/job/elastic+ansible-elasticsearch+master/) +[](https://galaxy.ansible.com/elastic/elasticsearch/) + +**THIS ROLE IS FOR 7.x & 6.x** + +Ansible role for 7.x/6.x Elasticsearch. Currently this works on Debian and RedHat based linux systems. Tested platforms are: + +* Ubuntu 14.04 +* Ubuntu 16.04 +* Ubuntu 18.04 +* Debian 8 +* Debian 9 +* Debian 10 +* CentOS 7 +* CentOS 8 +* Amazon Linux 2 + +The latest Elasticsearch versions of 7.x & 6.x are actively tested. + +## BREAKING CHANGES + +### Notice about multi-instance support + +* If you use only one instance but want to upgrade from an older ansible-elasticsearch version, follow [upgrade procedure](https://github.com/elastic/ansible-elasticsearch/blob/master/docs/multi-instance.md#upgrade-procedure) +* If you install more than one instance of Elasticsearch on the same host (with different ports, directory and config files), **do not update to ansible-elasticsearch >= 7.1.1**, please follow this [workaround](https://github.com/elastic/ansible-elasticsearch/blob/master/docs/multi-instance.md#workaround) instead. +* For multi-instances use cases, we are now recommending Docker containers using our official images (https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html). + +### Removing the MAX_THREAD settings + +Ansible-elasticsearch 7.5.2 is removing the option to customize the maximum number of threads the process can start in [#637](https://github.com/elastic/ansible-elasticsearch/pull/637/files#diff-04c6e90faac2675aa89e2176d2eec7d8L408). +We discovered that this option wasn't working anymore since multi-instance support removal in ansible-elasticsearch 7.1.1. +This option will be added back in a following release if it's still relevant regarding latest Elasticsearch evolutions. + +### Changes about configuration files + +Ansible-elasticsearch 7.5.2 is updating the configuration files provided by this role in [#637](https://github.com/elastic/ansible-elasticsearch/pull/637) which contained some options deprecated in 6.x and 7.x: +- `/etc/default/elasticsearch`|`/etc/sysconfig/elasticsearch`: the new template reflect the configuration file provided by Elasticsearch >= 6.x, the parameters we removed were already not used in 6.x and 7.x +- `/etc/elasticsearch/jvm.options`: the new template reflect the configuration files provided by Elasticsearch >= 6.x +- `/etc/elasticsearch/log4j2.properties`: + - We removed `log4j2.properties.j2` template from this Ansible role as it was a static file not bringing any customization specific to some ansible variable. + - Deployment of this Ansible role on new servers will get the default `log4j2.properties` provided by Elasticsearch without any override. + - **WARNING**: For upgrade scenarios where this file was already managed by previous versions of ansible-elasticsearch, this file will become unmanaged and won't be updated by default. If you wish to update it to 7.5 version, you can retrieve it [here](https://github.com/elastic/elasticsearch/blob/7.5/distribution/src/config/log4j2.properties) and use this file with `es_config_log4j2` Ansible variable (see below). + +### Removing OSS distribution for versions >= 7.11.0 + +Starting from Elasticsearch 7.11.0, OSS distributions will no more provided following Elasticsearch +recent license change. + +This Ansible role will fail if `oss_version` is set to `true` and `es_version` is greater than +`7.11.0`. + +See [Doubling down on open, Part II](https://www.elastic.co/blog/licensing-change for more details) +blog post for more details. + +#### How to override configuration files provided by ansible-elasticsearch? + +You can now override the configuration files with your own versions by using the following Ansible variables: +- `es_config_default: "elasticsearch.j2"`: replace `elasticsearch.j2` by your own template to use a custom `/etc/default/elasticsearch`|`/etc/sysconfig/elasticsearch` configuration file +- `es_config_jvm: "jvm.options.j2"`: replace `jvm.options.j2` by your own template to use a custom `/etc/elasticsearch/jvm.options` configuration file +- `es_config_log4j2: ""`: set this variable to the path of your own template to use a custom `/etc/elasticsearch/log4j2.properties` configuration file + +## Dependency + +This role uses the json_query filter which [requires jmespath](https://github.com/ansible/ansible/issues/24319) on the local machine. + +## Usage + +Create your Ansible playbook with your own tasks, and include the role elasticsearch. You will have to have this repository accessible within the context of playbook. + +```sh +ansible-galaxy install elastic.elasticsearch,v7.11.1 +``` + +Then create your playbook yaml adding the role elasticsearch. +The application of the elasticsearch role results in the installation of a node on a host. + +The simplest configuration therefore consists of: + +```yaml +- name: Simple Example + hosts: localhost + roles: + - role: elasticsearch7 + vars: + es_version: 7.11.1 +``` + +The above installs Elasticsearch 7.11.1 in a single node 'node1' on the hosts 'localhost'. + + +This role also uses [Ansible tags](http://docs.ansible.com/ansible/playbooks_tags.html). Run your playbook with the `--list-tasks` flag for more information. + +## Testing + +This playbook uses [Kitchen](https://kitchen.ci/) for CI and local testing. + +### Requirements + +* Ruby +* Bundler +* Docker +* Make + +### Running the tests + +* Ensure you have checked out this repository to `elasticsearch`, not `ansible-elasticsearch`. +* If you don't have a Gold or Platinum license to test with you can run the trial versions of the `xpack-upgrade` suites by appending `-trial` to the `PATTERN` variable. +* You may need to explicitly specify `VERSION=7.x` if some suites are failing. + +Install the ruby dependencies with bundler + +```sh +make setup +``` + +If you want to test X-Pack features with a license you will first need to export the `ES_XPACK_LICENSE_FILE` variable. +```sh +export ES_XPACK_LICENSE_FILE="$(pwd)/license.json" +``` + +To converge an Ubuntu 16.04 host running X-Pack +```sh +$ make converge +``` + +To run the tests +```sh +$ make verify +``` + +To list all of the different test suits +```sh +$ make list +``` + +The default test suite is Ubuntu 16.04 with X-Pack. If you want to test another suite you can override this with the `PATTERN` variable +```sh +$ make converge PATTERN=security-centos-7 +``` + +The `PATTERN` is a kitchen pattern which can match multiple suites. To run all tests for CentOS +```sh +$ make converge PATTERN=centos-7 +``` + +The default version is 7.x. If you want to test 6.x you can override it with the `VERSION` variable, for example: +```sh +$ make converge VERSION=6.x PATTERN=security-centos-7 +``` + +When you are finished testing you can clean up everything with +```sh +$ make destroy-all +``` + +### Basic Elasticsearch Configuration + +All Elasticsearch configuration parameters are supported. This is achieved using a configuration map parameter 'es_config' which is serialized into the elasticsearch.yml file. +The use of a map ensures the Ansible playbook does not need to be updated to reflect new/deprecated/plugin configuration parameters. + +In addition to the es_config map, several other parameters are supported for additional functions e.g. script installation. These can be found in the role's defaults/main.yml file. + +The following illustrates applying configuration parameters to an Elasticsearch instance. + +```yaml +- name: Elasticsearch with custom configuration + hosts: localhost + roles: + - role: elasticsearch7 + vars: + es_data_dirs: + - "/opt/elasticsearch/data" + es_log_dir: "/opt/elasticsearch/logs" + es_config: + node.name: "node1" + cluster.name: "custom-cluster" + discovery.seed_hosts: "localhost:9301" + http.port: 9201 + transport.port: 9301 + node.data: false + node.master: true + bootstrap.memory_lock: true + es_heap_size: 1g + es_api_port: 9201 +``` + +Whilst the role installs Elasticsearch with the default configuration parameters, the following should be configured to ensure a cluster successfully forms: + +* ```es_config['http.port']``` - the http port for the node +* ```es_config['transport.port']``` - the transport port for the node +* ```es_config['discovery.seed_hosts']``` - the unicast discovery list, in the comma separated format ```"<host>:<port>,<host>:<port>"``` (typically the clusters dedicated masters) +* ```es_config['cluster.initial_master_nodes']``` - for 7.x and above the list of master-eligible nodes to boostrap the cluster, in the comma separated format ```"<node.name>:<port>,<node.name>:<port>"``` (typically the node names of the clusters dedicated masters) +* ```es_config['network.host']``` - sets both network.bind_host and network.publish_host to the same host value. The network.bind_host setting allows to control the host different network components will bind on. + +The `network.publish_host` setting allows to control the host the node will publish itself within the cluster so other nodes will be able to connect to it. + +See https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html for further details on default binding behavior and available options. +The role makes no attempt to enforce the setting of these are requires users to specify them appropriately. It is recommended master nodes are listed and thus deployed first where possible. + +A more complex example: + +```yaml +- name: Elasticsearch with custom configuration + hosts: localhost + roles: + - role: elasticsearch7 + vars: + es_data_dirs: + - "/opt/elasticsearch/data" + es_log_dir: "/opt/elasticsearch/logs" + es_config: + node.name: "node1" + cluster.name: "custom-cluster" + discovery.seed_hosts: "localhost:9301" + http.port: 9201 + transport.port: 9301 + node.data: false + node.master: true + bootstrap.memory_lock: true + es_heap_size: 1g + es_start_service: false + es_api_port: 9201 + es_plugins: + - plugin: ingest-attachment +``` + +#### Important Notes + +**The role uses es_api_host and es_api_port to communicate with the node for actions only achievable via http e.g. to install templates and to check the NODE IS ACTIVE. These default to "localhost" and 9200 respectively. +If the node is deployed to bind on either a different host or port, these must be changed.** + +**Only use es_data_dirs and es_log_dir for customizing the data and log dirs respectively. When using together with `es_config['path.data']` and `es_config['path.logs']` it would result in generating duplicate data- and logs-keys in `elasticsearch.yml` and thus let fail to start elasticsearch.** + +### Multi Node Server Installations + +The application of the elasticsearch role results in the installation of a node on a host. Specifying the role multiple times for a host therefore results in the installation of multiple nodes for the host. + +An example of a three server deployment is shown below. The first server holds the master and is thus declared first. Whilst not mandatory, this is recommended in any multi node cluster configuration. The two others servers hosts data nodes. + +**Note that we do not support anymore installation of more than one node in the same host** + +```yaml +- hosts: master_node + roles: + - role: elasticsearch7 + vars: + es_heap_size: "1g" + es_config: + cluster.name: "test-cluster" + cluster.initial_master_nodes: "elastic02" + discovery.seed_hosts: "elastic02:9300" + http.port: 9200 + node.data: false + node.master: true + bootstrap.memory_lock: false + es_plugins: + - plugin: ingest-attachment + +- hosts: data_node_1 + roles: + - role: elasticsearch7 + vars: + es_data_dirs: + - "/opt/elasticsearch" + es_config: + cluster.name: "test-cluster" + cluster.initial_master_nodes: "elastic02" + discovery.seed_hosts: "elastic02:9300" + http.port: 9200 + node.data: true + node.master: false + bootstrap.memory_lock: false + es_plugins: + - plugin: ingest-attachment + +- hosts: data_node_2 + roles: + - role: elasticsearch7 + vars: + es_config: + cluster.name: "test-cluster" + discovery.seed_hosts: "elastic02:9300" + http.port: 9200 + node.data: true + node.master: false + bootstrap.memory_lock: false + es_plugins: + - plugin: ingest-attachment +``` + +Parameters can additionally be assigned to hosts using the inventory file if desired. + +Make sure your hosts are defined in your ```inventory``` file with the appropriate ```ansible_ssh_host```, ```ansible_ssh_user``` and ```ansible_ssh_private_key_file``` values. + +Then run it: + +```sh +ansible-playbook -i hosts ./your-playbook.yml +``` + +### Installing X-Pack Features + +* ```es_role_mapping``` Role mappings file declared as yml as described [here](https://www.elastic.co/guide/en/x-pack/current/mapping-roles.html) + + +```yaml +es_role_mapping: + power_user: + - "cn=admins,dc=example,dc=com" + user: + - "cn=users,dc=example,dc=com" + - "cn=admins,dc=example,dc=com" +``` + +* ```es_users``` - Users can be declared here as yml. Two sub keys 'native' and 'file' determine the realm under which the user is created. Beneath each of these keys users should be declared as yml entries. e.g. + +```yaml +es_users: + native: + kibana4_server: + password: changeMe + roles: + - kibana4_server + file: + es_admin: + password: changeMe + roles: + - admin + testUser: + password: changeMeAlso! + roles: + - power_user + - user +``` + + +* ```es_roles``` - Elasticsearch roles can be declared here as yml. Two sub keys 'native' and 'file' determine how the role is created i.e. either through a file or http(native) call. Beneath each key list the roles with appropriate permissions, using the file based format described [here](https://www.elastic.co/guide/en/x-pack/current/file-realm.html) e.g. + +```yaml +es_roles: + file: + admin: + cluster: + - all + indices: + - names: '*' + privileges: + - all + power_user: + cluster: + - monitor + indices: + - names: '*' + privileges: + - all + user: + indices: + - names: '*' + privileges: + - read + kibana4_server: + cluster: + - monitor + indices: + - names: '.kibana' + privileges: + - all + native: + logstash: + cluster: + - manage_index_templates + indices: + - names: 'logstash-*' + privileges: + - write + - delete + - create_index +``` + +* ```es_xpack_license``` - X-Pack license. The license is a json blob. Set the variable directly (possibly protected by Ansible vault) or from a file in the Ansible project on the control machine via a lookup: + +```yaml +es_xpack_license: "{{ lookup('file', playbook_dir + '/files/' + es_cluster_name + '/license.json') }}" +``` + +If you don't have a license you can enable the 30-day trial by setting `es_xpack_trial` to `true`. + +X-Pack configuration parameters can be added to the elasticsearch.yml file using the normal `es_config` parameter. + +For a full example see [here](https://github.com/elastic/ansible-elasticsearch/blob/master/test/integration/xpack-upgrade.yml) + +#### Important Note for Native Realm Configuration + +In order for native users and roles to be configured, the role calls the Elasticsearch API. Given security is installed this requires definition of two parameters: + +* ```es_api_basic_auth_username``` - admin username +* ```es_api_basic_auth_password``` - admin password + +These can either be set to a user declared in the file based realm, with admin permissions, or the default "elastic" superuser (default password is changeme). + +#### X-Pack Security SSL/TLS + +* To configure your cluster with SSL/TLS for HTTP and/or transport communications follow the [SSL/TLS setup procedure](https://github.com/elastic/ansible-elasticsearch/blob/master/docs/ssl-tls-setup.md) + + +### Additional Configuration + +In addition to es_config, the following parameters allow the customization of the Java and Elasticsearch versions as well as the role behavior. Options include: + +* ```oss_version``` Default `false`. Setting this to `true` will install the oss release of Elasticsearch (for version <7.11.0 only). +* `es_xpack_trial` Default `false`. Setting this to `true` will start the 30-day trail once the cluster starts. +* ```es_version``` (e.g. "7.11.1"). +* ```es_api_host``` The host name used for actions requiring HTTP e.g. installing templates. Defaults to "localhost". +* ```es_api_port``` The port used for actions requiring HTTP e.g. installing templates. Defaults to 9200. **CHANGE IF THE HTTP PORT IS NOT 9200** +* ```es_api_basic_auth_username``` The Elasticsearch username for making admin changing actions. Used if Security is enabled. Ensure this user is admin. +* ```es_api_basic_auth_password``` The password associated with the user declared in `es_api_basic_auth_username` +* `es_delete_unmanaged_file` Default `true`. Set to false to keep file realm users that have been added outside of ansible. +* `es_delete_unmanaged_native` Default `true`. Set to false to keep native realm users that have been added outside of ansible. +* ```es_start_service``` (true (default) or false) +* ```es_plugins_reinstall``` (true or false (default) ) +* ```es_plugins``` an array of plugin definitions e.g.: + + ```yaml + es_plugins: + - plugin: ingest-attachment + ``` + +* ```es_path_repo``` Sets the whitelist for allowing local back-up repositories +* ```es_action_auto_create_index``` Sets the value for auto index creation, use the syntax below for specifying indexes (else true/false): + es_action_auto_create_index: '[".watches", ".triggered_watches", ".watcher-history-*"]' +* ```es_allow_downgrades``` For development purposes only. (true or false (default) ) +* ```es_java_install``` If set to true, Java will be installed. (false (default for 7.x) or true (default for 6.x)) +* ```update_java``` Updates Java to the latest version. (true or false (default)) +* ```es_max_map_count``` maximum number of VMA (Virtual Memory Areas) a process can own. Defaults to 262144. +* ```es_max_open_files``` the maximum file descriptor number that can be opened by this process. Defaults to 65536. +* ```es_debian_startup_timeout``` how long Debian-family SysV init scripts wait for the service to start, in seconds. Defaults to 10 seconds. +* ```es_use_repository``` Setting this to `false` will stop Ansible from using the official Elastic package from any repository configured on the system. +* ```es_add_repository``` Setting this to `false` will stop Ansible to add the official Elastic package repositories (if es_use_repository is true) if you want to use a repo already present. +* ```es_custom_package_url``` the URL to the rpm or deb package for Ansible to install. When using this you will also need to set `es_use_repository: false` and make sure that the `es_version` matches the version being installed from your custom URL. E.g. `es_custom_package_url: https://downloads.example.com/elasticsearch.rpm` + +Earlier examples illustrate the installation of plugins using `es_plugins`. For officially supported plugins no version or source delimiter is required. The plugin script will determine the appropriate plugin version based on the target Elasticsearch version. For community based plugins include the full url. This approach should NOT be used for the X-Pack plugin. See X-Pack below for details here. + +If installing Monitoring or Alerting, ensure the license plugin is also specified. Security configuration currently has limited support, but more support is planned for later versions. + +To configure X-pack to send mail, the following configuration can be added to the role. When require_auth is true, you will also need to provide the user and password. If not these can be removed: + +```yaml + es_mail_config: + account: <functional name> + profile: standard + from: <from address> + require_auth: <true or false> + host: <mail domain> + port: <port number> + user: <e-mail address> --optional + pass: <password> --optional +``` + +* ```es_user``` - defaults to elasticsearch. +* ```es_group``` - defaults to elasticsearch. +* ```es_user_id``` - default is undefined. +* ```es_group_id``` - default is undefined. + +Both ```es_user_id``` and ```es_group_id``` must be set for the user and group ids to be set. + +* ```es_restart_on_change``` - defaults to true. If false, changes will not result in Elasticsearch being restarted. +* ```es_plugins_reinstall``` - defaults to false. If true, all currently installed plugins will be removed from a node. Listed plugins will then be re-installed. + +To add, update or remove elasticsearch.keystore entries, use the following variable: + +```yaml +# state is optional and defaults to present +es_keystore_entries: +- key: someKeyToAdd + value: someValue + state: present + +- key: someKeyToUpdate + value: newValue + # state: present + force: Yes + +- key: someKeyToDelete + state: absent +``` + + + +This role ships with sample templates located in the [test/integration/files/templates-7.x](https://github.com/elastic/ansible-elasticsearch/tree/master/test/integration/files/templates-7.x) directory. `es_templates_fileglob` variable is used with the Ansible [with_fileglob](http://docs.ansible.com/ansible/playbooks_loops.html#id4) loop. When setting the globs, be sure to use an absolute path. + +### Proxy + +To define proxy globally, set the following variables: + +* ```es_proxy_host``` - global proxy host +* ```es_proxy_port``` - global proxy port + +## Notes + +* The role assumes the user/group exists on the server. The elasticsearch packages create the default elasticsearch user. If this needs to be changed, ensure the user exists. +* The playbook relies on the inventory_name of each host to ensure its directories are unique +* KitchenCI has been used for testing. This is used to confirm images reach the correct state after a play is first applied. We currently test the latest version of 7.x and 6.x on all supported platforms. +* The role aims to be idempotent. Running the role multiple times, with no changes, should result in no state change on the server. If the configuration is changed, these will be applied and Elasticsearch restarted where required. +* In order to run x-pack tests a license file with security enabled is required. Set the environment variable `ES_XPACK_LICENSE_FILE` to the full path of the license file prior to running tests. A trial license is appropriate and can be used by setting `es_xpack_trial` to `true` + +## IMPORTANT NOTES RE PLUGIN MANAGEMENT + +* If the ES version is changed, all plugins will be removed. Those listed in the playbook will be re-installed. This is behavior is required in ES 6.x. +* If no plugins are listed in the playbook for a node, all currently installed plugins will be removed. +* The role supports automatic detection of differences between installed and listed plugins - installing those listed but not installed, and removing those installed but not listed. Should users wish to re-install plugins they should set es_plugins_reinstall to true. This will cause all currently installed plugins to be removed and those listed to be installed. + +## Questions on Usage + +We welcome questions on how to use the role. However, in order to keep the GitHub issues list focused on "issues" we ask the community to raise questions at https://discuss.elastic.co/c/elasticsearch. This is monitored by the maintainers. diff --git a/ansible/roles/es7/ansible.cfg b/ansible/roles/es7/ansible.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0440d4894baa917e0e639d8f4468624bf04ca86f --- /dev/null +++ b/ansible/roles/es7/ansible.cfg @@ -0,0 +1 @@ +[defaults] diff --git a/ansible/roles/es7/defaults/main.yml b/ansible/roles/es7/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..818f7c1e6163c1e5feb6723f966a301658786b4d --- /dev/null +++ b/ansible/roles/es7/defaults/main.yml @@ -0,0 +1,71 @@ +--- +es_version: "7.8.0" +es_use_snapshot_release: false +oss_version: false +es_package_name: "elasticsearch" +es_version_lock: false +es_use_repository: true +es_add_repository: true +es_templates_fileglob: "" +es_repo_base: "https://artifacts.elastic.co" +es_apt_key: "{{ es_repo_base }}/GPG-KEY-elasticsearch" +es_apt_url: "deb {{ es_repo_base }}/packages/{{ es_repo_name }}/apt stable main" +es_apt_url_old: "deb http://packages.elastic.co/elasticsearch/{{ es_repo_name }}/debian stable main" +es_start_service: true +es_java_install: "{{ false if (es_version is version('7.0.0', '>=')) else true }}" +update_java: false +es_restart_on_change: true +es_plugins_reinstall: false +es_templates: false +es_user: elasticsearch +es_group: elasticsearch +es_config: {} +es_config_default: "elasticsearch.j2" +es_config_log4j2: "" +es_config_jvm: "jvm.options.j2" +#Need to provide default directories +es_conf_dir: "/etc/elasticsearch" +es_pid_dir: "/var/run/elasticsearch" +es_tmp_dir: "/tmp" +es_data_dirs: + - "/var/lib/elasticsearch" +es_log_dir: "/var/log/elasticsearch" +es_action_auto_create_index: true +es_max_open_files: 65536 +es_max_map_count: 262144 +es_allow_downgrades: false +es_xpack_trial: false +#These are used for internal operations performed by ansible. +#They do not affect the current configuration +es_api_scheme: "http" +es_api_host: "localhost" +es_api_port: 9200 +es_api_uri: "{{ es_api_scheme }}://{{ es_api_host }}:{{ es_api_port }}" +es_security_api: "{{ '_security' if es_version is version('7.0.0', '>=') else '_xpack/security' }}" +es_license_api: "{{ '_license' if es_version is version('7.0.0', '>=') else '_xpack/license' }}" +es_api_sleep: 15 +es_debian_startup_timeout: 10 + +# JVM custom parameters +es_java_home: '' +es_jvm_custom_parameters: '' +es_heap_dump_path: "/var/lib/elasticsearch" + +# SSL/TLS parameters +es_enable_auto_ssl_configuration: true +es_enable_http_ssl: false +es_enable_transport_ssl: false +es_ssl_upload: true +es_ssl_keystore: "" +es_ssl_keystore_password: "" +es_ssl_truststore: "" +es_ssl_truststore_password: "" +es_ssl_key: "" +es_ssl_key_password: "" +es_ssl_certificate: "" +es_ssl_certificate_authority: "" +es_ssl_certificate_path: "{{ es_conf_dir }}/certs" +es_ssl_verification_mode: "certificate" +es_validate_certs: "yes" +es_delete_unmanaged_file: true +es_delete_unmanaged_native: true diff --git a/ansible/roles/es7/docs/multi-instance.md b/ansible/roles/es7/docs/multi-instance.md new file mode 100644 index 0000000000000000000000000000000000000000..57b62388ef4b6c1352505cfc75efaa9dd4447501 --- /dev/null +++ b/ansible/roles/es7/docs/multi-instance.md @@ -0,0 +1,145 @@ +# Multi-instance Support + +Starting with ansible-elasticsearch:7.1.1, installing more than one instance of Elasticsearch **on the same host** is no longer supported. + +See [554#issuecomment-496804929](https://github.com/elastic/ansible-elasticsearch/issues/554#issuecomment-496804929) for more details about why we removed it. + +## Upgrade procedure + +If you have single-instances hosts and want to upgrade from previous versions of the role: + +### Procedure with data move + +This procedure will allow you to move your data to the new standard paths (see [#581](https://github.com/elastic/ansible-elasticsearch/issues/581)): + +1. Stop Elasticsearch before the migration + +2. Migrate your data to the new standard paths: +``` +# mv /etc/elasticsearch/${ES_INSTANCE_NAME}/* /etc/elasticsearch/ && rm -fr /etc/elasticsearch/${ES_INSTANCE_NAME}/ +mv: overwrite '/etc/elasticsearch/elasticsearch.keystore'? y +# mv /var/lib/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/* /var/lib/elasticsearch/ && rm -fr /var/lib/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +# ls /var/lib/elasticsearch/ +nodes +# mv /var/log/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/* /var/log/elasticsearch/ && rm -fr /var/log/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +# rm -fr /var/run/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +``` + +3. Update playbook (remove `es_conf_dir`, `es_data_dirs`, `es_log_dir`, `es_pid_dir` and `es_instance_name` variables) + +4. Update ansible-role to new version ([7.1.1](https://github.com/elastic/ansible-elasticsearch/releases/tag/7.1.1) at the time of writing) and deploy ansible-role + +5. After ansible-role new deployment, you can do some cleanup of old Init file and Default file: + +Example: +``` +$ systemctl stop elasticsearch +$ mv /etc/elasticsearch/${ES_INSTANCE_NAME}/* /etc/elasticsearch/ && rm -fr /etc/elasticsearch/${ES_INSTANCE_NAME}/ +mv: overwrite '/etc/elasticsearch/elasticsearch.keystore'? y +$ mv /var/lib/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/* /var/lib/elasticsearch/ && rm -fr /var/lib/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +$ ls /var/lib/elasticsearch/ +nodes +$ mv /var/log/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/* /var/log/elasticsearch/ && rm -fr /var/log/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +$ rm -fr /var/run/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}/ +$ ansible-galaxy install --force elastic.elasticsearch,7.1.1 +- changing role elastic.elasticsearch from 6.6.0 to 7.1.1 +- downloading role 'elasticsearch', owned by elastic +- downloading role from https://github.com/elastic/ansible-elasticsearch/archive/7.1.1.tar.gz +- extracting elastic.elasticsearch to /home/jmlrt/.ansible/roles/elastic.elasticsearch +- elastic.elasticsearch (7.1.1) was installed successfully +$ ansible-playbook playbook.yml + +... + +TASK [elastic.elasticsearch : Create Directories] +ok: [localhost] => (item=/var/run/elasticsearch) +ok: [localhost] => (item=/var/log/elasticsearch) +changed: [localhost] => (item=/etc/elasticsearch) +ok: [localhost] => (item=/var/lib/elasticsearch) + +TASK [elastic.elasticsearch : Copy Configuration File] +changed: [localhost] + +TASK [elastic.elasticsearch : Copy Default File] +changed: [localhost] + +TASK [elastic.elasticsearch : Copy jvm.options File] +changed: [localhost] + +... + +RUNNING HANDLER [elastic.elasticsearch : restart elasticsearch] +changed: [localhost] + +... + +PLAY RECAP +localhost : ok=26 changed=6 unreachable=0 failed=0 skipped=116 rescued=0 ignored=0 +$ find /etc -name '${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME}*' +/etc/default/node1_elasticsearch +/etc/systemd/system/multi-user.target.wants/node1_elasticsearch.service +``` + +### Procedure without data move + +This procedure will allow you to keep your data to the old paths: + +1. Override these variables to match previous values: +```yaml +es_conf_dir: /etc/elasticsearch/${ES_INSTANCE_NAME} +es_data_dirs: + - /var/lib/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME} +es_log_dir: /var/log/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME} +es_pid_dir: /var/run/elasticsearch/${INVENTORY_HOSTNAME}-${ES_INSTANCE_NAME} +``` + +2. Deploy ansible-role. **Even if these variables are overrided, Elasticsearch config file and default option file will change, which imply an Elasticsearch restart.** + +3. After ansible-role new deployment, you can do some cleanup of old Init file and Default file. + +Example: +```bash +$ ansible-playbook -e '{"es_conf_dir":"/etc/elasticsearch/node1","es_data_dirs":["/var/lib/elasticsearch/localhost-node1"],"es_log_dir":"/var/log/elasticsearch/localhost-node1","es_pid_dir":"/var/run/elasticsearch/localhost-node1"}' playbook.yml +... +TASK [elasticsearch : Create Directories] ********************************************************************************************************************************************************************************************************************** +ok: [localhost] => (item=/var/run/elasticsearch/localhost-node1) +ok: [localhost] => (item=/var/log/elasticsearch/localhost-node1) +ok: [localhost] => (item=/etc/elasticsearch/node1) +ok: [localhost] => (item=/var/lib/elasticsearch/localhost-node1) + +TASK [elasticsearch : Copy Configuration File] ***************************************************************************************************************************************************************************************************************** +changed: [localhost] + +TASK [elasticsearch : Copy Default File] *********************************************************************************************************************************************************************************************************************** +changed: [localhost] +... +PLAY RECAP ***************************************************************************************************************************************************************************************************************************************************** +localhost : ok=32 changed=3 unreachable=0 failed=0 + +$ find /etc -name 'node1_elasticsearch*' +/etc/default/node1_elasticsearch +/etc/systemd/system/multi-user.target.wants/node1_elasticsearch.service +$ rm /etc/default/node1_elasticsearch /etc/systemd/system/multi-user.target.wants/node1_elasticsearch.service +``` + +## Workaround + +If you use more than one instance of Elasticsearch on the same host (with different ports, directory and config files), you are still be able to install Elasticsearch 6.x and 7.x in multi-instance mode by using ansible-elasticsearch commit [25bd09f](https://github.com/elastic/ansible-elasticsearch/commit/25bd09f6835b476b6a078676a7d614489a6739c5) (last commit before multi-instance removal) and overriding `es_version` variable: + +```sh +$ cat << EOF >> requirements.yml # require git +- src: https://github.com/elastic/ansible-elasticsearch + version: 25bd09f + name: elasticsearch +EOF +$ ansible-galaxy install -r requirements.yml +$ cat << EOF >> playbook.yml +- hosts: localhost + roles: + - role: elasticsearch + vars: + es_instance_name: "node1" + es_version: 7.1.1 # or 6.8.0 for example +EOF +$ ansible-playbook playbook.yml +``` diff --git a/ansible/roles/es7/docs/ssl-tls-setup.md b/ansible/roles/es7/docs/ssl-tls-setup.md new file mode 100644 index 0000000000000000000000000000000000000000..4eec7614a1aa4c28316ea29ac59b8906b110b837 --- /dev/null +++ b/ansible/roles/es7/docs/ssl-tls-setup.md @@ -0,0 +1,105 @@ +# X-Pack Security SSL/TLS + +The role allows configuring HTTP and transport layer SSL/TLS for the cluster. You will need to generate and provide your own PKCS12 or PEM encoded certificates as described in [Encrypting communications in Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.4/configuring-tls.html#configuring-tls). + +By default this role will upload the certs to your elasticsearch servers. If you already copied the certs by your own way, set `es_ssl_upload` to `false` (default: `true`) + +If you don't want this role to add autogenerated SSL configuration to elasticsearch.yml set `es_enable_auto_ssl_configuration` to `false` (default: `true`). + +The following should be configured to ensure a security-enabled cluster successfully forms: + +* `es_enable_http_ssl` Default `false`. Setting this to `true` will enable HTTP client SSL/TLS +* `es_enable_transport_ssl` - Default `false`. Setting this to `true` will enable transport layer SSL/TLS + +When using a [PKCS12](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html#security-http-pkcs12-files) keystore and truststore: + +* `es_ssl_keystore` path to your PKCS12 keystore (can be the same as `es_ssl_truststore`) +* `es_ssl_keystore_password` set this if your keystore is protected with a password +* `es_ssl_truststore` path to your PKCS12 keystore (can be the same as `es_ssl_keystore`) +* `es_ssl_truststore_password` set this if your truststore is protected with a password + +When using [PEM encoded](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html#_pem_encoded_files_3) certificates: + +* `es_ssl_key` path to your SSL key +* `es_ssl_key_password` set this if your SSL key is protected with a password +* `es_ssl_certificate` the path to your SSL certificate + +## Generating an SSL keystore + +With a password: + +```shell +$ bin/elasticsearch-certutil ca --out ./my-ca.p12 --pass "ca_password" +$ bin/elasticsearch-certutil cert --ca ./my-ca.p12 --ca-pass "ca_password" --out ./my-keystore.p12 --pass "keystore_password" +``` + +Without a password: + +```shell +$ bin/elasticsearch-certutil ca --out ./my-ca.p12 --pass "" +$ bin/elasticsearch-certutil cert --ca ./my-ca.p12 --out ./my-keystore.p12 --pass "" +``` + +## Additional optional SSL/TLS configuration + +* `es_enable_auto_ssl_configuration` Default `true`. Whether this role should add automatically generated SSL config to elasticsearch.yml. +* `es_ssl_certificate_path` Default `{{ es_conf_dir }}/certs`. The location where certificates should be stored on the ES node. +* `es_ssl_verification_mode` Default `certificate`. See [SSL verification_mode](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html#ssl-tls-settings) for options. +* `es_ssl_certificate_authority` PEM encoded certificate file that should be trusted. +* `es_validate_certs` Default `yes`. Determines if ansible should validate SSL certificates when performing actions over HTTPS. e.g. installing templates and managing native users. + +## Example SSL/TLS configuration + +```yaml +- name: Elasticsearch with SSL/TLS enabled + hosts: localhost + roles: + - role: elastic.elasticsearch + vars: + es_config: + node.name: "node1" + cluster.name: "custom-cluster" + discovery.seed_hosts: "localhost:9301" + http.port: 9201 + transport.port: 9301 + node.data: false + node.master: true + bootstrap.memory_lock: true + xpack.security.authc.realms.file.file1.order: 0 + xpack.security.authc.realms.native.native1.order: 1 + es_heap_size: 1g + es_api_basic_auth_username: "elastic" # This is the default user created by the installation of elasticsearch + es_api_basic_auth_password: "changeme" # This is the default password created by the installation of elasticsearch + es_enable_http_ssl: true + es_enable_transport_ssl: true + es_ssl_keystore: "files/certs/my-keystore.p12" + es_ssl_truststore: "files/certs/my-ca.p12" + es_ssl_keystore_password: "keystore_password" + es_ssl_truststore_password: "ca_password" + es_validate_certs: no +``` + +## Changing the default password of elastic user + +To change the default password of user elastic: + +* Add this line to your playbook: + +``` +vars: + es_api_basic_auth_username: "elastic" + es_api_basic_auth_password: "changeme" + es_users: + native: + elastic: + password: "<new password>" +``` + +* Deploy your playbook +* Update your playbook with: + +``` +vars: + es_api_basic_auth_username: "elastic" + es_api_basic_auth_password: "<new password>" +``` diff --git a/ansible/roles/es7/files/systemd/elasticsearch_override.conf b/ansible/roles/es7/files/systemd/elasticsearch_override.conf new file mode 100644 index 0000000000000000000000000000000000000000..bf0220364cc027fdfa5c31623c6fc2c264432420 --- /dev/null +++ b/ansible/roles/es7/files/systemd/elasticsearch_override.conf @@ -0,0 +1,2 @@ +[Service] +LimitMEMLOCK=infinity diff --git a/ansible/roles/es7/filter_plugins/custom.py b/ansible/roles/es7/filter_plugins/custom.py new file mode 100644 index 0000000000000000000000000000000000000000..ad13ab183fd3ec570b7c99d78c8fd4bb9186e53b --- /dev/null +++ b/ansible/roles/es7/filter_plugins/custom.py @@ -0,0 +1,75 @@ +__author__ = "dale mcdiarmid" + +import re +import os.path +from six import string_types + + +def modify_list(values=[], pattern="", replacement="", ignorecase=False): + """ Perform a `re.sub` on every item in the list""" + if ignorecase: + flags = re.I + else: + flags = 0 + _re = re.compile(pattern, flags=flags) + return [_re.sub(replacement, value) for value in values] + + +def append_to_list(values=[], suffix=""): + if isinstance(values, string_types): + values = values.split(",") + return [str(value + suffix) for value in values] + + +def array_to_str(values=[], separator=","): + return separator.join(values) + + +def extract_role_users(users={}, exclude_users=[]): + role_users = [] + for user, details in list(users.items()): + if user not in exclude_users and "roles" in details: + for role in details["roles"]: + role_users.append(role + ":" + user) + return role_users + + +def filename(filename=""): + return os.path.splitext(os.path.basename(filename))[0] + + +def remove_reserved(user_roles={}): + not_reserved = [] + for user_role, details in list(user_roles.items()): + if ( + not "metadata" in details + or not "_reserved" in details["metadata"] + or not details["metadata"]["_reserved"] + ): + not_reserved.append(user_role) + return not_reserved + + +def filter_reserved(users_role={}): + reserved = [] + for user_role, details in list(users_role.items()): + if ( + "metadata" in details + and "_reserved" in details["metadata"] + and details["metadata"]["_reserved"] + ): + reserved.append(user_role) + return reserved + + +class FilterModule(object): + def filters(self): + return { + "modify_list": modify_list, + "append_to_list": append_to_list, + "filter_reserved": filter_reserved, + "array_to_str": array_to_str, + "extract_role_users": extract_role_users, + "remove_reserved": remove_reserved, + "filename": filename, + } diff --git a/ansible/roles/es7/handlers/main.yml b/ansible/roles/es7/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..e2fb1765dfac038de3726c08f19511b2f8f69608 --- /dev/null +++ b/ansible/roles/es7/handlers/main.yml @@ -0,0 +1,15 @@ + +- name: reload systemd configuration + become: yes + systemd: + daemon_reload: true + +# Restart service and ensure it is enabled + +- name: restart elasticsearch + become: yes + service: name=elasticsearch state=restarted enabled=yes + when: + - es_restart_on_change + - es_start_service + register: es_restarted diff --git a/ansible/roles/es7/meta/main.yml b/ansible/roles/es7/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..053dcac75094377823199fc48763c47086b4fdcc --- /dev/null +++ b/ansible/roles/es7/meta/main.yml @@ -0,0 +1,27 @@ +--- + +allow_duplicates: yes + +galaxy_info: + author: Robin Clarke, Jakob Reiter, Dale McDiarmid + description: Elasticsearch for Linux + company: "Elastic.co" + license: "license (Apache)" + min_ansible_version: 2.5.0 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all + - galaxy_tags: + - elastic + - elasticsearch + - elk + - logging +dependencies: [] diff --git a/ansible/roles/es7/tasks/azure-plugin.yml b/ansible/roles/es7/tasks/azure-plugin.yml new file mode 100644 index 0000000000000000000000000000000000000000..f810e57a7844b2aaa508f0a2c96d632cd003722a --- /dev/null +++ b/ansible/roles/es7/tasks/azure-plugin.yml @@ -0,0 +1,13 @@ +--- +- name: Check if plugin already installed or not + shell: "curl -s localhost:9200/_cat/plugins | awk '{print $2}' |head -1" + register: plugin_output + +- name: check the output + debug: + var: plugin_output + +- name: Install plugin + shell: | + echo 'y' | /usr/share/elasticsearch/bin/elasticsearch-plugin install repository-azure + when: plugin_output.stdout != "repository-azure" diff --git a/ansible/roles/es7/tasks/compatibility-variables.yml b/ansible/roles/es7/tasks/compatibility-variables.yml new file mode 100644 index 0000000000000000000000000000000000000000..213d3668abc90855ec5aa75850f918f7a04c1d99 --- /dev/null +++ b/ansible/roles/es7/tasks/compatibility-variables.yml @@ -0,0 +1,38 @@ +--- + +# It is possible to set these are defaults with messy jinja templating one liners however: +# 1. That is really hard to read and debug +# 2. When running multiple plays with the same role the defaults are not re-evaluated. An example of this +# can be seen in our the https://github.com/elastic/ansible-elasticsearch/blob/master/test/integration/xpack.yml +# integration test and in the Multi Node server documentation examples https://github.com/elastic/ansible-elasticsearch/blob/master/test/integration/xpack.yml +- name: Set backward compatibility for deprecated es_enable_xpack variable + when: es_enable_xpack is defined and not es_enable_xpack + block: + - name: Set fact oss_version when using es_enable_xpack + set_fact: oss_version=true + - name: Warn about deprecated es_enable_xpack variable + debug: + msg: "WARNING: es_enable_xpack variable is now deprecated. You should use oss_version instead" + +- name: Set the defaults here otherwise they can't be overriden in the same play if the role is called twice + set_fact: + es_repo_name: "{{ es_major_version }}" + es_package_name: "elasticsearch" + es_other_package_name: "elasticsearch-oss" + es_other_repo_name: "{{ 'oss-' + es_major_version }}" + es_other_apt_url: "deb {{ es_repo_base }}/packages/{{ 'oss-' + es_major_version }}/apt stable main" + +- name: Use the oss repo and package + set_fact: + es_repo_name: "{{ 'oss-' + es_major_version }}" + es_other_repo_name: "{{ es_major_version }}" + es_other_apt_url: "deb {{ es_repo_base }}/packages/{{ es_major_version }}/apt stable main" + es_package_name: "elasticsearch-oss" + es_other_package_name: "elasticsearch" + when: + - oss_version + +- name: Set the URL scheme to https if SSL/TLS is enabled + set_fact: + es_api_scheme: "https" + when: es_enable_http_ssl | bool diff --git a/ansible/roles/es7/tasks/elasticsearch-Debian.yml b/ansible/roles/es7/tasks/elasticsearch-Debian.yml new file mode 100644 index 0000000000000000000000000000000000000000..b344b41391958cffcb69a73ed7c5510a5e849f17 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-Debian.yml @@ -0,0 +1,116 @@ +--- + +- name: set fact force_install to no + set_fact: force_install=no + +- name: set fact force_install to yes + set_fact: force_install=yes + when: es_allow_downgrades + +- name: Gracefully stop and remove elasticsearch package if switching between OSS and standard + become: yes + block: + - name: Check if the elasticsearch package is installed + shell: "dpkg-query -W -f'${Status}' {{ es_other_package_name }}" + register: elasticsearch_package + failed_when: False + changed_when: False + check_mode: no + + - name: unhold elasticsearch package when switching to a different package type + become: yes + dpkg_selections: + name: "{{ es_other_package_name }}" + selection: "install" + when: elasticsearch_package.stdout == 'install ok installed' + + - name: stop elasticsearch + service: + name: 'elasticsearch' + state: stopped + when: elasticsearch_package.stdout == 'install ok installed' + + - name: Debian - Remove elasticsearch package if we are switching to a different package type + apt: + name: '{{ es_other_package_name }}' + state: absent + when: elasticsearch_package.stdout == 'install ok installed' + + +- name: Install Elasticsearch repository + when: es_use_repository + become: yes + block: + - name: Debian - Install apt-transport-https to support https APT downloads + apt: + name: apt-transport-https + state: present + + - name: Debian - Add Elasticsearch repository key + apt_key: + url: '{{ es_apt_key }}' + id: '{{ es_apt_key_id }}' + state: present + when: es_add_repository and es_apt_key | string + + - name: Debian - Add elasticsearch repository + apt_repository: + repo: '{{ item.repo }}' + state: '{{ item.state }}' + when: es_add_repository + with_items: + - { repo: "{{ es_apt_url_old }}", state: "absent" } + - { repo: "{{ es_apt_url }}", state: "present" } + - { repo: "{{ es_other_apt_url }}", state: "absent" } + +- name: Include optional user and group creation. + when: (es_user_id is defined) and (es_group_id is defined) + include: elasticsearch-optional-user.yml + +- name: Debian - Get installed elasticsearch version + command: dpkg-query --showformat='${Version}' --show {{ es_package_name }} + register: installed_es_version + failed_when: False + changed_when: False + check_mode: no + +- name: Debian - unhold elasticsearch version + become: yes + dpkg_selections: + name: "{{ es_package_name }}" + selection: "install" + when: not es_version_lock or (installed_es_version.stdout and installed_es_version.stdout != es_version) + +- name: Debian - Ensure elasticsearch is installed + become: yes + apt: + name: '{{ es_package_name }}{% if es_version is defined and es_version != "" %}={{ es_version }}{% endif %}' + state: present + force: '{{ force_install }}' + allow_unauthenticated: "{{ 'no' if es_apt_key else 'yes' }}" + cache_valid_time: 86400 + when: es_use_repository + register: debian_elasticsearch_install_from_repo + notify: restart elasticsearch + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + +- name: Debian - hold elasticsearch version + become: yes + dpkg_selections: + name: "{{ es_package_name }}" + selection: "hold" + when: es_version_lock + +- name: Debian - Download elasticsearch from url + get_url: url={% if es_custom_package_url is defined %}{{ es_custom_package_url }}{% else %}{{ es_package_url }}-{{ es_version }}-amd64.deb{% endif %} dest=/tmp/elasticsearch-{{ es_version }}.deb validate_certs=no + when: not es_use_repository + +- name: Debian - Ensure elasticsearch is installed from downloaded package + become: yes + apt: deb=/tmp/elasticsearch-{{ es_version }}.deb + when: not es_use_repository + register: elasticsearch_install_from_package + notify: restart elasticsearch + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" diff --git a/ansible/roles/es7/tasks/elasticsearch-RedHat-version-lock.yml b/ansible/roles/es7/tasks/elasticsearch-RedHat-version-lock.yml new file mode 100644 index 0000000000000000000000000000000000000000..7835be42e92d466f45e0e7ced6716dcd67dc7dc0 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-RedHat-version-lock.yml @@ -0,0 +1,47 @@ +--- +- name: RedHat - install yum-version-lock + become: yes + yum: + name: yum-plugin-versionlock + state: present + update_cache: yes + +- name: RedHat - check if requested elasticsearch version lock exists + become: yes + shell: 'yum versionlock list | grep {{es_package_name}} | grep -c "{{es_version}}"' + register: es_requested_version_locked + args: + warn: false + failed_when: False + changed_when: False + check_mode: False + +- name: RedHat - lock elasticsearch version + become: yes + shell: yum versionlock delete 0:elasticsearch* ; yum versionlock add {{ es_package_name }}-{{ es_version }} + args: + warn: false + when: + - es_version_lock + - es_requested_version_locked is defined + - es_requested_version_locked.stdout|int == 0 + +- name: RedHat - check if any elasticsearch version lock exists + become: yes + shell: yum versionlock list | grep -c elasticsearch + register: es_version_locked + args: + warn: false + failed_when: False + changed_when: False + check_mode: False + +- name: RedHat - unlock elasticsearch version + become: yes + shell: yum versionlock delete 0:elasticsearch* + args: + warn: false + when: + - not es_version_lock + - es_version_locked is defined + - es_version_locked.stdout|int > 0 diff --git a/ansible/roles/es7/tasks/elasticsearch-RedHat.yml b/ansible/roles/es7/tasks/elasticsearch-RedHat.yml new file mode 100644 index 0000000000000000000000000000000000000000..f3ebc1edae10c30d7b5ce66473678e60d4e3f173 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-RedHat.yml @@ -0,0 +1,62 @@ +--- +- name: set fact allow_downgrade to no + set_fact: allow_downgrade=no + +- name: set fact allow_downgrade to yes + set_fact: allow_downgrade=yes + when: es_allow_downgrades + +- name: Ensure libselinux-python on CentOS 6.x + become: yes + yum: name=libselinux-python state=present update_cache=yes + when: ( ansible_distribution == "CentOS" ) and ( ansible_distribution_major_version == "6" ) + +- name: RedHat - add Elasticsearch repo + become: yes + template: + src: 'elasticsearch.repo' + dest: '/etc/yum.repos.d/elasticsearch-{{ es_repo_name }}.repo' + when: es_use_repository and es_add_repository + +- name: RedHat - remove unused Elasticsearch repo + become: yes + file: + path: '/etc/yum.repos.d/elasticsearch-{{ es_other_repo_name }}.repo' + state: absent + when: es_use_repository + +- name: RedHat - include versionlock + include: elasticsearch-RedHat-version-lock.yml + +- name: RedHat - Remove the other elasticsearch package if switching between OSS and standard + become: yes + yum: + name: '{{ es_other_package_name }}' + state: 'absent' + +- name: Include optional user and group creation. + when: (es_user_id is defined) and (es_group_id is defined) + include: elasticsearch-optional-user.yml + +- name: RedHat - Install Elasticsearch + become: yes + yum: + name: '{{ es_package_name }}{% if es_version is defined and es_version != "" %}-{{ es_version }}{% endif %}' + state: present + update_cache: yes + allow_downgrade: '{{ allow_downgrade }}' + when: es_use_repository and not ansible_check_mode + register: redhat_elasticsearch_install_from_repo + notify: restart elasticsearch + until: redhat_elasticsearch_install_from_repo.rc == 0 + retries: 5 + delay: 10 + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + +- name: RedHat - Install Elasticsearch from url + become: yes + yum: name={% if es_custom_package_url is defined %}{{ es_custom_package_url }}{% else %}{{ es_package_url }}-{{ es_version }}.noarch.rpm{% endif %} state=present + when: not es_use_repository + register: elasticsearch_install_from_package + notify: restart elasticsearch diff --git a/ansible/roles/es7/tasks/elasticsearch-config.yml b/ansible/roles/es7/tasks/elasticsearch-config.yml new file mode 100644 index 0000000000000000000000000000000000000000..36d928b3a9f7d79ff437e6153f4d41d8b5859796 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-config.yml @@ -0,0 +1,105 @@ +--- +# Configure Elasticsearch Node + +#Create conf directory +- name: Create Configuration Directory + become: yes + file: + path: "{{ es_conf_dir }}" + state: directory + owner: root + group: "{{ es_group }}" + mode: "2750" + +#Create pid directory +- name: Create PID Directory + become: yes + file: + path: "{{ es_pid_dir }}" + state: directory + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "755" + +#Create required directories +- name: Create Others Directories + become: yes + file: + path: "{{ item }}" + state: directory + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "2750" + with_items: + - "{{ es_log_dir }}" + - "{{ es_data_dirs }}" + +#Copy the config template +- name: Copy Configuration File + become: yes + template: + src: elasticsearch.yml.j2 + dest: "{{ es_conf_dir }}/elasticsearch.yml" + owner: root + group: "{{ es_group }}" + mode: "660" + force: yes + register: system_change + notify: restart elasticsearch + +#Copy the default file +- name: Copy Default File + become: yes + template: + src: "{{ es_config_default }}" + dest: "{{ default_file }}" + owner: root + group: "{{ es_group }}" + mode: "660" + force: yes + notify: restart elasticsearch + +#Copy the systemd specific file if systemd is installed +- when: use_system_d and (m_lock_enabled or es_max_open_files is defined) + become: yes + block: + - name: Make sure destination dir exists + file: + path: "{{ sysd_config_file | dirname }}" + state: directory + mode: "755" + + - name: Copy specific ElasticSearch Systemd config file + template: + src: "override.conf.j2" + dest: "{{ sysd_config_file }}" + owner: root + group: "{{ es_group }}" + mode: "644" + force: yes + notify: + - reload systemd configuration + - restart elasticsearch + +- name: Copy jvm.options File + become: yes + template: + src: "{{ es_config_jvm }}" + dest: "{{ es_conf_dir }}/jvm.options" + owner: root + group: "{{ es_group }}" + mode: "660" + force: yes + notify: restart elasticsearch + +- name: Copy log4j2.properties File + become: yes + template: + src: "{{ es_config_log4j2 }}" + dest: "{{ es_conf_dir }}/log4j2.properties" + owner: root + group: "{{ es_group }}" + mode: "660" + force: yes + notify: restart elasticsearch + when: es_config_log4j2 != '' diff --git a/ansible/roles/es7/tasks/elasticsearch-optional-user.yml b/ansible/roles/es7/tasks/elasticsearch-optional-user.yml new file mode 100644 index 0000000000000000000000000000000000000000..d8f787e4b7d12f1623aa6952b1c0877ef5e5a229 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-optional-user.yml @@ -0,0 +1,24 @@ +--- +#Add the elasticsearch user before installing from packages. +- name: Ensure optional elasticsearch group is created with the correct id. + become: yes + #Restart if these change + notify: restart elasticsearch + group: + state: present + name: "{{ es_group }}" + system: yes + gid: "{{ es_group_id }}" + +- name: Ensure optional elasticsearch user is created with the correct id. + become: yes + #Restart if these change + notify: restart elasticsearch + user: + state: present + name: "{{ es_user }}" + comment: elasticsearch system user + system: yes + createhome: no + uid: "{{ es_user_id }}" + group: "{{ es_group }}" diff --git a/ansible/roles/es7/tasks/elasticsearch-parameters.yml b/ansible/roles/es7/tasks/elasticsearch-parameters.yml new file mode 100644 index 0000000000000000000000000000000000000000..c73d7ae8eb22ebe4ca664badfd06acb0592009e6 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-parameters.yml @@ -0,0 +1,52 @@ +# Check for mandatory parameters + +- name: Warn about deprecated es_xpack_features variable + debug: + msg: "WARNING: es_xpack_features variable is now deprecated. All feature are now enabled by default" + when: es_xpack_features is defined and not oss_version + +- name: "fail when oss_version is true with es_version >= 7.11.0" + fail: + msg: > + OSS versions are not available for Elasticsearch >= 7.11.0. + See https://www.elastic.co/blog/licensing-change for more details. + when: oss_version and es_version is version('7.11.0', '>=') + +- name: fail when es_proxy_port is not defined or is blank + fail: msg="es_proxy_port must be specified and cannot be blank when es_proxy_host is defined" + when: (es_proxy_port is not defined or es_proxy_port == '') and (es_proxy_host is defined and es_proxy_host != '') + +#If the user attempts to lock memory they must specify a heap size +- name: fail when heap size is not specified when using memory lock + fail: msg="If locking memory with bootstrap.memory_lock a heap size must be specified" + when: es_config['bootstrap.memory_lock'] is defined and es_config['bootstrap.memory_lock'] == True and es_heap_size is not defined and not ansible_check_mode + +#Check if working with security we have an es_api_basic_auth_username and es_api_basic_auth_username - otherwise any http calls wont work +- name: fail when api credentials are not declared when using security + fail: msg="Enabling security requires an es_api_basic_auth_username and es_api_basic_auth_password to be provided to allow cluster operations" + when: + - not oss_version + - es_api_basic_auth_username is defined + - es_api_basic_auth_password is not defined + +- name: fail when ssl enabled without defining a key and certificate + fail: msg="Enabling SSL/TLS (es_enable_http_ssl or es_enable_transport_ssl) requires es_ssl_keystore and es_ssl_truststore or es_ssl_key and es_ssl_certificate to be provided" + when: + - es_enable_http_ssl or es_enable_transport_ssl + - (es_ssl_key == "" or es_ssl_certificate == "") + - (es_ssl_keystore == "" or es_ssl_truststore == "") + +- name: set fact file_reserved_users + set_fact: file_reserved_users={{ es_users.file.keys() | list | intersect (reserved_xpack_users) }} + when: es_users is defined and es_users.file is defined and (es_users.file.keys() | list | length > 0) and (es_users.file.keys() | list | intersect (reserved_xpack_users) | length > 0) + +- name: fail when changing users through file realm + fail: + msg: "ERROR: INVALID CONFIG - YOU CANNOT CHANGE RESERVED USERS THROUGH THE FILE REALM. THE FOLLOWING CANNOT BE CHANGED: {{file_reserved_users}}. USE THE NATIVE REALM." + when: file_reserved_users | default([]) | length > 0 + +- name: set fact m_lock_enabled + set_fact: m_lock_enabled={{ es_config['bootstrap.memory_lock'] is defined and es_config['bootstrap.memory_lock'] == True }} + +- name: set fact use_system_d + set_fact: use_system_d={{ (ansible_distribution == 'Debian' and ansible_distribution_version is version('8', '>=')) or (ansible_distribution in ['RedHat','CentOS'] and ansible_distribution_version is version('7', '>=')) or (ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('15', '>=')) or (ansible_distribution == 'Amazon' and ansible_distribution_version is version('2', '>=')) }} diff --git a/ansible/roles/es7/tasks/elasticsearch-plugins.yml b/ansible/roles/es7/tasks/elasticsearch-plugins.yml new file mode 100644 index 0000000000000000000000000000000000000000..7e1829a05b2ff3f19cbb62c205e109798a083fbe --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-plugins.yml @@ -0,0 +1,80 @@ +--- + +# es_plugins_reinstall will be set to true if elasticsearch_install_from_repo.changed or elasticsearch_install_from_package.changed +# i.e. we have changed ES version(or we have clean installation of ES), or if no plugins listed. Otherwise it is false and requires explicitly setting. +- name: set fact es_plugins_reinstall to true + set_fact: es_plugins_reinstall=true + when: (((debian_elasticsearch_install_from_repo is defined and debian_elasticsearch_install_from_repo.changed) or (redhat_elasticsearch_install_from_repo is defined and redhat_elasticsearch_install_from_repo.changed)) or (elasticsearch_install_from_package is defined and elasticsearch_install_from_package.changed)) or es_plugins is not defined or es_plugins is none + +- name: set fact list_command + set_fact: list_command="" +#If we are reinstalling all plugins, e.g. to a version change, we need to remove all plugins (inc. x-pack) to install any plugins. Otherwise we don't consider x-pack so the role stays idempotent. +- name: set fact list_command check for x-pack + set_fact: list_command="| grep -vE 'x-pack'" + when: not es_plugins_reinstall + +- name: remove x-pack plugin directory when it isn't a plugin + file: + dest: "{{ es_home }}/plugins/x-pack" + state: "absent" + +#List currently installed plugins. We have to list the directories as the list commmand fails if the ES version is different than the plugin version. +- name: Check installed elasticsearch plugins + become: yes + shell: "ls {{es_home}}/plugins {{list_command}}" + register: installed_plugins + changed_when: False + ignore_errors: yes + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_INCLUDE: "{{ default_file }}" + check_mode: no + +#if es_plugins_reinstall is set to true we remove ALL plugins +- name: set fact plugins_to_remove to install_plugins.stdout_lines + set_fact: plugins_to_remove="{{ installed_plugins.stdout_lines | default([]) }}" + when: es_plugins_reinstall + +#if the plugins listed are different than those requested, we remove those installed but not listed in the config +- name: set fact plugins_to_remove to delete plugins installed but not listed in es_plugins + set_fact: plugins_to_remove="{{ installed_plugins.stdout_lines | difference(es_plugins | json_query('[*].plugin')) | default([]) }}" + when: not es_plugins_reinstall + +#if es_plugins_reinstall is set to true we (re)install ALL plugins +- name: set fact plugins_to_install to es_plugins + set_fact: plugins_to_install="{{ es_plugins | json_query('[*].plugin') | default([]) }}" + when: es_plugins_reinstall + +#if the plugins listed are different than those requested, we install those not installed but listed in the config +- name: set fact to plugins_to_install to those in es_config but not installed + set_fact: plugins_to_install="{{ es_plugins | json_query('[*].plugin') | difference(installed_plugins.stdout_lines) | default([]) }}" + when: not es_plugins_reinstall + +# This removes any currently installed plugins (to prevent errors when reinstalling) +- name: Remove elasticsearch plugins + become: yes + command: "{{es_home}}/bin/elasticsearch-plugin remove {{item}} --silent" + with_items: "{{ plugins_to_remove | default([]) }}" + notify: restart elasticsearch + register: plugin_removed + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_INCLUDE: "{{ default_file }}" + +- name: Install elasticsearch plugins + become: yes + command: "{{es_home}}/bin/elasticsearch-plugin install {{ item.url | default(item.plugin) }} --batch --silent" + register: plugin_installed + changed_when: plugin_installed.rc == 0 + with_items: "{{ es_plugins }}" + when: item.plugin in plugins_to_install + notify: restart elasticsearch + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_INCLUDE: "{{ default_file }}" + until: plugin_installed.rc == 0 + retries: 5 + delay: 5 diff --git a/ansible/roles/es7/tasks/elasticsearch-ssl.yml b/ansible/roles/es7/tasks/elasticsearch-ssl.yml new file mode 100644 index 0000000000000000000000000000000000000000..af5e15ba9eda169876b8d575720d65196969bfae --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-ssl.yml @@ -0,0 +1,124 @@ +--- + +- name: set fact es_same_keystore + set_fact: es_same_keystore=false + +- name: set fact es_same_keystore if stores match + set_fact: es_same_keystore=true + when: es_ssl_keystore == es_ssl_truststore + +- name: Ensure certificate directory exists + become: yes + file: + dest: "{{ es_ssl_certificate_path }}" + state: directory + owner: root + group: "{{ es_group }}" + mode: "750" + when: es_ssl_upload + +- name: Upload SSL/TLS keystore + become: yes + copy: + src: "{{ es_ssl_keystore }}" + dest: "{{ es_ssl_certificate_path }}/{{ es_ssl_keystore | basename }}" + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "640" + when: es_ssl_upload and es_ssl_keystore and es_ssl_truststore + notify: restart elasticsearch + register: copy_keystore + +- name: Upload SSL/TLS truststore + become: yes + copy: + src: "{{ es_ssl_truststore }}" + dest: "{{ es_ssl_certificate_path }}/{{ es_ssl_truststore | basename }}" + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "640" + when: es_ssl_upload and es_ssl_keystore and es_ssl_truststore + notify: restart elasticsearch + register: copy_truststore + +- name: Upload SSL/TLS key and certificate + become: yes + copy: + src: "{{ item }}" + dest: "{{ es_ssl_certificate_path }}/{{ item | basename }}" + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "640" + with_items: + - "{{ es_ssl_key }}" + - "{{ es_ssl_certificate }}" + when: es_ssl_upload and es_ssl_key and es_ssl_certificate + #Restart if these change + notify: restart elasticsearch + register: copy_certificates + +- name: Upload SSL Certificate Authority + become: yes + copy: + src: "{{ es_ssl_certificate_authority }}" + dest: "{{ es_ssl_certificate_path }}/{{ es_ssl_certificate_authority | basename }}" + owner: "{{ es_user }}" + group: "{{ es_group }}" + mode: "640" + #Restart if this changes + notify: restart elasticsearch + when: es_ssl_upload and (es_ssl_certificate_authority is defined) and (es_ssl_certificate_authority|length > 0) + +- name: Set keystore password + become: yes + shell: echo "{{ es_ssl_keystore_password }}" | {{ es_home }}/bin/elasticsearch-keystore add -x -f 'xpack.security.{{ item }}.ssl.keystore.secure_password' + no_log: True + when: es_ssl_keystore_password and (copy_keystore.changed or (es_same_keystore and copy_truststore.changed)) + with_items: + - http + - transport + +- name: Set truststore password + become: yes + shell: echo "{{ es_ssl_truststore_password }}" | {{ es_home }}/bin/elasticsearch-keystore add -x -f 'xpack.security.{{ item }}.ssl.truststore.secure_password' + no_log: True + when: es_ssl_truststore_password and (copy_truststore.changed or (es_same_keystore and copy_keystore.changed)) + with_items: + - http + - transport + +- name: Remove keystore password + become: yes + shell: "{{ es_home }}/bin/elasticsearch-keystore remove 'xpack.security.{{ item }}.ssl.keystore.secure_password'" + when: es_ssl_keystore_password == "" and (copy_keystore.changed or (es_same_keystore and copy_truststore.changed)) + ignore_errors: yes + with_items: + - http + - transport + +- name: Remove truststore password + become: yes + shell: "{{ es_home }}/bin/elasticsearch-keystore remove 'xpack.security.{{ item }}.ssl.truststore.secure_password'" + when: es_ssl_truststore_password == "" and (copy_truststore.changed or (es_same_keystore and copy_keystore.changed)) + ignore_errors: yes + with_items: + - http + - transport + +- name: Set key password + become: yes + shell: echo "{{ es_ssl_key_password }}" | {{ es_home }}/bin/elasticsearch-keystore add -x -f 'xpack.security.{{ item }}.ssl.secure_key_passphrase' + no_log: True + when: es_ssl_key_password and copy_certificates.changed + with_items: + - http + - transport + +- name: Remove key password + become: yes + shell: "{{ es_home }}/bin/elasticsearch-keystore remove 'xpack.security.{{ item }}.ssl.secure_key_passphrase'" + when: es_ssl_key_password == "" and copy_certificates.changed + ignore_errors: yes + with_items: + - http + - transport diff --git a/ansible/roles/es7/tasks/elasticsearch-template.yml b/ansible/roles/es7/tasks/elasticsearch-template.yml new file mode 100644 index 0000000000000000000000000000000000000000..e766932491a62a97796c2048e6ea520a1c7c8b84 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch-template.yml @@ -0,0 +1,31 @@ +--- + +- name: ensure templates dir is created + file: + path: "{{ es_conf_dir }}/templates" + state: directory + owner: root + group: "{{ es_group }}" + mode: "2750" + +- name: Copy templates to elasticsearch + copy: src={{ item }} dest={{ es_conf_dir }}/templates owner=root group={{ es_group }} mode=0660 + register: load_templates + with_fileglob: + - "{{ es_templates_fileglob | default('') }}" + +- name: Install templates + uri: + url: "{{ es_api_uri }}/_template/{{item | filename}}" + method: PUT + status_code: 200 + user: "{{es_api_basic_auth_username | default(omit)}}" + password: "{{es_api_basic_auth_password | default(omit)}}" + force_basic_auth: yes + body_format: json + body: "{{ lookup('file', item) }}" + validate_certs: "{{ es_validate_certs }}" + when: load_templates.changed and es_start_service + with_fileglob: + - "{{ es_templates_fileglob | default('') }}" + run_once: True diff --git a/ansible/roles/es7/tasks/elasticsearch.yml b/ansible/roles/es7/tasks/elasticsearch.yml new file mode 100644 index 0000000000000000000000000000000000000000..05fd93bc4d9ea7fcfa449ba342be6b2891a320a6 --- /dev/null +++ b/ansible/roles/es7/tasks/elasticsearch.yml @@ -0,0 +1,9 @@ +--- + +- name: Include specific Elasticsearch + include: elasticsearch-Debian.yml + when: ansible_os_family == 'Debian' + +- name: Include specific Elasticsearch + include: elasticsearch-RedHat.yml + when: ansible_os_family == 'RedHat' diff --git a/ansible/roles/es7/tasks/java.yml b/ansible/roles/es7/tasks/java.yml new file mode 100644 index 0000000000000000000000000000000000000000..649d424f58e9d7f66b68b1ab63a1221928817363 --- /dev/null +++ b/ansible/roles/es7/tasks/java.yml @@ -0,0 +1,54 @@ +--- + +- name: set fact java_state to present + set_fact: java_state="present" + +- name: set fact java_state to latest + set_fact: java_state="latest" + when: update_java == true + +- name: RedHat - Ensure Java is installed + become: yes + yum: name={{ java }} state={{java_state}} + when: ansible_os_family == 'RedHat' + +- name: Get the installed java path + shell: "update-alternatives --display java | grep '^/' | awk '{print $1}' | grep 1.8.0-openjdk | head -1" + become: yes + register: java_full_path + failed_when: False + changed_when: False + check_mode: no + when: ansible_os_family == 'RedHat' + +- name: correct java version selected + alternatives: + name: java + path: "{{ java_full_path.stdout }}" + link: /usr/bin/java + when: ansible_os_family == 'RedHat' and java_full_path is defined + +- name: Refresh java repo + become: yes + apt: update_cache=yes + changed_when: false + when: ansible_os_family == 'Debian' + +- name: Debian - Ensure Java is installed + become: yes + apt: name={{ java }} state={{java_state}} + when: ansible_os_family == 'Debian' + +- name: register open_jdk version + shell: java -version 2>&1 | grep OpenJDK + register: open_jdk + ignore_errors: yes + changed_when: false + check_mode: no + +#https://github.com/docker-library/openjdk/issues/19 - ensures tests pass due to java 8 broken certs +- name: refresh the java ca-certificates + become: yes + command: /var/lib/dpkg/info/ca-certificates-java.postinst configure + when: ansible_distribution == 'Ubuntu' and open_jdk.rc == 0 + changed_when: false diff --git a/ansible/roles/es7/tasks/main.yml b/ansible/roles/es7/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..f4cda41773d00f24638bed9df7c9bedfa7aa5a6e --- /dev/null +++ b/ansible/roles/es7/tasks/main.yml @@ -0,0 +1,128 @@ +--- + +- set_fact: "es_major_version={{ es_version.split('.')[0] }}.x" + when: + - es_major_version is undefined + tags: + - always + +- name: os-specific vars + include_vars: "{{ansible_os_family}}.yml" + tags: + - always + +- name: set compatibility variables + include: compatibility-variables.yml + tags: + - always + +- name: check-set-parameters + include: elasticsearch-parameters.yml + tags: + - always + +- name: use snapshot release + include: snapshot-release.yml + when: es_use_snapshot_release + +- name: include java.yml + include: java.yml + when: es_java_install + tags: + - java + +- name: include elasticsearch.yml + include: elasticsearch.yml + tags: + - install + +- name: include elasticsearch-config.yml + include: elasticsearch-config.yml + tags: + - config + +- name: include elasticsearch-plugins.yml + include: elasticsearch-plugins.yml + when: es_plugins is defined or es_plugins_reinstall + tags: + - plugins + +# Install Elasticsearch plugin for backups +- name: include elasticsearch plugin install + include: azure-plugin.yml + +# Add ES Plugin credentials for backups +- name: Add ES Backup variables to elasticsearch to have backups enabled + lineinfile: + path: '{{ es_conf_dir }}/elasticsearch.yml' + line: 'cloud.azure.storage.default.{{item.key}}: {{item.value}}' + regexp: "cloud.azure.storage.default.{{ item.key }}.*" + with_items: + - {key: 'account', value: '{{ sunbird_management_storage_account_name }}'} + - {key: 'key', value: '{{ sunbird_management_storage_account_key }}'} + when: sunbird_management_storage_account_name is defined and sunbird_management_storage_account_key is defined + notify: restart elasticsearch + + + #We always execute xpack as we may need to remove features +- name: include xpack/elasticsearch-xpack.yml + include: xpack/elasticsearch-xpack.yml + tags: + - xpack + +- name: include elasticsearch-ssl.yml + include: elasticsearch-ssl.yml + when: es_enable_http_ssl or es_enable_transport_ssl + tags: + - xpack + +- name: flush handlers + meta: flush_handlers + +- name: Make sure elasticsearch is started + become: yes + service: name=elasticsearch state=started enabled=yes + when: es_start_service + +- name: Wait for elasticsearch to startup + wait_for: host={{ es_api_host }} port={{ es_api_port }} delay=5 connect_timeout=1 + when: es_restarted is defined and es_restarted.changed and es_start_service + +- name: set fact manage_native_realm to false + set_fact: manage_native_realm=false + +- name: set fact manage_native_realm to true + set_fact: manage_native_realm=true + when: + - es_start_service + - not oss_version + - (es_users is defined and es_users.native is defined) or (es_roles is defined and es_roles.native is defined) + +# If playbook runs too fast, Native commands could fail as the Native Realm is not yet up +- name: Wait {{ es_api_sleep }} seconds for the Native Realm to come up + command: "sleep {{ es_api_sleep }}" + when: manage_native_realm | bool + +- name: activate-license + include: ./xpack/security/elasticsearch-xpack-activation.yml + when: es_start_service and not oss_version and es_xpack_license is defined and es_xpack_license != '' + run_once: True + +- name: activate-trial + include: ./xpack/security/elasticsearch-xpack-trial-activation.yml + when: es_start_service and not oss_version and es_xpack_trial + run_once: True + +#perform security actions here now elasticsearch is started +- name: include xpack/security/elasticsearch-security-native.yml + include: ./xpack/security/elasticsearch-security-native.yml + when: manage_native_realm | bool + run_once: True + +#Templates done after restart - handled by flushing the handlers. e.g. suppose user removes security on a running node and doesn't specify es_api_basic_auth_username and es_api_basic_auth_password. The templates will subsequently not be removed if we don't wait for the node to restart. +#We also do after the native realm to ensure any changes are applied here first and its denf up. +- name: include elasticsearch-template.yml + include: elasticsearch-template.yml + when: es_templates | bool + tags: + - templates diff --git a/ansible/roles/es7/tasks/snapshot-release.yml b/ansible/roles/es7/tasks/snapshot-release.yml new file mode 100644 index 0000000000000000000000000000000000000000..c86eed82091d38e0ff714ffa69723757500eb7ee --- /dev/null +++ b/ansible/roles/es7/tasks/snapshot-release.yml @@ -0,0 +1,55 @@ +# These tasks are to run ansible-elasticsearch using pre-release snapshot builds +# This should only be used for testing purposes and can be enabled by setting +# es_use_snapshot_release: true + +- name: detect if we need the .deb or .rpm + set_fact: + package_type: "{{ 'deb' if (ansible_os_family == 'Debian') else 'rpm' }}" + +- name: get the minor version + set_fact: + minor_version: "{{ es_version.split('.')[0:2] | join('.')}}" + +- name: set the package_name + set_fact: + package_name: "{{ es_package_name + '-' + es_version + '-SNAPSHOT.' + package_type }}" + +- name: generate the artifacts url + set_fact: + artifacts_url: "{{ 'https://artifacts-api.elastic.co/v1/search/' + minor_version + '/' + package_name }}" + +- name: get latest snapshot build + uri: + url: "{{ artifacts_url }}" + return_contents: true + register: snapshots + retries: 5 + delay: 1 + ignore_errors: true + until: "'status' in snapshots and snapshots.status == 200" + check_mode: no + +- name: use the custom package url instead of the repository + set_fact: + es_custom_package_url: "{{ snapshots.json['packages'][package_name]['url'] }}" + es_use_repository: false + +- name: set snapshot urls for es_plugins when it is defined + when: es_plugins is defined + block: + - name: split up the snapshot url so we can create the plugin url + set_fact: + split_url: "{{ es_custom_package_url.split('/') }}" + + - name: set base plugin url + set_fact: + plugin_url: "{{ split_url[0] + '//' + split_url[2:5]|join('/') + '/elasticsearch-plugins/'}}" + + - name: create es_plugins with the snapshot url + set_fact: + es_plugins_temp: "{{ es_plugins_temp|default([]) + [{'plugin': item.plugin, 'url': plugin_url + item.plugin + '/' + item.plugin + '-' + es_version + '-SNAPSHOT.zip'}] }}" + with_items: "{{ es_plugins }}" + + - name: override the original es_plugins with the snapshot version + set_fact: + es_plugins: "{{ es_plugins_temp }}" diff --git a/ansible/roles/es7/tasks/xpack/elasticsearch-xpack.yml b/ansible/roles/es7/tasks/xpack/elasticsearch-xpack.yml new file mode 100644 index 0000000000000000000000000000000000000000..9b494083088398ee468b4335741ce9f93f62051b --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/elasticsearch-xpack.yml @@ -0,0 +1,16 @@ +--- + +#Security configuration +- name: include security/elasticsearch-security.yml + include: security/elasticsearch-security.yml + when: not oss_version + +#Make sure elasticsearch.keystore has correct Permissions +- name: Set elasticsearch.keystore Permissions + become: yes + file: + state: file + path: "{{ es_conf_dir }}/elasticsearch.keystore" + owner: root + group: "{{ es_group }}" + mode: "0660" diff --git a/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-file.yml b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-file.yml new file mode 100644 index 0000000000000000000000000000000000000000..b169b9ee23078b4fa5e71981c0877b9186817fdf --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-file.yml @@ -0,0 +1,110 @@ +--- +- set_fact: manage_file_users=false + +- set_fact: manage_file_users=true + when: es_users is defined and es_users.file is defined and es_users.file.keys() | list | length > 0 + +# Users migration from elasticsearch < 6.3 versions +- name: Check if old users file exists + become: yes + stat: + path: '{{ es_conf_dir }}/x-pack/users' + register: old_users_file + check_mode: no + +- name: Copy the old users file from the old deprecated location + become: yes + copy: + remote_src: yes + force: no # only copy it if the new path doesn't exist yet + src: "{{ es_conf_dir }}/x-pack/users" + dest: "{{ es_conf_dir }}/users" + group: "{{ es_group }}" + owner: root + when: old_users_file.stat.exists +# End of users migrations + +#List current users +- name: List Users + become: yes + shell: cat {{ es_conf_dir }}/users | awk -F':' '{print $1}' + register: current_file_users + when: manage_file_users + changed_when: False + check_mode: no + +- name: set fact users_to_remove + set_fact: users_to_remove={{ current_file_users.stdout_lines | difference (es_users.file.keys() | list) }} + when: manage_file_users and es_delete_unmanaged_file + +#Remove users +- name: Remove Users + become: yes + command: > + {{es_home}}/bin/elasticsearch-users userdel {{item}} + with_items: "{{users_to_remove | default([])}}" + when: manage_file_users + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_HOME: "{{es_home}}" + +- name: set fact users_to_add + set_fact: users_to_add={{ es_users.file.keys() | list | difference (current_file_users.stdout_lines) }} + when: manage_file_users and es_delete_unmanaged_file + +#Add users +- name: Add Users + become: yes + command: > + {{es_home}}/bin/elasticsearch-users useradd {{item}} -p {{es_users.file[item].password}} + with_items: "{{ users_to_add | default([]) }}" + when: manage_file_users + no_log: True + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_HOME: "{{es_home}}" + +#Set passwords for all users declared - Required as the useradd will not change existing user passwords +- name: Set User Passwords + become: yes + command: > + {{es_home}}/bin/elasticsearch-users passwd {{ item }} -p {{es_users.file[item].password}} + with_items: "{{ es_users.file.keys() | list }}" + when: manage_file_users + #Currently no easy way to figure out if the password has changed or to know what it currently is so we can skip. + changed_when: False + no_log: True + environment: + CONF_DIR: "{{ es_conf_dir }}" + ES_PATH_CONF: "{{ es_conf_dir }}" + ES_HOME: "{{es_home}}" + +- name: set fact users_roles + set_fact: users_roles={{es_users.file | extract_role_users () }} + when: manage_file_users + +#Copy Roles files +- name: Copy roles.yml File for Instance + become: yes + template: + src: security/roles.yml.j2 + dest: "{{ es_conf_dir }}/roles.yml" + owner: root + group: "{{ es_group }}" + mode: "0660" + force: yes + when: es_roles is defined and es_roles.file is defined + +#Overwrite users_roles file +- name: Copy User Roles + become: yes + template: + src: security/users_roles.j2 + dest: "{{ es_conf_dir }}/users_roles" + owner: root + group: "{{ es_group }}" + mode: "0660" + force: yes + when: manage_file_users and users_roles | length > 0 diff --git a/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-native.yml b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-native.yml new file mode 100644 index 0000000000000000000000000000000000000000..f850264099215d52fe38936faa9e4e9a9cf2ee81 --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security-native.yml @@ -0,0 +1,200 @@ +--- +- name: set fact change_api_password to false + set_fact: change_api_password=false + +- name: set fact manage_native_users to false + set_fact: manage_native_users=false + +- name: set fact manage_native_users to true + set_fact: manage_native_users=true + when: es_users is defined and es_users.native is defined and es_users.native.keys() | list | length > 0 + +- name: set fact manage_native_role to false + set_fact: manage_native_roles=false + +- name: set fact manage_native_roles to true + set_fact: manage_native_roles=true + when: es_roles is defined and es_roles.native is defined and es_roles.native.keys() | list | length > 0 + +#If the node has just has security installed it maybe either stopped or started 1. if stopped, we need to start to load native realms 2. if started, we need to restart to load + +#List current users +- name: List Native Users + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/user" + method: GET + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + status_code: 200 + validate_certs: "{{ es_validate_certs }}" + register: user_list_response + when: manage_native_users + check_mode: no + +- name: set fact reserved_users equals user_list_response.json + set_fact: reserved_users={{ user_list_response.json | filter_reserved }} + when: manage_native_users + +#Current users not inc. those reserved +- name: set fact current_users equals user_list_response.json.keys not including reserved + set_fact: current_users={{ user_list_response.json.keys() | list | difference (reserved_users) }} + when: manage_native_users + +#We are changing the es_api_basic_auth_username password, so we need to do it first and update the param +- name: set fact native_users + set_fact: native_users={{ es_users.native }} + when: manage_native_users + +- name: set fact change_api_password to true + set_fact: change_api_password=true + when: manage_native_users and es_api_basic_auth_username in native_users and native_users[es_api_basic_auth_username].password is defined + +- name: Update API User Password + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/user/{{es_api_basic_auth_username}}/_password" + method: POST + body_format: json + body: "{ \"password\":\"{{native_users[es_api_basic_auth_username].password}}\" }" + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: change_api_password + +- name: set fact es_api_basic_auth_password + set_fact: es_api_basic_auth_password={{native_users[es_api_basic_auth_username].password}} + when: change_api_password + +#Identify users that are present in ES but not declared and thus should be removed +- name: set fact users_to_remove + set_fact: users_to_remove={{ current_users | difference ( native_users.keys() | list) }} + when: manage_native_users + +#Delete all non required users NOT inc. reserved +- name: Delete Native Users + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/user/{{item}}" + method: DELETE + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: manage_native_users and es_delete_unmanaged_native + with_items: "{{ users_to_remove | default([]) }}" + +- name: set fact users_to_ignore + set_fact: users_to_ignore={{ native_users.keys() | list | intersect (reserved_users) }} + when: manage_native_users + +- name: debug message + debug: + msg: "WARNING: YOU CAN ONLY CHANGE THE PASSWORD FOR RESERVED USERS IN THE NATIVE REALM. ANY ROLE CHANGES WILL BE IGNORED: {{users_to_ignore}}" + when: manage_native_users and users_to_ignore | length > 0 + +#Update password on all reserved users +- name: Update Reserved User Passwords + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/user/{{ item | urlencode }}/_password" + method: POST + body_format: json + body: "{ \"password\":\"{{native_users[item].password}}\" }" + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: native_users[item].password is defined + no_log: True + with_items: "{{ users_to_ignore | default([]) }}" + +- name: set fact users_to_modify + set_fact: users_to_modify={{ native_users.keys() | list | difference (reserved_users) }} + when: manage_native_users + +#Overwrite all other users NOT inc. those reserved +- name: Update Non-Reserved Native User Details + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/user/{{ item | urlencode }}" + method: POST + body_format: json + body: "{{ native_users[item] | to_json }}" + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: manage_native_users + no_log: True + with_items: "{{ users_to_modify | default([]) }}" + +## ROLE CHANGES + +#List current roles not. inc those reserved +- name: List Native Roles + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/role" + method: GET + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + status_code: 200 + validate_certs: "{{ es_validate_certs }}" + register: role_list_response + when: manage_native_roles + check_mode: no + +- name: set fact reserved roles + set_fact: reserved_roles={{ role_list_response.json | filter_reserved }} + when: manage_native_roles + +- name: set fact current roles + set_fact: current_roles={{ role_list_response.json.keys() | list | difference (reserved_roles) }} + when: manage_native_roles + +- name: set fact roles to ignore + set_fact: roles_to_ignore={{ es_roles.native.keys() | list | intersect (reserved_roles) | default([]) }} + when: manage_native_roles + +- name: debug message + debug: + msg: "WARNING: YOU CANNOT CHANGE RESERVED ROLES. THE FOLLOWING WILL BE IGNORED: {{roles_to_ignore}}" + when: manage_native_roles and roles_to_ignore | length > 0 + +- name: set fact roles_to_remove + set_fact: roles_to_remove={{ current_roles | difference ( es_roles.native.keys() | list) }} + when: manage_native_roles + +#Delete all non required roles NOT inc. reserved +- name: Delete Native Roles + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/role/{{ item | urlencode }}" + method: DELETE + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: manage_native_roles and es_delete_unmanaged_native + with_items: "{{roles_to_remove | default([]) }}" + +- name: set fact roles_to_modify + set_fact: roles_to_modify={{ es_roles.native.keys() | list | difference (reserved_roles) }} + when: manage_native_roles + +#Update other roles - NOT inc. reserved roles +- name: Update Native Roles + uri: + url: "{{ es_api_uri }}/{{ es_security_api }}/role/{{ item | urlencode }}" + method: POST + body_format: json + body: "{{ es_roles.native[item] | to_json}}" + status_code: 200 + user: "{{es_api_basic_auth_username}}" + password: "{{es_api_basic_auth_password}}" + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + when: manage_native_roles + with_items: "{{ roles_to_modify | default([]) }}" diff --git a/ansible/roles/es7/tasks/xpack/security/elasticsearch-security.yml b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security.yml new file mode 100644 index 0000000000000000000000000000000000000000..febecfe471b6550a09cbe452a54119515cbc04de --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/security/elasticsearch-security.yml @@ -0,0 +1,91 @@ +--- +#Security specific configuration done here + +#TODO: 1. Skip users with no password defined or error 2. Passwords | length > 6 + +#-----------------------------Create Bootstrap User----------------------------------- +### START BLOCK elasticsearch keystore ### +- name: create the elasticsearch keystore + block: + - name: create the keystore if it doesn't exist yet + become: yes + command: > + {{es_home}}/bin/elasticsearch-keystore create + args: + creates: "{{ es_conf_dir }}/elasticsearch.keystore" + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + + - name: Check if bootstrap password is set + become: yes + command: > + {{es_home}}/bin/elasticsearch-keystore list + register: list_keystore + changed_when: False + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + check_mode: no + + - name: Create Bootstrap password for elastic user + become: yes + shell: echo {{ es_api_basic_auth_password | quote }} | {{ es_home }}/bin/elasticsearch-keystore add -x 'bootstrap.password' + when: + - es_api_basic_auth_username is defined and list_keystore is defined and es_api_basic_auth_username == 'elastic' and 'bootstrap.password' not in list_keystore.stdout_lines + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + no_log: true + + - name: Remove keystore entries + become: yes + command: > + echo {{ es_api_basic_auth_password | quote }} | {{ es_home }}/bin/elasticsearch-keystore remove '{{ item.key }}' + with_items: "{{ es_keystore_entries }}" + when: + - es_keystore_entries is defined and es_keystore_entries | length > 0 + - item.state is defined and item.state == 'absent' + - item.key in list_keystore.stdout_lines + - ('bootstrap.password' not in item.key) + no_log: true + + - name: Reload keystore entries + become: yes + command: > + {{es_home}}/bin/elasticsearch-keystore list + register: list_keystore + changed_when: False + environment: + ES_PATH_CONF: "{{ es_conf_dir }}" + check_mode: no + + - name: Add keystore entries + become: yes + shell: echo {{ item.value | quote }} | {{ es_home }}/bin/elasticsearch-keystore add -x -f {{ item.key }} + with_items: "{{ es_keystore_entries }}" + when: + - es_keystore_entries is defined and es_keystore_entries | length > 0 + - item.state is undefined or item.state == 'present' + - item.force|default(False) or ( not item.force|default(False) and item.key not in list_keystore.stdout_lines ) + - ('bootstrap.password' not in item.key) + no_log: true + + +### END BLOCK elasticsearch keystore ### + +#-----------------------------FILE BASED REALM---------------------------------------- + +- include: elasticsearch-security-file.yml + when: (es_users is defined and es_users.file is defined) or (es_roles is defined and es_roles.file is defined) + +#-----------------------------ROLE MAPPING ---------------------------------------- + +#Copy Roles files +- name: Copy role_mapping.yml file for instance + become: yes + template: + src: security/role_mapping.yml.j2 + dest: "{{ es_conf_dir }}/role_mapping.yml" + owner: root + group: "{{ es_group }}" + mode: "0660" + force: yes + when: es_role_mapping is defined diff --git a/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-activation.yml b/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-activation.yml new file mode 100644 index 0000000000000000000000000000000000000000..5bf08cb6a244a75dddcd0c98a42b1ebd5ffde24f --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-activation.yml @@ -0,0 +1,21 @@ +--- +- name: Activate ES license (with security authentication) + uri: + method: PUT + url: "{{ es_api_uri }}/{{ es_license_api }}?acknowledge=true" + user: "{{es_api_basic_auth_username | default(omit)}}" + password: "{{es_api_basic_auth_password | default(omit)}}" + body_format: json + body: "{{ es_xpack_license }}" + return_content: yes + force_basic_auth: yes + validate_certs: "{{ es_validate_certs }}" + register: license_activated + no_log: True + failed_when: > + license_activated.status != 200 or + license_activated.json.license_status is not defined or + license_activated.json.license_status != 'valid' + +- name: License + debug: msg={{ license_activated }} diff --git a/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-trial-activation.yml b/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-trial-activation.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0cc73e09e372b4b0d045272b24b3cc49bd6f9ac --- /dev/null +++ b/ansible/roles/es7/tasks/xpack/security/elasticsearch-xpack-trial-activation.yml @@ -0,0 +1,18 @@ +--- +- name: Activate ES trial license (with security authentication) + uri: + method: POST + url: "{{ es_api_uri }}/{{ es_license_api }}/start_trial?acknowledge=true" + user: "{{es_api_basic_auth_username | default(omit)}}" + password: "{{es_api_basic_auth_password | default(omit)}}" + return_content: yes + force_basic_auth: yes + status_code: + - 200 + - 403 + validate_certs: "{{ es_validate_certs }}" + register: trial_license_activated + when: es_xpack_trial + +- name: Trial license + debug: msg={{ trial_license_activated }} \ No newline at end of file diff --git a/ansible/roles/es7/templates/elasticsearch.j2 b/ansible/roles/es7/templates/elasticsearch.j2 new file mode 100644 index 0000000000000000000000000000000000000000..367bf9505d63ce779dfebb2a5bb57440985c1cd4 --- /dev/null +++ b/ansible/roles/es7/templates/elasticsearch.j2 @@ -0,0 +1,67 @@ +################################ +# Elasticsearch +################################ + +# Elasticsearch home directory +ES_HOME={{es_home}} + +# Elasticsearch temp directory +ES_TMPDIR={{ es_tmp_dir }} + +# Elasticsearch Java path +{% if es_java_home | length > 0 %} +JAVA_HOME={{ es_java_home }} +{% else %} +#JAVA_HOME= +{% endif %} + +# Elasticsearch configuration directory +ES_PATH_CONF={{ es_conf_dir }} + +# Elasticsearch PID directory +PID_DIR={{ es_pid_dir }} + +# Additional Java OPTS +ES_JAVA_OPTS="{% if es_proxy_host is defined and es_proxy_host != '' %}-Dhttp.proxyHost={{ es_proxy_host }} -Dhttp.proxyPort={{ es_proxy_port }} -Dhttps.proxyHost={{ es_proxy_host }} -Dhttps.proxyPort={{ es_proxy_port }}{% endif %}" + +# Configure restart on package upgrade (true, every other setting will lead to not restarting) +#RESTART_ON_UPGRADE=true + +################################ +# Elasticsearch service +################################ + +# SysV init.d +# +# The number of seconds to wait before checking if Elasticsearch started successfully as a daemon process +ES_STARTUP_SLEEP_TIME=5 + +################################ +# System properties +################################ + +# Specifies the maximum file descriptor number that can be opened by this process +# When using Systemd, this setting is ignored and the LimitNOFILE defined in +# /usr/lib/systemd/system/elasticsearch.service takes precedence +#MAX_OPEN_FILES=65535 +{% if es_max_open_files is defined %} +MAX_OPEN_FILES={{es_max_open_files}} +{% endif %} + +# The maximum number of bytes of memory that may be locked into RAM +# Set to "unlimited" if you use the 'bootstrap.memory_lock: true' option +# in elasticsearch.yml. +# When using systemd, LimitMEMLOCK must be set in a unit file such as +# /etc/systemd/system/elasticsearch.service.d/override.conf. +#MAX_LOCKED_MEMORY=unlimited +{% if m_lock_enabled %} +MAX_LOCKED_MEMORY=unlimited +{% endif %} + +# Maximum number of VMA (Virtual Memory Areas) a process can own +# When using Systemd, this setting is ignored and the 'vm.max_map_count' +# property is set at boot time in /usr/lib/sysctl.d/elasticsearch.conf +#MAX_MAP_COUNT=262144 +{% if es_max_map_count is defined %} +MAX_MAP_COUNT={{es_max_map_count}} +{% endif %} diff --git a/ansible/roles/es7/templates/elasticsearch.repo b/ansible/roles/es7/templates/elasticsearch.repo new file mode 100644 index 0000000000000000000000000000000000000000..0cf2fb77cdbc32808914f8facd9cd3beb795801d --- /dev/null +++ b/ansible/roles/es7/templates/elasticsearch.repo @@ -0,0 +1,11 @@ +[elasticsearch-{{ es_repo_name }}] +name=Elasticsearch repository for {{ es_repo_name }} packages +baseurl={{ es_repo_base }}/packages/{{ es_repo_name }}/yum +gpgcheck=1 +gpgkey={{ es_repo_base }}/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md +{% if es_proxy_host is defined and es_proxy_host != '' and es_proxy_port is defined %} +proxy=http://{{ es_proxy_host }}:{{es_proxy_port}} +{% endif %} diff --git a/ansible/roles/es7/templates/elasticsearch.yml.j2 b/ansible/roles/es7/templates/elasticsearch.yml.j2 new file mode 100644 index 0000000000000000000000000000000000000000..10986688833fa01989520d27af0c17b5ce6a18bf --- /dev/null +++ b/ansible/roles/es7/templates/elasticsearch.yml.j2 @@ -0,0 +1,82 @@ + +{% if es_config %} +{{ es_config | to_nice_yaml(indent=2) }} +{% endif %} + +{% if es_config['cluster.name'] is not defined %} +cluster.name: elasticsearch +{% endif %} + +{% if es_config['node.name'] is not defined %} +node.name: {{inventory_hostname}} +{% endif %} + +#################################### Paths #################################### + +# Path to directory containing configuration (this file and logging.yml): + +path.data: {{ es_data_dirs | array_to_str }} + +path.logs: {{ es_log_dir }} + +{% if es_path_repo is defined %} +path.repo: {{ es_path_repo }} +{% endif %} + +{% if es_action_auto_create_index == true %} +action.auto_create_index: true +{% elif not es_action_auto_create_index %} +action.auto_create_index: false +{% else %} +action.auto_create_index: {{ es_action_auto_create_index }} +{% endif %} + +{% if not oss_version and es_api_basic_auth_username is defined and es_api_basic_auth_password is defined %} +xpack.security.enabled: true + +{% if es_enable_transport_ssl and es_enable_auto_ssl_configuration %} +xpack.security.transport.ssl.enabled: true +xpack.security.transport.ssl.verification_mode: "{{ es_ssl_verification_mode }}" +{% if es_ssl_keystore and es_ssl_truststore %} +xpack.security.transport.ssl.keystore.path: "{{ es_ssl_certificate_path }}/{{ es_ssl_keystore | basename }}" +xpack.security.transport.ssl.truststore.path: "{{ es_ssl_certificate_path }}/{{ es_ssl_truststore | basename }}" +{% elif es_ssl_key and es_ssl_certificate %} +xpack.security.transport.ssl.key: "{{ es_ssl_certificate_path }}/{{ es_ssl_key | basename }}" +xpack.security.transport.ssl.certificate: "{{ es_ssl_certificate_path }}/{{ es_ssl_certificate | basename }}" +{% if es_ssl_certificate_authority %} +xpack.security.transport.ssl.certificate_authorities: "{{ es_ssl_certificate_path }}/{{ es_ssl_certificate_authority | basename }}" +{% endif %} +{% endif %} +{% endif %} + +{% if es_enable_http_ssl and es_enable_auto_ssl_configuration %} +xpack.security.http.ssl.enabled: true +{% if es_ssl_keystore and es_ssl_truststore %} +xpack.security.http.ssl.keystore.path: "{{ es_ssl_certificate_path }}/{{ es_ssl_keystore | basename }}" +xpack.security.http.ssl.truststore.path: "{{ es_ssl_certificate_path }}/{{ es_ssl_truststore | basename }}" +{% elif es_ssl_key and es_ssl_certificate %} +xpack.security.http.ssl.key: "{{ es_ssl_certificate_path }}/{{ es_ssl_key | basename }}" +xpack.security.http.ssl.certificate: "{{ es_ssl_certificate_path }}/{{ es_ssl_certificate | basename }}" +{% if es_ssl_certificate_authority %} +xpack.security.http.ssl.certificate_authorities: "{{ es_ssl_certificate_path }}/{{ es_ssl_certificate_authority | basename }}" +{% endif %} +{% endif %} +{% endif %} +{% endif %} + +{% if es_mail_config is defined %} +xpack.notification.email: + account: + {{ es_mail_config['account'] }}: + profile: {{ es_mail_config['profile'] }} + email_defaults: + from: {{ es_mail_config['from'] }} + smtp: + auth: {{ es_mail_config['require_auth'] }} + host: {{ es_mail_config['host'] }} + port: {{ es_mail_config['port'] }} + {% if es_mail_config['require_auth'] == true -%} + user: {{ es_mail_config['user'] }} + password: {{ es_mail_config['pass'] }} + {%- endif %} +{% endif %} diff --git a/ansible/roles/es7/templates/jvm.options.j2 b/ansible/roles/es7/templates/jvm.options.j2 new file mode 100644 index 0000000000000000000000000000000000000000..3acf39883bc57da8c48ef902832db785dfefa811 --- /dev/null +++ b/ansible/roles/es7/templates/jvm.options.j2 @@ -0,0 +1,163 @@ +## JVM configuration + +################################################################ +## IMPORTANT: JVM heap size +################################################################ +## +## You should always set the min and max JVM heap +## size to the same value. For example, to set +## the heap to 4 GB, set: +## +## -Xms4g +## -Xmx4g +## +## See https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html +## for more information +## +################################################################ + +# Xms represents the initial size of total heap space +# Xmx represents the maximum size of total heap space +{% if es_heap_size is defined %} +-Xms{{ es_heap_size }} +-Xmx{{ es_heap_size }} +{% else %} +-Xms2g +-Xmx2g +{% endif %} + +################################################################ +## Expert settings +################################################################ +## +## All settings below this section are considered +## expert settings. Don't tamper with them unless +## you understand what you are doing +## +################################################################ + +## GC configuration +{% if es_version is version('7.6.0', '<') %} +-XX:+UseConcMarkSweepGC +-XX:CMSInitiatingOccupancyFraction=75 +-XX:+UseCMSInitiatingOccupancyOnly +{% else %} +8-13:-XX:+UseConcMarkSweepGC +8-13:-XX:CMSInitiatingOccupancyFraction=75 +8-13:-XX:+UseCMSInitiatingOccupancyOnly +{% endif %} + +## G1GC Configuration +# NOTE: G1 GC is only supported on JDK version 10 or later +{% if es_version is version('7.6.0', '<') %} +# To use G1GC uncomment the lines below. +# 10-:-XX:-UseConcMarkSweepGC +# 10-:-XX:-UseCMSInitiatingOccupancyOnly +# 10-:-XX:+UseG1GC +{% if es_version is version('7.4.0', '<') %} +# 10-:-XX:InitiatingHeapOccupancyPercent=75 +{% else %} +# 10-:-XX:G1ReservePercent=25 +# 10-:-XX:InitiatingHeapOccupancyPercent=30 +{% endif %} +{% else %} +# to use G1GC, uncomment the next two lines and update the version on the +# following three lines to your version of the JDK +# 10-13:-XX:-UseConcMarkSweepGC +# 10-13:-XX:-UseCMSInitiatingOccupancyOnly +14-:-XX:+UseG1GC +14-:-XX:G1ReservePercent=25 +14-:-XX:InitiatingHeapOccupancyPercent=30 +{% endif %} + +{% if es_version is version('7.5.0', '<') %} +## DNS cache policy +# cache ttl in seconds for positive DNS lookups noting that this overrides the +# JDK security property networkaddress.cache.ttl; set to -1 to cache forever +-Des.networkaddress.cache.ttl=60 +# cache ttl in seconds for negative DNS lookups noting that this overrides the +# JDK security property networkaddress.cache.negative ttl; set to -1 to cache +# forever +-Des.networkaddress.cache.negative.ttl=10 + +## optimizations + +# pre-touch memory pages used by the JVM during initialization +-XX:+AlwaysPreTouch + +## basic + +# explicitly set the stack size +-Xss1m + +# set to headless, just in case +-Djava.awt.headless=true + +# ensure UTF-8 encoding by default (e.g. filenames) +-Dfile.encoding=UTF-8 + +# use our provided JNA always versus the system one +-Djna.nosys=true + +# turn off a JDK optimization that throws away stack traces for common +# exceptions because stack traces are important for debugging +-XX:-OmitStackTraceInFastThrow + +# flags to configure Netty +-Dio.netty.noUnsafe=true +-Dio.netty.noKeySetOptimization=true +-Dio.netty.recycler.maxCapacityPerThread=0 +{% if es_version is version('7.4.0', '>=') %} +-Dio.netty.allocator.numDirectArenas=0 +{% endif %} + +# log4j 2 +-Dlog4j.shutdownHookEnabled=false +-Dlog4j2.disable.jmx=true +{% endif %} + +## JVM temporary directory +-Djava.io.tmpdir=${ES_TMPDIR} + +## heap dumps + +# generate a heap dump when an allocation from the Java heap fails +# heap dumps are created in the working directory of the JVM +-XX:+HeapDumpOnOutOfMemoryError + +# specify an alternative path for heap dumps; ensure the directory exists and +# has sufficient space +-XX:HeapDumpPath={{ es_heap_dump_path }} + +# specify an alternative path for JVM fatal error logs +-XX:ErrorFile={{ es_log_dir }}/hs_err_pid%p.log + +## JDK 8 GC logging + +8:-XX:+PrintGCDetails +8:-XX:+PrintGCDateStamps +8:-XX:+PrintTenuringDistribution +8:-XX:+PrintGCApplicationStoppedTime +8:-Xloggc:{{ es_log_dir }}/gc.log +8:-XX:+UseGCLogFileRotation +8:-XX:NumberOfGCLogFiles=32 +8:-XX:GCLogFileSize=64m + +# JDK 9+ GC logging +9-:-Xlog:gc*,gc+age=trace,safepoint:file={{ es_log_dir }}/gc.log:utctime,pid,tags:filecount=32,filesize=64m +{% if es_version is version('7.5.0', '<') %} +# due to internationalization enhancements in JDK 9 Elasticsearch need to set the provider to COMPAT otherwise +# time/date parsing will break in an incompatible way for some date patterns and locals +9-:-Djava.locale.providers=COMPAT + +{% if es_major_version == "6.x" %} +# temporary workaround for C2 bug with JDK 10 on hardware with AVX-512 +10-:-XX:UseAVX=2 +{% endif %} +{% endif %} + +{% if es_jvm_custom_parameters !='' %} +{% for item in es_jvm_custom_parameters %} +{{ item }} +{% endfor %} +{% endif %} diff --git a/ansible/roles/es7/templates/override.conf.j2 b/ansible/roles/es7/templates/override.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..38aab167da56aa6799a09cc32538952ede744347 --- /dev/null +++ b/ansible/roles/es7/templates/override.conf.j2 @@ -0,0 +1,7 @@ +[Service] +{% if m_lock_enabled %} +LimitMEMLOCK = infinity +{% endif %} +{% if es_max_open_files is defined %} +LimitNOFILE = {{ es_max_open_files }} +{% endif %} \ No newline at end of file diff --git a/ansible/roles/es7/templates/security/role_mapping.yml.j2 b/ansible/roles/es7/templates/security/role_mapping.yml.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a3af322a868cd225e1e4566419e6c29e03c7a132 --- /dev/null +++ b/ansible/roles/es7/templates/security/role_mapping.yml.j2 @@ -0,0 +1 @@ +{{ es_role_mapping | to_nice_yaml(indent=2) }} diff --git a/ansible/roles/es7/templates/security/roles.yml.j2 b/ansible/roles/es7/templates/security/roles.yml.j2 new file mode 100644 index 0000000000000000000000000000000000000000..149d458a61422a6238fecd6c1cb26d1cb9d84893 --- /dev/null +++ b/ansible/roles/es7/templates/security/roles.yml.j2 @@ -0,0 +1 @@ +{{ es_roles.file | to_nice_yaml(indent=2) }} diff --git a/ansible/roles/es7/templates/security/users_roles.j2 b/ansible/roles/es7/templates/security/users_roles.j2 new file mode 100644 index 0000000000000000000000000000000000000000..91574bdaacbff10751b5553994a8c28dd6cc413e --- /dev/null +++ b/ansible/roles/es7/templates/security/users_roles.j2 @@ -0,0 +1 @@ +{{ users_roles | join("\n") }} diff --git a/ansible/roles/es7/vars/Debian.yml b/ansible/roles/es7/vars/Debian.yml new file mode 100644 index 0000000000000000000000000000000000000000..69b6cd843c63b509ff6f8a4bf989846b33154904 --- /dev/null +++ b/ansible/roles/es7/vars/Debian.yml @@ -0,0 +1,6 @@ +--- +java_version: "{% if ansible_os_family == 'Debian' and ansible_distribution_major_version == '10' %}11{% else %}8{% endif %}" +java: "{% if es_java is defined %}{{es_java}}{% else %}openjdk-{{ java_version }}-jre-headless{% endif %}" +default_file: "/etc/default/elasticsearch" +es_home: "/usr/share/elasticsearch" +es_apt_key_id: "46095ACC8548582C1A2699A9D27D666CD88E42B4" diff --git a/ansible/roles/es7/vars/RedHat.yml b/ansible/roles/es7/vars/RedHat.yml new file mode 100644 index 0000000000000000000000000000000000000000..b0aa42b2bb3f60548b6308c8c5859aee83ee40e8 --- /dev/null +++ b/ansible/roles/es7/vars/RedHat.yml @@ -0,0 +1,4 @@ +--- +java: "{{ es_java | default('java-1.8.0-openjdk.x86_64') }}" +default_file: "/etc/sysconfig/elasticsearch" +es_home: "/usr/share/elasticsearch" \ No newline at end of file diff --git a/ansible/roles/es7/vars/main.yml b/ansible/roles/es7/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..91b7b699053f8143f480484ae2cfdbc64a5a1038 --- /dev/null +++ b/ansible/roles/es7/vars/main.yml @@ -0,0 +1,4 @@ +--- +es_package_url: "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch" +reserved_xpack_users: ["elastic","kibana","logstash_system"] +sysd_config_file: "/etc/systemd/system/elasticsearch.service.d/override.conf" diff --git a/private_repo/ansible/inventory/dev/Core/hosts b/private_repo/ansible/inventory/dev/Core/hosts index cba74004b69c0c810409716ebda5c6b1dee42d55..78b659c0da7b3e5fd9f3be93b82958506e8db3c5 100644 --- a/private_repo/ansible/inventory/dev/Core/hosts +++ b/private_repo/ansible/inventory/dev/Core/hosts @@ -84,6 +84,13 @@ log-es-2 [es:children] es-1 + +[es7-1] +10.10.10.15 es_instance_name=es7-1 es_etc_node_master=true es_etc_node_data=true +[es7:children] +es7-1 + + [cassandra-1] 18.3.0.4