├── Makefile ├── README.md ├── distribute.yaml ├── group_vars └── all ├── store.yaml └── unseal.yaml /Makefile: -------------------------------------------------------------------------------- 1 | JUMPHOST="" # Host where keys should be placed while being distributed 2 | # Allow additional options to be passed to Ansible 3 | 4 | help: 5 | @echo 'usage: make [target] [options]' 6 | @echo 'options:' 7 | @echo ' IDENTIFIER=meaningful-name' 8 | @echo ' VAULT_HOST=hostname' 9 | @echo 'IT IS IMPORTANT TO READ THE README to fully understand what this is doing.' 10 | @echo 'targets:' 11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 12 | 13 | check-host: 14 | ifndef VAULT_HOST 15 | $(error VAULT_HOST is undefined) 16 | endif 17 | 18 | check-dc: 19 | ifeq (,$(subst "",,$(IDENTIFIER))) 20 | $(error IDENTIFIER is undefined) 21 | endif 22 | 23 | store-key: check-dc ## Pull a key from jumphost and store it in local mac keychain 24 | ansible-playbook $(ANSIBLE_OPTIONS) -i ${JUMPHOST}, -e identifier=$(IDENTIFIER) store.yaml 25 | 26 | unseal: check-host ## Send your unseal key to the Vault API to unseal a host 27 | ansible-playbook $(ANSIBLE_OPTIONS) -e vault_host=$(VAULT_HOST) -e identifier=$(IDENTIFIER) unseal.yaml 28 | 29 | distribute: check-dc ## Send keys to each home directory of keyholders on jumphost 30 | ansible-playbook $(ANSIBLE_OPTIONS) -i ${JUMPHOST}, -e identifier=$(IDENTIFIER) distribute.yaml 31 | 32 | distribute-clean: ## Remove your local copy of keyfile after distribution 33 | rm -rf ./keyfile 34 | 35 | .DEFAULT_GOAL := help 36 | .PHONY: help 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vault-unseal 2 | 3 | Playbooks for managing the Vault keys in your MacOS keychain. These playbooks allow for the distribution, storage, and transmission of Hashicorp Vault keys. 4 | 5 | 6 | # Requirements 7 | - Current Ansible version installed from pip or brew in your path. 8 | 9 | `brew install ansible` 10 | 11 | - Make (should be present by default on MacOS) 12 | 13 | # Usage 14 | 15 | After initializing Vault, five keys are provided and these playbooks provide a method of distributing those keys to individual keyholders and a method for those keyholders to transmit their keys to the Vault API for unsealing. 16 | 17 | It is important in all the steps below to specify a unique name using the IDENTIFIER var. 18 | 19 | ## Distribution 20 | 21 | After Vault is initialized five (5) unseal keys are displayed on the console. These 5 keys should be copied into a file called `keyfile` in this directory. The format of `keyfile` is one key per line. 22 | 23 | After this file is in place, you can run: 24 | 25 | `make distribute IDENTIFIER=your_unique_name` 26 | 27 | This will iterate over the key holders defined in `group_vars/all` and copy one key to the each user's home directory on the jumphost. This process should be done with all key holders available to receive the keys ASAP as we don't want these keys to persist any longer than is needed. 28 | 29 | NOTE: the number of key holders MUST match the number of keys in the `keyfile` 30 | 31 | ## Storing Key 32 | 33 | The key holders then run the following command to retrieve the key from the jumphost and store it in their MacOS keychain: 34 | 35 | `make store-key IDENTIFIER=your_unique_name` 36 | 37 | This stores the key in their MacOS keychain, validates what was stored matches what was distributed, then removes their key from the jumphost. 38 | 39 | ## Delete Keys 40 | 41 | Once it has been confirmed that all keyholders have retrieved their keys, run the following command to delete the `keyfile`: 42 | 43 | `make distribute-clean` 44 | 45 | ## Unseal Vault 46 | 47 | To issue your unseal key to vault: 48 | 49 | ``` 50 | make unseal VAULT_HOST=FQDN_of_vault_instance 51 | ``` 52 | 53 | Replace the hostname with the one you want to unseal. This should parse the hostname to determine which key to send, then make the unseal api call. 54 | 55 | -------------------------------------------------------------------------------- /distribute.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: true 4 | gather_facts: false 5 | 6 | tasks: 7 | - name: Send Keys to Jumphost 8 | copy: 9 | content: "{{ item.1 }}" 10 | dest: "/home/{{ item.0 }}/{{ identifier }}.vaultkey" 11 | owner: "{{ item.0 }}" 12 | mode: 0400 13 | with_together: 14 | - "{{ keyholders }}" 15 | - "{{ keys }}" 16 | -------------------------------------------------------------------------------- /group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | user: "{{ lookup('env','LOGNAME') }}" 3 | store: false 4 | unseal: false 5 | vault_host: "" 6 | # identifer is a unique name to identify the key in keychain 7 | identifier: "test" 8 | # keyholders is list of users who will be recieving keys should be the same number of unseal keys created 9 | keyholders: 10 | - example_user1 11 | - example_user2 12 | - example_user3 13 | - exmaple_user4 14 | - example_user5 15 | keys: "{{ lookup('file', 'keyfile').splitlines() }}" 16 | -------------------------------------------------------------------------------- /store.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: false 4 | gather_facts: false 5 | 6 | tasks: 7 | - name: Pull Key From Jumphost 8 | slurp: 9 | src: "/home/{{ user }}/{{ identifier }}.vaultkey" 10 | register: unseal_key 11 | 12 | - name: Store Keys in MacOS Keychain 13 | shell: "/usr/bin/security add-generic-password -s vault_{{ identifier }} -w {{ unseal_key['content'] | b64decode }} -a {{ user }} -U" 14 | delegate_to: localhost 15 | 16 | - name: Validate Key Stored Correctly 17 | shell: "/usr/bin/security find-generic-password -s vault_{{ identifier }} -a {{ user }} -w" 18 | register: local_unseal_key 19 | failed_when: local_unseal_key.stdout != unseal_key['content'] | b64decode 20 | delegate_to: localhost 21 | 22 | - name: Remove Key from Jumphost 23 | file: 24 | path: "/home/{{ user }}/{{ identifier }}.vaultkey" 25 | state: absent 26 | 27 | -------------------------------------------------------------------------------- /unseal.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | become: false 4 | gather_facts: false 5 | 6 | tasks: 7 | 8 | - name: Get Key from MacOS Keychain 9 | command: "/usr/bin/security find-generic-password -s vault_{{ identifier }} -a {{ user }} -w" 10 | register: unseal_key 11 | 12 | - name: Send Unseal Key 13 | uri: 14 | url: "https://{{ vault_host }}:8200/v1/sys/unseal" 15 | method: PUT 16 | body_format: json 17 | status_code: 200 18 | body: 19 | key: "{{ unseal_key.stdout }}" 20 | --------------------------------------------------------------------------------