Skip to content

Commit 57bfa82

Browse files
mnasiadkabbezakmarkgoddard
authored
Vault PKI (#539)
Add Vault PKI and Barbican docs/playbooks Co-authored-by: Bartosz Bezak <[email protected]> Co-authored-by: Mark Goddard <[email protected]>
1 parent 7df8b8e commit 57bfa82

13 files changed

+822
-0
lines changed

doc/source/configuration/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ the various features provided.
1616
cephadm
1717
monitoring
1818
wazuh
19+
vault

doc/source/configuration/vault.rst

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
================================
2+
Hashicorp Vault for internal PKI
3+
================================
4+
5+
This document describes how to deploy Hashicorp Vault for
6+
internal PKI purposes using the
7+
`StackHPC Hashicorp collection <https://galaxy.ansible.com/stackhpc/hashicorp>`_
8+
9+
Background
10+
==========
11+
12+
Our OpenStack environment employs two separate HashiCorp Vault instances.
13+
These instances manage the Public Key Infrastructure (PKI) by handling the
14+
creation and issuance of certificates.
15+
16+
- The first HashiCorp Vault instance is located on the seed host.
17+
It handles infrastructure-level certificates, generating the root
18+
Certificate Authority (CA) and intermediate CA for the second Vault.
19+
The ``vault-deploy-seed.yml`` playbook sets up this instance.
20+
21+
- The second HashiCorp Vault instance is within the OpenStack
22+
overcloud, located on the controller nodes. This instance uses the
23+
intermediate CA from the seed Vault to issue application-specific
24+
certificates. The ``vault-deploy-overcloud.yml`` playbook is used
25+
for its setup. It ensures that all controller nodes trust the
26+
intermediate CA from the root Vault.
27+
28+
The dual Vault setup enhances security by protecting the root CA's key. The more
29+
exposed overcloud vault only possesses the intermediate key, ensuring that
30+
the root key remains secure even if the overcloud Vault instance is compromised.
31+
32+
Prerequisites
33+
=============
34+
35+
Before beginning the deployment of vault for openstack internal TLS and backend TLS you should ensure that you have the following.
36+
37+
* Seed Node or a host to run the vault container on
38+
* Overcloud controller hosts to install second vault on
39+
40+
Deployment
41+
==========
42+
43+
Setup Vault on the seed node
44+
----------------------------
45+
46+
1. Run vault-deploy-seed.yml custom playbook
47+
48+
.. code-block::
49+
50+
kayobe playbook run $KAYOBE_CONFIG_PATH/ansible/vault-deploy-seed.yml
51+
52+
2. Encrypt generated certs/keys with ansible-vault (use proper location of vault password file)
53+
54+
.. code-block::
55+
56+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/vault/OS-TLS-INT.pem
57+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/vault/seed-vault-keys.json
58+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/vault/overcloud.key
59+
60+
Or if environments are being used
61+
62+
.. code-block::
63+
64+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/vault/OS-TLS-INT.pem
65+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/vault/seed-vault-keys.json
66+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/vault/overcloud.key
67+
68+
Setup HAProxy config for Vault
69+
------------------------------
70+
71+
1. Create the HAProxy config to reverse proxy the Vault HA container
72+
73+
Set the vault_front to the external VIP address or internal VIP address depending on the installation. Set the vault_back to the IPs of the control nodes.
74+
75+
Set the following in etc/kayobe/kolla/config/haproxy/services.d/vault.cfg or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/kolla/config/haproxy/services.d/vault.cfg
76+
77+
.. code-block::
78+
79+
# Delete "verify none" if not using self-signed/unknown issuer
80+
{% raw %}
81+
frontend vault_front
82+
mode tcp
83+
option tcplog
84+
bind {{ kolla_internal_vip_address }}:8200
85+
default_backend vault_back
86+
87+
backend vault_back
88+
mode tcp
89+
option httpchk GET /v1/sys/health
90+
# https://www.vaultproject.io/api-docs/system/health
91+
# 200: initialized, unsealed, and active
92+
# 501: not initialised (required for bootstrapping)
93+
# 503: sealed (required for bootstrapping)
94+
http-check expect rstatus (200|501|503)
95+
96+
{% for host in groups['control'] %}
97+
{% set host_name = hostvars[host].ansible_facts.hostname %}
98+
{% set host_ip = 'api' | kolla_address(host) %}
99+
server {{ host_name }} {{ host_ip }}:8200 check check-ssl verify none inter 2000 rise 2 fall 5
100+
{% endfor %}
101+
{% endraw %}
102+
103+
2. Deploy HAProxy with the new Vault service configuration:
104+
105+
.. code-block::
106+
107+
kayobe overcloud service deploy -kt haproxy
108+
109+
Setup Vault HA on the overcloud hosts
110+
-------------------------------------
111+
112+
1. Run vault-deploy-overcloud.yml custom playbook
113+
114+
.. code-block::
115+
116+
kayobe playbook run $KAYOBE_CONFIG_PATH/ansible/vault-deploy-overcloud.yml
117+
118+
2. Encrypt overcloud vault keys (use proper location of vault password file)
119+
120+
.. code-block::
121+
122+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/vault/overcloud-vault-keys.json
123+
124+
Or if environments are being used
125+
126+
.. code-block::
127+
128+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/vault/overcloud-vault-keys.json
129+
130+
Certificates generation
131+
=======================
132+
133+
Create the internal TLS certificates
134+
------------------------------------
135+
136+
1. Run the playbook
137+
138+
.. code-block::
139+
140+
kayobe playbook run $KAYOBE_CONFIG_PATH/ansible/vault-generate-internal-tls.yml
141+
142+
2. Use ansible-vault to encrypt the PEM bundle in $KAYOBE_CONFIG_PATH/kolla/certificates/haproxy-internal.pem. Commit the PEM bundle and root CA to the kayobe configuration.
143+
144+
.. code-block::
145+
146+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/kolla/certificates/haproxy-internal.pem
147+
148+
Or if environments are being used
149+
150+
.. code-block::
151+
152+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/kolla/certificates/haproxy-internal.pem
153+
154+
Create the backend TLS and RabbitMQ TLS certificates
155+
----------------------------------------------------
156+
157+
1. Run the playbook
158+
159+
.. code-block::
160+
161+
kayobe playbook run $KAYOBE_CONFIG_PATH/ansible/vault-generate-backend-tls.yml
162+
163+
2. Use ansible-vault to encrypt the keys in $KAYOBE_CONFIG_PATH/kolla/certificates/<controller>-key.pem. Commit the certificates and keys to the kayobe configuration.
164+
165+
.. code-block::
166+
167+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/kolla/certificates/<controller>-key.pem
168+
169+
Or if environments are being used
170+
171+
.. code-block::
172+
173+
ansible-vault encrypt --vault-password-file ~/vault.pass $KAYOBE_CONFIG_PATH/environments/$KAYOBE_ENVIRONMENT/kolla/certificates/<controller>-key.pem
174+
175+
Certificates deployment
176+
=======================
177+
178+
.. warning::
179+
180+
The switch from HTTP to HTTPS during the deployment of internal/backend TLS certificates can temporarily disrupt service availability and necessitates a restart of all services. During this transition, endpoints may become unreachable following the HAProxy restart, persisting until the endpoint catalogue and client have been reconfigured to use HTTPS.
181+
182+
Enable the required TLS variables in kayobe and kolla
183+
-----------------------------------------------------
184+
185+
1. Set the following in kayobe-config/etc/kayobe/kolla.yml or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/kolla.yml
186+
187+
.. code-block::
188+
189+
# Whether TLS is enabled for the internal API endpoints. Default is 'no'.
190+
kolla_enable_tls_internal: yes
191+
192+
2. Set the following in etc/kayobe/kolla/globals.yml or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/kolla/globals.yml
193+
194+
.. code-block::
195+
196+
# Internal TLS configuration
197+
# Copy the self-signed CA into the kolla containers
198+
kolla_copy_ca_into_containers: "yes"
199+
# Use the following trust store within the container
200+
openstack_cacert: "{{ '/etc/pki/tls/certs/ca-bundle.crt' if os_distribution in ["centos", "rocky"] else '/etc/ssl/certs/ca-certificates.crt' }}"
201+
202+
# Backend TLS config
203+
# Enable backend TLS
204+
kolla_enable_tls_backend: "yes"
205+
206+
# If using RabbitMQ TLS:
207+
rabbitmq_enable_tls: "yes"
208+
209+
3. Deploy backend and internal TLS
210+
211+
.. code-block::
212+
213+
kayobe overcloud service deploy
214+
215+
Barbican integration
216+
====================
217+
218+
Enable Barbican in kayobe
219+
-------------------------
220+
221+
1. Set the following in kayobe-config/etc/kayobe/kolla.yml or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/kolla.yml
222+
223+
.. code-block::
224+
225+
kolla_enable_barbican: yes
226+
227+
Generate secrets_barbican_approle_secret_id
228+
-------------------------------------------
229+
230+
1. Run ``uuidgen`` to generate secret id
231+
2. Insert into secrets.yml or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/secrets.yml
232+
233+
.. code-block::
234+
235+
secrets_barbican_approle_secret_id: "YOUR-SECRET-GOES-HERE"
236+
237+
Create required configuration in Vault
238+
--------------------------------------
239+
240+
1. Run vault-deploy-barbican.yml custom playbook
241+
242+
.. code-block::
243+
244+
kayobe playbook run $KAYOBE_CONFIG_PATH/ansible/vault-deploy-barbican.yml
245+
246+
Add secrets_barbican_approle_id to secrets
247+
------------------------------------------
248+
249+
1. Note the role id from playbook output and insert into secrets.yml or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/secrets.yml
250+
251+
.. code-block::
252+
253+
secrets_barbican_approle_role_id: "YOUR-APPROLE-ID-GOES-HERE"
254+
255+
Configure Barbican
256+
------------------
257+
258+
1. Put required configuration in kayobe-config/etc/kayobe/kolla/config/barbican.conf or if environments are being used etc/kayobe/environments/$KAYOBE_ENVIRONMENT/kolla/config/barbican.conf
259+
260+
.. code-block::
261+
262+
[secretstore]
263+
namespace=barbican.secretstore.plugin
264+
enable_multiple_secret_stores=false
265+
enabled_secretstore_plugins=vault_plugin
266+
267+
[vault_plugin]
268+
vault_url = https://{{ kolla_internal_vip_address }}:8200
269+
use_ssl = True
270+
approle_role_id = {{ secrets_barbican_approle_role_id }}
271+
approle_secret_id = {{ secrets_barbican_approle_secret_id }}
272+
kv_mountpoint = barbican
273+
274+
Deploy Barbican
275+
---------------
276+
277+
.. code-block::
278+
279+
kayobe overcloud service deploy -kt barbican

etc/kayobe/ansible/requirements.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ collections:
44
version: 1.13.1
55
- name: stackhpc.pulp
66
version: 0.4.1
7+
- name: stackhpc.hashicorp
8+
version: 2.3.0
79
roles:
810
- src: stackhpc.vxlan
911
- name: ansible-lockdown.rhel8_cis
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
- name: Configure AppRole
3+
any_errors_fatal: True
4+
gather_facts: True
5+
hosts: controllers[0]
6+
vars:
7+
vault_api_addr: "https://{{ kolla_internal_fqdn }}:8200"
8+
vault_ca_cert: "{{ '/etc/pki/tls/certs/ca-bundle.crt' if ansible_facts.os_family == 'RedHat' else '/usr/local/share/ca-certificates/OS-TLS-ROOT.crt' }}"
9+
tasks:
10+
- name: Assert that secrets_barbican_approle_secret_id is defined
11+
assert:
12+
that:
13+
- secrets_barbican_approle_secret_id is defined
14+
fail_msg: "Please define secrets_barbican_approle_secret_id in your secrets.yml"
15+
16+
- name: Include Vault keys
17+
include_vars:
18+
file: "{{ kayobe_env_config_path }}/vault/overcloud-vault-keys.json"
19+
name: vault_keys
20+
21+
- name: Ensure hvac is installed
22+
pip:
23+
name: hvac
24+
state: present
25+
extra_args: "{% if pip_upper_constraints_file %}-c {{ pip_upper_constraints_file }}{% endif %}"
26+
virtualenv: "{{ virtualenv_path }}/kayobe"
27+
28+
- name: Enable AppRole auth module
29+
hashivault_auth_method:
30+
url: "{{ vault_api_addr }}"
31+
ca_cert: "{{ vault_ca_cert }}"
32+
token: "{{ vault_keys.root_token }}"
33+
method_type: approle
34+
state: enabled
35+
36+
- name: Enable barbican kv store
37+
hashivault_secret_engine:
38+
url: "{{ vault_api_addr }}"
39+
ca_cert: "{{ vault_ca_cert }}"
40+
token: "{{ vault_keys.root_token }}"
41+
name: barbican
42+
backend: kv
43+
description: "Barbican kv store"
44+
45+
- name: Ensure barbican policy is defined
46+
hashivault_policy:
47+
url: "{{ vault_api_addr }}"
48+
ca_cert: "{{ vault_ca_cert }}"
49+
token: "{{ vault_keys.root_token }}"
50+
name: "barbican-policy"
51+
state: present
52+
rules: |
53+
path "barbican/*" {
54+
capabilities = ["create", "read", "update", "delete", "list"]
55+
}
56+
57+
- name: Ensure barbican AppRole is defined
58+
hashivault_approle_role:
59+
url: "{{ vault_api_addr }}"
60+
ca_cert: "{{ vault_ca_cert }}"
61+
token: "{{ vault_keys.root_token }}"
62+
bind_secret_id: true
63+
secret_id_bound_cidrs: "{{ internal_net_name | net_cidr }}"
64+
secret_id_ttl: 0
65+
token_policies: barbican-policy
66+
name: barbican
67+
68+
- name: Get barbican Approle ID
69+
hashivault_approle_role_id:
70+
url: "{{ vault_api_addr }}"
71+
ca_cert: "{{ vault_ca_cert }}"
72+
token: "{{ vault_keys.root_token }}"
73+
name: barbican
74+
register: barbican_role_id
75+
76+
- name: Print barbican Approle ID
77+
debug:
78+
msg: "barbican role id is {{ barbican_role_id.id }}"
79+
80+
- name: Check if barbican Approle Secret ID is defined
81+
hashivault_approle_role_secret_list:
82+
url: "{{ vault_api_addr }}"
83+
ca_cert: "{{ vault_ca_cert }}"
84+
token: "{{ vault_keys.root_token }}"
85+
name: barbican
86+
register: barbican_approle_secret_list
87+
88+
- name: Ensure barbican AppRole Secret ID is defined
89+
hashivault_approle_role_secret:
90+
url: "{{ vault_api_addr }}"
91+
ca_cert: "{{ vault_ca_cert }}"
92+
token: "{{ vault_keys.root_token }}"
93+
secret: "{{ secrets_barbican_approle_secret_id }}"
94+
name: barbican
95+
when: barbican_approle_secret_list.secrets is match(secrets_barbican_approle_secret_id)

0 commit comments

Comments
 (0)