Merge "Support regenerating PKI"
This commit is contained in:
commit
567a134e01
@ -473,8 +473,13 @@ Generate PKI
|
|||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
Generate certificates and keys according to all PKICatalog documents in the
|
Generate certificates and keys according to all PKICatalog documents in the
|
||||||
site using the PKI module. Regenerating certificates can be
|
site using the PKI module. The default behavior is to generate all
|
||||||
accomplished by re-running this command.
|
certificates that are not yet present. For example, the first time generate PKI
|
||||||
|
is run or when new entries are added to the PKICatalogue, only those new
|
||||||
|
entries will be generated on subsequent runs.
|
||||||
|
|
||||||
|
Pegleg also supports a full regeneration of all certificates at any time, by
|
||||||
|
using the --regenerate-all flag.
|
||||||
|
|
||||||
Pegleg places generated document files in ``<site>/secrets/passphrases``,
|
Pegleg places generated document files in ``<site>/secrets/passphrases``,
|
||||||
``<site>/secrets/certificates``, or ``<site>/secrets/keypairs`` as
|
``<site>/secrets/certificates``, or ``<site>/secrets/keypairs`` as
|
||||||
@ -511,6 +516,10 @@ Minimum=0, no maximum. Values less than 0 will raise an exception.
|
|||||||
NOTE: A generated certificate where days = 0 should only be used for testing.
|
NOTE: A generated certificate where days = 0 should only be used for testing.
|
||||||
A certificate generated in such a way will be valid for 0 seconds.
|
A certificate generated in such a way will be valid for 0 seconds.
|
||||||
|
|
||||||
|
**--regenerate-all** (Optional, Default=False).
|
||||||
|
|
||||||
|
Force Pegleg to regenerate all PKI items.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
""""""""
|
""""""""
|
||||||
|
|
||||||
@ -520,7 +529,8 @@ Examples
|
|||||||
secrets generate-pki \
|
secrets generate-pki \
|
||||||
<site_name> \
|
<site_name> \
|
||||||
-a <author> \
|
-a <author> \
|
||||||
-d <days>
|
-d <days> \
|
||||||
|
--regenerate-all
|
||||||
|
|
||||||
.. _command-line-repository-overrides:
|
.. _command-line-repository-overrides:
|
||||||
|
|
||||||
|
@ -421,9 +421,13 @@ def secrets():
|
|||||||
|
|
||||||
@secrets.command(
|
@secrets.command(
|
||||||
'generate-pki',
|
'generate-pki',
|
||||||
|
short_help='Generate certs and keys according to the site PKICatalog',
|
||||||
help='Generate certificates and keys according to all PKICatalog '
|
help='Generate certificates and keys according to all PKICatalog '
|
||||||
'documents in the site. Regenerating certificates can be '
|
'documents in the site using the PKI module. The default behavior is '
|
||||||
'accomplished by re-running this command.')
|
'to generate all certificates that are not yet present. For example, '
|
||||||
|
'the first time generate PKI is run or when new entries are added '
|
||||||
|
'to the PKICatalogue, only those new entries will be generated on '
|
||||||
|
'subsequent runs.')
|
||||||
@click.option(
|
@click.option(
|
||||||
'-a',
|
'-a',
|
||||||
'--author',
|
'--author',
|
||||||
@ -439,8 +443,15 @@ def secrets():
|
|||||||
default=365,
|
default=365,
|
||||||
show_default=True,
|
show_default=True,
|
||||||
help='Duration in days generated certificates should be valid.')
|
help='Duration in days generated certificates should be valid.')
|
||||||
|
@click.option(
|
||||||
|
'--regenerate-all',
|
||||||
|
'regenerate_all',
|
||||||
|
is_flag=True,
|
||||||
|
default=False,
|
||||||
|
show_default=True,
|
||||||
|
help='Force Pegleg to regenerate all PKI items.')
|
||||||
@click.argument('site_name')
|
@click.argument('site_name')
|
||||||
def generate_pki(site_name, author, days):
|
def generate_pki(site_name, author, days, regenerate_all):
|
||||||
"""Generate certificates, certificate authorities and keypairs for a given
|
"""Generate certificates, certificate authorities and keypairs for a given
|
||||||
site.
|
site.
|
||||||
|
|
||||||
@ -448,7 +459,7 @@ def generate_pki(site_name, author, days):
|
|||||||
|
|
||||||
engine.repository.process_repositories(site_name, overwrite_existing=True)
|
engine.repository.process_repositories(site_name, overwrite_existing=True)
|
||||||
pkigenerator = catalog.pki_generator.PKIGenerator(
|
pkigenerator = catalog.pki_generator.PKIGenerator(
|
||||||
site_name, author=author, duration=days)
|
site_name, author=author, duration=days, regenerate_all=regenerate_all)
|
||||||
output_paths = pkigenerator.generate()
|
output_paths = pkigenerator.generate()
|
||||||
|
|
||||||
click.echo("Generated PKI files written to:\n%s" % '\n'.join(output_paths))
|
click.echo("Generated PKI files written to:\n%s" % '\n'.join(output_paths))
|
||||||
|
@ -21,6 +21,7 @@ from pegleg import config
|
|||||||
from pegleg.engine.catalog import pki_utility
|
from pegleg.engine.catalog import pki_utility
|
||||||
from pegleg.engine.common import managed_document as md
|
from pegleg.engine.common import managed_document as md
|
||||||
from pegleg.engine import exceptions
|
from pegleg.engine import exceptions
|
||||||
|
from pegleg.engine import site
|
||||||
from pegleg.engine import util
|
from pegleg.engine import util
|
||||||
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
||||||
|
|
||||||
@ -42,7 +43,12 @@ class PKIGenerator(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self, sitename, block_strings=True, author=None, duration=365):
|
self,
|
||||||
|
sitename,
|
||||||
|
block_strings=True,
|
||||||
|
author=None,
|
||||||
|
duration=365,
|
||||||
|
regenerate_all=False):
|
||||||
"""Constructor for ``PKIGenerator``.
|
"""Constructor for ``PKIGenerator``.
|
||||||
|
|
||||||
:param int duration: Duration in days that generated certificates
|
:param int duration: Duration in days that generated certificates
|
||||||
@ -53,11 +59,12 @@ class PKIGenerator(object):
|
|||||||
block-style YAML string. Defaults to true.
|
block-style YAML string. Defaults to true.
|
||||||
:param str author: Identifying name of the author generating new
|
:param str author: Identifying name of the author generating new
|
||||||
certificates.
|
certificates.
|
||||||
|
:param bool regenerate_all: If Pegleg should regenerate all certs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self._regenerate_all = regenerate_all
|
||||||
self._sitename = sitename
|
self._sitename = sitename
|
||||||
self._documents = util.definition.documents_for_site(sitename)
|
self._documents = site.get_rendered_docs(sitename)
|
||||||
self._author = author
|
self._author = author
|
||||||
|
|
||||||
self.keys = pki_utility.PKIUtility(
|
self.keys = pki_utility.PKIUtility(
|
||||||
@ -126,11 +133,10 @@ class PKIGenerator(object):
|
|||||||
|
|
||||||
def _get_or_gen(self, generator, kinds, document_name, *args, **kwargs):
|
def _get_or_gen(self, generator, kinds, document_name, *args, **kwargs):
|
||||||
docs = self._find_docs(kinds, document_name)
|
docs = self._find_docs(kinds, document_name)
|
||||||
if not docs:
|
if not docs or self._regenerate_all:
|
||||||
docs = generator(document_name, *args, **kwargs)
|
docs = generator(document_name, *args, **kwargs)
|
||||||
else:
|
else:
|
||||||
docs = PeglegSecretManagement(docs=docs)
|
docs = PeglegSecretManagement(docs=docs)
|
||||||
|
|
||||||
# Adding these to output should be idempotent, so we use a dict.
|
# Adding these to output should be idempotent, so we use a dict.
|
||||||
|
|
||||||
for wrapper_doc in docs:
|
for wrapper_doc in docs:
|
||||||
|
@ -106,24 +106,7 @@ def collect(site_name, save_location):
|
|||||||
|
|
||||||
|
|
||||||
def render(site_name, output_stream, validate):
|
def render(site_name, output_stream, validate):
|
||||||
documents = []
|
rendered_documents = get_rendered_docs(site_name, validate=validate)
|
||||||
# Ignore YAML tags, only construct dicts
|
|
||||||
SafeConstructor.add_multi_constructor(
|
|
||||||
'', lambda loader, suffix, node: None)
|
|
||||||
for filename in util.definition.site_files(site_name):
|
|
||||||
with open(filename, 'r') as f:
|
|
||||||
documents.extend(list(yaml.safe_load_all(f)))
|
|
||||||
|
|
||||||
rendered_documents, errors = util.deckhand.deckhand_render(
|
|
||||||
documents=documents, validate=validate)
|
|
||||||
err_msg = ''
|
|
||||||
if errors:
|
|
||||||
for err in errors:
|
|
||||||
if isinstance(err, tuple) and len(err) > 1:
|
|
||||||
err_msg += ': '.join(err) + '\n'
|
|
||||||
else:
|
|
||||||
err_msg += str(err) + '\n'
|
|
||||||
raise click.ClickException(err_msg)
|
|
||||||
|
|
||||||
if output_stream:
|
if output_stream:
|
||||||
files.dump_all(
|
files.dump_all(
|
||||||
@ -142,6 +125,30 @@ def render(site_name, output_stream, validate):
|
|||||||
explicit_end=True))
|
explicit_end=True))
|
||||||
|
|
||||||
|
|
||||||
|
def get_rendered_docs(site_name, validate=True):
|
||||||
|
documents = []
|
||||||
|
# Ignore YAML tags, only construct dicts
|
||||||
|
SafeConstructor.add_multi_constructor(
|
||||||
|
'', lambda loader, suffix, node: None)
|
||||||
|
for filename in util.definition.site_files(site_name):
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
documents.extend(list(yaml.safe_load_all(f)))
|
||||||
|
|
||||||
|
rendered_documents, errors = util.deckhand.deckhand_render(
|
||||||
|
documents=documents, validate=validate)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
err_msg = ''
|
||||||
|
for err in errors:
|
||||||
|
if isinstance(err, tuple) and len(err) > 1:
|
||||||
|
err_msg += ': '.join(err) + '\n'
|
||||||
|
else:
|
||||||
|
err_msg += str(err) + '\n'
|
||||||
|
raise click.ClickException(err_msg)
|
||||||
|
|
||||||
|
return rendered_documents
|
||||||
|
|
||||||
|
|
||||||
def list_(output_stream):
|
def list_(output_stream):
|
||||||
"""List site names for a given repository."""
|
"""List site names for a given repository."""
|
||||||
|
|
||||||
|
@ -63,6 +63,18 @@ _SITE_DEFINITION = textwrap.dedent(
|
|||||||
...
|
...
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
_LAYERING_DEFINITION = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
schema: deckhand/LayeringPolicy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Control/v1
|
||||||
|
name: layering-policy
|
||||||
|
data:
|
||||||
|
layerOrder:
|
||||||
|
- site
|
||||||
|
""")
|
||||||
|
|
||||||
_CA_KEY_NAME = "kubernetes"
|
_CA_KEY_NAME = "kubernetes"
|
||||||
_CERT_KEY_NAME = "kubelet-n3"
|
_CERT_KEY_NAME = "kubelet-n3"
|
||||||
_KEYPAIR_KEY_NAME = "service-account"
|
_KEYPAIR_KEY_NAME = "service-account"
|
||||||
@ -192,6 +204,8 @@ def create_tmp_pki_structure(tmpdir):
|
|||||||
test_structure = copy.deepcopy(_SITE_TEST_STRUCTURE)
|
test_structure = copy.deepcopy(_SITE_TEST_STRUCTURE)
|
||||||
test_structure['files']['site-definition.yaml'] = yaml.safe_load(
|
test_structure['files']['site-definition.yaml'] = yaml.safe_load(
|
||||||
site_definition)
|
site_definition)
|
||||||
|
test_structure['files']['layering-definition.yaml'] = yaml.safe_load(
|
||||||
|
_LAYERING_DEFINITION)
|
||||||
test_structure['directories']['pki']['files'][
|
test_structure['directories']['pki']['files'][
|
||||||
'pki-catalog.yaml'] = yaml.safe_load(pki_catalog)
|
'pki-catalog.yaml'] = yaml.safe_load(pki_catalog)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user