summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr OspalĂ˝ <p.ospaly@partner.samsung.com>2019-04-08 08:39:41 +0200
committerMichal Ptacek <m.ptacek@partner.samsung.com>2019-04-24 14:04:17 +0000
commit3a6558a1af5ba14bc6614d94f768dd1a1fc86d9b (patch)
tree9c442934b9dbe7dfb5eedc25b27652265a043d79
parent72b09b1a46200b6544600ff2432693f0b43c3918 (diff)
Add support for resetting the admin password
The module rancher1_api can now reset an admin password of the default admin account (account_id: '1a1') and keep local authentication enabled. By default the authentication is not enabled, because the ansible module rancher_k8s_environment.py is not idempotent and it would need to be rewritten. Change-Id: Ib432537651b91216c32438ec1233dba3602e3faf Issue-ID: OOM-1734 Signed-off-by: Petr OspalĂ˝ <p.ospaly@partner.samsung.com>
-rw-r--r--ansible/library/rancher1_api.py142
-rw-r--r--ansible/roles/rancher/defaults/main.yml7
-rw-r--r--ansible/roles/rancher/tasks/rancher_server.yml2
3 files changed, 110 insertions, 41 deletions
diff --git a/ansible/library/rancher1_api.py b/ansible/library/rancher1_api.py
index d49e6252..5d74da1e 100644
--- a/ansible/library/rancher1_api.py
+++ b/ansible/library/rancher1_api.py
@@ -5,6 +5,7 @@ from ansible.module_utils.basic import AnsibleModule
import requests
import json
import functools
+import time
DOCUMENTATION = """
---
@@ -96,8 +97,11 @@ def _decorate_rancher_api_request(request_method):
def wrap_request(*args, **kwargs):
response = request_method(*args, **kwargs)
+ authorized = True
- if response.status_code != requests.codes.ok:
+ if response.status_code == 401:
+ authorized = False
+ elif response.status_code != requests.codes.ok:
response.raise_for_status()
try:
@@ -105,7 +109,7 @@ def _decorate_rancher_api_request(request_method):
except Exception:
json_data = None
- return json_data
+ return json_data, authorized
return wrap_request
@@ -214,17 +218,18 @@ def mode_access_control(api_url, data=None, headers=None,
# API get current value
try:
- json_response = get_rancher_api_value(request_url,
- username=access_key,
- password=secret_key,
- headers=headers,
- timeout=timeout)
+ json_response, authorized = \
+ get_rancher_api_value(request_url,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
raise ModeError(str(e))
except requests.Timeout as e:
raise ModeError(str(e))
- if not json_response:
+ if not authorized or not json_response:
raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in '
+ 'the response')
@@ -238,6 +243,37 @@ def mode_access_control(api_url, data=None, headers=None,
return None
+ def remove_password(password_id, action):
+ if action == 'deactivate':
+ action_status = 'deactivating'
+ elif action == 'remove':
+ action_status = 'removing'
+
+ request_url = api_url + 'passwords/' + password_id + \
+ '/?action=' + action
+
+ try:
+ json_response, authorized = \
+ set_rancher_api_value(request_url,
+ {},
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ method='POST',
+ timeout=timeout)
+ except requests.HTTPError as e:
+ raise ModeError(str(e))
+ except requests.Timeout as e:
+ raise ModeError(str(e))
+
+ if not authorized or not json_response:
+ raise ModeError('ERROR: BAD RESPONSE (POST) - no json value in '
+ + 'the response')
+
+ if json_response['state'] != action_status:
+ raise ModeError("ERROR: Failed to '%s' the password: %s" %
+ (action, password_id))
+
# check if data contains all required fields
try:
if not isinstance(data['account_id'], str) or data['account_id'] == '':
@@ -258,17 +294,18 @@ def mode_access_control(api_url, data=None, headers=None,
# API get current value
try:
- json_response = get_rancher_api_value(request_url,
- username=access_key,
- password=secret_key,
- headers=headers,
- timeout=timeout)
+ json_response, authorized = \
+ get_rancher_api_value(request_url,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
raise ModeError(str(e))
except requests.Timeout as e:
raise ModeError(str(e))
- if not json_response:
+ if not authorized or not json_response:
raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in the '
+ 'response')
@@ -285,7 +322,7 @@ def mode_access_control(api_url, data=None, headers=None,
enabled = False
if dry_run:
- # we will not set anything, only signal potential change
+ # we will not set anything and only signal potential change
if enabled:
changed = False
else:
@@ -293,22 +330,23 @@ def mode_access_control(api_url, data=None, headers=None,
else:
# we will try to enable again with the same password
localauth_payload = create_localauth_payload(data['password'])
- json_response = None
try:
- json_response = set_rancher_api_value(request_url,
- localauth_payload,
- username=access_key,
- password=secret_key,
- headers=headers,
- method='POST',
- timeout=timeout)
+ json_response, authorized = \
+ set_rancher_api_value(request_url,
+ localauth_payload,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ method='POST',
+ timeout=timeout)
except requests.HTTPError as e:
raise ModeError(str(e))
except requests.Timeout as e:
raise ModeError(str(e))
+ # here we ignore authorized status - we will try to reset password
if not json_response:
- raise ModeError('ERROR: BAD RESPONSE (PUT) - no json value in '
+ raise ModeError('ERROR: BAD RESPONSE (POST) - no json value in '
+ 'the response')
# we check if the admin was already set or not...
@@ -318,7 +356,7 @@ def mode_access_control(api_url, data=None, headers=None,
elif is_admin_enabled(json_response, data['password']):
# we enabled it for the first time
changed = True
- # ...and reset password if needed
+ # ...and reset password if needed (unauthorized access)
else:
# local auth is enabled but the password differs
# we must reset the admin's password
@@ -328,9 +366,29 @@ def mode_access_control(api_url, data=None, headers=None,
raise ModeError("ERROR: admin's password is set, but we "
+ "cannot identify it")
- # TODO
- raise ModeError("TODO: Reset of the admin password is not yet "
- + "implemented")
+ # One of the way to reset the password is to remove it first
+ # TODO - refactor this
+ remove_password(password_id, 'deactivate')
+ time.sleep(2)
+ remove_password(password_id, 'remove')
+ time.sleep(1)
+
+ try:
+ json_response, authorized = \
+ set_rancher_api_value(request_url,
+ localauth_payload,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ method='POST',
+ timeout=timeout)
+ except requests.HTTPError as e:
+ raise ModeError(str(e))
+ except requests.Timeout as e:
+ raise ModeError(str(e))
+
+ # finally we signal the change
+ changed = True
if changed:
msg = "Local authentication is enabled, admin has assigned password"
@@ -401,17 +459,18 @@ def mode_settings(api_url, data=None, headers=None, timeout=default_timeout,
# API get current value
try:
- json_response = get_rancher_api_value(request_url,
- username=access_key,
- password=secret_key,
- headers=headers,
- timeout=timeout)
+ json_response, authorized = \
+ get_rancher_api_value(request_url,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
raise ModeError(str(e))
except requests.Timeout as e:
raise ModeError(str(e))
- if not json_response:
+ if not authorized or not json_response:
raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in the '
+ 'response')
@@ -432,18 +491,19 @@ def mode_settings(api_url, data=None, headers=None, timeout=default_timeout,
elif valid and differs:
# API set new value
try:
- json_response = set_rancher_api_value(request_url,
- payload,
- username=access_key,
- password=secret_key,
- headers=headers,
- timeout=timeout)
+ json_response, authorized = \
+ set_rancher_api_value(request_url,
+ payload,
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
raise ModeError(str(e))
except requests.Timeout as e:
raise ModeError(str(e))
- if not json_response:
+ if not authorized or not json_response:
raise ModeError('ERROR: BAD RESPONSE (PUT) - no json value in '
+ 'the response')
else:
diff --git a/ansible/roles/rancher/defaults/main.yml b/ansible/roles/rancher/defaults/main.yml
index e4d5cb9f..6d354e6e 100644
--- a/ansible/roles/rancher/defaults/main.yml
+++ b/ansible/roles/rancher/defaults/main.yml
@@ -22,5 +22,12 @@ rancher:
# Auto-purge Audit Log entries after this long (seconds)
audit_log_purge_after_seconds: 2592000 # 30 days
+ # By default we don't enable local authentication (mainly due to
+ # to the fact that rancher_k8s_environment.py would have to be
+ # rewritten completely)
+ # But if you don't need to run rancher_kubernetes playbook more
+ # than once (you should not have to under the terms of a regular
+ # installation), then you can safely enable it.
+ auth_enabled: false
# Set this password for the rancher admin account:
admin_password: "admin"
diff --git a/ansible/roles/rancher/tasks/rancher_server.yml b/ansible/roles/rancher/tasks/rancher_server.yml
index e93dd0e0..4cda3722 100644
--- a/ansible/roles/rancher/tasks/rancher_server.yml
+++ b/ansible/roles/rancher/tasks/rancher_server.yml
@@ -48,6 +48,7 @@
rancher_agent_image: "{{ env.data.registration_tokens.image }}"
rancher_agent_reg_url: "{{ env.data.registration_tokens.reg_url }}"
+# By default disabled - when enabled this playbook cannot be run more than once.
- name: Setup rancher admin password and enable authentication
rancher1_api:
server: "{{ rancher_server_url }}"
@@ -56,6 +57,7 @@
data:
account_id: 1a1 # default rancher admin account
password: "{{ rancher.admin_password }}"
+ when: "rancher.auth_enabled is defined and rancher.auth_enabled"
- name: Configure the size of the rancher cattle db and logs
block: