Merge "Added document wrapping command"
This commit is contained in:
commit
6348b83e3c
@ -421,12 +421,36 @@ Usage:
|
||||
./pegleg.sh site <options> upload <site_name> --context-marker=<uuid>
|
||||
|
||||
Site Secrets Group
|
||||
==================
|
||||
------------------
|
||||
|
||||
Subgroup of :ref:`site-group`.
|
||||
|
||||
A sub-group of site command group, which allows you to perform secrets
|
||||
level operations for secrets documents of a site.
|
||||
|
||||
.. note::
|
||||
|
||||
For the CLI commands ``encrypt``, ``decrypt``, ``generate-pki``, and ``wrap``
|
||||
in the ``secrets`` command
|
||||
group, which encrypt or decrypt site secrets, two environment variables,
|
||||
``PEGLEG_PASSPHRASE``, and ``PEGLEG_SALT``, are used to capture the
|
||||
master passphrase, and the salt needed for encryption and decryption of the
|
||||
site secrets. The contents of ``PEGLEG_PASSPHRASE``, and ``PEGLEG_SALT``
|
||||
are not generated by Pegleg, but are created externally, and set by
|
||||
deployment engineers or tooling.
|
||||
|
||||
A minimum length of 24 for master passphrases will be checked by all CLI
|
||||
commands, which use the ``PEGLEG_PASSPHRASE`` and ``PEGLEG_SALT``.
|
||||
All other criteria around master passphrase strength are assumed to be
|
||||
enforced elsewhere.
|
||||
|
||||
::
|
||||
|
||||
./pegleg.sh site -r <site_repo> -e <extra_repo> secrets <command> <options>
|
||||
|
||||
|
||||
Generate PKI
|
||||
------------
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Generate certificates and keys according to all PKICatalog documents in the
|
||||
site using the PKI module. Regenerating certificates can be
|
||||
@ -454,7 +478,7 @@ Dashes in the document names will be converted to underscores for consistency.
|
||||
Name of site.
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
""""""""
|
||||
|
||||
::
|
||||
|
||||
@ -472,31 +496,6 @@ Examples
|
||||
|
||||
.. _command-line-repository-overrides:
|
||||
|
||||
Secrets
|
||||
-------
|
||||
|
||||
A sub-group of site command group, which allows you to perform secrets
|
||||
level operations for secrets documents of a site.
|
||||
|
||||
.. note::
|
||||
|
||||
For the CLI commands ``encrypt`` and ``decrypt`` in the ``secrets`` command
|
||||
group, which encrypt or decrypt site secrets, two environment variables,
|
||||
``PEGLEG_PASSPHRASE``, and ``PEGLEG_SALT``, are used to capture the
|
||||
master passphrase, and the salt needed for encryption and decryption of the
|
||||
site secrets. The contents of ``PEGLEG_PASSPHRASE``, and ``PEGLEG_SALT``
|
||||
are not generated by Pegleg, but are created externally, and set by a
|
||||
deployment engineers or tooling.
|
||||
|
||||
A minimum length of 24 for master passphrases will be checked by all CLI
|
||||
commands, which use the ``PEGLEG_PASSPHRASE``. All other criteria around
|
||||
master passphrase strength are assumed to be enforced elsewhere.
|
||||
|
||||
::
|
||||
|
||||
./pegleg.sh site -r <site_repo> -e <extra_repo> secrets <command> <options>
|
||||
|
||||
|
||||
Encrypt
|
||||
^^^^^^^
|
||||
|
||||
@ -612,6 +611,58 @@ Example:
|
||||
secrets decrypt site1 -f \
|
||||
/opt/security-manifests/site/site1/passwords/password1.yaml
|
||||
|
||||
Wrap
|
||||
^^^^
|
||||
|
||||
Wrap bare files (e.g. pem or crt) in a PeglegManagedDocument and optionally encrypt them.
|
||||
|
||||
**site_name** (Required).
|
||||
|
||||
Name of site.
|
||||
|
||||
**-a / --author**
|
||||
|
||||
Identifying name of the author generating new certificates. Used
|
||||
for tracking provenance information in the PeglegManagedDocuments.
|
||||
An attempt is made to automatically determine this value,
|
||||
but should be provided.
|
||||
|
||||
**-f / --filename**
|
||||
|
||||
The relative path to the file to be wrapped.
|
||||
|
||||
**-o / --output-path**
|
||||
|
||||
The output path for the wrapped file. (default: input path with the extension
|
||||
replaced with .yaml)
|
||||
|
||||
**-s / --schema**
|
||||
|
||||
The schema for the document to be wrapped, e.g. deckhand/Certificate/v1
|
||||
|
||||
**-n / --name**
|
||||
|
||||
The name for the document to be wrapped, e.g. new-cert.
|
||||
|
||||
**-l / --layer**
|
||||
|
||||
The layer for the document to be wrapped, e.g. site.
|
||||
|
||||
**--encrypt / --no-encrypt**
|
||||
|
||||
A flag specifying whether to encrypt the output file. (default: True)
|
||||
|
||||
Examples
|
||||
""""""""
|
||||
|
||||
::
|
||||
|
||||
./pegleg.sh site -r /home/myuser/myrepo \
|
||||
secrets wrap -a myuser -f secrets/certificates/new_cert.crt \
|
||||
-o secrets/certificates/new_cert.yaml -s "deckhand/Certificate/v1" \
|
||||
-n "new-cert" -l site mysite
|
||||
|
||||
|
||||
genesis_bundle
|
||||
--------------
|
||||
|
||||
|
@ -23,6 +23,7 @@ from pegleg import config
|
||||
from pegleg import engine
|
||||
from pegleg.engine import bundle
|
||||
from pegleg.engine import catalog
|
||||
from pegleg.engine.secrets import wrap_secret
|
||||
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
||||
from pegleg.engine.util.shipyard_helper import ShipyardHelper
|
||||
|
||||
@ -415,6 +416,62 @@ def generate_pki(site_name, author):
|
||||
click.echo("Generated PKI files written to:\n%s" % '\n'.join(output_paths))
|
||||
|
||||
|
||||
@secrets.command(
|
||||
'wrap',
|
||||
help='Wrap bare files (e.g. pem or crt) in a PeglegManagedDocument '
|
||||
'and encrypt them (by default).')
|
||||
@click.option(
|
||||
'-a',
|
||||
'--author',
|
||||
'author',
|
||||
help='Author for the new wrapped file.')
|
||||
@click.option(
|
||||
'-f',
|
||||
'--filename',
|
||||
'file_name',
|
||||
help='The relative file path for the file to be wrapped.')
|
||||
@click.option(
|
||||
'-o',
|
||||
'--output-path',
|
||||
'output_path',
|
||||
required=False,
|
||||
help='The output path for the wrapped file. (default: input path with '
|
||||
'.yaml)')
|
||||
@click.option(
|
||||
'-s',
|
||||
'--schema',
|
||||
'schema',
|
||||
help='The schema for the document to be wrapped, e.g. '
|
||||
'deckhand/Certificate/v1')
|
||||
@click.option(
|
||||
'-n',
|
||||
'--name',
|
||||
'name',
|
||||
help='The name for the document to be wrapped, e.g. new-cert')
|
||||
@click.option(
|
||||
'-l',
|
||||
'--layer',
|
||||
'layer',
|
||||
help='The layer for the document to be wrapped., e.g. site.')
|
||||
@click.option(
|
||||
'--encrypt/--no-encrypt',
|
||||
'encrypt',
|
||||
is_flag=True,
|
||||
default=True,
|
||||
help='Whether to encrypt the wrapped file (default: True).')
|
||||
@click.argument('site_name')
|
||||
def wrap_secret_cli(*, site_name, author, file_name, output_path, schema,
|
||||
name, layer, encrypt):
|
||||
"""Wrap a bare secrets file in a YAML and ManagedDocument.
|
||||
|
||||
"""
|
||||
|
||||
engine.repository.process_repositories(site_name,
|
||||
overwrite_existing=True)
|
||||
wrap_secret(author, file_name, output_path, schema,
|
||||
name, layer, encrypt)
|
||||
|
||||
|
||||
@site.command(
|
||||
'genesis_bundle',
|
||||
help='Construct the genesis deployment bundle.')
|
||||
|
@ -14,11 +14,14 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from pegleg.engine.generators.passphrase_generator import PassphraseGenerator
|
||||
from pegleg.engine.util.cryptostring import CryptoString
|
||||
from pegleg.engine.util import definition
|
||||
from pegleg.engine.util import files
|
||||
from pegleg.engine.util.pegleg_managed_document import \
|
||||
PeglegManagedSecretsDocument as PeglegManagedSecret
|
||||
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
||||
|
||||
__all__ = ('encrypt', 'decrypt', 'generate_passphrases')
|
||||
@ -141,3 +144,45 @@ def generate_crypto_string(length):
|
||||
"""
|
||||
|
||||
return CryptoString().get_crypto_string(length)
|
||||
|
||||
|
||||
def wrap_secret(author, file_name, output_path, schema,
|
||||
name, layer, encrypt):
|
||||
"""Wrap a bare secrets file in a YAML and ManagedDocument.
|
||||
|
||||
:param author: author for ManagedDocument
|
||||
:param file_name: file path for input file
|
||||
:param output_path: file path for output file
|
||||
:param schema: schema for wrapped document
|
||||
:param name: name for wrapped document
|
||||
:param layer: layer for wrapped document
|
||||
:param encrypt: whether to encrypt the output doc
|
||||
"""
|
||||
|
||||
if not output_path:
|
||||
output_path = os.path.splitext(file_name)[0] + ".yaml"
|
||||
|
||||
with open(file_name, "r") as in_fi:
|
||||
data = in_fi.read()
|
||||
|
||||
inner_doc = {
|
||||
"schema": schema,
|
||||
"data": data,
|
||||
"metadata": {
|
||||
"layeringDefinition": {
|
||||
"abstract": False,
|
||||
"layer": layer
|
||||
},
|
||||
"name": name,
|
||||
"schema": "metadata/Document/v1",
|
||||
"storagePolicy": "encrypted" if encrypt else "cleartext"
|
||||
}
|
||||
}
|
||||
managed_secret = PeglegManagedSecret(inner_doc, author=author)
|
||||
if encrypt:
|
||||
psm = PeglegSecretManagement(docs=[inner_doc], author=author)
|
||||
output_doc = psm.get_encrypted_secrets()[0][0]
|
||||
else:
|
||||
output_doc = managed_secret.pegleg_document
|
||||
with open(output_path, "w") as output_fi:
|
||||
yaml.safe_dump(output_doc, output_fi)
|
||||
|
@ -36,6 +36,16 @@ TEST_PARAMS = {
|
||||
"repo_url": "https://github.com/openstack/airship-treasuremap.git",
|
||||
}
|
||||
|
||||
test_cert = """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
||||
DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
|
||||
DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
|
||||
DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
|
||||
DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
|
||||
|
||||
-----END CERTIFICATE-----
|
||||
"""
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not test_utils.is_connected(),
|
||||
@ -552,6 +562,53 @@ class TestSiteSecretsActions(BaseCLIActionTest):
|
||||
result = self.runner.invoke(cli.site, ['-r', repo_path] + secrets_opts)
|
||||
assert result.exit_code == 0, result.output
|
||||
|
||||
@mock.patch.dict(os.environ, {
|
||||
"PEGLEG_PASSPHRASE": "123456789012345678901234567890",
|
||||
"PEGLEG_SALT": "123456"
|
||||
})
|
||||
def test_site_secrets_wrap(self):
|
||||
"""Validates ``generate-pki`` action using local repo path."""
|
||||
# Scenario:
|
||||
#
|
||||
# 1) Encrypt a file in a local repo
|
||||
|
||||
repo_path = self.treasuremap_path
|
||||
file_dir = os.path.join(repo_path, "site", "airship-seaworthy",
|
||||
"secrets", "certificates")
|
||||
file_path = os.path.join(file_dir, "test.crt")
|
||||
output_path = os.path.join(file_dir, "test.yaml")
|
||||
|
||||
with open(file_path, "w") as test_crt_fi:
|
||||
test_crt_fi.write(test_cert)
|
||||
secrets_opts = ['secrets', 'wrap', "-a", "lm734y", "-f", file_path,
|
||||
"-s", "deckhand/Certificate/v1",
|
||||
"-n", "test-certificate", "-l", "site", "--no-encrypt",
|
||||
self.site_name]
|
||||
result = self.runner.invoke(cli.site, ["-r", repo_path] + secrets_opts)
|
||||
assert result.exit_code == 0
|
||||
|
||||
with open(output_path, "r") as output_fi:
|
||||
doc = yaml.safe_load(output_fi)
|
||||
assert doc["data"]["managedDocument"]["data"] == test_cert
|
||||
assert doc["data"]["managedDocument"]["schema"] == "deckhand/Certificate/v1"
|
||||
assert doc["data"]["managedDocument"]["metadata"]["name"] == "test-certificate"
|
||||
assert doc["data"]["managedDocument"]["metadata"]["layeringDefinition"]["layer"] == "site"
|
||||
assert doc["data"]["managedDocument"]["metadata"]["storagePolicy"] == "cleartext"
|
||||
|
||||
os.remove(output_path)
|
||||
secrets_opts = ['secrets', 'wrap', "-a", "lm734y", "-f", file_path,
|
||||
"-o", output_path, "-s", "deckhand/Certificate/v1",
|
||||
"-n", "test-certificate", "-l", "site",
|
||||
self.site_name]
|
||||
result = self.runner.invoke(cli.site, ["-r", repo_path] + secrets_opts)
|
||||
assert result.exit_code == 0
|
||||
|
||||
with open(output_path, "r") as output_fi:
|
||||
doc = yaml.safe_load(output_fi)
|
||||
assert "encrypted" in doc["data"]
|
||||
assert "managedDocument" in doc["data"]
|
||||
|
||||
|
||||
class TestTypeCliActions(BaseCLIActionTest):
|
||||
"""Tests type-level CLI actions."""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user