Test reindex-from-remote with security

Original commit: elastic/x-pack-elasticsearch@7e3530a958
This commit is contained in:
Nik Everett 2016-07-06 15:48:20 -04:00
parent 51f91bf9eb
commit b9e1bdfce6
6 changed files with 439 additions and 6 deletions

View File

@ -8,6 +8,8 @@ integTest {
cluster { cluster {
setting 'script.inline', 'true' setting 'script.inline', 'true'
plugin ':x-plugins:elasticsearch:x-pack' plugin ':x-plugins:elasticsearch:x-pack'
// Whitelist reindexing from the local node so we can test it.
setting 'reindex.remote.whitelist', 'myself'
extraConfigFile 'x-pack/roles.yml', 'roles.yml' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[ [
test_admin: 'superuser', test_admin: 'superuser',

View File

@ -10,6 +10,8 @@ admin:
# Search and write on both source and destination indices. It should work if you could just search on the source and # Search and write on both source and destination indices. It should work if you could just search on the source and
# write to the destination but that isn't how security works. # write to the destination but that isn't how security works.
minimal: minimal:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:
@ -26,18 +28,24 @@ minimal:
# Read only operations on indices # Read only operations on indices
readonly: readonly:
cluster:
- cluster:monitor/main
indices: indices:
- names: '*' - names: '*'
privileges: [ read ] privileges: [ read ]
# Write operations on destination index, none on source index # Write operations on destination index, none on source index
dest_only: dest_only:
cluster:
- cluster:monitor/main
indices: indices:
- names: dest - names: dest
privileges: [ write ] privileges: [ write ]
# Search and write on both source and destination indices with document level security filtering out some docs. # Search and write on both source and destination indices with document level security filtering out some docs.
can_not_see_hidden_docs: can_not_see_hidden_docs:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:
@ -59,6 +67,8 @@ can_not_see_hidden_docs:
# Search and write on both source and destination indices with field level security. # Search and write on both source and destination indices with field level security.
can_not_see_hidden_fields: can_not_see_hidden_fields:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:

View File

@ -147,10 +147,9 @@
indices.refresh: {} indices.refresh: {}
- do: - do:
headers: {es-security-runas-user: dest_only_user} headers: {es-security-runas-user: minimal_user}
catch: forbidden catch: forbidden
reindex: reindex:
refresh: true
body: body:
source: source:
index: source index: source

View File

@ -0,0 +1,418 @@
---
"Reindex from remote as superuser works":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
---
"Reindex from remote searching as user with minimal privileges works":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: minimal_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
---
"Reindex from remote reading as readonly user works when the indexing user is allowed to index":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: readonly_user
password: changeme
index: source
dest:
index: dest
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
---
"Reindex from remote as user that can't read from the source is forbidden":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: forbidden
reindex:
body:
source:
remote:
host: http://${host}
username: dest_only_user
password: changeme
index: source
dest:
index: dest
---
"Using a script to write to an index to which you don't have access is forbidden even if you read as a superuser":
- do:
index:
index: source
type: tweet
id: 1
body: { "user": "kimchy" }
- do:
index:
index: source
type: tweet
id: 2
body: { "user": "another" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
headers: {es-security-runas-user: minimal_user}
catch: forbidden
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: changeme
index: source
dest:
index: dest
script:
inline: if (ctx._source.user == "kimchy") {ctx._index = 'other_dest'}
- do:
indices.refresh: {}
# The index to which the user tried the unauthorized write didn't even get created
- do:
catch: missing
search:
index: other_dest
# Even the authorized index won't have made it because it was in the same batch as the unauthorized one.
# If there had been lots of documents being copied then some might have made it into the authorized index.
- do:
catch: missing
search:
index: dest
---
"Reindex from remote misses hidden docs":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
index:
index: source
type: foo
id: 2
body: { "text": "test", "hidden": true }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: can_not_see_hidden_docs_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
# We copied just one doc, presumably the one without the hidden field
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
# We didn't copy the doc with the hidden field
- do:
search:
index: dest
body:
query:
match:
hidden: true
- match: { hits.total: 0 }
---
"Reindex misses hidden fields":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test", "foo": "z", "bar": "z" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: can_not_see_hidden_fields_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
- do:
search:
index: dest
body:
query:
match:
foo: z
- match: { hits.total: 1 }
- do:
search:
index: dest
body:
query:
match:
bar: z
- match: { hits.total: 1 }
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 0 }
---
"Reindex from remote with bad password is unauthorized":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: unauthorized
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: badpass
index: source
dest:
index: dest
---
"Reindex from remote with no username or password is unauthorized":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: unauthorized
reindex:
body:
source:
remote:
host: http://${host}
index: source
dest:
index: dest

View File

@ -52,6 +52,8 @@ teardown:
--- ---
"Test changing users password": "Test changing users password":
- skip:
features: catch_unauthorized
# validate that the user actually works # validate that the user actually works
- do: - do:
headers: headers:
@ -70,7 +72,7 @@ teardown:
# attempt to login with invalid credentials # attempt to login with invalid credentials
- do: - do:
catch: request catch: unauthorized
headers: headers:
Authorization: "Basic am9lOnMza3JpdA==" Authorization: "Basic am9lOnMza3JpdA=="
cluster.health: {} cluster.health: {}
@ -84,6 +86,8 @@ teardown:
--- ---
"Test user changing their own password": "Test user changing their own password":
- skip:
features: catch_unauthorized
# test that the role actually works # test that the role actually works
- do: - do:
headers: headers:
@ -103,7 +107,7 @@ teardown:
# attempt to login with invalid credentials # attempt to login with invalid credentials
- do: - do:
catch: request catch: unauthorized
headers: headers:
Authorization: "Basic dW5wcml2aWxlZ2VkX3VzZXI6czNrcml0" Authorization: "Basic dW5wcml2aWxlZ2VkX3VzZXI6czNrcml0"
cluster.health: {} cluster.health: {}

View File

@ -35,7 +35,7 @@ teardown:
--- ---
"Test create user and update without and with password": "Test create user and update without and with password":
- skip: - skip:
features: headers features: [headers, catch_unauthorized]
# test that the role actually works # test that the role actually works
- do: - do:
@ -108,7 +108,7 @@ teardown:
# validate old password doesn't work # validate old password doesn't work
- do: - do:
catch: request catch: unauthorized
headers: headers:
Authorization: "Basic am9lOnMza3JpdA==" Authorization: "Basic am9lOnMza3JpdA=="
cluster.health: {} cluster.health: {}