diff --git a/elk_metrics_7x/README.rst b/elk_metrics_7x/README.rst index d08b6af0..db32f2c7 100644 --- a/elk_metrics_7x/README.rst +++ b/elk_metrics_7x/README.rst @@ -635,3 +635,84 @@ all `elk_metrics_7x` related services within the local test environment. .. code-block:: bash tests/run-cleanup.sh + + +Enabling ELK security +--------------------- + +By default, ELK 7 is deployed without security enabled. This means that all +service and user interactions are unauthenticated, and communication is +unencrypted. + +If you wish to enable security features, it is recommended to start with a +deployed cluster with security disabled, before following these steps. Note +that this is a multi-stage process and requires unavoidable downtime. + +https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-basic-setup.html#generate-certificates + +* Generate a certificate authority which is unique to the Elastic cluster. + Ensure you set a password against the certificate bundle. + +* Generate a key and certificate for ElasticSearch instances. You may use a + single bundle for all hosts, or unique bundles if preferred. Again, set a + password against these. + +* Store the CA bundle securely, and configure the following elasticsearch + Ansible role variables. Note that it may be useful to base64 encode and + decode the binary certificate bundle files. + elastic_security_enabled: True + elastic_security_cert_bundle: "cert-bundle-contents" + elastic_security_cert_password: "cert-bundle-password" + +* Stop all Elasticsearch services. + +* Run the 'installElastic.yml' playbook against all cluster nodes. This will + enable security features, but will halt log ingest and monitoring tasks + due to missing authentication credentials. + +https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-minimal-setup.html#security-create-builtin-users + +* Generate usernames and passwords for key ELK services. Store the output + securely and set up the following Ansible variables. Note that the + credentials for system users are generated for you. + + For Kibana hosts, set the following variables: + kibana_system_username + kibana_system_password + kibana_setup_username (*) + kibana_setup_password (*) + + For Logstash hosts, set the following variables: + logstash_system_username + logstash_system_password + logstash_internal_username (*) + logstash_internal_password (*) + + For Beats hosts, set the following variables: + beats_system_username + beats_system_password + beats_setup_username (*) + beats_setup_password (*) + + (*) Users marked with a star are not generated automatically. These must be + set up manually via the Kibana interface once it has been configured. In + order for the Kibana playbook to run successfully, the 'elastic' superuser + can be used initially as the 'kibana_setup_username/password'. + + kibana_setup - any user which is assigned the built in kibana_admin role + logstash_internal - see https://www.elastic.co/guide/en/logstash/7.17/ls-security.html#ls-http-auth-basic + beats_setup - see setup role at https://www.elastic.co/guide/en/beats/filebeat/7.17/feature-roles.html + - this user must also be assigned the built in ingest_admin role + +* Set 'kibana_object_encryption_key' to a string with a minimum length of 32 + bytes. + +* Run the 'installKibana.yml' playbook against Kibana hosts. This will complete + their configuration and should allow you to log in to the web interface using + the 'elastic' user generated earlier. + +* Set up any additional users required by Logstash, Beats or others via the + Kibana interface and set their variables as noted above. + +* Complete deployment by running the 'installLogstash.yml' and Beat install + playbooks. diff --git a/elk_metrics_7x/fieldRefresh.yml b/elk_metrics_7x/fieldRefresh.yml index de64c886..651b728f 100644 --- a/elk_metrics_7x/fieldRefresh.yml +++ b/elk_metrics_7x/fieldRefresh.yml @@ -35,6 +35,9 @@ headers: Content-Type: "application/json" kbn-xsrf: "{{ inventory_hostname | to_uuid }}" + url_username: "{{ kibana_setup_username | default(omit) }}" + url_password: "{{ kibana_setup_password | default(omit) }}" + force_basic_auth: "{{ kibana_setup_username is defined }}" register: index_fields_return until: index_fields_return is success retries: 6 @@ -51,6 +54,9 @@ headers: Content-Type: "application/json" kbn-xsrf: "{{ inventory_hostname | to_uuid }}" + url_username: "{{ kibana_setup_username | default(omit) }}" + url_password: "{{ kibana_setup_password | default(omit) }}" + force_basic_auth: "{{ kibana_setup_username is defined }}" register: index_fields_format_return until: index_fields_format_return is success retries: 6 @@ -83,6 +89,9 @@ headers: Content-Type: "application/json" kbn-xsrf: "{{ inventory_hostname | to_uuid }}" + url_username: "{{ kibana_setup_username | default(omit) }}" + url_password: "{{ kibana_setup_password | default(omit) }}" + force_basic_auth: "{{ kibana_setup_username is defined }}" register: index_fields_return until: index_fields_return is success retries: 6 diff --git a/elk_metrics_7x/roles/elastic_auditbeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_auditbeat/defaults/main.yml index 8d9bb8e6..73e8ecb1 100644 --- a/elk_metrics_7x/roles/elastic_auditbeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_auditbeat/defaults/main.yml @@ -42,3 +42,7 @@ auditbeat_ignore_socket_data: false # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_auditbeat/templates/auditbeat.yml.j2 b/elk_metrics_7x/roles/elastic_auditbeat/templates/auditbeat.yml.j2 index 5fe36e4e..e3cf7b75 100644 --- a/elk_metrics_7x/roles/elastic_auditbeat/templates/auditbeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_auditbeat/templates/auditbeat.yml.j2 @@ -1155,7 +1155,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('auditbeat', auditbeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('auditbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('auditbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elastic_beat_setup/defaults/main.yml b/elk_metrics_7x/roles/elastic_beat_setup/defaults/main.yml index d6c0b4ee..56adec96 100644 --- a/elk_metrics_7x/roles/elastic_beat_setup/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_beat_setup/defaults/main.yml @@ -23,6 +23,8 @@ elastic_setup_flags: elastic_beat_setup_options: >- -E 'output.logstash.enabled=false' -E 'output.elasticsearch.hosts={{ coordination_nodes | to_json }}' + {{ (beats_setup_username is defined) | ternary("-E 'output.elasticsearch.username=" ~ beats_setup_username | default("") ~ "'", "") }} + {{ (beats_setup_password is defined) | ternary("-E 'output.elasticsearch.password=" ~ beats_setup_password | default("") ~ "'", "") }} -E 'setup.template.enabled=true' -E 'setup.template.overwrite=true' @@ -37,3 +39,11 @@ elastic_beat_no_proxy: "{{ elastic_beat_kibana_host }}" # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Username and password for beat setup when using ELK security +# beats_setup_username: "" +# beats_setup_password: "" + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_beat_setup/tasks/main.yml b/elk_metrics_7x/roles/elastic_beat_setup/tasks/main.yml index 3628de4e..1d5e2a25 100644 --- a/elk_metrics_7x/roles/elastic_beat_setup/tasks/main.yml +++ b/elk_metrics_7x/roles/elastic_beat_setup/tasks/main.yml @@ -58,6 +58,7 @@ until: templates is success retries: 5 delay: 5 + no_log: True when: - (((ansible_local['elastic']['setup'][elastic_beat_name + '_loaded_templates'] is undefined) or (not (ansible_local['elastic']['setup'][elastic_beat_name + '_loaded_templates'] | bool))) or @@ -76,3 +77,13 @@ - templates is changed tags: - setup + +- name: Set xpack authentication password + shell: "echo '{{ beats_system_password }}' | {{ elastic_beat_name }} keystore add {{ beats_system_username }} --stdin --force" + no_log: True + changed_when: False + when: + - beats_system_username is defined + - beats_system_password is defined + tags: + - setup diff --git a/elk_metrics_7x/roles/elastic_filebeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_filebeat/defaults/main.yml index a28cb810..1f076a38 100644 --- a/elk_metrics_7x/roles/elastic_filebeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_filebeat/defaults/main.yml @@ -318,3 +318,7 @@ filebeat_iptables_log_paths: ["var/log/syslog"] # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_filebeat/templates/filebeat.yml.j2 b/elk_metrics_7x/roles/elastic_filebeat/templates/filebeat.yml.j2 index 033c9652..24eeeb36 100644 --- a/elk_metrics_7x/roles/elastic_filebeat/templates/filebeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_filebeat/templates/filebeat.yml.j2 @@ -2048,7 +2048,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('filebeat', filebeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('filebeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('filebeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elastic_heartbeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_heartbeat/defaults/main.yml index 2fe60e70..a798d6f1 100644 --- a/elk_metrics_7x/roles/elastic_heartbeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_heartbeat/defaults/main.yml @@ -41,3 +41,7 @@ heartbeat_log_level: "{{ elastic_beat_log_level | default('info') }}" # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_heartbeat/templates/heartbeat.yml.j2 b/elk_metrics_7x/roles/elastic_heartbeat/templates/heartbeat.yml.j2 index 192da36c..f41c6b9a 100644 --- a/elk_metrics_7x/roles/elastic_heartbeat/templates/heartbeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_heartbeat/templates/heartbeat.yml.j2 @@ -1282,7 +1282,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('heartbeat', heartbeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('heartbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('heartbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elastic_ilm/defaults/main.yml b/elk_metrics_7x/roles/elastic_ilm/defaults/main.yml index c343488f..6ce326fb 100644 --- a/elk_metrics_7x/roles/elastic_ilm/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_ilm/defaults/main.yml @@ -18,3 +18,6 @@ default_ilm_policy_filename: "default-ilm-policy.json" default_ilm_policy_file_location: "/tmp" elastic_beat_no_proxy: "{{ hostvars[groups['elastic'][0]]['ansible_host'] }}" + +# beats_setup_username: "" +# beats_setup_password: "" diff --git a/elk_metrics_7x/roles/elastic_ilm/tasks/elastic_ilm_update_policy.yml b/elk_metrics_7x/roles/elastic_ilm/tasks/elastic_ilm_update_policy.yml index 9b30ef8a..1154c5d9 100644 --- a/elk_metrics_7x/roles/elastic_ilm/tasks/elastic_ilm_update_policy.yml +++ b/elk_metrics_7x/roles/elastic_ilm/tasks/elastic_ilm_update_policy.yml @@ -4,6 +4,8 @@ url: "http://{{ elasticsearch_data_node_details[0] }}/_ilm/policy/{{ ilm_policy_name }}" method: GET status_code: 200,404 + url_username: "{{ beats_setup_username | default(omit) }}" + url_password: "{{ beats_setup_password | default(omit) }}" register: check_policy when: ilm_policy_name is defined and ilm_policy is defined @@ -14,6 +16,8 @@ body: "{{ ilm_policy }}" status_code: 200 body_format: json + url_username: "{{ beats_setup_username | default(omit) }}" + url_password: "{{ beats_setup_password | default(omit) }}" when: check_policy.status == 200 and ilm_policy_name is defined and ilm_policy is defined and (elk_package_state | default('present')) != "latest" @@ -25,6 +29,8 @@ body: "{{ ilm_policy }}" status_code: 200 body_format: json + url_username: "{{ beats_setup_username | default(omit) }}" + url_password: "{{ beats_setup_password | default(omit) }}" when: check_policy.status == 404 and ilm_policy_name is defined and ilm_policy is defined and (elk_package_state | default('present')) != "latest" @@ -33,6 +39,8 @@ url: "http://{{ elasticsearch_data_node_details[0] }}/_template/{{ ilm_policy_template }}/" method: GET status_code: 200,404 + url_username: "{{ beats_setup_username | default(omit) }}" + url_password: "{{ beats_setup_password | default(omit) }}" register: template when: ilm_policy_template is defined and ilm_policy_name is defined @@ -50,4 +58,6 @@ headers: Content-Type: "application/json" kbn-xsrf: "{{ inventory_hostname | to_uuid }}" + url_username: "{{ beats_setup_username | default(omit) }}" + url_password: "{{ beats_setup_password | default(omit) }}" when: template.status == 200 and ilm_policy_template is defined and ilm_policy_name is defined diff --git a/elk_metrics_7x/roles/elastic_journalbeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_journalbeat/defaults/main.yml index 15089827..5fe93c83 100644 --- a/elk_metrics_7x/roles/elastic_journalbeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_journalbeat/defaults/main.yml @@ -51,3 +51,7 @@ journalbeat_seek: head # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_journalbeat/templates/journalbeat.yml.j2 b/elk_metrics_7x/roles/elastic_journalbeat/templates/journalbeat.yml.j2 index 9d68f0c4..f7ed0233 100644 --- a/elk_metrics_7x/roles/elastic_journalbeat/templates/journalbeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_journalbeat/templates/journalbeat.yml.j2 @@ -1019,7 +1019,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('journalbeat', journalbeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('journalbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('journalbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elastic_kibana/defaults/main.yml b/elk_metrics_7x/roles/elastic_kibana/defaults/main.yml index 8c429108..8e90a4d0 100644 --- a/elk_metrics_7x/roles/elastic_kibana/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_kibana/defaults/main.yml @@ -39,3 +39,9 @@ kibana_elastic_endpoints: # The URL which users access Kibana from # kibana_base_url: "" + +# The following are required to grant Kibana access to Elasticsearch +# when security is enabled. The preferred method for setting the +# password is to use the Kibana keystore. +# kibana_system_username: "" +# kibana_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_kibana/tasks/main.yml b/elk_metrics_7x/roles/elastic_kibana/tasks/main.yml index dc5b0dda..727237b4 100644 --- a/elk_metrics_7x/roles/elastic_kibana/tasks/main.yml +++ b/elk_metrics_7x/roles/elastic_kibana/tasks/main.yml @@ -82,3 +82,21 @@ mode: "0666" notify: - Enable and restart kibana services + +- name: Set authentication password + shell: "echo '{{ kibana_system_password }}' | /usr/share/kibana/bin/kibana-keystore add elasticsearch.password --stdin --force" + no_log: True + changed_when: False + when: + - kibana_system_username is defined + - kibana_system_password is defined + +- name: Set permissions on keystore + file: + path: "/etc/kibana/kibana.keystore" + group: "kibana" + owner: "root" + mode: "0660" + when: + - kibana_system_username is defined + - kibana_system_password is defined diff --git a/elk_metrics_7x/roles/elastic_kibana/templates/kibana.yml.j2 b/elk_metrics_7x/roles/elastic_kibana/templates/kibana.yml.j2 index c7c99642..0f3e7dd4 100644 --- a/elk_metrics_7x/roles/elastic_kibana/templates/kibana.yml.j2 +++ b/elk_metrics_7x/roles/elastic_kibana/templates/kibana.yml.j2 @@ -49,7 +49,9 @@ elasticsearch.hosts: {{ kibana_elastic_endpoints | to_json }} # the username and password that the Kibana server uses to perform maintenance on the Kibana # index at startup. Your Kibana users still need to authenticate with Elasticsearch, which # is proxied through the Kibana server. -#elasticsearch.username: "user" +{% if kibana_system_username is defined %} +elasticsearch.username: "{{ kibana_system_username }}" +{% endif %} #elasticsearch.password: "pass" # Enables SSL and paths to the PEM-format SSL certificate and SSL key files, respectively. @@ -135,3 +137,6 @@ xpack.security.encryptionKey: {{ kibana_security_encryption_key }} {% if kibana_reporting_encryption_key is defined %} xpack.reporting.encryptionKey: {{ kibana_reporting_encryption_key }} {% endif %} +{% if kibana_object_encryption_key is defined %} +xpack.encryptedSavedObjects.encryptionKey: {{ kibana_object_encryption_key }} +{% endif %} diff --git a/elk_metrics_7x/roles/elastic_logstash/defaults/main.yml b/elk_metrics_7x/roles/elastic_logstash/defaults/main.yml index 3ddc4d41..eed88d68 100644 --- a/elk_metrics_7x/roles/elastic_logstash/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_logstash/defaults/main.yml @@ -105,3 +105,13 @@ logstash_collectd_security_level: Sign # Set the descriptive name by which Logstash is identified logstash_node_name: "{{ inventory_hostname }}" + +# Username and password for XPack monitoring when security +# is enabled +# logstash_system_username: "" +# logstash_system_password: "" + +# Username and password for Elasticsearch writes when security +# is enabled +# logstash_internal_username: "" +# logstash_internal_password: "" diff --git a/elk_metrics_7x/roles/elastic_logstash/tasks/main.yml b/elk_metrics_7x/roles/elastic_logstash/tasks/main.yml index f42d9359..2bb341de 100644 --- a/elk_metrics_7x/roles/elastic_logstash/tasks/main.yml +++ b/elk_metrics_7x/roles/elastic_logstash/tasks/main.yml @@ -223,6 +223,35 @@ group: "logstash" mode: "0750" +- name: Check whether Logstash keystore exists + shell: "/usr/share/logstash/bin/logstash-keystore list --path.settings /etc/logstash" + changed_when: False + failed_when: False + register: logstash_keystore + +- name: Create Logstash keystore if required + expect: + command: "/usr/share/logstash/bin/logstash-keystore create --path.settings /etc/logstash" + responses: + WARNING: y + when: logstash_keystore.rc == 1 + +- name: Set xpack authentication password + shell: "echo '{{ logstash_system_password }}' | /usr/share/logstash/bin/logstash-keystore add {{ logstash_system_username }} --stdin --force --path.settings /etc/logstash" + no_log: True + changed_when: False + when: + - logstash_system_username is defined + - logstash_system_password is defined + +- name: Set pipeline authentication password + shell: "echo '{{ logstash_internal_password }}' | /usr/share/logstash/bin/logstash-keystore add {{ logstash_internal_username }} --stdin --force --path.settings /etc/logstash" + no_log: True + changed_when: False + when: + - logstash_internal_username is defined + - logstash_internal_password is defined + - name: Deploy arcsight collector include_tasks: logstash_arcsight.yml when: diff --git a/elk_metrics_7x/roles/elastic_logstash/templates/logstash.yml.j2 b/elk_metrics_7x/roles/elastic_logstash/templates/logstash.yml.j2 index 9e14c7a4..5fc5b542 100644 --- a/elk_metrics_7x/roles/elastic_logstash/templates/logstash.yml.j2 +++ b/elk_metrics_7x/roles/elastic_logstash/templates/logstash.yml.j2 @@ -229,8 +229,10 @@ path.logs: /var/log/logstash # X-Pack Monitoring # https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html xpack.monitoring.enabled: true -#xpack.monitoring.elasticsearch.username: logstash_system -#xpack.monitoring.elasticsearch.password: password +{% if logstash_system_username is defined %} +xpack.monitoring.elasticsearch.username: {{ logstash_system_username }} +xpack.monitoring.elasticsearch.password: ${% raw %}{{% endraw %}{{ logstash_system_username }}{% raw %}}{% endraw +%} +{% endif %} xpack.monitoring.elasticsearch.hosts: {{ logstash_elasticsearch_endpoints | to_json }} #xpack.monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] #xpack.monitoring.elasticsearch.ssl.truststore.path: path/to/file diff --git a/elk_metrics_7x/roles/elastic_logstash/vars/redhat.yml b/elk_metrics_7x/roles/elastic_logstash/vars/redhat.yml index 0d0e66ee..f988d21f 100644 --- a/elk_metrics_7x/roles/elastic_logstash/vars/redhat.yml +++ b/elk_metrics_7x/roles/elastic_logstash/vars/redhat.yml @@ -16,5 +16,6 @@ logstash_distro_packages: - logrotate - logstash + - python3-pexpect logstash_sysconfig_path: /etc/default/logstash diff --git a/elk_metrics_7x/roles/elastic_logstash/vars/suse.yml b/elk_metrics_7x/roles/elastic_logstash/vars/suse.yml index 0d0e66ee..f988d21f 100644 --- a/elk_metrics_7x/roles/elastic_logstash/vars/suse.yml +++ b/elk_metrics_7x/roles/elastic_logstash/vars/suse.yml @@ -16,5 +16,6 @@ logstash_distro_packages: - logrotate - logstash + - python3-pexpect logstash_sysconfig_path: /etc/default/logstash diff --git a/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu-18.04.yml b/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu-18.04.yml new file mode 100644 index 00000000..8ffbbeda --- /dev/null +++ b/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu-18.04.yml @@ -0,0 +1,21 @@ +--- +# Copyright 2018, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +logstash_distro_packages: + - logrotate + - logstash + - python-pexpect + +logstash_sysconfig_path: /etc/default/logstash diff --git a/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu.yml b/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu.yml index 0d0e66ee..f988d21f 100644 --- a/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu.yml +++ b/elk_metrics_7x/roles/elastic_logstash/vars/ubuntu.yml @@ -16,5 +16,6 @@ logstash_distro_packages: - logrotate - logstash + - python3-pexpect logstash_sysconfig_path: /etc/default/logstash diff --git a/elk_metrics_7x/roles/elastic_metricbeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_metricbeat/defaults/main.yml index ede1d4c0..97bf0bcf 100644 --- a/elk_metrics_7x/roles/elastic_metricbeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_metricbeat/defaults/main.yml @@ -48,3 +48,7 @@ metricbeat_log_level: "{{ elastic_beat_log_level | default('info') }}" # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_metricbeat/templates/metricbeat.yml.j2 b/elk_metrics_7x/roles/elastic_metricbeat/templates/metricbeat.yml.j2 index 0cfdf87f..bd6311e4 100644 --- a/elk_metrics_7x/roles/elastic_metricbeat/templates/metricbeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_metricbeat/templates/metricbeat.yml.j2 @@ -279,8 +279,10 @@ metricbeat.modules: - ml_job period: 30s hosts: ["localhost:{{ elastic_port }}"] - #username: "elastic" - #password: "changeme" +{% if beats_system_username is defined %} + username: "{{ beats_system_username }}" + password: "${% raw %}{{% endraw %}{{ beats_system_username }}{% raw %}}{% endraw %}" +{% endif %} #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] #index_recovery.active_only: true @@ -483,6 +485,10 @@ metricbeat.modules: hosts: ["localhost:5601"] basepath: "" enabled: true +{% if beats_system_username is defined %} + username: "{{ beats_system_username }}" + password: "${% raw %}{{% endraw %}{{ beats_system_username }}{% raw %}}{% endraw %}" +{% endif %} # Set to true to send data collected by module to X-Pack # Monitoring instead of metricbeat-* indices. @@ -1910,7 +1916,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('metricbeat', metricbeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('metricbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('metricbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elastic_packetbeat/defaults/main.yml b/elk_metrics_7x/roles/elastic_packetbeat/defaults/main.yml index faa8d6e2..4a76df09 100644 --- a/elk_metrics_7x/roles/elastic_packetbeat/defaults/main.yml +++ b/elk_metrics_7x/roles/elastic_packetbeat/defaults/main.yml @@ -41,3 +41,7 @@ packetbeat_log_level: "{{ elastic_beat_log_level | default('info') }}" # set, templates are only pushed when the user is either upgrading the # beat version or deploying for the first time in the presence of kibana nodes elk_beat_setup: false + +# Authentication credentials for monitoring when using ELK security features +# beats_system_username: "" +# beats_system_password: "" diff --git a/elk_metrics_7x/roles/elastic_packetbeat/templates/packetbeat.yml.j2 b/elk_metrics_7x/roles/elastic_packetbeat/templates/packetbeat.yml.j2 index dbe7cbd4..2cbff5dd 100644 --- a/elk_metrics_7x/roles/elastic_packetbeat/templates/packetbeat.yml.j2 +++ b/elk_metrics_7x/roles/elastic_packetbeat/templates/packetbeat.yml.j2 @@ -1578,7 +1578,7 @@ setup.ilm.policy_file: "{{ ilm_policy_file_location }}/{{ ilm_policy_filename }} {{ elk_macros.beat_logging('packetbeat', packetbeat_log_level) }} # ============================= X-Pack Monitoring ============================== -{{ elk_macros.xpack_monitoring_elasticsearch('packetbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count) }} +{{ elk_macros.xpack_monitoring_elasticsearch('packetbeat', inventory_hostname, elasticsearch_data_hosts, ansible_processor_count, beats_system_username) }} # =============================== HTTP Endpoint ================================ diff --git a/elk_metrics_7x/roles/elasticsearch/defaults/main.yml b/elk_metrics_7x/roles/elasticsearch/defaults/main.yml index f30f26c5..35683eab 100644 --- a/elk_metrics_7x/roles/elasticsearch/defaults/main.yml +++ b/elk_metrics_7x/roles/elasticsearch/defaults/main.yml @@ -50,3 +50,9 @@ elasticsearch_bind_addresses: ["127.0.0.1", "{{ ansible_host }}", "{{ ansible_ho # Allow a slow startup before the systemd notifier module kicks in to extend # the timeout. #elastic_systemd_timeout: 75 + +# Enable Elastic security, including TLS communication between Elasticsearch +# nodes +elastic_security_enabled: False +# elastic_security_cert_bundle: "" +# elastic_security_cert_password: "" diff --git a/elk_metrics_7x/roles/elasticsearch/tasks/main.yml b/elk_metrics_7x/roles/elasticsearch/tasks/main.yml index 715aa41c..df405295 100644 --- a/elk_metrics_7x/roles/elasticsearch/tasks/main.yml +++ b/elk_metrics_7x/roles/elasticsearch/tasks/main.yml @@ -128,6 +128,38 @@ group: "elasticsearch" mode: "0750" +- name: Copy elasticsearch certificate bundle + copy: + content: "{{ elastic_security_cert_bundle }}" + dest: "/etc/elasticsearch/elastic-certificates.p12" + owner: root + group: elasticsearch + mode: 0660 + when: + - elastic_security_enabled + - elastic_security_cert_bundle is defined + +- name: Set certificate bundle password + shell: "echo '{{ elastic_security_cert_password }}' | /usr/share/elasticsearch/bin/elasticsearch-keystore add {{ item }} --stdin --force" + no_log: True + changed_when: False + with_items: + - "xpack.security.transport.ssl.keystore.secure_password" + - "xpack.security.transport.ssl.truststore.secure_password" + when: + - elastic_security_enabled + - elastic_security_cert_password is defined + +- name: Set permissions on keystore + file: + path: "/etc/elasticsearch/elasticsearch.keystore" + group: "elasticsearch" + owner: "root" + mode: "0660" + when: + - elastic_security_enabled + - elastic_security_cert_password is defined + - include_tasks: "elasticsearch_nfs_setup.yml" when: - elastic_shared_fs_repos is defined diff --git a/elk_metrics_7x/roles/elasticsearch/templates/elasticsearch.yml.j2 b/elk_metrics_7x/roles/elasticsearch/templates/elasticsearch.yml.j2 index 98acc122..2a6a9ec9 100644 --- a/elk_metrics_7x/roles/elasticsearch/templates/elasticsearch.yml.j2 +++ b/elk_metrics_7x/roles/elasticsearch/templates/elasticsearch.yml.j2 @@ -159,3 +159,13 @@ indices.recovery.max_bytes_per_sec: {{ elasticsearch_interface_speed }}mb xpack.monitoring.collection.enabled: true # Set to true to enable machine learning on the node. xpack.ml.enabled: false +# Elastic security +xpack.security.enabled: {{ elastic_security_enabled | bool | lower }} +xpack.security.transport.ssl.enabled: {{ elastic_security_enabled | bool | lower }} +{% if elastic_security_enabled %} +xpack.security.transport.ssl.verification_mode: certificate +xpack.security.transport.ssl.client_authentication: required +xpack.security.transport.ssl.keystore.path: elastic-certificates.p12 +xpack.security.transport.ssl.truststore.path: elastic-certificates.p12 +xpack.security.authc.api_key.enabled: true +{% endif %} diff --git a/elk_metrics_7x/templates/_macros.j2 b/elk_metrics_7x/templates/_macros.j2 index e8b565d8..d0b83938 100644 --- a/elk_metrics_7x/templates/_macros.j2 +++ b/elk_metrics_7x/templates/_macros.j2 @@ -532,7 +532,7 @@ logging.files: #logging.ecs: false {%- endmacro %} -{% macro xpack_monitoring_elasticsearch(beat_name, host, data_hosts, processors) -%} +{% macro xpack_monitoring_elasticsearch(beat_name, host, data_hosts, processors, username) -%} # {{ beat_name | capitalize }} can export internal metrics to a central Elasticsearch monitoring # cluster. This requires xpack monitoring to be enabled in Elasticsearch. The # reporting is disabled by default. @@ -568,8 +568,10 @@ monitoring.elasticsearch: # Authentication credentials - either API key or username/password. #api_key: "id:api_key" - #username: "beats_system" - #password: "changeme" +{% if username is defined %} + username: "{{ username }}" + password: "${% raw %}{{% endraw %}{{ username }}{% raw %}}{% endraw %}" +{% endif %} # Dictionary of HTTP parameters to pass within the URL with index operations. #parameters: diff --git a/elk_metrics_7x/templates/logstash-pipelines.yml.j2 b/elk_metrics_7x/templates/logstash-pipelines.yml.j2 index 748d4ebf..2eedf2d8 100644 --- a/elk_metrics_7x/templates/logstash-pipelines.yml.j2 +++ b/elk_metrics_7x/templates/logstash-pipelines.yml.j2 @@ -571,6 +571,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "%{[@metadata][beat]}-%{[@metadata][version]}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if [@metadata][beat] { elasticsearch { @@ -580,6 +584,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if "syslog" in [tags] { elasticsearch { @@ -589,6 +597,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "syslog-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if "collectd" in [tags] { elasticsearch { @@ -598,6 +610,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "collectd-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else { elasticsearch { @@ -607,6 +623,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "undefined-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } } else { @@ -617,6 +637,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "%{[@metadata][beat]}-%{[@metadata][version]}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if [@metadata][beat] { elasticsearch { @@ -625,6 +649,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if "syslog" in [tags] { elasticsearch { @@ -633,6 +661,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "syslog-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else if "collectd" in [tags] { elasticsearch { @@ -641,6 +673,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "collectd-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } else { elasticsearch { @@ -649,6 +685,10 @@ sniffing => {{ (elastic_sniffing_enabled | default(not data_node)) | bool | string | lower }} manage_template => {{ (data_node | bool) | lower }} index => "undefined-%{+YYYY.MM.dd}" +{% if logstash_internal_username is defined %} + user => {{ logstash_internal_username }} + password => "${% raw %}{{% endraw %}{{ logstash_internal_username }}{% raw %}}{% endraw %}" +{% endif %} } } } diff --git a/elk_metrics_7x/vars/variables.yml b/elk_metrics_7x/vars/variables.yml index 8eea68b7..d43a438e 100644 --- a/elk_metrics_7x/vars/variables.yml +++ b/elk_metrics_7x/vars/variables.yml @@ -459,3 +459,6 @@ _elastic_apt_pin_packages: apt_package_pinning_file_name: "{{ elastic_apt_pin_file_name | default('elasticsearch.pref') }}" apt_pinned_packages: "{{ elastic_apt_pin_packages | default(_elastic_apt_pin_packages) }}" + +# kibana_setup_username: "" +# kibana_setup_password: ""