Add basic network spaces support
New extra-binding - 'access' - is used to configure in frontend Vault API address. The 'cluster' relation is used to configure inter-unit cluster communcation in HA deployments. Change-Id: I72031fef5c59e9aeb90f0dee1aea65c2ad27aef7
This commit is contained in:
parent
68068c64d8
commit
d895a358d5
|
@ -18,3 +18,10 @@ deploying on bionic, you'll need to deploy a 9.x version of PostgreSQL.
|
|||
After deploying and relating the charm to postgresql, install
|
||||
the vault snap locally and use "vault init" to create the
|
||||
master key shards and the root token, and store them safely.
|
||||
|
||||
## Network Spaces support
|
||||
|
||||
The vault charm directly supports network binding via the 'access'
|
||||
extra-binding and the 'cluster' peer relation. These allow the Vault
|
||||
API and inter-unit Cluster addresses to be configured using Juju
|
||||
network spaces.
|
||||
|
|
|
@ -16,6 +16,8 @@ series:
|
|||
- bionic
|
||||
tags:
|
||||
- security
|
||||
extra-bindings:
|
||||
access:
|
||||
requires:
|
||||
db:
|
||||
interface: pgsql
|
||||
|
@ -30,3 +32,6 @@ provides:
|
|||
nrpe-external-master:
|
||||
interface: nrpe-external-master
|
||||
scope: container
|
||||
peers:
|
||||
cluster:
|
||||
interface: vault-ha
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import base64
|
||||
import functools
|
||||
import hvac
|
||||
import psycopg2
|
||||
import requests
|
||||
|
@ -23,6 +24,7 @@ from charmhelpers.core.hookenv import (
|
|||
application_version_set,
|
||||
atexit,
|
||||
local_unit,
|
||||
network_get_primary_address,
|
||||
)
|
||||
|
||||
from charmhelpers.core.host import (
|
||||
|
@ -136,9 +138,10 @@ def configure_vault(context):
|
|||
key=context['etcd_tls_key_file'],
|
||||
cert=context['etcd_tls_cert_file'],
|
||||
ca=context['etcd_tls_ca_file'])
|
||||
context['vault_api_url'] = get_api_url()
|
||||
log("Etcd detected, setting vault_api_url to {}".format(
|
||||
context['vault_api_url']))
|
||||
context['api_addr'] = get_api_url()
|
||||
context['cluster_addr'] = get_cluster_url()
|
||||
log("Etcd detected, setting api_addr to {}".format(
|
||||
context['api_addr']))
|
||||
else:
|
||||
log("Etcd not detected", level=DEBUG)
|
||||
log("Rendering vault.hcl.j2", level=DEBUG)
|
||||
|
@ -162,15 +165,27 @@ def configure_vault(context):
|
|||
open_port(8200)
|
||||
|
||||
|
||||
def get_api_url():
|
||||
def binding_address(binding):
|
||||
try:
|
||||
return network_get_primary_address(binding)
|
||||
except NotImplementedError:
|
||||
return unit_private_ip()
|
||||
|
||||
|
||||
def get_vault_url(binding, port):
|
||||
protocol = 'http'
|
||||
port = '8200'
|
||||
ip = unit_private_ip()
|
||||
ip = binding_address(binding)
|
||||
if is_state('vault.ssl.available'):
|
||||
protocol = 'https'
|
||||
return '{}://{}:{}'.format(protocol, ip, port)
|
||||
|
||||
|
||||
get_api_url = functools.partial(get_vault_url,
|
||||
binding='access', port=8200)
|
||||
get_cluster_url = functools.partial(get_vault_url,
|
||||
binding='cluster', port=8201)
|
||||
|
||||
|
||||
@when('snap.installed.vault')
|
||||
@when_not('configured')
|
||||
@when('db.master.available')
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{%- if vault_api_url %}
|
||||
api_addr = "{{ vault_api_url }}"
|
||||
{%- if api_addr %}
|
||||
api_addr = "{{ api_addr }}"
|
||||
{%- endif %}
|
||||
{%- if cluster_addr %}
|
||||
cluster_addr = "{{ cluster_addr }}"
|
||||
{%- endif %}
|
||||
{%- if disable_mlock %}
|
||||
disable_mlock = true
|
||||
|
@ -19,21 +22,19 @@ storage "mysql" {
|
|||
{%- if etcd_conn %}
|
||||
ha_storage "etcd" {
|
||||
ha_enabled = "true"
|
||||
address = "{{ etcd_conn }}"
|
||||
tls_ca_file = "{{ etcd_tls_ca_file }}"
|
||||
tls_cert_file = "{{ etcd_tls_cert_file }}"
|
||||
tls_key_file = "{{ etcd_tls_key_file }}"
|
||||
address = "{{ etcd_conn }}"
|
||||
tls_ca_file = "{{ etcd_tls_ca_file }}"
|
||||
tls_cert_file = "{{ etcd_tls_cert_file }}"
|
||||
tls_key_file = "{{ etcd_tls_key_file }}"
|
||||
etcd_api = "v3"
|
||||
}
|
||||
{%- endif %}
|
||||
listener "tcp" {
|
||||
address = "0.0.0.0:8200"
|
||||
address = "0.0.0.0:8200"
|
||||
{%- if ssl_available %}
|
||||
tls_cert_file = "/var/snap/vault/common/vault.crt"
|
||||
tls_key_file = "/var/snap/vault/common/vault.key"
|
||||
tls_cert_file = "/var/snap/vault/common/vault.crt"
|
||||
tls_key_file = "/var/snap/vault/common/vault.key"
|
||||
{%- else %}
|
||||
tls_disable = 1
|
||||
tls_disable = 1
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -64,6 +64,7 @@ class TestHandlers(unittest.TestCase):
|
|||
'unit_private_ip',
|
||||
'application_version_set',
|
||||
'local_unit',
|
||||
'network_get_primary_address',
|
||||
]
|
||||
self.patch_all()
|
||||
|
||||
|
@ -218,12 +219,15 @@ class TestHandlers(unittest.TestCase):
|
|||
])
|
||||
|
||||
@patch.object(handlers, 'save_etcd_client_credentials')
|
||||
@patch.object(handlers, 'get_cluster_url')
|
||||
@patch.object(handlers, 'can_restart')
|
||||
@patch.object(handlers, 'get_api_url')
|
||||
def test_configure_vault_etcd(self, get_api_url, can_restart,
|
||||
get_cluster_url,
|
||||
save_etcd_client_credentials):
|
||||
can_restart.return_value = True
|
||||
get_api_url.return_value = 'http://this-unit'
|
||||
get_api_url.return_value = 'http://this-unit:8200'
|
||||
get_cluster_url.return_value = 'http://this-unit:8201'
|
||||
self.config.return_value = {'disable-mlock': False}
|
||||
etcd_mock = mock.MagicMock()
|
||||
etcd_mock.connection_string.return_value = 'http://etcd'
|
||||
|
@ -237,7 +241,8 @@ class TestHandlers(unittest.TestCase):
|
|||
'etcd_tls_ca_file': '/var/snap/vault/common/etcd-ca.pem',
|
||||
'etcd_tls_cert_file': '/var/snap/vault/common/etcd-cert.pem',
|
||||
'etcd_tls_key_file': '/var/snap/vault/common/etcd.key',
|
||||
'vault_api_url': 'http://this-unit'}
|
||||
'api_addr': 'http://this-unit:8200',
|
||||
'cluster_addr': 'http://this-unit:8201'}
|
||||
render_calls = [
|
||||
mock.call(
|
||||
'vault.hcl.j2',
|
||||
|
@ -294,13 +299,27 @@ class TestHandlers(unittest.TestCase):
|
|||
|
||||
def test_get_api_url_ssl(self):
|
||||
self.is_state.return_value = True
|
||||
self.unit_private_ip.return_value = '1.2.3.4'
|
||||
self.network_get_primary_address.return_value = '1.2.3.4'
|
||||
self.assertEqual(handlers.get_api_url(), 'https://1.2.3.4:8200')
|
||||
self.network_get_primary_address.assert_called_with('access')
|
||||
|
||||
def test_get_api_url_nossl(self):
|
||||
self.is_state.return_value = False
|
||||
self.unit_private_ip.return_value = '1.2.3.4'
|
||||
self.network_get_primary_address.return_value = '1.2.3.4'
|
||||
self.assertEqual(handlers.get_api_url(), 'http://1.2.3.4:8200')
|
||||
self.network_get_primary_address.assert_called_with('access')
|
||||
|
||||
def test_get_cluster_url_ssl(self):
|
||||
self.is_state.return_value = True
|
||||
self.network_get_primary_address.return_value = '1.2.3.4'
|
||||
self.assertEqual(handlers.get_cluster_url(), 'https://1.2.3.4:8201')
|
||||
self.network_get_primary_address.assert_called_with('cluster')
|
||||
|
||||
def test_get_cluster_url_nossl(self):
|
||||
self.is_state.return_value = False
|
||||
self.network_get_primary_address.return_value = '1.2.3.4'
|
||||
self.assertEqual(handlers.get_cluster_url(), 'http://1.2.3.4:8201')
|
||||
self.network_get_primary_address.assert_called_with('cluster')
|
||||
|
||||
def test_cluster_connected(self):
|
||||
self.config.return_value = '10.1.1.1'
|
||||
|
|
Loading…
Reference in New Issue