mirror of
https://github.com/ansible/awx-operator.git
synced 2026-03-26 21:33:14 +00:00
Merge pull request #397 from rooftopcellist/dynamic_secrets
Dynamic secret backup & restore
This commit is contained in:
@@ -76,4 +76,4 @@ spec:
|
||||
type: array
|
||||
restoreComplete:
|
||||
description: Restore process complete
|
||||
type: string
|
||||
type: boolean
|
||||
|
||||
@@ -560,7 +560,7 @@ spec:
|
||||
type: array
|
||||
restoreComplete:
|
||||
description: Restore process complete
|
||||
type: string
|
||||
type: boolean
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -76,4 +76,4 @@ spec:
|
||||
type: array
|
||||
restoreComplete:
|
||||
description: Restore process complete
|
||||
type: string
|
||||
type: boolean
|
||||
|
||||
@@ -16,6 +16,15 @@
|
||||
set_fact:
|
||||
awx_spec: "{{ _awx['spec'] }}"
|
||||
|
||||
- name: Set names of backed up secrets in the CR spec
|
||||
set_fact:
|
||||
awx_spec: "{{ awx_spec | combine ({ item.key : item.value }) }}"
|
||||
with_items:
|
||||
- {"key": "secret_key_secret", "value": "{{ this_awx['resources'][0]['status']['secretKeySecret'] }}"}
|
||||
- {"key": "admin_password_secret", "value": "{{ this_awx['resources'][0]['status']['adminPasswordSecret'] }}"}
|
||||
- {"key": "broadcast_websocket_secret", "value": "{{ this_awx['resources'][0]['status']['broadcastWebsocketSecret'] }}"}
|
||||
- {"key": "postgres_configuration_secret", "value": "{{ this_awx['resources'][0]['status']['postgresConfigurationSecret'] }} "}
|
||||
|
||||
- name: Write awx object to pvc
|
||||
k8s_exec:
|
||||
namespace: "{{ backup_pvc_namespace }}"
|
||||
|
||||
35
roles/backup/tasks/dump_generated_secret.yml
Normal file
35
roles/backup/tasks/dump_generated_secret.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
|
||||
- name: Get secret name
|
||||
set_fact:
|
||||
_name: "{{ this_awx['resources'][0]['status'][item] }}"
|
||||
|
||||
- name: Fail if status is not set on AWX CR
|
||||
block:
|
||||
- name: Set error message
|
||||
set_fact:
|
||||
error_msg: "{{ item }} status is not set on AWX object yet"
|
||||
|
||||
- name: Handle error
|
||||
import_tasks: error_handling.yml
|
||||
|
||||
- name: Fail early if secret name status is not set
|
||||
fail:
|
||||
msg: "{{ error_msg }}"
|
||||
when: _name is not defined or _name == ''
|
||||
|
||||
- name: Get secret
|
||||
k8s_info:
|
||||
version: v1
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ _name }}"
|
||||
register: _secret
|
||||
|
||||
- name: Set secret data
|
||||
set_fact:
|
||||
_data: "{{ _secret['resources'][0]['data'] }}"
|
||||
|
||||
- name: Create and Add secret names and data to dictionary
|
||||
set_fact:
|
||||
secret_dict: "{{ secret_dict | default({}) | combine({ item: {'name': _name, 'data': _data }}) }}"
|
||||
24
roles/backup/tasks/dump_secret.yml
Normal file
24
roles/backup/tasks/dump_secret.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
|
||||
- name: Get Secret Name
|
||||
set_fact:
|
||||
_name: "{{ awx_spec[item] | default('') }}"
|
||||
|
||||
- name: Skip if secret name not defined
|
||||
block:
|
||||
- name: Get secret
|
||||
k8s_info:
|
||||
version: v1
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ _name }}"
|
||||
register: _secret
|
||||
|
||||
- name: Set secret key
|
||||
set_fact:
|
||||
_data: "{{ _secret['resources'][0]['data'] }}"
|
||||
|
||||
- name: Create and Add secret names and data to dictionary
|
||||
set_fact:
|
||||
secret_dict: "{{ secret_dict | default({}) | combine({item: { 'name': _name, 'data': _data }}) }}"
|
||||
when: _name != ''
|
||||
@@ -30,10 +30,10 @@
|
||||
|
||||
- include_tasks: postgres.yml
|
||||
|
||||
- include_tasks: secrets.yml
|
||||
|
||||
- include_tasks: awx-cro.yml
|
||||
|
||||
- include_tasks: secrets.yml
|
||||
|
||||
- name: Set flag signifying this backup was successful
|
||||
set_fact:
|
||||
backup_complete: true
|
||||
@@ -45,5 +45,3 @@
|
||||
|
||||
- name: Update status variables
|
||||
include_tasks: update_status.yml
|
||||
|
||||
# TODO: backup tower settings or make sure that users only specify settings/config changes via AWX object. See ticket
|
||||
|
||||
@@ -1,65 +1,33 @@
|
||||
---
|
||||
|
||||
- name: Get secret_key
|
||||
k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ this_awx['resources'][0]['status']['secretKeySecret'] }}"
|
||||
register: _secret_key
|
||||
- name: Create Temporary secrets file
|
||||
tempfile:
|
||||
state: file
|
||||
suffix: .json
|
||||
register: tmp_secrets
|
||||
|
||||
- name: Set secret key
|
||||
- name: Dump (generated) secret names from statuses and data into file
|
||||
include_tasks: dump_generated_secret.yml
|
||||
with_items:
|
||||
- secretKeySecret
|
||||
- adminPasswordSecret
|
||||
- broadcastWebsocketSecret
|
||||
- postgresConfigurationSecret
|
||||
|
||||
- name: Dump secret names from awx spec and data into file
|
||||
include_tasks: dump_secret.yml
|
||||
loop:
|
||||
- route_tls_secret
|
||||
- ldap_cacert_secret
|
||||
- image_pull_secret
|
||||
|
||||
- name: Nest secrets under a single variable
|
||||
set_fact:
|
||||
secret_key: "{{ _secret_key['resources'][0]['data']['secret_key'] | b64decode }}"
|
||||
|
||||
- name: Get admin_password
|
||||
k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ this_awx['resources'][0]['status']['adminPasswordSecret'] }}"
|
||||
register: _admin_password
|
||||
|
||||
- name: Set admin_password
|
||||
set_fact:
|
||||
admin_password: "{{ _admin_password['resources'][0]['data']['password'] | b64decode }}"
|
||||
|
||||
- name: Get broadcast_websocket
|
||||
k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ this_awx['resources'][0]['status']['broadcastWebsocketSecret'] }}"
|
||||
register: _broadcast_websocket
|
||||
|
||||
- name: Set broadcast_websocket key
|
||||
set_fact:
|
||||
broadcast_websocket: "{{ _broadcast_websocket['resources'][0]['data']['secret'] | b64decode }}"
|
||||
|
||||
- name: Get postgres configuration
|
||||
k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: "{{ this_awx['resources'][0]['status']['postgresConfigurationSecret'] }}"
|
||||
register: _postgres_configuration
|
||||
|
||||
- name: Set postgres type
|
||||
set_fact:
|
||||
database_type: "{{ _postgres_configuration['resources'][0]['data']['type'] | b64decode }}"
|
||||
when: _postgres_configuration['resources'][0]['data']['type'] is defined
|
||||
|
||||
- name: Set postgres configuration
|
||||
set_fact:
|
||||
database_password: "{{ _postgres_configuration['resources'][0]['data']['password'] | b64decode }}"
|
||||
database_username: "{{ _postgres_configuration['resources'][0]['data']['username'] | b64decode }}"
|
||||
database_name: "{{ _postgres_configuration['resources'][0]['data']['database'] | b64decode }}"
|
||||
database_port: "{{ _postgres_configuration['resources'][0]['data']['port'] | b64decode }}"
|
||||
database_host: "{{ _postgres_configuration['resources'][0]['data']['host'] | b64decode }}"
|
||||
|
||||
- name: Template secrets into yaml
|
||||
set_fact:
|
||||
secrets_file: "{{ lookup('template', 'secrets.yml.j2') }}"
|
||||
secrets: {"secrets": '{{ secret_dict }}'}
|
||||
|
||||
- name: Write postgres configuration to pvc
|
||||
k8s_exec:
|
||||
namespace: "{{ backup_pvc_namespace }}"
|
||||
pod: "{{ meta.name }}-db-management"
|
||||
command: >-
|
||||
bash -c "echo '{{ secrets_file }}' > {{ backup_dir }}/secrets.yml"
|
||||
bash -c "echo '{{ secrets | to_yaml }}' > {{ backup_dir }}/secrets.yml"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
secret_key_secret_name: "{{ _secret_key['resources'][0]['metadata']['name'] }}"
|
||||
admin_password_secret_name: "{{ _admin_password['resources'][0]['metadata']['name'] }}"
|
||||
broadcast_websocket_secret_name: "{{ _broadcast_websocket['resources'][0]['metadata']['name'] }}"
|
||||
postgres_configuration_secret_name: "{{ _postgres_configuration['resources'][0]['metadata']['name'] }}"
|
||||
secret_key: {{ secret_key }}
|
||||
admin_password: {{ admin_password }}
|
||||
broadcast_websocket: {{ broadcast_websocket }}
|
||||
database_password: {{ database_password }}
|
||||
database_username: {{ database_username }}
|
||||
database_name: {{ database_name }}
|
||||
database_port: {{ database_port }}
|
||||
database_host: {{ database_host }}
|
||||
database_type: {{ database_type }}
|
||||
@@ -18,7 +18,19 @@
|
||||
namespace: '{{ meta.namespace }}'
|
||||
ownerReferences: null
|
||||
loop:
|
||||
- '{{ secret_key_secret_name }}'
|
||||
- '{{ admin_password_secret_name }}'
|
||||
- '{{ broadcast_websocket_secret_name }}'
|
||||
- '{{ postgres_configuration_secret_name }}'
|
||||
- '{{ secret_key_secret }}'
|
||||
- '{{ admin_password_secret }}'
|
||||
- '{{ broadcast_websocket_secret }}'
|
||||
- '{{ postgres_configuration_secret }}'
|
||||
|
||||
- name: Cleanup temp spec file
|
||||
file:
|
||||
path: "{{ tmp_spec.path }}"
|
||||
state: absent
|
||||
when: tmp_spec.path is defined
|
||||
|
||||
- name: Cleanup temp secret vars file
|
||||
file:
|
||||
path: "{{ secret_vars.path }}"
|
||||
state: absent
|
||||
when: secret_vars.path is defined
|
||||
|
||||
@@ -31,15 +31,6 @@
|
||||
set_fact:
|
||||
awx_spec: "{{ spec.ansible_facts }}"
|
||||
|
||||
- name: Set names of backed up secrets in the CR spec
|
||||
set_fact:
|
||||
awx_spec: "{{ awx_spec | combine ({ item.key : item.value }) }}"
|
||||
with_items:
|
||||
- {'key': 'secret_key_secret', 'value': '{{ secret_key_secret_name }}'}
|
||||
- {'key': 'admin_password_secret', 'value': '{{ admin_password_secret_name }}'}
|
||||
- {'key': 'broadcast_websocket_secret', 'value': '{{ broadcast_websocket_secret_name }}'}
|
||||
- {'key': 'postgres_configuration_secret', 'value': '{{ postgres_configuration_secret_name }}'}
|
||||
|
||||
- name: Restore kind
|
||||
set_fact:
|
||||
kind: "{{ _kind }}"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ meta.namespace }}'
|
||||
name: '{{ postgres_configuration_secret_name }}'
|
||||
name: '{{ postgres_configuration_secret }}'
|
||||
register: pg_config
|
||||
|
||||
- name: Store Database Configuration
|
||||
|
||||
@@ -6,27 +6,45 @@
|
||||
pod: "{{ meta.name }}-db-management"
|
||||
command: >-
|
||||
bash -c "cat '{{ backup_dir }}/secrets.yml'"
|
||||
register: secrets
|
||||
register: _secrets
|
||||
|
||||
- name: Create temp vars file
|
||||
- name: Create Temporary secrets file
|
||||
tempfile:
|
||||
prefix: secret_vars-
|
||||
register: secret_vars
|
||||
state: file
|
||||
suffix: .json
|
||||
register: tmp_secrets
|
||||
|
||||
- name: Write vars to file locally
|
||||
copy:
|
||||
dest: "{{ secret_vars.path }}"
|
||||
content: "{{ secrets.stdout }}"
|
||||
dest: "{{ tmp_secrets.path }}"
|
||||
content: "{{ _secrets.stdout }}"
|
||||
mode: 0640
|
||||
|
||||
- name: Include secret vars from backup
|
||||
include_vars: "{{ secret_vars.path }}"
|
||||
include_vars: "{{ tmp_secrets.path }}"
|
||||
|
||||
- name: Set new database host based on supplied deployment_name
|
||||
set_fact:
|
||||
database_host: "{{ deployment_name }}-postgres"
|
||||
when:
|
||||
- database_type == 'managed'
|
||||
- name: If deployment is managed, set the database_host in the pg config secret
|
||||
block:
|
||||
- name: Set new database host
|
||||
set_fact:
|
||||
database_host: "{{ deployment_name }}-postgres"
|
||||
|
||||
- name: Set tmp postgres secret dict
|
||||
set_fact:
|
||||
_pg_secret: "{{ secrets['postgresConfigurationSecret'] }}"
|
||||
|
||||
- name: Change postgres host value
|
||||
set_fact:
|
||||
_pg_data: "{{ _pg_secret['data'] | combine({'host': database_host | b64encode }) }}"
|
||||
|
||||
- name: Create a postgres secret with the new host value
|
||||
set_fact:
|
||||
_pg_secret: "{{ _pg_secret | combine({'data': _pg_data}) }}"
|
||||
|
||||
- name: Create a new dict of secrets with the new postgres secret
|
||||
set_fact:
|
||||
secrets: "{{ secrets | combine({'postgresConfigurationSecret': _pg_secret}) }}"
|
||||
when: secrets['postgresConfigurationSecret']['data']['type'] | b64decode == 'managed'
|
||||
|
||||
- name: Apply secret
|
||||
k8s:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Postgres Secret
|
||||
{% for secret in secrets %}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: '{{ postgres_configuration_secret_name }}'
|
||||
name: '{{ secrets[secret]['name'] }}'
|
||||
namespace: '{{ meta.namespace }}'
|
||||
labels:
|
||||
app.kubernetes.io/name: '{{ meta.name }}'
|
||||
@@ -12,57 +12,8 @@ metadata:
|
||||
app.kubernetes.io/component: '{{ deployment_type }}'
|
||||
app.kubernetes.io/operator-version: '{{ lookup("env", "OPERATOR_VERSION") }}'
|
||||
stringData:
|
||||
password: '{{ database_password }}'
|
||||
username: '{{ database_username }}'
|
||||
database: '{{ database_name }}'
|
||||
port: '{{ database_port }}'
|
||||
host: '{{ database_host }}'
|
||||
type: '{{ database_type }}'
|
||||
{% for key, value in secrets[secret]['data'].items() %}
|
||||
'{{ key }}': '{{ value | b64decode }}'
|
||||
{% endfor %}
|
||||
|
||||
# Secret Key Secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: '{{ secret_key_secret_name }}'
|
||||
namespace: '{{ meta.namespace }}'
|
||||
labels:
|
||||
app.kubernetes.io/name: '{{ meta.name }}'
|
||||
app.kubernetes.io/part-of: '{{ meta.name }}'
|
||||
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
|
||||
app.kubernetes.io/component: '{{ deployment_type }}'
|
||||
app.kubernetes.io/operator-version: '{{ lookup("env", "OPERATOR_VERSION") }}'
|
||||
stringData:
|
||||
secret_key: '{{ secret_key }}'
|
||||
|
||||
# Admin Password Secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: '{{ admin_password_secret_name }}'
|
||||
namespace: '{{ meta.namespace }}'
|
||||
labels:
|
||||
app.kubernetes.io/name: '{{ meta.name }}'
|
||||
app.kubernetes.io/part-of: '{{ meta.name }}'
|
||||
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
|
||||
app.kubernetes.io/component: '{{ deployment_type }}'
|
||||
app.kubernetes.io/operator-version: '{{ lookup("env", "OPERATOR_VERSION") }}'
|
||||
stringData:
|
||||
password: '{{ admin_password }}'
|
||||
|
||||
# Broadcast Websocket Secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: '{{ broadcast_websocket_secret_name }}'
|
||||
namespace: '{{ meta.namespace }}'
|
||||
labels:
|
||||
app.kubernetes.io/name: '{{ meta.name }}'
|
||||
app.kubernetes.io/part-of: '{{ meta.name }}'
|
||||
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
|
||||
app.kubernetes.io/component: '{{ deployment_type }}'
|
||||
app.kubernetes.io/operator-version: '{{ lookup("env", "OPERATOR_VERSION") }}'
|
||||
stringData:
|
||||
secret: '{{ broadcast_websocket }}'
|
||||
{% endfor %}
|
||||
|
||||
@@ -8,7 +8,7 @@ backup_api_version: '{{ deployment_type }}.ansible.com/v1beta1'
|
||||
backup_kind: 'AWXBackup'
|
||||
|
||||
# set default secret names to be used if a backup dir and claim are provided (not a backup_name)
|
||||
secret_key_secret_name: '{{ deployment_name }}-secret-key'
|
||||
admin_password_secret_name: '{{ deployment_name }}-admin-password'
|
||||
broadcast_websocket_secret_name: '{{ deployment_name }}-broadcast-websocket'
|
||||
postgres_configuration_secret_name: '{{ deployment_name }}-postgres-configuration'
|
||||
secret_key_secret: '{{ deployment_name }}-secret-key'
|
||||
admin_password_secret: '{{ deployment_name }}-admin-password'
|
||||
broadcast_websocket_secret: '{{ deployment_name }}-broadcast-websocket'
|
||||
postgres_configuration_secret: '{{ deployment_name }}-postgres-configuration'
|
||||
|
||||
Reference in New Issue
Block a user