Fix for issue #369

This commit is contained in:
Dale McDiarmid 2017-09-19 20:11:09 +01:00
parent 0676799d1c
commit e9a6f74d09
8 changed files with 216 additions and 47 deletions

View file

@ -116,4 +116,4 @@ suites:
attributes:
provisioner:
playbook: test/integration/issue-test.yml
idempotency_test: true
idempotency_test: false

View file

@ -21,10 +21,10 @@ def append_to_list(values=[], suffix=''):
def array_to_str(values=[],separator=','):
return separator.join(values)
def extract_role_users(users={}):
def extract_role_users(users={},exclude_users=[]):
role_users=[]
for user,details in users.iteritems():
if "roles" in details:
if user not in exclude_users and "roles" in details:
for role in details["roles"]:
role_users.append(role+":"+user)
return role_users
@ -32,19 +32,26 @@ def extract_role_users(users={}):
def filename(filename=''):
return os.path.splitext(os.path.basename(filename))[0]
def filter_reserved(user_roles={}):
def remove_reserved(user_roles={}):
not_reserved = []
for user_role,details in 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 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,
'filter_reserved':filter_reserved,
'remove_reserved':remove_reserved,
'filename':filename}

View file

@ -1,5 +1,5 @@
---
- set_fact: manage_file_users=es_users is defined and es_users.file is defined
- set_fact: manage_file_users=es_users is defined and es_users.file is defined and es_users.file.keys() | length > 0
#List current users
- name: List Users
@ -21,27 +21,36 @@
CONF_DIR: "{{ conf_dir }}"
ES_HOME: "{{es_home}}"
- set_fact: users_to_add={{ es_users.file.keys() | difference (current_file_users.stdout_lines) }}
- set_fact: users_to_add={{ es_users.file.keys() | difference (current_file_users.stdout_lines) | difference (reserved_xpack_users) | default([]) }}
when: manage_file_users
- set_fact: users_to_ignore={{ es_users.file.keys() | difference (current_file_users.stdout_lines) | intersect (reserved_xpack_users) }}
when: manage_file_users
- debug:
msg: "WARNING: YOU CANNOT CHANGE RESERVED USERS THROUGH THE FILE REALM. THE FOLLOWING WILL BE IGNORED: {{users_to_ignore}}"
when: manage_file_users and users_to_ignore | length > 0
#Add users
- name: Add Users
command: >
{{es_home}}/bin/x-pack/users useradd {{item}} -p {{es_users.file[item].password}}
with_items: "{{users_to_add | default([])}}"
with_items: "{{ users_to_add }}"
when: manage_file_users and users_to_add | length > 0
no_log: True
environment:
CONF_DIR: "{{ conf_dir }}"
ES_HOME: "{{es_home}}"
- set_fact: users_to_modify={{ es_users.file.keys() | difference (reserved_xpack_users) | default([]) }}
when: manage_file_users
#Set passwords for all users declared - Required as the useradd will not change existing user passwords
- name: Set User Passwords
command: >
{{es_home}}/bin/x-pack/users passwd {{item.key}} -p {{item.value.password}}
with_dict: "{{(es_users | default({'file':{}})).file}}"
when: manage_file_users and es_users.file.keys() | length > 0
{{es_home}}/bin/x-pack/users passwd {{ item }} -p {{es_users.file[item].password}}
with_items: "{{ users_to_modify }}"
when: manage_file_users and users_to_modify | length > 0
#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
@ -49,7 +58,7 @@
CONF_DIR: "{{ conf_dir }}"
ES_HOME: "{{es_home}}"
- set_fact: users_roles={{es_users.file | extract_role_users}}
- set_fact: users_roles={{es_users.file | extract_role_users (reserved_xpack_users) }}
when: manage_file_users
#Copy Roles files

View file

@ -1,14 +1,15 @@
---
- set_fact: change_api_password=false
- set_fact: manage_native_users=false
- set_fact: manage_native_users=true
when: es_users is defined and es_users.native is defined
when: es_users is defined and es_users.native is defined and es_users.native.keys() | length > 0
- set_fact: manage_native_roles=false
- set_fact: manage_native_roles=true
when: es_roles is defined and es_roles.native is defined
when: es_roles is defined and es_roles.native is defined and es_roles.native.keys() | length > 0
# If playbook runs too fast, Native commands could fail as the Native Realm is not yet up
- name: Wait 15 seconds for the Native Relm to come up
@ -28,15 +29,40 @@
register: user_list_response
when: manage_native_users
- set_fact: reserved_users={{ user_list_response.json | filter_reserved }}
when: manage_native_users
#Current users not inc. those reserved
- set_fact: current_users={{ user_list_response.json | filter_reserved }}
- set_fact: current_users={{ user_list_response.json.keys() | difference (reserved_users) }}
when: manage_native_users
#Identify non declared users
- set_fact: users_to_remove={{ current_users | difference ( es_users.native.keys() ) }}
#We are changing the es_api_basic_auth_username password, so we need to do it first and update the param
- set_fact: native_users={{ es_users.native }}
when: manage_native_users
#Delete all non required users
- 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: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/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
when: change_api_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
- set_fact: users_to_remove={{ current_users | difference ( native_users.keys() ) }}
when: manage_native_users
#Delete all non required users NOT inc. reserved
- name: Delete Native Users
uri:
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/user/{{item}}
@ -45,26 +71,50 @@
user: "{{es_api_basic_auth_username}}"
password: "{{es_api_basic_auth_password}}"
force_basic_auth: yes
when: manage_native_users and users_to_remove | length > 0
with_items: "{{users_to_remove | default([]) }}"
when: manage_native_users
with_items: "{{ users_to_remove | default([]) }}"
- set_fact: native_users={{ es_users.native }}
when: manage_native_users and es_users.native.keys() > 0
- set_fact: users_to_ignore={{ native_users.keys() | intersect (reserved_users) }}
when: manage_native_users
#Overwrite all other users
- name: Update Native Users
- 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: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/user/{{item.key}}
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/user/{{item}}/_password
method: POST
body_format: json
body: "{{item.value | to_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
when: manage_native_users and native_users.keys() > 0
when: native_users[item].password is defined
no_log: True
with_dict: "{{native_users | default({}) }}"
with_items: "{{ users_to_ignore | default([]) }}"
- set_fact: users_to_modify={{ native_users.keys() | difference (reserved_users) }}
when: manage_native_users
#Overwrite all other users NOT inc. those reserved
- name: Update Non-Reserved Native User Details
uri:
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/user/{{item}}
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
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
@ -79,16 +129,23 @@
register: role_list_response
when: manage_native_roles
- set_fact: current_roles={{ role_list_response.json | filter_reserved }}
- set_fact: reserved_roles={{ role_list_response.json | filter_reserved }}
when: manage_native_roles
- debug: msg="{{current_roles}}"
- set_fact: current_roles={{ role_list_response.json.keys() | difference (reserved_roles) }}
when: manage_native_roles
- set_fact: roles_to_ignore={{ es_roles.native.keys() | intersect (reserved_roles) | default([]) }}
when: manage_native_roles
- 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
- set_fact: roles_to_remove={{ current_roles | difference ( es_roles.native.keys() ) }}
when: manage_native_roles
#Delete all non required roles
#Delete all non required roles NOT inc. reserved
- name: Delete Native Roles
uri:
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/role/{{item}}
@ -97,23 +154,22 @@
user: "{{es_api_basic_auth_username}}"
password: "{{es_api_basic_auth_password}}"
force_basic_auth: yes
when: manage_native_roles and roles_to_remove | length > 0
when: manage_native_roles
with_items: "{{roles_to_remove | default([]) }}"
- set_fact: roles_to_modify={{ es_roles.native.keys() | difference (reserved_roles) }}
when: manage_native_roles
- set_fact: native_roles={{ es_roles.native }}
when: manage_native_roles and es_roles.native.keys() > 0
#Update other roles
#Update other roles - NOT inc. reserved roles
- name: Update Native Roles
uri:
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/role/{{item.key}}
url: http://{{es_api_host}}:{{es_api_port}}/_xpack/security/role/{{item}}
method: POST
body_format: json
body: "{{item.value | to_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
when: manage_native_roles and native_roles.keys() > 0
with_dict: "{{ native_roles | default({})}}"
when: manage_native_roles
with_items: "{{ roles_to_modify | default([]) }}"

View file

