Skip to content

Commit 531d824

Browse files
authored
Merge pull request #67 from stackhpc/add-openbao
feat: add `openbao` role
2 parents 6b54a84 + 675d4b6 commit 531d824

File tree

10 files changed

+442
-2
lines changed

10 files changed

+442
-2
lines changed

.github/workflows/pull_request.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ jobs:
2222
exclude:
2323
- python_version: "3.9"
2424
ansible_version: "2.18"
25+
type:
26+
- openbao
27+
- vault
2528
steps:
2629
- name: Github Checkout 🛎
2730
uses: actions/checkout@v4
@@ -42,4 +45,4 @@ jobs:
4245
4346
- name: Run integration tests 🧪
4447
run: |
45-
ansible-playbook -i tests/inventory -v tests/*.yml -e ansible_python_interpreter=$(which python3)
48+
ansible-playbook -i tests/inventory -v tests/test_${{ matrix.type }}.yml -e ansible_python_interpreter=$(which python3)

galaxy.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace: stackhpc
22
name: hashicorp
33
description: >
44
Hashicorp Vault/Consul deployment and configuration
5-
version: "2.5.1"
5+
version: "2.6.0"
66
readme: "README.md"
77
authors:
88
- "Michał Nasiadka"
@@ -11,6 +11,7 @@ authors:
1111
- "Pierre Riteau"
1212
- "Bartosz Bezak"
1313
- "Kyle Dean"
14+
- "Jack Hodgkiss"
1415
dependencies:
1516
"community.docker": "*"
1617
license:
@@ -21,4 +22,5 @@ tags:
2122
- infrastructure
2223
- security
2324
- vault
25+
- openbao
2426
repository: "https://github.com/stackhpc/ansible-collection-hashicorp"

roles/openbao/README.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
This role deploys and initializes OpenBao with a Raft backend.
2+
3+
Requirements
4+
------------
5+
6+
`ansible-modules-hashivault` Python package installed on the Ansible control host
7+
`hvac` Python package installed on the remote hosts
8+
9+
Note that since version `4.6.4`, `ansible-modules-hashivault` requires
10+
`ansible>4`.
11+
12+
Role variables
13+
--------------
14+
15+
* Common variables
16+
* Optional
17+
* `openbao_registry_url`: Address of the Docker registry used to authenticate (default: "")
18+
* `openbao_registry_username`: Username used to authenticate with the Docker registry (default: "")
19+
* `openbao_registry_password`: Password used to authenticate with the Docker registry (default: "")
20+
21+
* OpenBao
22+
* Mandatory
23+
* `openbao_cluster_name`: OpenBao cluster name (e.g. "prod_cluster")
24+
* `openbao_config_dir`: Directory into which to bind mount OpenBao configuration
25+
* Optional
26+
* `openbao_bind_address`: Which IP address should OpenBao bind to (default: "127.0.0.1")
27+
* `openbao_api_addr`: OpenBao [API addr](https://openbao.org/docs/configuration/#high-availability-parameters) - Full URL including protocol and port (default: "http://127.0.0.1:8200")
28+
* `openbao_init_addr`: OpenBao init addr (used only for initialisation purposes) - full URL including protocol and port (default: "http://127.0.0.1:8200")
29+
* `openbao_docker_name`: Docker - under which name to run the OpenBao image (default: "bao")
30+
* `openbao_docker_image`: Docker image for OpenBao (default: "openbao/openbao")
31+
* `openbao_docker_tag`: Docker image tag for OpenBao (default: "latest")
32+
* `openbao_extra_volumes`: List of `"<host_location>:<container_mountpoint>"`
33+
* `openbao_ca_cert`: Path to CA certificate used to verify OpenBao server TLS cert
34+
* `openbao_tls_key`: Path to TLS key to use by OpenBao
35+
* `openbao_tls_cert`: Path to TLS cert to use by OpenBao
36+
* `openbao_log_keys`: Whether to log the root token and unseal keys in the Ansible output. Default `false`
37+
* `openbao_set_keys_fact`: Whether to set a `openbao_keys` fact containing the root token and unseal keys. Default `false`
38+
* `openbao_write_keys_file`: Whether to write the root token and unseal keys to a file. Default `false`
39+
* `openbao_write_keys_file_host`: Host on which to write root token and unseal keys. Default `localhost`
40+
* `openbao_write_keys_file_path`: Path of file to write root token and unseal keys. Default `bao-keys.json`
41+
42+
Root and unseal keys
43+
--------------------
44+
45+
After OpenBao has been initialised, a root token and a set of unseal keys are emitted.
46+
It is very important to store these keys safely and securely.
47+
This role provides several mechanisms for extracting the root token and unseal keys:
48+
49+
1. Print to Ansible log output (`openbao_log_keys`)
50+
1. Set a `openbao_keys` fact (`openbao_set_keys_fact`)
51+
1. Write to a file (`openbao_write_keys_file`)
52+
53+
In each case, the output will contain the following:
54+
55+
```json
56+
{
57+
"keys": [
58+
"...",
59+
"..."
60+
],
61+
"keys_base64": [
62+
"...",
63+
"..."
64+
],
65+
"root_token": "..."
66+
}
67+
```
68+
69+
Example playbook (used with OpenStack Kayobe)
70+
---------------------------------------------
71+
72+
```
73+
---
74+
- name: Prepare for OpenBao role
75+
any_errors_fatal: True
76+
gather_facts: True
77+
hosts: consul
78+
tasks:
79+
- name: Ensure /opt/kayobe/bao exists
80+
file:
81+
path: /opt/kayobe/bao
82+
state: directory
83+
84+
- name: Template out tls key and cert
85+
vars:
86+
tls_files:
87+
- content: "{{ secrets_external_tls_cert }}"
88+
dest: "tls.cert"
89+
- content: "{{ secrets_external_tls_key }}"
90+
dest: "tls.key"
91+
copy:
92+
content: "{{ item.content }}"
93+
dest: "/opt/kayobe/bao/{{ item.dest }}"
94+
owner: 100
95+
group: 1001
96+
mode: 0600
97+
loop: "{{ tls_files }}"
98+
no_log: True
99+
become: true
100+
101+
- name: Run OpenBao role
102+
any_errors_fatal: True
103+
gather_facts: True
104+
hosts: consul
105+
roles:
106+
- role: stackhpc.hashicorp.openbao
107+
openbao_bind_address: "{{ external_net_ips[inventory_hostname] }}"
108+
openbao_api_addr: "https://{{ external_net_fqdn }}:8200"
109+
openbao_config_dir: "/opt/kayobe/bao"
110+
```
111+
112+
Example post-config playbook to enable secrets engines:
113+
```
114+
---
115+
- name: OpenBao post deployment config
116+
any_errors_fatal: True
117+
gather_facts: True
118+
hosts: bao
119+
tasks:
120+
- name: Enable bao secrets engines
121+
hashivault_secret_engine:
122+
url: "https://vault.example.com:8200"
123+
token: "{{ secrets_openbao_keys.root_token }}"
124+
name: pki
125+
backend: pki
126+
run_once: True
127+
```
128+
129+
NOTE: secrets_external_tls_cert/key are variables in Kayobe's secrets.yml

roles/openbao/defaults/main.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
openbao_registry_url: ""
3+
openbao_registry_username: ""
4+
openbao_registry_password: ""
5+
6+
openbao_docker_name: "bao"
7+
openbao_docker_image: "openbao/openbao"
8+
openbao_docker_tag: "latest"
9+
10+
openbao_cluster_name: ""
11+
openbao_protocol: "{{ 'https' if openbao_tls_key and openbao_tls_cert else 'http' }}"
12+
# Allow openbao_vip_url and openbao_vip_address for backwards compatibility.
13+
openbao_vip_address: "{{ openbao_vip_url | default(openbao_bind_address) }}"
14+
openbao_api_addr: "{{ openbao_protocol ~ '://' ~ openbao_vip_address ~ ':8200' }}"
15+
openbao_bind_address: "127.0.0.1"
16+
openbao_init_addr: "http://127.0.0.1:8200"
17+
openbao_tls_key: ""
18+
openbao_tls_cert: ""
19+
20+
openbao_config_dir: ""
21+
22+
openbao_config: >
23+
{
24+
"cluster_name": "{{ openbao_cluster_name }}",
25+
"ui": false,
26+
"api_addr": "{{ openbao_api_addr }}",
27+
"cluster_addr": "http://127.0.0.1:8201",
28+
"listener": [{
29+
"tcp": {
30+
"address": "{{ openbao_bind_address }}:8200",
31+
{% if openbao_tls_key and openbao_tls_cert %}
32+
"tls_min_version": "tls12",
33+
"tls_key_file": "/bao/config/{{ openbao_tls_key }}",
34+
"tls_cert_file": "/bao/config/{{ openbao_tls_cert }}"
35+
{% else %}
36+
"tls_disable": "true"
37+
{% endif %}
38+
}{% if openbao_bind_address != '127.0.0.1' %},
39+
},
40+
{
41+
"tcp": {
42+
"address": "127.0.0.1:8200",
43+
"tls_disable": "true"
44+
}
45+
{% endif %}
46+
}],
47+
"storage": {
48+
"raft": {
49+
"node_id": "raft_{{ ansible_facts.nodename }}",
50+
"path": "/openbao/file"
51+
}
52+
},
53+
"telemetry": {
54+
"prometheus_retention_time": "30s",
55+
"disable_hostname": true
56+
}
57+
}
58+
59+
# Docker options
60+
openbao_container: {}
61+
62+
# Docker volumes
63+
# Default volume mapping
64+
_openbao_default_volumes:
65+
- "{{ openbao_config_dir | default('openbao_config', true) }}:/openbao/config"
66+
- "openbao_file:/openbao/file"
67+
- "openbao_logs:/openbao/logs"
68+
69+
# Exposed for playbooks to access later
70+
openbao_extra_volumes: []
71+
72+
# Combined volume lists
73+
_openbao_volumes: "{{ _openbao_default_volumes + openbao_extra_volumes }}"
74+
75+
# Whether to log the root token and unseal keys in the Ansible output.
76+
openbao_log_keys: false
77+
78+
# Whether to set a openbao_keys fact containing the root token and unseal keys.
79+
openbao_set_keys_fact: false
80+
81+
# Whether to write the root token and unseal keys to a file.
82+
openbao_write_keys_file: false
83+
# Host on which to write root token and unseal keys.
84+
openbao_write_keys_file_host: localhost
85+
# Path of file to write root token and unseal keys.
86+
openbao_write_keys_file_path: bao-keys.json

roles/openbao/meta/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
# WORKAROUND: Without this, we see the following in some setups:
3+
# ERROR! couldn't resolve module/action 'hashivault_unseal'. This often indicates a misspelling, missing collection, or incorrect module path.
4+
# Seen using Kayobe on Ansible 2.10.17, running modules on a remote host.
5+
collections:
6+
- community.docker

roles/openbao/tasks/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
- name: "Vault Prerequisites"
3+
import_tasks: prereqs.yml
4+
5+
- name: "Deploy OpenBao"
6+
import_tasks: openbao.yml

roles/openbao/tasks/openbao.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
- name: Ensure OpenBao container is running
3+
docker_container:
4+
name: "{{ openbao_docker_name }}"
5+
image: "{{ openbao_docker_image }}:{{ openbao_docker_tag }}"
6+
network_mode: host
7+
etc_hosts: "{{ openbao_container.etc_hosts | default(omit) }}"
8+
capabilities: IPC_LOCK
9+
volumes: "{{ _openbao_volumes }}"
10+
comparisons:
11+
'*': strict
12+
restart_policy: "always"
13+
env:
14+
BAO_LOCAL_CONFIG: "{{ openbao_config | to_json }}"
15+
command: >
16+
server
17+
become: true
18+
19+
- name: Check if OpenBao is initialized
20+
uri:
21+
url: "{{ openbao_init_addr }}/v1/sys/init"
22+
register: openbao_init_status
23+
retries: 50
24+
delay: 1
25+
run_once: true
26+
until: openbao_init_status.status == 200
27+
28+
- name: "Initialize OpenBao"
29+
run_once: true
30+
when:
31+
- not openbao_init_status.json.initialized
32+
block:
33+
- name: Initialize OpenBao
34+
hashivault_init:
35+
url: "{{ openbao_init_addr }}"
36+
ca_cert: "{{ openbao_ca_cert | default(omit) }}"
37+
no_log: true
38+
register: openbao_keys_result
39+
40+
- name: Print OpenBao keys
41+
debug:
42+
var: openbao_keys_result
43+
when:
44+
- openbao_log_keys | bool
45+
46+
- name: Set openbao_keys fact
47+
set_fact:
48+
openbao_keys: "{{ openbao_keys_result }}"
49+
when:
50+
- openbao_set_keys_fact | bool
51+
52+
- name: Write OpenBao keys to a file
53+
copy:
54+
content: "{{ openbao_keys_result | to_nice_json }}"
55+
dest: "{{ openbao_write_keys_file_path }}"
56+
mode: "0600"
57+
delegate_to: "{{ openbao_write_keys_file_host }}"
58+
when:
59+
- openbao_write_keys_file | bool

roles/openbao/tasks/prereqs.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
- name: Log into Docker registry
3+
docker_login:
4+
registry: "{{ openbao_registry_url }}"
5+
username: "{{ openbao_registry_username }}"
6+
password: "{{ openbao_registry_password }}"
7+
when: openbao_registry_username | length > 0
8+
become: true

tests/inventory

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[consul]
22
localhost ansible_connection=local
3+
4+
[openbao]
5+
localhost ansible_connection=local

0 commit comments

Comments
 (0)