Merge pull request #2 from ajkavanagh/feature/add-hsm-interface
Add barbican-hsm-plugin interface support
This commit is contained in:
commit
6edcea4d2e
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
4
Makefile
4
Makefile
|
@ -8,8 +8,8 @@ build: clean
|
|||
LAYER_PATH=$(LAYER_PATH) tox -e build
|
||||
|
||||
lint:
|
||||
@tox -e lint
|
||||
@tox -e pep8
|
||||
|
||||
test:
|
||||
@echo Starting unit tests...
|
||||
@tox -e py27,py34,py35
|
||||
@tox -e py34,py35
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
# Barbican Source Charm
|
||||
|
||||
THIS CHARM IS FOR EXPERIMENTAL USE AT PRESENT.
|
||||
|
||||
This repository is for the reactive, layered,
|
||||
[Barbican](https://wiki.openstack.org/wiki/Barbican) _source_ charm. From the
|
||||
[wiki](https://wiki.openstack.org/wiki/Barbican) 'Barbican is a REST API
|
||||
designed for the secure storage, provisioning and management of secrets such as
|
||||
passwords, encryption keys and X.509 Certificates. It is aimed at being useful
|
||||
for all environments, including large ephemeral Clouds.'
|
||||
|
||||
# Plugins
|
||||
|
||||
The Barbican charm currently supports the following plugins:
|
||||
|
||||
- charm-barbican-softhsm
|
||||
|
||||
# Creating the primary MKEK and primary HMAC
|
||||
|
||||
Barbican (can use|uses) a Master Key Encryption Key (MKEK) scheme to wrap other
|
||||
keys so that in the course of issuing new encryption keys, it doesn't exhaust
|
||||
the storage capacity of an HSM.
|
||||
|
||||
See [KMIP MKEK Model
|
||||
Plugin](https://specs.openstack.org/openstack/barbican-specs/specs/kilo/barbican-mkek-model.html)
|
||||
for more details.
|
||||
|
||||
Barbican itself can generate the MKEK and HMAC keys and store them in the
|
||||
associated HSM through the use of two actions 'generate-mkek' and
|
||||
'generate-hmac'.
|
||||
|
||||
The names of the keys are stored in the configuration for the service as
|
||||
'mkek-label' and 'hmac-label'. These default to 'primarymkek' and
|
||||
'primaryhmac' respectively.
|
||||
|
||||
Note that these keys are not recoverable _from_ the HSM. If the HSM has
|
||||
already been configured with these keys then these actions would overwrite the
|
||||
existing key. So only use them for the initial implementation or to change the
|
||||
MKEK and HMAC keys in the HSM.
|
||||
|
||||
## Use of actions
|
||||
|
||||
For juju 1.x:
|
||||
```bash
|
||||
juju action do generate-mkek
|
||||
```
|
||||
|
||||
For juju 2.x:
|
||||
|
||||
```bash
|
||||
juju run-action generate-mkek
|
||||
```
|
||||
|
||||
Note that, depending on the HSM, it may only be possible to do this ONCE as the
|
||||
HSM may reject setting up the keys more than once.
|
||||
|
||||
# Developer Notes
|
||||
|
||||
The Barbican charm has to be able to set `[crypto]` and `[xxx_plugin]` sections
|
||||
in the `barbican-api.conf` file. This data comes via the `barbican-hsm`
|
||||
interface from a charm (probably a subordinate) that provides the interface.
|
||||
|
||||
On the `barbican-hsm` interface the data is provided in the `plugin_data()`
|
||||
method of the interface (or if it is adapted) in the `plugin_data` property.
|
||||
|
||||
The theory of operation for the crypto plugin is that a local library that
|
||||
supports the PKCS#11 interface that Barbican can talk to locally.
|
||||
|
||||
Note(AJK): it is not clear yet how a clustered Barbican can be created with
|
||||
a single HSM backend. It's likely to be a separate piece of hardward with
|
||||
a local library that talks to it.
|
||||
|
||||
In order for Barbican to be configured for the example softhsm2 library, the
|
||||
configuration file needs to include the entries:
|
||||
|
||||
```ini
|
||||
[crypto]
|
||||
enabled_crypto_plugins = p11_crypto
|
||||
|
||||
[p11_crypto_plugin]
|
||||
library_path = '/usr/lib/libCryptoki2_64.so'
|
||||
login = 'catt'
|
||||
mkek_label = 'primarymkek'
|
||||
mkek_length = 32
|
||||
hmac_label = 'primaryhmac' slot_id = <slot_id>
|
||||
```
|
||||
|
||||
Note that the /var/lib/softhsm/tokens directory HAS to exist as otherwise the
|
||||
softhsm2-util command won't work.
|
13
copyright
13
copyright
|
@ -1,13 +0,0 @@
|
|||
Copyright 2016 Canonical Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,8 @@
|
|||
generate-mkek:
|
||||
description: |
|
||||
Generate an MKEK in the associated HSM (via the barbican-hsm-plugin
|
||||
interface).
|
||||
generate-hmac:
|
||||
description: |
|
||||
Generate an HMAC in the associated HSM (via the barbican-hsm-plugin
|
||||
interface).
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Load modules from $CHARM_DIR/lib
|
||||
sys.path.append('lib')
|
||||
|
||||
from charms.layer import basic
|
||||
basic.bootstrap_charm_deps()
|
||||
basic.init_config_states()
|
||||
|
||||
import charms.reactive as reactive
|
||||
|
||||
import charmhelpers.core.hookenv as hookenv
|
||||
|
||||
import charm.openstack.barbican as barbican
|
||||
|
||||
|
||||
def generate_mkek_action(*args):
|
||||
"""Generate an MKEK in the backend HSM"""
|
||||
# try and get the reactive relation instance for hsm:
|
||||
# We only do this because there's no @action(<name>) yet that we could
|
||||
# access from the reactive file.
|
||||
hsm = reactive.RelationBase.from_state('hsm.available')
|
||||
if hsm is None:
|
||||
hookenv.action_fail(
|
||||
"Can't generate an MKEK in associated HSM because HSM is not "
|
||||
"available.")
|
||||
return
|
||||
barbican.generate_mkek(hsm)
|
||||
|
||||
|
||||
def generate_hmac_action(*args):
|
||||
"""Generate an HMAC in the backend HSM"""
|
||||
# try and get the reactive relation instance for hsm:
|
||||
# We only do this because there's no @action(<name>) yet that we could
|
||||
# access from the reactive file.
|
||||
hsm = reactive.RelationBase.from_state('hsm.available')
|
||||
if hsm is None:
|
||||
hookenv.action_fail(
|
||||
"Can't generate an HMAC in associated HSM because HSM is not "
|
||||
"available.")
|
||||
barbican.generate_hmac(hsm)
|
||||
|
||||
|
||||
# Actions to function mapping, to allow for illegal python action names that
|
||||
# can map to a python function.
|
||||
ACTIONS = {
|
||||
"generate-mkek": generate_mkek_action,
|
||||
"generate-hmac": generate_hmac_action,
|
||||
}
|
||||
|
||||
|
||||
def main(args):
|
||||
action_name = os.path.basename(args[0])
|
||||
try:
|
||||
action = ACTIONS[action_name]
|
||||
except KeyError:
|
||||
return "Action %s undefined" % action_name
|
||||
else:
|
||||
try:
|
||||
action(args)
|
||||
except Exception as e:
|
||||
hookenv.action_fail(str(e))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
|
@ -0,0 +1 @@
|
|||
actions.py
|
|
@ -0,0 +1 @@
|
|||
actions.py
|
|
@ -46,3 +46,38 @@ options:
|
|||
default: "3"
|
||||
type: string
|
||||
description: none, 2 or 3
|
||||
require-hsm-plugin:
|
||||
default: True
|
||||
type: boolean
|
||||
description: |
|
||||
If True (the default) then the barbcian-worker process won't be fully
|
||||
functional until an HSM is associated with the charm. The charm will
|
||||
remain in the blocked state until an HSM is available.
|
||||
label-mkek:
|
||||
default: primarymkek
|
||||
type: string
|
||||
description: |
|
||||
This is the label for the primary MKEK (Master Key Encryption Key) stored
|
||||
in the HSM that is used by Barbican to wrap other encryption keys that
|
||||
are provided to projects.
|
||||
|
||||
Note the assocated action 'generate-mkek' is used to create an MKEK when
|
||||
initialising a system.
|
||||
mkek-key-length:
|
||||
default: 32
|
||||
type: int
|
||||
description: The length for generating an MKEK
|
||||
label-hmac:
|
||||
default: primaryhmac
|
||||
type: string
|
||||
description: |
|
||||
This is the label for the primary HMAC (keyed-hash message authentication
|
||||
code) stored in the HSM that is used by Barbican to wrap other HMACs that
|
||||
are provided to projects.
|
||||
|
||||
Note the assocated action 'generate-hmac' is used to create an HMAC when
|
||||
initialising a system.
|
||||
hmac-key-length:
|
||||
default: 32
|
||||
type: int
|
||||
description: The length for generating an HMAC
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Wrapper to deal with newer Ubuntu versions that don't have py2 installed
|
||||
# by default.
|
||||
|
||||
check_and_install() {
|
||||
pkg="${1}"
|
||||
if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
|
||||
apt-get -y install ${pkg}
|
||||
fi
|
||||
}
|
||||
status-set maintenance "Install hook running"
|
||||
|
||||
if [[ $(lsb_release -sc) -eq "trusty" ]]; then
|
||||
juju-log "Enabling cloud archive to work around old trusty tools"
|
||||
# Add a random cloud archive for the Openstack python3 clients
|
||||
add-apt-repository --yes ppa:ubuntu-cloud-archive/mitaka-staging
|
||||
apt-get update
|
||||
check_and_install 'python3-pip'
|
||||
# The trusty version of tox is too low (tox version is 1.6, required is at least 2.3.1)
|
||||
# pip install tox to get around this and die a little inside
|
||||
pip3 install tox
|
||||
else
|
||||
juju-log "Installing tox"
|
||||
check_and_install 'tox'
|
||||
fi
|
||||
|
||||
declare -a DEPS=('libssl-dev' 'libffi-dev' 'apt' 'python3-netaddr' 'python3-netifaces' 'python3-pip' 'python3-yaml' 'python-cinderclient' 'python-glanceclient' 'python-heatclient' 'python-keystoneclient' 'python-neutronclient' 'python-novaclient' 'python-swiftclient' 'python-ceilometerclient' 'openvswitch-test' 'python3-cinderclient' 'python3-glanceclient' 'python3-heatclient' 'python3-keystoneclient' 'python3-neutronclient' 'python3-novaclient' 'python3-swiftclient' 'python3-ceilometerclient')
|
||||
|
||||
|
||||
PYTHON="python"
|
||||
|
||||
for dep in ${DEPS[@]}; do
|
||||
check_and_install ${dep}
|
||||
done
|
||||
|
||||
exec ./hooks/install.real
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Load modules from $CHARM_DIR/lib
|
||||
import sys
|
||||
sys.path.append('lib')
|
||||
|
||||
from charms.layer import basic
|
||||
basic.bootstrap_charm_deps()
|
||||
basic.init_config_states()
|
||||
|
||||
|
||||
# This will load and run the appropriate @hook and other decorated
|
||||
# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
|
||||
# and $CHARM_DIR/hooks/relations.
|
||||
#
|
||||
# See https://jujucharms.com/docs/stable/authors-charm-building
|
||||
# for more information on this pattern.
|
||||
from charms.reactive import main
|
||||
main()
|
|
@ -1 +1,11 @@
|
|||
includes: ['layer:openstack', 'interface:mysql-shared', 'interface:rabbitmq', 'interface:keystone']
|
||||
includes:
|
||||
- layer:openstack
|
||||
- interface:mysql-shared
|
||||
- interface:rabbitmq
|
||||
- interface:keystone
|
||||
- interface:barbican-hsm
|
||||
options:
|
||||
basic:
|
||||
use_venv: True
|
||||
include_system_packages: True
|
||||
repo: git@github.com:openstack-charmers/charm-barbican.git
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
|
@ -1,11 +1,28 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# The barbican handlers class
|
||||
|
||||
# bare functions are provided to the reactive handlers to perform the functions
|
||||
# needed on the class.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import charmhelpers.fetch
|
||||
import subprocess
|
||||
|
||||
import charmhelpers.contrib.openstack.utils as ch_utils
|
||||
import charmhelpers.core.hookenv as hookenv
|
||||
import charmhelpers.core.unitdata as unitdata
|
||||
import charmhelpers.fetch
|
||||
|
||||
import charms_openstack.charm
|
||||
import charms_openstack.adapters
|
||||
|
@ -13,10 +30,11 @@ import charms_openstack.ip as os_ip
|
|||
|
||||
PACKAGES = ['barbican-common', 'barbican-api', 'barbican-worker',
|
||||
'python-mysqldb']
|
||||
BARBICAN_DIR = '/etc/barbican'
|
||||
BARBICAN_ADMIN_PASTE_CONF = "barbican-admin-paste.ini"
|
||||
BARBICAN_API_CONF = "barbican-api.conf"
|
||||
BARBICAN_API_PASTE_CONF = "barbican-api-paste.ini"
|
||||
BARBICAN_DIR = '/etc/barbican/'
|
||||
BARBICAN_CONF = BARBICAN_DIR + "barbican.conf"
|
||||
BARBICAN_API_PASTE_CONF = BARBICAN_DIR + "barbican-api-paste.ini"
|
||||
|
||||
OPENSTACK_RELEASE_KEY = 'barbican-charm.openstack-release-version'
|
||||
|
||||
|
||||
###
|
||||
|
@ -26,12 +44,15 @@ def install():
|
|||
"""Use the singleton from the BarbicanCharm to install the packages on the
|
||||
unit
|
||||
"""
|
||||
unitdata.kv().unset(OPENSTACK_RELEASE_KEY)
|
||||
BarbicanCharm.singleton.install()
|
||||
|
||||
|
||||
def setup_endpoint(keystone):
|
||||
"""When the keystone interface connects, register this unit in the keystone
|
||||
catalogue.
|
||||
|
||||
:param keystone: instance of KeystoneRequires() class from i/f
|
||||
"""
|
||||
charm = BarbicanCharm.singleton
|
||||
keystone.register_endpoints(charm.service_type,
|
||||
|
@ -44,10 +65,26 @@ def setup_endpoint(keystone):
|
|||
def render_configs(interfaces_list):
|
||||
"""Using a list of interfaces, render the configs and, if they have
|
||||
changes, restart the services on the unit.
|
||||
|
||||
:param interfaces_list: [RelationBase] interfaces from reactive
|
||||
"""
|
||||
BarbicanCharm.singleton.render_with_interfaces(interfaces_list)
|
||||
|
||||
|
||||
def generate_mkek(hsm):
|
||||
"""Ask barbican to generate an MKEK in the backend store using the HSM.
|
||||
This assumes that an HSM is available, and configured. Uses the charm.
|
||||
"""
|
||||
BarbicanCharm.singleton.action_generate_mkek(hsm)
|
||||
|
||||
|
||||
def generate_hmac(hsm):
|
||||
"""Ask barbican to generate an HMAC in the backend store using the HSM.
|
||||
This assumes that an HSM is available, and configured. Uses the charm.
|
||||
"""
|
||||
BarbicanCharm.singleton.action_generate_hmac(hsm)
|
||||
|
||||
|
||||
def assess_status():
|
||||
"""Just call the BarbicanCharm.singleton.assess_status() command to update
|
||||
status on the unit.
|
||||
|
@ -71,29 +108,75 @@ class BarbicanConfigurationAdapter(
|
|||
@property
|
||||
def barbican_api_keystone_pipeline(self):
|
||||
if self.keystone_api_version == "2":
|
||||
return 'keystone_authtoken context apiapp'
|
||||
return 'cors keystone_authtoken context apiapp'
|
||||
else:
|
||||
return 'keystone_v3_authtoken context apiapp'
|
||||
return 'cors keystone_v3_authtoken context apiapp'
|
||||
|
||||
@property
|
||||
def barbican_api_pipeline(self):
|
||||
return {
|
||||
"2": "keystone_authtoken context apiapp",
|
||||
"3": "keystone_v3_authtoken context apiapp",
|
||||
"none": "unauthenticated-context apiapp"
|
||||
"2": "cors keystone_authtoken context apiapp",
|
||||
"3": "cors keystone_v3_authtoken context apiapp",
|
||||
"none": "cors unauthenticated-context apiapp"
|
||||
}[self.keystone_api_version]
|
||||
|
||||
@property
|
||||
def barbican_api_keystone_audit_pipeline(self):
|
||||
if self.keystone_api_version == "2":
|
||||
return 'keystone_authtoken context audit apiapp'
|
||||
else:
|
||||
return 'keystone_v3_authtoken context audit apiapp'
|
||||
|
||||
class BarbicanAdapters(charms_openstack.adapters.OpenStackRelationAdapters):
|
||||
|
||||
class HSMAdapter(charms_openstack.adapters.OpenStackRelationAdapter):
|
||||
"""Adapt the barbican-hsm-plugin relation for use in rendering the config
|
||||
for Barbican. Note that the HSM relation is optional, so we have a class
|
||||
variable 'exists' that we can test in the template to see if we should
|
||||
render HSM parameters into the template.
|
||||
"""
|
||||
|
||||
interface_type = 'hsm'
|
||||
|
||||
@property
|
||||
def library_path(self):
|
||||
"""Provide a library_path property to the template if it exists"""
|
||||
try:
|
||||
return self.relation.plugin_data['library_path']
|
||||
except:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def login(self):
|
||||
"""Provide a login property to the template if it exists"""
|
||||
try:
|
||||
return self.relation.plugin_data['login']
|
||||
except:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def slot_id(self):
|
||||
"""Provide a slot_id property to the template if it exists"""
|
||||
try:
|
||||
return self.relation.plugin_data['slot_id']
|
||||
except:
|
||||
return ''
|
||||
|
||||
|
||||
class BarbicanAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters):
|
||||
"""
|
||||
Adapters class for the Barbican charm.
|
||||
|
||||
This plumbs in the BarbicanConfigurationAdapter as the ConfigurationAdapter
|
||||
to provide additional properties.
|
||||
"""
|
||||
|
||||
relation_adapters = {
|
||||
'hsm': HSMAdapter,
|
||||
}
|
||||
|
||||
def __init__(self, relations):
|
||||
super(BarbicanAdapters, self).__init__(
|
||||
relations, options=BarbicanConfigurationAdapter)
|
||||
relations, options_instance=BarbicanConfigurationAdapter())
|
||||
|
||||
|
||||
class BarbicanCharm(charms_openstack.charm.OpenStackCharm):
|
||||
|
@ -101,58 +184,128 @@ class BarbicanCharm(charms_openstack.charm.OpenStackCharm):
|
|||
functionality to manage a barbican unit.
|
||||
"""
|
||||
|
||||
release = 'liberty'
|
||||
release = 'mitaka'
|
||||
name = 'barbican'
|
||||
packages = PACKAGES
|
||||
api_ports = {
|
||||
'barbican-api': {
|
||||
'barbican-worker': {
|
||||
os_ip.PUBLIC: 9311,
|
||||
os_ip.ADMIN: 9312,
|
||||
os_ip.INTERNAL: 9313,
|
||||
os_ip.INTERNAL: 9311,
|
||||
}
|
||||
}
|
||||
service_type = 'barbican'
|
||||
default_service = 'barbican-api'
|
||||
services = ['barbican-api', 'barbican-worker']
|
||||
default_service = 'barbican-worker'
|
||||
services = ['apache2', 'barbican-worker']
|
||||
|
||||
# Note that the hsm interface is optional - defined in config.yaml
|
||||
required_relations = ['shared-db', 'amqp', 'identity-service']
|
||||
|
||||
restart_map = {
|
||||
"{}/{}".format(BARBICAN_DIR, BARBICAN_API_CONF): services,
|
||||
"{}/{}".format(BARBICAN_DIR, BARBICAN_ADMIN_PASTE_CONF): services,
|
||||
"{}/{}".format(BARBICAN_DIR, BARBICAN_API_PASTE_CONF): services,
|
||||
BARBICAN_CONF: services,
|
||||
BARBICAN_API_PASTE_CONF: services,
|
||||
}
|
||||
|
||||
adapters_class = BarbicanAdapters
|
||||
|
||||
def __init__(self, release=None, **kwargs):
|
||||
"""Custom initialiser for class
|
||||
|
||||
If no release is passed, then the charm determines the release from the
|
||||
ch_utils.os_release() function.
|
||||
|
||||
Note that the release_selector can be used to control which class is
|
||||
instantiated.
|
||||
"""
|
||||
if release is None:
|
||||
# release = ch_utils.os_release('barbican-common')
|
||||
release = ch_utils.os_release('python-keystonemiddleware')
|
||||
super(BarbicanCharm, self).__init__(release=release, **kwargs)
|
||||
|
||||
def install(self):
|
||||
"""Customise the installation, configure the source and then call the
|
||||
parent install() method to install the packages
|
||||
"""
|
||||
charmhelpers.fetch.add_source("ppa:gnuoy/barbican-alt")
|
||||
# DEBUG - until seed random change lands into xenial cloud archive
|
||||
# BUG #1599550 - barbican + softhsm2 + libssl1.0.0:
|
||||
# pkcs11:_generate_random() fails
|
||||
# WARNING: This charm can't be released into stable until the bug is
|
||||
# fixed.
|
||||
charmhelpers.fetch.add_source("ppa:ajkavanagh/barbican")
|
||||
self.configure_source()
|
||||
# and do the actual install
|
||||
super(BarbicanCharm, self).install()
|
||||
|
||||
def action_generate_mkek(self, hsm):
|
||||
"""Generate an MKEK on a connected HSM. Requires that an HSM is
|
||||
avaiable via the barbican-hsm-plugin interface, generically known as
|
||||
'hsm'.
|
||||
|
||||
Uses the barbican-manage command.
|
||||
|
||||
:param hsm: instance of BarbicanRequires() class from the
|
||||
barbican-hsm-plugin interface
|
||||
"""
|
||||
plugin_data = hsm.plugin_data
|
||||
cmd = [
|
||||
'barbican-manage', 'hsm', 'gen_mkek',
|
||||
'--library-path', plugin_data['library_path'],
|
||||
'--passphrase', plugin_data['login'],
|
||||
'--slot-id', plugin_data['slot_id'],
|
||||
'--length', str(hookenv.config('mkek-key-length')),
|
||||
'--label', hookenv.config('label-mkek'),
|
||||
]
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
hookenv.log("barbican-mangage hsm gen_mkek succeeded")
|
||||
except subprocess.CalledProcessError:
|
||||
str_err = "barbican-manage hsm gen_mkek failed."
|
||||
hookenv.log(str_err)
|
||||
raise Exception(str_err)
|
||||
|
||||
def action_generate_hmac(self, hsm):
|
||||
"""Generate an HMAC on a connected HSM. Requires that an HSM is
|
||||
avaiable via the barbican-hsm-plugin interface, generically known as
|
||||
'hsm'.
|
||||
|
||||
Uses the barbican-manage command.
|
||||
|
||||
:param hsm: instance of BarbicanRequires() class from the
|
||||
barbican-hsm-plugin interface
|
||||
"""
|
||||
plugin_data = hsm.plugin_data
|
||||
cmd = [
|
||||
'barbican-manage', 'hsm', 'gen_hmac',
|
||||
'--library-path', plugin_data['library_path'],
|
||||
'--passphrase', plugin_data['login'],
|
||||
'--slot-id', plugin_data['slot_id'],
|
||||
'--length', str(hookenv.config('hmac-key-length')),
|
||||
'--label', hookenv.config('label-hmac'),
|
||||
]
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
hookenv.log("barbican-mangage hsm gen_hmac succeeded")
|
||||
except subprocess.CalledProcessError:
|
||||
str_err = "barbican-manage hsm gen_hmac failed."
|
||||
hookenv.log(str_err)
|
||||
raise Exception(str_err)
|
||||
|
||||
def states_to_check(self, required_relations=None):
|
||||
"""Override the default states_to_check() for the assess_status
|
||||
functionality so that, if we have to have an HSM relation, then enforce
|
||||
it on the assess_status() call.
|
||||
|
||||
If param required_relations is not None then it overrides the
|
||||
instance/class variable self.required_relations.
|
||||
|
||||
:param required_relations: [list of state names]
|
||||
:returns: [states{} as per parent method]
|
||||
"""
|
||||
if required_relations is None:
|
||||
required_relations = self.required_relations
|
||||
if hookenv.config('require-hsm-plugin'):
|
||||
required_relations.append('hsm')
|
||||
return super(BarbicanCharm, self).states_to_check(
|
||||
required_relations=required_relations)
|
||||
|
||||
|
||||
# Determine the charm class by the supported release
|
||||
@charms_openstack.charm.register_os_release_selector
|
||||
def select_release():
|
||||
"""Determine the release based on the python-keystonemiddleware that is
|
||||
installed.
|
||||
|
||||
Note that this function caches the release after the first install so that
|
||||
it doesn't need to keep going and getting it from the package information.
|
||||
"""
|
||||
return ch_utils.os_release('python-keystonemiddleware')
|
||||
release_version = unitdata.kv().get(OPENSTACK_RELEASE_KEY, None)
|
||||
if release_version is None:
|
||||
release_version = ch_utils.os_release('python-keystonemiddleware')
|
||||
unitdata.kv().set(OPENSTACK_RELEASE_KEY, release_version)
|
||||
return release_version
|
||||
|
|
|
@ -18,3 +18,6 @@ requires:
|
|||
interface: rabbitmq
|
||||
identity-service:
|
||||
interface: keystone
|
||||
hsm:
|
||||
interface: barbican-hsm
|
||||
optional: true
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# this is just for the reactive handlers and calls into the charm.
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
@ -48,6 +62,16 @@ def setup_endpoint(keystone):
|
|||
@reactive.when('identity-service.available')
|
||||
@reactive.when('amqp.available')
|
||||
def render_stuff(*args):
|
||||
"""Render the configuration for Barbican when all the interfaces are
|
||||
available.
|
||||
|
||||
Note that the HSM interface is optional (hence the @when_any) and thus is
|
||||
only used if it is available.
|
||||
"""
|
||||
# Get the optional hsm relation, if it is available for rendering.
|
||||
hsm = reactive.RelationBase.from_state('hsm.available')
|
||||
if hsm is not None:
|
||||
args = args + (hsm, )
|
||||
barbican.render_configs(args)
|
||||
barbican.assess_status()
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[pipeline:main]
|
||||
pipeline = unauthenticated-context admin
|
||||
|
||||
[app:admin]
|
||||
paste.app_factory = barbican.api.app:create_admin_app
|
||||
|
||||
[filter:unauthenticated-context]
|
||||
paste.filter_factory = barbican.api.middleware.context:UnauthenticatedContextMiddleware.factory
|
|
@ -5,24 +5,28 @@ use = egg:Paste#urlmap
|
|||
|
||||
# Use this pipeline for Barbican API - versions no authentication
|
||||
[pipeline:barbican_version]
|
||||
pipeline = versionapp
|
||||
pipeline = cors versionapp
|
||||
|
||||
# Use this pipeline for Barbican API - DEFAULT no authentication
|
||||
[pipeline:barbican_api]
|
||||
####pipeline = simple apiapp
|
||||
#pipeline = keystone_authtoken context apiapp
|
||||
# pipeline = cors unauthenticated-context apiapp
|
||||
pipeline = {{ options.barbican_api_pipeline }}
|
||||
|
||||
#Use this pipeline to activate a repoze.profile middleware and HTTP port,
|
||||
# to provide profiling information for the REST API processing.
|
||||
[pipeline:barbican-profile]
|
||||
pipeline = unauthenticated-context egg:Paste#cgitb egg:Paste#httpexceptions profile apiapp
|
||||
pipeline = cors unauthenticated-context egg:Paste#cgitb egg:Paste#httpexceptions profile apiapp
|
||||
|
||||
#Use this pipeline for keystone auth
|
||||
[pipeline:barbican-api-keystone]
|
||||
#pipeline = keystone_authtoken context apiapp
|
||||
# pipeline = cors keystone_authtoken context apiapp
|
||||
pipeline = {{ options.barbican_api_keystone_pipeline }}
|
||||
|
||||
#Use this pipeline for keystone auth with audit feature
|
||||
[pipeline:barbican-api-keystone-audit]
|
||||
# pipeline = keystone_authtoken context audit apiapp
|
||||
pipeline = {{ options.barbican_api_keystone_audit_pipeline }}
|
||||
|
||||
[app:apiapp]
|
||||
paste.app_factory = barbican.api.app:create_main_app
|
||||
|
||||
|
@ -32,39 +36,43 @@ paste.app_factory = barbican.api.app:create_version_app
|
|||
[filter:simple]
|
||||
paste.filter_factory = barbican.api.middleware.simple:SimpleFilter.factory
|
||||
|
||||
[filter:unauthenticated-context]
|
||||
[filter:unauthenticated-context]
|
||||
paste.filter_factory = barbican.api.middleware.context:UnauthenticatedContextMiddleware.factory
|
||||
|
||||
[filter:context]
|
||||
[filter:context]
|
||||
paste.filter_factory = barbican.api.middleware.context:ContextMiddleware.factory
|
||||
|
||||
[filter:keystone_authtoken]
|
||||
[filter:audit]
|
||||
paste.filter_factory = keystonemiddleware.audit:filter_factory
|
||||
audit_map_file = /etc/barbican/api_audit_map.conf
|
||||
|
||||
[filter:keystone_authtoken]
|
||||
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
|
||||
signing_dir = /var/lib/barbican/keystone-signing
|
||||
auth_host = {{ identity_service.auth_host }}
|
||||
#need ability to re-auth a token, thus admin url
|
||||
auth_port = {{ identity_service.auth_port }}
|
||||
auth_protocol = {{ identity_service.auth_protocol }}
|
||||
admin_tenant_name = {{ identity_service.service_tenant }}
|
||||
admin_user = {{ identity_service.service_username }}
|
||||
admin_password = {{ identity_service.service_password }}
|
||||
auth_version = v2.0
|
||||
auth_port = {{ identity_service.auth_port }}
|
||||
auth_protocol = {{ identity_service.auth_protocol }}
|
||||
admin_tenant_name = {{ identity_service.service_tenant }}
|
||||
admin_user = {{ identity_service.service_username }}
|
||||
admin_password = {{ identity_service.service_password }}
|
||||
auth_version = v2.0
|
||||
#delay failing perhaps to log the unauthorized request in barbican ..
|
||||
#delay_auth_decision = true
|
||||
|
||||
[filter:keystone_v3_authtoken]
|
||||
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
|
||||
[filter:keystone_v3_authtoken]
|
||||
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
|
||||
signing_dir = /var/lib/barbican/keystone-signing
|
||||
auth_host = {{ identity_service.auth_host }}
|
||||
#need ability to re-auth a token, thus admin url
|
||||
auth_port = {{ identity_service.auth_port }}
|
||||
auth_protocol = {{ identity_service.auth_protocol }}
|
||||
admin_tenant_name = {{ identity_service.service_tenant }}
|
||||
admin_user = {{ identity_service.service_username }}
|
||||
admin_password = {{ identity_service.service_password }}
|
||||
auth_version = v3.0
|
||||
auth_port = {{ identity_service.auth_port }}
|
||||
auth_protocol = {{ identity_service.auth_protocol }}
|
||||
admin_tenant_name = {{ identity_service.service_tenant }}
|
||||
admin_user = {{ identity_service.service_username }}
|
||||
admin_password = {{ identity_service.service_password }}
|
||||
auth_version = v3.0
|
||||
#delay failing perhaps to log the unauthorized request in barbican ..
|
||||
#delay_auth_decision = true
|
||||
#delay_auth_decision = true
|
||||
|
||||
[filter:profile]
|
||||
use = egg:repoze.profile
|
||||
|
@ -74,3 +82,7 @@ discard_first_request = true
|
|||
path = /__profile__
|
||||
flush_at_shutdown = true
|
||||
unwind = false
|
||||
|
||||
[filter:cors]
|
||||
paste.filter_factory = oslo_middleware.cors:filter_factory
|
||||
oslo_config_project = barbican
|
||||
|
|
|
@ -11,7 +11,7 @@ bind_host = 0.0.0.0
|
|||
# Port to bind the API server to
|
||||
bind_port = 9311
|
||||
|
||||
# Host name, for use in HATEOS-style references
|
||||
# Host name, for use in HATEOAS-style references
|
||||
# Note: Typically this would be the load balanced endpoint that clients would use
|
||||
# communicate back with this service.
|
||||
host_href = http://localhost:9311
|
||||
|
@ -38,6 +38,10 @@ max_allowed_request_size_in_bytes = 1000000
|
|||
#sql_connection = sqlite:///barbican.sqlite
|
||||
# Note: For absolute addresses, use '////' slashes after 'sqlite:'
|
||||
# Uncomment for a more global development environment
|
||||
#sql_connection = sqlite:////var/lib/barbican/barbican.sqlite
|
||||
|
||||
# This is shared_db.uri from the shared_db relationship.
|
||||
{% include "parts/database" %}
|
||||
|
||||
# Period in seconds after which SQLAlchemy should reestablish its connection
|
||||
# to the database.
|
||||
|
@ -48,19 +52,39 @@ max_allowed_request_size_in_bytes = 1000000
|
|||
# before MySQL can drop the connection.
|
||||
sql_idle_timeout = 3600
|
||||
|
||||
# Accepts a class imported from the sqlalchemy.pool module, and handles the
|
||||
# details of building the pool for you. If commented out, SQLAlchemy
|
||||
# will select based on the database dialect. Other options are QueuePool
|
||||
# (for SQLAlchemy-managed connections) and NullPool (to disabled SQLAlchemy
|
||||
# management of connections).
|
||||
# See http://docs.sqlalchemy.org/en/latest/core/pooling.html for more details.
|
||||
#sql_pool_class = QueuePool
|
||||
|
||||
# Show SQLAlchemy pool-related debugging output in logs (sets DEBUG log level
|
||||
# output) if specified.
|
||||
#sql_pool_logging = True
|
||||
|
||||
# Size of pool used by SQLAlchemy. This is the largest number of connections
|
||||
# that will be kept persistently in the pool. Can be set to 0 to indicate no
|
||||
# size limit. To disable pooling, use a NullPool with sql_pool_class instead.
|
||||
# Comment out to allow SQLAlchemy to select the default.
|
||||
#sql_pool_size = 5
|
||||
|
||||
# The maximum overflow size of the pool used by SQLAlchemy. When the number of
|
||||
# checked-out connections reaches the size set in sql_pool_size, additional
|
||||
# connections will be returned up to this limit. It follows then that the
|
||||
# total number of simultaneous connections the pool will allow is
|
||||
# sql_pool_size + sql_pool_max_overflow. Can be set to -1 to indicate no
|
||||
# overflow limit, so no limit will be placed on the total number of concurrent
|
||||
# connections. Comment out to allow SQLAlchemy to select the default.
|
||||
#sql_pool_max_overflow = 10
|
||||
|
||||
# Default page size for the 'limit' paging URL parameter.
|
||||
default_limit_paging = 10
|
||||
|
||||
# Maximum page size for the 'limit' paging URL parameter.
|
||||
max_limit_paging = 100
|
||||
|
||||
# Number of Barbican API worker processes to start.
|
||||
# On machines with more than one CPU increasing this value
|
||||
# may improve performance (especially if using SSL with
|
||||
# compression turned on). It is typically recommended to set
|
||||
# this value to the number of CPUs present on your machine.
|
||||
workers = 1
|
||||
|
||||
# Role used to identify an authenticated user as administrator
|
||||
#admin_role = admin
|
||||
|
||||
|
@ -92,17 +116,27 @@ workers = 1
|
|||
# Should be set to a random string of length 16, 24 or 32 bytes
|
||||
#metadata_encryption_key = <16, 24 or 32 char registry metadata key>
|
||||
|
||||
# ============ Delayed Delete Options =============================
|
||||
# ================= Queue Options - oslo.messaging ==========================
|
||||
|
||||
# Turn on/off delayed delete
|
||||
delayed_delete = False
|
||||
# rabbitmq-olso section from the rabbit-mq and releated relations.
|
||||
{% include "parts/section-rabbitmq-oslo" %}
|
||||
|
||||
# Delayed delete time in seconds
|
||||
scrub_time = 43200
|
||||
|
||||
# Directory that the scrubber will use to remind itself of what to delete
|
||||
# Make sure this is also set in glance-scrubber.conf
|
||||
scrubber_datadir = /var/lib/barbican/scrubber
|
||||
# For HA, specify queue nodes in cluster as 'user@host:5672', comma delimited, ending with '/offset':
|
||||
# For example: transport_url = rabbit://guest@192.168.50.8:5672,guest@192.168.50.9:5672/
|
||||
# DO NOT USE THIS, due to '# FIXME(markmc): support multiple hosts' in oslo/messaging/_drivers/amqpdriver.py
|
||||
# transport_url = rabbit://guest@localhost:5672/
|
||||
|
||||
# oslo notification driver for sending audit events via audit middleware.
|
||||
# Meaningful only when middleware is enabled in barbican paste ini file.
|
||||
# This is oslo config MultiStrOpt so can be defined multiple times in case
|
||||
# there is need to route audit event to messaging as well as log.
|
||||
# notification_driver = messagingv2
|
||||
# notification_driver = log
|
||||
|
||||
# ======== OpenStack policy - oslo_policy ===============
|
||||
|
||||
[oslo_policy]
|
||||
|
||||
# ======== OpenStack policy integration
|
||||
# JSON file representing policy (string value)
|
||||
|
@ -112,17 +146,6 @@ policy_file=/etc/barbican/policy.json
|
|||
policy_default_rule=default
|
||||
|
||||
|
||||
{% include "parts/database" %}
|
||||
# ================= Queue Options - oslo.messaging ==========================
|
||||
|
||||
{% include "parts/section-rabbitmq-oslo" %}
|
||||
|
||||
# For HA, specify queue nodes in cluster as 'user@host:5672', comma delimited, ending with '/offset':
|
||||
# For example: transport_url = rabbit://guest@192.168.50.8:5672,guest@192.168.50.9:5672/
|
||||
# DO NOT USE THIS, due to '# FIXME(markmc): support multiple hosts' in oslo/messaging/_drivers/amqpdriver.py
|
||||
# transport_url = rabbit://guest@localhost:5672/
|
||||
|
||||
|
||||
# ================= Queue Options - Application ==========================
|
||||
|
||||
[queue]
|
||||
|
@ -142,6 +165,44 @@ version = '1.1'
|
|||
# Server name for RPC service
|
||||
server_name = 'barbican.queue'
|
||||
|
||||
# Number of asynchronous worker processes.
|
||||
# When greater than 1, then that many additional worker processes are
|
||||
# created for asynchronous worker functionality.
|
||||
asynchronous_workers = 1
|
||||
|
||||
# ================= Retry/Scheduler Options ==========================
|
||||
|
||||
[retry_scheduler]
|
||||
# Seconds (float) to wait between starting retry scheduler
|
||||
initial_delay_seconds = 10.0
|
||||
|
||||
# Seconds (float) to wait between starting retry scheduler
|
||||
periodic_interval_max_seconds = 10.0
|
||||
|
||||
|
||||
# ====================== Quota Options ===============================
|
||||
|
||||
[quotas]
|
||||
# For each resource, the default maximum number that can be used for
|
||||
# a project is set below. This value can be overridden for each
|
||||
# project through the API. A negative value means no limit. A zero
|
||||
# value effectively disables the resource.
|
||||
|
||||
# default number of secrets allowed per project
|
||||
quota_secrets = -1
|
||||
|
||||
# default number of orders allowed per project
|
||||
quota_orders = -1
|
||||
|
||||
# default number of containers allowed per project
|
||||
quota_containers = -1
|
||||
|
||||
# default number of consumers allowed per project
|
||||
quota_consumers = -1
|
||||
|
||||
# default number of CAs allowed per project
|
||||
quota_cas = -1
|
||||
|
||||
# ================= Keystone Notification Options - Application ===============
|
||||
|
||||
[keystone_notifications]
|
||||
|
@ -187,7 +248,11 @@ enabled_secretstore_plugins = store_crypto
|
|||
# ================= Crypto plugin ===================
|
||||
[crypto]
|
||||
namespace = barbican.crypto.plugin
|
||||
{% if hsm -%}
|
||||
enabled_crypto_plugins = p11_crypto
|
||||
{% else -%}
|
||||
enabled_crypto_plugins = simple_crypto
|
||||
{%- endif %}
|
||||
|
||||
[simple_crypto_plugin]
|
||||
# the kek should be a 32-byte value which is base64 encoded
|
||||
|
@ -198,19 +263,40 @@ pem_path = '/etc/barbican/kra_admin_cert.pem'
|
|||
dogtag_host = localhost
|
||||
dogtag_port = 8443
|
||||
nss_db_path = '/etc/barbican/alias'
|
||||
nss_db_path_ca = '/etc/barbican/alias-ca'
|
||||
nss_password = 'password123'
|
||||
simple_cmc_profile = 'caOtherCert'
|
||||
ca_expiration_time = 1
|
||||
plugin_working_dir = '/etc/barbican/dogtag'
|
||||
|
||||
|
||||
{% if hsm -%}
|
||||
[p11_crypto_plugin]
|
||||
# Path to vendor PKCS11 library
|
||||
library_path = '/usr/lib/libCryptoki2_64.so'
|
||||
library_path = {{ hsm.library_path }}
|
||||
# Password to login to PKCS11 session
|
||||
login = 'mypassword'
|
||||
login = {{ hsm.login }}
|
||||
# Label to identify master KEK in the HSM (must not be the same as HMAC label)
|
||||
mkek_label = 'an_mkek'
|
||||
mkek_label = {{ options.label_mkek }}
|
||||
# Length in bytes of master KEK
|
||||
mkek_length = 32
|
||||
mkek_length = {{ options.mkek_key_length }}
|
||||
# Label to identify HMAC key in the HSM (must not be the same as MKEK label)
|
||||
hmac_label = 'my_hmac_label'
|
||||
hmac_label = {{ options.label_hmac }}
|
||||
# HSM Slot id (Should correspond to a configured PKCS11 slot). Default: 1
|
||||
slot_id = {{ hsm.slot_id }}
|
||||
# Enable Read/Write session with the HSM?
|
||||
# rw_session = True
|
||||
# Length of Project KEKs to create
|
||||
# pkek_length = 32
|
||||
# How long to cache unwrapped Project KEKs
|
||||
# pkek_cache_ttl = 900
|
||||
# Max number of items in pkek cache
|
||||
# pkek_cache_limit = 100
|
||||
# Seedfile to generate random data from.
|
||||
seed_file = /dev/random
|
||||
# Seed length to read the random data for seeding the RNG
|
||||
seed_length = 32
|
||||
{%- endif %}
|
||||
|
||||
|
||||
# ================== KMIP plugin =====================
|
||||
|
@ -218,13 +304,84 @@ hmac_label = 'my_hmac_label'
|
|||
username = 'admin'
|
||||
password = 'password'
|
||||
host = localhost
|
||||
port = 9090
|
||||
port = 5696
|
||||
keyfile = '/path/to/certs/cert.key'
|
||||
certfile = '/path/to/certs/cert.crt'
|
||||
ca_certs = '/path/to/certs/LocalCA.crt'
|
||||
|
||||
|
||||
# ================= Certificate plugin ===================
|
||||
[certificate]
|
||||
namespace = barbican.certificate.plugin
|
||||
enabled_certificate_plugins = simple_certificate
|
||||
enabled_certificate_plugins = snakeoil_ca
|
||||
|
||||
[certificate_event]
|
||||
namespace = barbican.certificate.event.plugin
|
||||
enabled_certificate_event_plugins = simple_certificate
|
||||
enabled_certificate_event_plugins = simple_certificate_event
|
||||
|
||||
[snakeoil_ca_plugin]
|
||||
ca_cert_path = /etc/barbican/snakeoil-ca.crt
|
||||
ca_cert_key_path = /etc/barbican/snakeoil-ca.key
|
||||
ca_cert_chain_path = /etc/barbican/snakeoil-ca.chain
|
||||
ca_cert_pkcs7_path = /etc/barbican/snakeoil-ca.p7b
|
||||
subca_cert_key_directory=/etc/barbican/snakeoil-cas
|
||||
|
||||
[cors]
|
||||
|
||||
#
|
||||
# From oslo.middleware.cors
|
||||
#
|
||||
|
||||
# Indicate whether this resource may be shared with the domain
|
||||
# received in the requests "origin" header. (list value)
|
||||
#allowed_origin = <None>
|
||||
|
||||
# Indicate that the actual request can include user credentials
|
||||
# (boolean value)
|
||||
#allow_credentials = true
|
||||
|
||||
# Indicate which headers are safe to expose to the API. Defaults to
|
||||
# HTTP Simple Headers. (list value)
|
||||
#expose_headers = X-Auth-Token, X-Openstack-Request-Id, X-Project-Id, X-Identity-Status, X-User-Id, X-Storage-Token, X-Domain-Id, X-User-Domain-Id, X-Project-Domain-Id, X-Roles
|
||||
|
||||
# Maximum cache age of CORS preflight requests. (integer value)
|
||||
#max_age = 3600
|
||||
|
||||
# Indicate which methods can be used during the actual request. (list
|
||||
# value)
|
||||
#allow_methods = GET,PUT,POST,DELETE,PATCH
|
||||
|
||||
# Indicate which header field names may be used during the actual
|
||||
# request. (list value)
|
||||
#allow_headers = X-Auth-Token, X-Openstack-Request-Id, X-Project-Id, X-Identity-Status, X-User-Id, X-Storage-Token, X-Domain-Id, X-User-Domain-Id, X-Project-Domain-Id, X-Roles
|
||||
|
||||
|
||||
[cors.subdomain]
|
||||
|
||||
#
|
||||
# From oslo.middleware.cors
|
||||
#
|
||||
|
||||
# Indicate whether this resource may be shared with the domain
|
||||
# received in the requests "origin" header. (list value)
|
||||
#allowed_origin = <None>
|
||||
|
||||
# Indicate that the actual request can include user credentials
|
||||
# (boolean value)
|
||||
#allow_credentials = true
|
||||
|
||||
# Indicate which headers are safe to expose to the API. Defaults to
|
||||
# HTTP Simple Headers. (list value)
|
||||
#expose_headers = X-Auth-Token, X-Openstack-Request-Id, X-Project-Id, X-Identity-Status, X-User-Id, X-Storage-Token, X-Domain-Id, X-User-Domain-Id, X-Project-Domain-Id, X-Roles
|
||||
|
||||
# Maximum cache age of CORS preflight requests. (integer value)
|
||||
#max_age = 3600
|
||||
|
||||
# Indicate which methods can be used during the actual request. (list
|
||||
# value)
|
||||
#allow_methods = GET,PUT,POST,DELETE,PATCH
|
||||
|
||||
# Indicate which header field names may be used during the actual
|
||||
# request. (list value)
|
||||
#allow_headers = X-Auth-Token, X-Openstack-Request-Id, X-Project-Id, X-Identity-Status, X-User-Id, X-Storage-Token, X-Domain-Id, X-User-Domain-Id, X-Project-Domain-Id, X-Roles
|
|
@ -3,4 +3,4 @@ os-testr>=0.4.1
|
|||
charms.reactive
|
||||
mock>=1.2
|
||||
coverage>=3.6
|
||||
git+https://github.com/ajkavanagh/charm.openstack#egg=charms-openstack
|
||||
git+https://github.com/openstack/charms.openstack.git#egg=charms-openstack
|
||||
|
|
10
tox.ini
10
tox.ini
|
@ -9,6 +9,7 @@ setenv = VIRTUAL_ENV={envdir}
|
|||
TERM=linux
|
||||
INTERFACE_PATH={toxinidir}/interfaces
|
||||
LAYER_PATH={toxinidir}/layers
|
||||
INTERFACE_PATH={toxinidir}/interfaces
|
||||
JUJU_REPOSITORY={toxinidir}/build
|
||||
passenv = http_proxy https_proxy
|
||||
install_command =
|
||||
|
@ -19,12 +20,7 @@ deps =
|
|||
[testenv:build]
|
||||
basepython = python2.7
|
||||
commands =
|
||||
charm build --log-level DEBUG -o {toxinidir}/build src
|
||||
|
||||
[testenv:py27]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = ostestr {posargs}
|
||||
charm-build --log-level DEBUG -o {toxinidir}/build src {posargs}
|
||||
|
||||
[testenv:py34]
|
||||
basepython = python3.4
|
||||
|
@ -36,7 +32,7 @@ basepython = python3.5
|
|||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:lint]
|
||||
[testenv:pep8]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = flake8 {posargs} src unit_tests
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import mock
|
||||
|
||||
|
@ -11,6 +25,7 @@ sys.modules['charmhelpers'] = charmhelpers
|
|||
sys.modules['charmhelpers.core'] = charmhelpers.core
|
||||
sys.modules['charmhelpers.core.hookenv'] = charmhelpers.core.hookenv
|
||||
sys.modules['charmhelpers.core.host'] = charmhelpers.core.host
|
||||
sys.modules['charmhelpers.core.unitdata'] = charmhelpers.core.unitdata
|
||||
sys.modules['charmhelpers.core.templating'] = charmhelpers.core.templating
|
||||
sys.modules['charmhelpers.contrib'] = charmhelpers.contrib
|
||||
sys.modules['charmhelpers.contrib.openstack'] = charmhelpers.contrib.openstack
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
|
@ -93,6 +107,7 @@ class TestBarbicanHandlers(unittest.TestCase):
|
|||
'render_stuff': ('shared-db.available',
|
||||
'identity-service.available',
|
||||
'amqp.available',),
|
||||
'config_changed': ('config.changed', ),
|
||||
}
|
||||
when_not_patterns = {
|
||||
'install_packages': ('charm.installed', ),
|
||||
|
@ -102,6 +117,7 @@ class TestBarbicanHandlers(unittest.TestCase):
|
|||
(_when_not_args, when_not_patterns)]:
|
||||
for f, args in t.items():
|
||||
# check that function is in patterns
|
||||
# print("f: {}, args: {}".format(f, args))
|
||||
self.assertTrue(f in p.keys())
|
||||
# check that the lists are equal
|
||||
l = [a['args'][0] for a in args]
|
||||
|
@ -122,9 +138,11 @@ class TestBarbicanHandlers(unittest.TestCase):
|
|||
'rabbit-vhost': 'vhost1',
|
||||
}
|
||||
self.config.side_effect = lambda x: reply[x]
|
||||
self.patch(handlers.barbican, 'assess_status')
|
||||
handlers.setup_amqp_req(amqp)
|
||||
amqp.request_access.assert_called_once_with(
|
||||
username='user1', vhost='vhost1')
|
||||
self.assess_status.assert_called_once_with()
|
||||
|
||||
def test_database(self):
|
||||
database = mock.MagicMock()
|
||||
|
@ -135,16 +153,25 @@ class TestBarbicanHandlers(unittest.TestCase):
|
|||
}
|
||||
self.config.side_effect = lambda x: reply[x]
|
||||
self.patch(handlers.hookenv, 'unit_private_ip', 'private_ip')
|
||||
self.patch(handlers.barbican, 'assess_status')
|
||||
handlers.setup_database(database)
|
||||
database.configure.assert_called_once_with(
|
||||
'db1', 'dbuser1', 'private_ip')
|
||||
self.assess_status.assert_called_once_with()
|
||||
|
||||
def test_setup_endpoint(self):
|
||||
self.patch(handlers.barbican, 'setup_endpoint')
|
||||
self.patch(handlers.barbican, 'assess_status')
|
||||
handlers.setup_endpoint('endpoint_object')
|
||||
self.setup_endpoint.assert_called_once_with('endpoint_object')
|
||||
self.assess_status.assert_called_once_with()
|
||||
|
||||
def test_render_stuff(self):
|
||||
self.patch(handlers.barbican, 'render_configs')
|
||||
self.patch(handlers.barbican, 'assess_status')
|
||||
self.patch(handlers.reactive.RelationBase, 'from_state',
|
||||
return_value='hsm')
|
||||
handlers.render_stuff('arg1', 'arg2')
|
||||
self.render_configs.assert_called_once_with(('arg1', 'arg2', ))
|
||||
self.render_configs.assert_called_once_with(('arg1', 'arg2', 'hsm'))
|
||||
self.assess_status.assert_called_once_with()
|
||||
self.from_state.assert_called_once_with('hsm.available')
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
|
@ -13,6 +27,11 @@ class Helper(unittest.TestCase):
|
|||
def setUp(self):
|
||||
self._patches = {}
|
||||
self._patches_start = {}
|
||||
# patch out the select_release to always return 'mitaka'
|
||||
self.patch(barbican.unitdata, 'kv')
|
||||
_getter = mock.MagicMock()
|
||||
_getter.get.return_value = barbican.BarbicanCharm.release
|
||||
self.kv.return_value = _getter
|
||||
|
||||
def tearDown(self):
|
||||
for k, v in self._patches.items():
|
||||
|
@ -76,23 +95,23 @@ class TestBarbicanConfigurationAdapter(Helper):
|
|||
# Make one with no errors, api version 2
|
||||
a = barbican.BarbicanConfigurationAdapter()
|
||||
self.assertEqual(a.barbican_api_keystone_pipeline,
|
||||
'keystone_authtoken context apiapp')
|
||||
'cors keystone_authtoken context apiapp')
|
||||
self.assertEqual(a.barbican_api_pipeline,
|
||||
'keystone_authtoken context apiapp')
|
||||
'cors keystone_authtoken context apiapp')
|
||||
# Now test it with api version 3
|
||||
reply['keystone-api-version'] = '3'
|
||||
a = barbican.BarbicanConfigurationAdapter()
|
||||
self.assertEqual(a.barbican_api_keystone_pipeline,
|
||||
'keystone_v3_authtoken context apiapp')
|
||||
'cors keystone_v3_authtoken context apiapp')
|
||||
self.assertEqual(a.barbican_api_pipeline,
|
||||
'keystone_v3_authtoken context apiapp')
|
||||
'cors keystone_v3_authtoken context apiapp')
|
||||
# and a 'none' version
|
||||
reply['keystone-api-version'] = 'none'
|
||||
a = barbican.BarbicanConfigurationAdapter()
|
||||
self.assertEqual(a.barbican_api_keystone_pipeline,
|
||||
'keystone_v3_authtoken context apiapp')
|
||||
'cors keystone_v3_authtoken context apiapp')
|
||||
self.assertEqual(a.barbican_api_pipeline,
|
||||
'unauthenticated-context apiapp')
|
||||
'cors unauthenticated-context apiapp')
|
||||
# finally, try to create an invalid one.
|
||||
reply['keystone-api-version'] = None
|
||||
with self.assertRaises(ValueError):
|
||||
|
@ -105,8 +124,18 @@ class TestBarbicanAdapters(Helper):
|
|||
def test_barbican_adapters(self, config):
|
||||
reply = {
|
||||
'keystone-api-version': '2',
|
||||
# for the charms.openstack code, which breaks if we don't have:
|
||||
'os-public-hostname': 'host',
|
||||
'os-internal-hostname': 'internal',
|
||||
'os-admin-hostname': 'admin',
|
||||
}
|
||||
config.side_effect = lambda: reply
|
||||
|
||||
def cf(key=None):
|
||||
if key is not None:
|
||||
return reply[key]
|
||||
return reply
|
||||
|
||||
config.side_effect = cf
|
||||
amqp_relation = mock.MagicMock()
|
||||
amqp_relation.relation_name = 'amqp'
|
||||
shared_db_relation = mock.MagicMock()
|
||||
|
@ -129,19 +158,96 @@ class TestBarbicanAdapters(Helper):
|
|||
|
||||
class TestBarbicanCharm(Helper):
|
||||
|
||||
def test__init__(self):
|
||||
self.patch(barbican.ch_utils, 'os_release')
|
||||
barbican.BarbicanCharm()
|
||||
self.os_release.assert_called_once_with('python-keystonemiddleware')
|
||||
def test_action_generate_mkek(self):
|
||||
hsm = mock.MagicMock()
|
||||
hsm.plugin_data = {
|
||||
'library_path': 'path1',
|
||||
'login': '1234',
|
||||
'slot_id': 'slot1'
|
||||
}
|
||||
self.patch(barbican.hookenv, 'config')
|
||||
config = {
|
||||
'mkek-key-length': 5,
|
||||
'label-mkek': 'the-label'
|
||||
}
|
||||
|
||||
def test_install(self):
|
||||
self.patch(barbican.charmhelpers.fetch, 'add_source')
|
||||
b = barbican.BarbicanCharm()
|
||||
self.patch(barbican.charms_openstack.charm.OpenStackCharm,
|
||||
'configure_source')
|
||||
self.patch(barbican.charms_openstack.charm.OpenStackCharm,
|
||||
'install')
|
||||
b.install()
|
||||
self.add_source.assert_called_once_with('ppa:gnuoy/barbican-alt')
|
||||
self.configure_source.assert_called_once_with()
|
||||
self.install.assert_called_once_with()
|
||||
def cf(key=None):
|
||||
if key is not None:
|
||||
return config[key]
|
||||
return config
|
||||
|
||||
self.config.side_effect = cf
|
||||
self.patch(barbican.subprocess, 'check_call')
|
||||
self.patch(barbican.hookenv, 'log')
|
||||
# try generating a an mkek with no failure
|
||||
c = barbican.BarbicanCharm()
|
||||
c.action_generate_mkek(hsm)
|
||||
cmd = [
|
||||
'barbican-manage', 'hsm', 'gen_mkek',
|
||||
'--library-path', 'path1',
|
||||
'--passphrase', '1234',
|
||||
'--slot-id', 'slot1',
|
||||
'--length', '5',
|
||||
'--label', 'the-label',
|
||||
]
|
||||
self.check_call.assert_called_once_with(cmd)
|
||||
self.log.assert_called_once_with(
|
||||
"barbican-mangage hsm gen_mkek succeeded")
|
||||
# and check that a problem is logged if it goes wrong
|
||||
|
||||
def side_effect():
|
||||
raise barbican.subprocess.CalledProcessError
|
||||
|
||||
self.check_call.side_effect = side_effect
|
||||
self.log.reset_mock()
|
||||
with self.assertRaises(Exception):
|
||||
c.action_generate_mkek(hsm)
|
||||
self.log.assert_called_once_with(
|
||||
"barbican-manage hsm gen_mkek failed.")
|
||||
|
||||
def test_action_generate_hmac(self):
|
||||
hsm = mock.MagicMock()
|
||||
hsm.plugin_data = {
|
||||
'library_path': 'path1',
|
||||
'login': '1234',
|
||||
'slot_id': 'slot1'
|
||||
}
|
||||
self.patch(barbican.hookenv, 'config')
|
||||
config = {
|
||||
'hmac-key-length': 5,
|
||||
'label-hmac': 'the-label'
|
||||
}
|
||||
|
||||
def cf(key=None):
|
||||
if key is not None:
|
||||
return config[key]
|
||||
return config
|
||||
|
||||
self.config.side_effect = cf
|
||||
self.patch(barbican.subprocess, 'check_call')
|
||||
self.patch(barbican.hookenv, 'log')
|
||||
# try generating a an hmac with no failure
|
||||
c = barbican.BarbicanCharm()
|
||||
c.action_generate_hmac(hsm)
|
||||
cmd = [
|
||||
'barbican-manage', 'hsm', 'gen_hmac',
|
||||
'--library-path', 'path1',
|
||||
'--passphrase', '1234',
|
||||
'--slot-id', 'slot1',
|
||||
'--length', '5',
|
||||
'--label', 'the-label',
|
||||
]
|
||||
self.check_call.assert_called_once_with(cmd)
|
||||
self.log.assert_called_once_with(
|
||||
"barbican-mangage hsm gen_hmac succeeded")
|
||||
# and check that a problem is logged if it goes wrong
|
||||
|
||||
def side_effect():
|
||||
raise barbican.subprocess.CalledProcessError
|
||||
|
||||
self.check_call.side_effect = side_effect
|
||||
self.log.reset_mock()
|
||||
with self.assertRaises(Exception):
|
||||
c.action_generate_hmac(hsm)
|
||||
self.log.assert_called_once_with(
|
||||
"barbican-manage hsm gen_hmac failed.")
|
||||
|
|
Loading…
Reference in New Issue