@ -199,5 +199,45 @@ shared_examples 'xpack::init' do |es_version,plugins|
#Test contents as expected
its(:md5sum) { should eq '6ff0e6c4380a6ac0f6e04d871c0ca5e8' }
end
#check accounts are correct i.e. we can auth and they have the correct roles
describe 'kibana4_server access check' do
it 'should be reported as version '+es_version do
command = command('curl -s localhost:9200/ -u kibana4_server:changeMe | grep number')
expect(command.stdout).to match(es_version)
expect(command.exit_status).to eq(0)
end
end
describe command('curl -s localhost:9200/_xpack/security/user/kibana4_server -u elastic:elasticChanged | md5sum | grep f0548742161d9e50c7c7fbe2e061a1fa') do
its(:exit_status) { should eq 0 }
end
describe 'logstash_system access check' do
it 'should be reported as version '+es_version do
command = command('curl -s localhost:9200/ -u logstash_system:aNewLogstashPassword | grep number')
expect(command.stdout).to match(es_version)
expect(command.exit_status).to eq(0)
end
end
describe command('curl -s localhost:9200/_xpack/security/user/logstash_system -u elastic:elasticChanged | md5sum | grep 98d361ddfa5156abd33542a493b4fd85') do
its(:exit_status) { should eq 0 }
end
describe 'kibana access check' do
it 'should be reported as version '+es_version do
command = command('curl -s localhost:9200/ -u kibana:changeme | grep number')
expect(command.stdout).to match(es_version)
expect(command.exit_status).to eq(0)
end
end
describe command('curl -s localhost:9200/_xpack/security/user/kibana -u elastic:elasticChanged | md5sum | grep 34190c64eb3c7cfb002fa789df5fad20') do
its(:exit_status) { should eq 0 }
end
end

View file

@ -2,10 +2,20 @@
#Modify the playbook below and test with kitchen i.e. `kitchen test issue-test`
#To add custom tests modify the serverspec file ./helpers/serverspec/issue_test_spec.rb
#Idempot test is enabled for this test
- name: Simple Example
hosts: localhost
roles:
- { role: elasticsearch, es_config: { "xpack.security.authc.realms.file1.type": "file", "xpack.security.authc.realms.file1.order": 1, "xpack.security.authc.realms.native1.type": "native", "xpack.security.authc.realms.native1.order": 0 }, es_instance_name: "security_node" }
- {
role: elasticsearch,
es_config:
{
"xpack.security.authc.realms.file1.type": "file",
"xpack.security.authc.realms.file1.order": 1,
"xpack.security.authc.realms.native1.type": "native",
"xpack.security.authc.realms.native1.order": 0
},
es_instance_name: "security_node" }
vars:
es_heap_size: "1g"
es_enable_xpack: true
@ -17,8 +27,27 @@
es_api_basic_auth_username: elastic
es_api_basic_auth_password: changeme
es_users:
native:
testUser:
file:
kibana:
password: changeme
roles:
- kibana_user
- kibana_system
test_user:
password: changeme
roles:
- kibana_system
native:
kibana:
password: changeme
roles:
- kibana_system
elastic:
password: aNewPassWord
es_roles:
native:
logstash:
cluster:
- manage_index_templates
logstash_system:
cluster:
- manage_index_templates

View file

@ -31,6 +31,14 @@
password: changeMe
roles:
- kibana4_server
logstash_system:
#this should be successfully modified
password: aNewLogstashPassword
#this will be ignored
roles:
- kibana4_server
elastic:
password: elasticChanged
file:
es_admin:
password: changeMe
@ -41,6 +49,11 @@
roles:
- power_user
- user
#testing this shouldn't be impacted through the file call
kibana:
password: this_wont_be_set
roles:
- kibana_system
es_roles:
file:
admin:
@ -79,6 +92,16 @@
- write
- delete
- create_index
#this will be ignored - its reserved
logstash_system:
cluster:
- manage_index_templates
indices:
- names: 'logstash-*'
privileges:
- write
- delete
- create_index
#modifies the installation. Changes es_admin password and upgrades ES. Tests confirm the correct version is installed.
- name: Elasticsearch Xpack modify
@ -99,7 +122,7 @@
- security
- alerting
es_api_basic_auth_username: elastic
es_api_basic_auth_password: changeme
es_api_basic_auth_password: elasticChanged
es_role_mapping:
power_user:
- "cn=admins,dc=example,dc=com"
@ -112,6 +135,10 @@
password: changeMe
roles:
- kibana4_server
logstash_system:
#this will be ignored
roles:
- kibana4_server
file:
es_admin:
password: changeMeAgain

View file

@ -4,4 +4,5 @@ es_conf_dir: "/etc/elasticsearch"
sysd_script: "/usr/lib/systemd/system/elasticsearch.service"
init_script: "/etc/init.d/elasticsearch"
#add supported features here
supported_xpack_features: ["alerting","monitoring","graph","security"]
supported_xpack_features: ["alerting","monitoring","graph","security"]
reserved_xpack_users: ["elastic","kibana","logstash_system"]