diff --git a/README.md b/README.md index ad4ee47..3b423d6 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,24 @@ pip install hvac ## Vars -* For Vault access copy [ansible/roles/20-common-20-ssh/defaults/main.yml.example](ansible/roles/20-common-20-ssh/defaults/main.yml.example) to a proper `ansible/roles/20-common-20-ssh/defaults/main.yml` and set Vault credentials and locations as needed. +* For default variables copy [ansible/roles/20-common-20-ssh/defaults/main.yml.example](ansible/roles/20-common-20-ssh/defaults/main.yml.example) to a proper `ansible/roles/20-common-20-ssh/defaults/main.yml`, adjust as needed. -* Create your inventory, copy [ansible/hosts.yml.example](ansible/hosts.yml.example) into a proper `ansible/hosts.yml` file with at least one host in host group `all`. +* Create your inventory, copy [ansible/hosts.yml.example](ansible/hosts.yml.example) to a proper `ansible/hosts.yml` file with at least one host in host group `all`. -* Replace [ansible/group_vars/all/vars.yml.example](ansible/group_vars/all/vars.yml.example) with a proper `ansible/group_vars/all/vars.yml` file and set at least `ansible_user`. It defaults to `ansible_user: 'root'`. +* Replace [ansible/group_vars/all/vars.yml.example](ansible/group_vars/all/vars.yml.example) with a proper `ansible/group_vars/all/vars.yml` file and set at least `ansible_user` and Vault access variables. * In [ansible/roles/20-common-20-ssh/files/root/.ssh](ansible/roles/20-common-20-ssh/files/root/.ssh) copy both [authorized_keys.example](ansible/roles/20-common-20-ssh/files/root/.ssh/authorized_keys.example) and [known_hosts.example](ansible/roles/20-common-20-ssh/files/root/.ssh/known_hosts.example) to proper files. They contain SSH authorized_keys and public SSH host keys you want installed on target machines. +## Vault structure + +In Vault we're assuming that every host in your inventory has a secret stored that contains at least the following keys: + +* `initial_password`: The operating system's local account password at machine creation. Ansible will use this to SSH into the machine during `first_run`, see section [Run it](#run-it) below. +* `password`: The new password you want to set for the operating system's local account. +* `password_salt`: The salt you're going to use. We're hashing the password with SHA-512, the salt is a string of up to 16 characters length. + +For an example server `fully.qualified.domain.name` and example user `root` Vault secrets are located at `name/domain/qualified/fully/os/root/creds`. Per [ansible/group_vars/all/vars.yml.example](ansible/group_vars/all/vars.yml.example) the default secrets engine mount point is `kv` where this playbook expects a kv secrets engine. + ## Run it On first run execute it like so: diff --git a/ansible/group_vars/all/vars.yml.example b/ansible/group_vars/all/vars.yml.example index 13b092a..1dc327b 100644 --- a/ansible/group_vars/all/vars.yml.example +++ b/ansible/group_vars/all/vars.yml.example @@ -1 +1,6 @@ ansible_user: 'root' +ansible_hashi_vault_auth_method: 'token' +ansible_hashi_vault_token: 'hvs.xxxxxxxxxx' +ansible_hashi_vault_engine_mount_point: 'kv' +ansible_hashi_vault_token_validate: 'false' +ansible_hashi_vault_url: 'http://localhost:8200/' diff --git a/ansible/host_vars/mail-1.core.cliff.airlo.cc.yml b/ansible/host_vars/mail-1.core.cliff.airlo.cc.yml new file mode 100644 index 0000000..a6ffeb5 --- /dev/null +++ b/ansible/host_vars/mail-1.core.cliff.airlo.cc.yml @@ -0,0 +1 @@ +reset_password_for_account: 'root' diff --git a/ansible/playbook.yml b/ansible/playbook.yml index a35069d..0008efe 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -1,4 +1,5 @@ - name: 'Set up SSH' hosts: all roles: - - role: 20-common-20-ssh + - '20-common-20-ssh' + - '20-common-20-change-local-account-password' diff --git a/ansible/roles/10-include-40-check-if-vault-var/tasks/40-check-vault-var.yml b/ansible/roles/10-include-40-check-if-vault-var/tasks/40-check-vault-var.yml new file mode 100644 index 0000000..d7cbd4a --- /dev/null +++ b/ansible/roles/10-include-40-check-if-vault-var/tasks/40-check-vault-var.yml @@ -0,0 +1,7 @@ +- name: 'If a secret is missing fail progress' + failed_when: inc_fail_check not in inc_vault_data + loop_control: + loop_var: 'inc_fail_check' + loop: '{{ fail_check }}' + debug: + msg: 'Vault has {% if inc_fail_check not in inc_vault_data %}no {% endif %}secret ''{{ inc_fail_check }}'' at ''os/{{ reset_password_for_account }}/creds''' diff --git a/ansible/roles/10-include-40-check-if-vault-var/tasks/main.yml b/ansible/roles/10-include-40-check-if-vault-var/tasks/main.yml new file mode 100644 index 0000000..d088ac2 --- /dev/null +++ b/ansible/roles/10-include-40-check-if-vault-var/tasks/main.yml @@ -0,0 +1 @@ +- import_tasks: '40-check-vault-var.yml' diff --git a/ansible/roles/20-common-20-change-local-account-password/tasks/40-change-password-generic.yml b/ansible/roles/20-common-20-change-local-account-password/tasks/40-change-password-generic.yml new file mode 100644 index 0000000..107bf1f --- /dev/null +++ b/ansible/roles/20-common-20-change-local-account-password/tasks/40-change-password-generic.yml @@ -0,0 +1,35 @@ +- name: 'Get secrets' + no_log: 'true' + loop_control: + loop_var: 'server' + with_community.hashi_vault.vault_kv2_get: + - '{{ inventory_hostname | split(".") | reverse | join("/") }}/os/{{ reset_password_for_account }}/creds' + ansible.builtin.set_fact: + vault_data: '{{ server.secret }}' + + + +- name: 'If a secret is missing fail progress' + include_role: + name: '10-include-40-check-if-vault-var' + vars: + - inc_vault_data: '{{ vault_data }}' + - fail_check: + - 'password' + - 'password_salt' + + + +- name: 'Set fact new OS local account password' + no_log: 'true' + ansible.builtin.set_fact: + os_acc_pwd: '{{ vault_data.password }}' + os_acc_salt: '{{ vault_data.password_salt }}' + + + +- name: 'Set local OS account password' + ansible.builtin.user: + name: '{{ reset_password_for_account }}' + password: '{{ os_acc_pwd | string | password_hash(''sha512'', os_acc_salt) }}' + update_password: 'always' diff --git a/ansible/roles/20-common-20-change-local-account-password/tasks/main.yml b/ansible/roles/20-common-20-change-local-account-password/tasks/main.yml index e69de29..659eda5 100644 --- a/ansible/roles/20-common-20-change-local-account-password/tasks/main.yml +++ b/ansible/roles/20-common-20-change-local-account-password/tasks/main.yml @@ -0,0 +1 @@ +- import_tasks: '40-change-password-generic.yml' diff --git a/ansible/roles/20-common-20-ssh/defaults/main.yml.example b/ansible/roles/20-common-20-ssh/defaults/main.yml.example index b9e710f..0b7fd8c 100644 --- a/ansible/roles/20-common-20-ssh/defaults/main.yml.example +++ b/ansible/roles/20-common-20-ssh/defaults/main.yml.example @@ -1,6 +1 @@ root_home_dir_abs: '/root' -ansible_hashi_vault_auth_method: 'token' -ansible_hashi_vault_token: 'hvs.xxxxxxxxxx' -ansible_hashi_vault_engine_mount_point: 'kv' -ansible_hashi_vault_token_validate: 'false' -ansible_hashi_vault_url: 'http://localhost:8200/' diff --git a/ansible/roles/20-common-20-ssh/tasks/20-ssh.yml b/ansible/roles/20-common-20-ssh/tasks/20-ssh.yml index 01e9689..1fa960f 100644 --- a/ansible/roles/20-common-20-ssh/tasks/20-ssh.yml +++ b/ansible/roles/20-common-20-ssh/tasks/20-ssh.yml @@ -3,12 +3,25 @@ loop_control: loop_var: 'server' with_community.hashi_vault.vault_kv2_get: - - '{{ inventory_hostname | split(".") | reverse | join("/") }}/os/root/creds' + - '{{ inventory_hostname | split(".") | reverse | join("/") }}/os/{{ reset_password_for_account }}/creds' ansible.builtin.set_fact: vault_data: '{{ server.secret }}' +- name: 'If a secret is missing fail progress' + tags: + - 'first_run' + - 'never' + include_role: + name: '10-include-40-check-if-vault-var' + vars: + - inc_vault_data: '{{ vault_data }}' + - fail_check: + - 'initial_password' + + + - name: 'If first run: set SSH password' tags: - 'first_run'