Skip to content

Commit

Permalink
ApiKey: Add ApiKey authentication. (#103)
Browse files Browse the repository at this point in the history
* ApiKey: Add ApiKey authentication and tests.

Co-authored-by: andrefsp <[email protected]>
Co-authored-by: Rhys Campbell <[email protected]>
  • Loading branch information
3 people authored Oct 9, 2024
1 parent ea8b863 commit 4f9d11e
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 12 deletions.
9 changes: 9 additions & 0 deletions plugins/doc_fragments/login_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ModuleDocFragment(object):
choices:
- ''
- http_auth
- api_key
default: ''
auth_scheme:
description:
Expand Down Expand Up @@ -57,6 +58,14 @@ class ModuleDocFragment(object):
required: no
type: int
default: 9200
api_key_encoded:
description:
- API key credentials which is the Base64-encoding of the UTF-8\
representation of the id and api_key joined by a colon (:).
- Supported from Elastic 8+.
- See [Create API Key](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html) documentation for specifics.
required: no
type: str
timeout:
description:
- Response timeout in seconds.
Expand Down
36 changes: 24 additions & 12 deletions plugins/module_utils/elastic_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import traceback


elastic_found = False
E_IMP_ERR = None
NotFoundError = None
Expand All @@ -27,9 +28,10 @@ def elastic_common_argument_spec():
Returns a dict containing common options shared across the elastic modules
"""
options = dict(
auth_method=dict(type='str', choices=['', 'http_auth'], default=''),
auth_method=dict(type='str', choices=['', 'http_auth', 'api_key'], default=''),
auth_scheme=dict(type='str', choices=['http', 'https'], default='http'),
cafile=dict(type='str', default=None),
api_key_encoded=dict(type='str', default=None, no_log=True),
connection_options=dict(type='list', elements='dict', default=[]),
login_user=dict(type='str', required=False),
login_password=dict(type='str', required=False, no_log=True),
Expand All @@ -53,17 +55,27 @@ def build_auth(self, module):
Build the auth list for elastic according to the passed in parameters
'''
auth = {}
if module.params['auth_method'] != '':
if module.params['auth_method'] == 'http_auth':
auth["http_auth"] = (module.params['login_user'],
module.params['login_password'])

if module.params['cafile'] is not None:
from ssl import create_default_context
context = create_default_context(module.params['cafile'])
auth["ssl_context"] = context
else:
module.fail_json("Invalid or unsupported auth_method provided")
if not module.params['auth_method']:
return auth

if module.params['auth_method'] == 'http_auth':
# username/password authentication.
auth["http_auth"] = (module.params['login_user'],
module.params['login_password'])
elif module.params['auth_method'] == 'api_key':
# api key authentication. Won't work for v7 of the driver
# The api_key is actually the base64 encoded version of
# the id and api_key separated by a colon.
auth["api_key"] = module.params['api_key_encoded']
else:
module.fail_json("Invalid or unsupported auth_method provided")

# CA file has been provided. Add it to auth dict
if module.params['cafile'] is not None:
from ssl import create_default_context
context = create_default_context(module.params['cafile'])
auth["ssl_context"] = context

return auth

def connect(self):
Expand Down
59 changes: 59 additions & 0 deletions tests/integration/targets/elastic_index/tasks/103.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
- vars:
elastic_user: elastic
elastic_password: secret
elastic_port: 9200
elastic_api_key_name: "test-api-key"

block:

- name: Get Elasticsearch version
ansible.builtin.uri:
url: http://localhost:9200
method: GET
user: "{{ elastic_user }}"
password: "{{ elastic_password }}"
return_content: yes
headers:
Content-Type: "application/json"
register: es_version_response

- name: Create an API key for Elasticsearch
ansible.builtin.uri:
url: "http://localhost:{{ elastic_port }}/_security/api_key"
method: POST
user: "{{ elastic_user }}"
password: "{{ elastic_password }}"
body_format: json
body: |
{
"name": "{{ elastic_api_key_name }}",
"expiration": "1d",
"role_descriptors": {}
}
headers:
Content-Type: "application/json"
return_content: yes
register: api_key_response
when: es_version_response.json.version.number[0] | int > 7

- assert:
that:
- api_key_response.json.name == "test-api-key"
when: es_version_response.json.version.number[0] | int > 7

- name: Create an index using the api key
community.elastic.elastic_index:
name: myapikeyindex
auth_method: "api_key"
api_key_encoded: "{{ api_key_response.json.encoded }}"
auth_scheme: "http"
check_mode: yes
register: result
when: es_version_response.json.version.number[0] | int > 7

- assert:
that:
- result.msg == "The index 'myapikeyindex' was created."
- result.changed == True
when: es_version_response.json.version.number[0] | int > 7
2 changes: 2 additions & 0 deletions tests/integration/targets/elastic_index/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
name: setup_elastic

- import_tasks: 2-test-with-auth.yml

- import_tasks: 103.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ services:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- ELASTIC_PASSWORD=secret # password for default user: elastic
- xpack.security.enabled=true
- xpack.security.authc.api_key.enabled=true
ulimits:
memlock:
soft: -1
Expand Down

0 comments on commit 4f9d11e

Please sign in to comment.