Skip to content

Commit ac9381b

Browse files
committed
Initial commit
0 parents  commit ac9381b

File tree

8 files changed

+265
-0
lines changed

8 files changed

+265
-0
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# StackHPC pulp collection
2+
3+
This repo contains `stackhpc.hashicorp` Ansible Collection. The collection includes roles supported by StackHPC for Hashicorp Vault/Consul deployment and configuration.
4+
5+
## Tested with Ansible
6+
7+
Tested with the current Ansible 2.9-2.10 releases.
8+
9+
## Included content
10+
11+
* `vault` role
12+
13+
## Using this collection
14+
15+
Before using the collection, you need to install the collection with the `ansible-galaxy` CLI:
16+
17+
ansible-galaxy collection install stackhpc.hashicorp
18+
19+
You can also include it in a `requirements.yml` file and install it via ansible-galaxy collection install -r requirements.yml` using format:
20+
21+
```yaml
22+
collections:
23+
- name: stackhpc.hashicorp
24+
```
25+
26+
See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
27+
28+
## More information
29+
30+
- [Ansible Collection overview](https://github.com/ansible-collections/overview)
31+
- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
32+
- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
33+
- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
34+
35+
## Licensing
36+
37+
Apache License Version 2.0

galaxy.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace: "stackhpc"
2+
name: "hashicorp"
3+
version: "1.0.0"
4+
readme: "README.md"
5+
authors:
6+
- "Michał Nasiadka"
7+
license:
8+
- "Apache-2.0"
9+
tags:
10+
- hashicorp
11+
- vault
12+
- consul
13+
repository: "https://github.com/stackhpc/ansible-collection-hashicorp"

roles/vault/README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
This role deploys and initializes Hashicorp Vault with Consul backend
2+
3+
Role variables
4+
--------------
5+
6+
* Consul
7+
* Mandatory
8+
* `consul_bind_interface`: Which interface should be used for Consul
9+
* `consul_vip_address`: Under which IP address consul should be available (this role does not deploy keepalived)
10+
* Optional
11+
* `consul_docker_name`: Docker - under which name to run the Consul image (default: "consul")
12+
* `consul_docker_image`: Docker image for Consul (default: "consul")
13+
* `consul_docker_tag`: Docker image tag for Consul (default: "latest")
14+
* `consul_docker_volume`: Docker volume name for Consul data (default: "consul_data")
15+
* Vault
16+
* Mandatory
17+
* `vault_cluster_name`: Vault cluster name (e.g. "prod_cluster")
18+
* `vault_tls_key`: Path to TLS key to use by Vault
19+
* `vault_tls_cert`: Path to TLS cert to use by Vault
20+
21+
22+
Example playbook (used with OpenStack Kayobe)
23+
---------------------------------------------
24+
25+
```
26+
---
27+
- name: Prepare for hashicorp-vault role
28+
any_errors_fatal: True
29+
gather_facts: True
30+
hosts: consul
31+
tasks:
32+
- name: Ensure /opt/kayobe/vault exists
33+
file:
34+
state: present
35+
path: /opt/kayobe/vault
36+
state: directory
37+
38+
- name: Template out tls key and cert
39+
vars:
40+
tls_files:
41+
- content: "{{ secrets_external_tls_cert }}"
42+
dest: "tls.cert"
43+
- content: "{{ secrets_external_tls_key }}"
44+
dest: "tls.key"
45+
copy:
46+
content: "{{ item.content }}"
47+
dest: "/opt/kayobe/vault/{{ item.dest }}"
48+
owner: 100
49+
group: 1001
50+
mode: 0600
51+
loop: "{{ tls_files }}"
52+
no_log: True
53+
become: true
54+
55+
- name: Run hashicorp-vault role
56+
any_errors_fatal: True
57+
gather_facts: True
58+
hosts: consul
59+
roles:
60+
- role: stackhpc.hashicorp.vault
61+
consul_bind_interface: "{{ internal_net_interface }}"
62+
consul_bind_ip: "{{ internal_net_ips[ansible_hostnanme] }}"
63+
consul_vip_address: "{{ internal_net_vip_address }}"
64+
vault_bind_address: "{{ external_net_ips[ansible_hostname] }}"
65+
vault_vip_url: "{{ external_net_fqdn }}"
66+
vault_config_dir: "/opt/kayobe/vault"
67+
```
68+
69+
Example post-config playbook to enable secrets engines:
70+
```
71+
---
72+
- name: Vault post deployment config
73+
any_errors_fatal: True
74+
gather_facts: True
75+
hosts: vault
76+
tasks:
77+
- name: Enable vault secrets engines
78+
hashivault_secret_engine:
79+
url: "https://sparrow.cf.ac.uk:8200"
80+
token: "{{ secrets_vault_keys.root_token }}"
81+
name: pki
82+
backend: pki
83+
run_once: True
84+
```
85+
86+
Example vault unseal playbook based on Kayobe's secrets.yml
87+
```
88+
---
89+
- name: Unseal vault
90+
any_errors_fatal: True
91+
gather_facts: True
92+
hosts: vault
93+
tasks:
94+
- name: Unseal vault
95+
hashivault_unseal:
96+
url: "https://sparrow.cf.ac.uk:8200"
97+
keys: "{{ item }}"
98+
run_once: True
99+
with_items: "{{ secrets_vault_keys.unseal_keys_b64 }}"
100+
no_log: True
101+
```
102+
103+
NOTE: secrets_external_tls_cert/key are variables in Kayobe's secrets.yml

roles/vault/defaults/main.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
consul_docker_name: "consul"
3+
consul_docker_image: "consul"
4+
consul_docker_tag: "latest"
5+
consul_docker_volume: "consul_data"
6+
7+
vault_docker_name: "vault"
8+
vault_docker_image: "vault"
9+
vault_docker_tag: "latest"
10+
11+
vault_cluster_name: ""
12+
vault_tls_key: ""
13+
vault_tls_cert: ""
14+
15+
vault_config: >
16+
{
17+
"cluster_name": "{{ vault_cluster_name }}",
18+
"ui": true,
19+
"api_addr": "https://{{ vault_vip_url }}:8200",
20+
"listener": [{
21+
"tcp": {
22+
"address": "{{ vault_bind_address }}:8200",
23+
"tls_min_version": "tls12",
24+
"tls_key_file": "/vault/config/tls.key",
25+
"tls_cert_file": "/vault/config/tls.cert"
26+
}
27+
}],
28+
"storage": {
29+
"consul": {
30+
"address": "127.0.0.1:8500",
31+
"path": "vault/"
32+
}
33+
},
34+
"telemetry": {
35+
"prometheus_retention_time": "30s",
36+
"disable_hostname": true
37+
}
38+
}
39+
40+
consul_bind_interface: ""
41+
consul_bind_ip: "{{ hostvars[inventory_hostname]['ansible_'~consul_bind_interface].ipv4.address }}"
42+
consul_vip_address: ""

roles/vault/tasks/consul.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
- name: Ensure consul_server container is running
3+
docker_container:
4+
name: "{{ consul_docker_name }}"
5+
image: "{{ consul_docker_image }}:{{ consul_docker_tag }}"
6+
network_mode: host
7+
volumes:
8+
- "{{ consul_docker_volume }}:/consul/data"
9+
comparisons:
10+
'*': strict
11+
env:
12+
CONSUL_BIND_INTERFACE: "{{ consul_bind_interface }}"
13+
CONSUL_CLIENT_INTERFACE: "{{ consul_bind_interface }}"
14+
command: >
15+
consul agent
16+
-bind "{{ hostvars[inventory_hostname]['ansible_'~consul_bind_interface].ipv4.address }}"
17+
-data-dir /consul/data
18+
-server
19+
-bootstrap-expect "{{ groups['consul'] | length }}"
20+
{% for host in groups['consul'] %}
21+
{% if host != inventory_hostname %}
22+
-retry-join "{{ hostvars[host]['ansible_'~consul_bind_interface].ipv4.address }}"
23+
{% endif %}
24+
{% endfor %}
25+
become: True

roles/vault/tasks/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
- import_tasks: prechecks.yml
3+
- import_tasks: consul.yml
4+
- import_tasks: vault.yml

roles/vault/tasks/prechecks.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
- name: Check if consul_bind_interface is defined
3+
fail:
4+
msg: "ERROR: consul_bind_interface must be defined"
5+
when: not consul_bind_interface

roles/vault/tasks/vault.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
- name: Ensure vault container is running
3+
docker_container:
4+
name: "{{ vault_docker_name }}"
5+
image: "{{ vault_docker_image }}:{{ vault_docker_tag }}"
6+
network_mode: host
7+
capabilities: IPC_LOCK
8+
volumes:
9+
- "{{ vault_config_dir }}:/vault/config"
10+
comparisons:
11+
'*': strict
12+
env:
13+
VAULT_LOCAL_CONFIG: "{{ vault_config | to_json }}"
14+
command: >
15+
server
16+
become: True
17+
18+
- name: Check if vault is initialized
19+
uri:
20+
url: "https://{{ vault_vip_url }}:8200/v1/sys/init"
21+
register: vault_init_status
22+
retries: 10
23+
24+
- name: Initialize vault
25+
command: "docker exec -e 'VAULT_ADDR=https://{{ vault_vip_url }}:8200' {{ vault_docker_name }} vault operator init -format yaml"
26+
when: not vault_init_status.json.initialized
27+
run_once: True
28+
register: vault_init_output
29+
30+
- name: Set fact
31+
set_fact:
32+
vault_keys: "{{ vault_init_output.stdout | from_yaml }}"
33+
34+
- name: Print vault keys
35+
debug:
36+
var: vault_keys

0 commit comments

Comments
 (0)