# Copyright 2018 AT&T Intellectual Property. All other rights reserved. # # 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 datetime import datetime import logging from pegleg import config from pegleg.engine.util import git PEGLEG_MANAGED_SCHEMA = 'pegleg/PeglegManagedDocument/v1' ENCRYPTED = 'encrypted' GENERATED = 'generated' STORAGE_POLICY = 'storagePolicy' METADATA = 'metadata' LOG = logging.getLogger(__name__) __all__ = ['PeglegManagedSecretsDocument'] class PeglegManagedSecretsDocument(object): """Object representing one Pegleg managed secret document.""" def __init__(self, document, generated=False, catalog=None, author=None): """ Parse and wrap an externally generated document in a pegleg managed document. :param document: The content of the source document :type document: dict :param bool generated: A flag to indicate the documents are auto-generated by pegleg (True), or manually created (False). :param catalog: catalog of the generated secret documents. A catalog must be provided, only if generated is True. :type catalog: A subclass of the ABC pegleg.catalogs.base_catalog.BaseCatalog """ self._catalog = catalog self._author = author self._generated = generated if self.is_pegleg_managed_secret(document): self._pegleg_document = document else: self._pegleg_document = self.__wrap( document, generated, catalog, author) self._embedded_document = \ self._pegleg_document['data']['managedDocument'] @staticmethod def __wrap(secrets_document, generated=False, catalog=None, author=None): """ Embeds a valid deckhand document in a pegleg managed document. :param secrets_document: secrets document to be embedded in a pegleg managed document. :type secrets_document: dict :param bool generated: A flag to indicate the documents are auto-generated by pegleg (True), or manually created (False). :return: pegleg manged document with the wrapped original secrets document. :rtype: dict """ doc = { 'schema': PEGLEG_MANAGED_SCHEMA, 'metadata': { 'name': secrets_document['metadata']['name'], 'schema': 'metadata/Document/v1', 'labels': secrets_document['metadata'].get('labels', {}), 'layeringDefinition': { 'abstract': False, # The current requirement only requires site layer. 'layer': 'site', }, 'storagePolicy': 'cleartext' }, 'data': { 'managedDocument': { 'schema': secrets_document['schema'], 'metadata': secrets_document['metadata'], 'data': secrets_document['data'] } } } if generated: doc['data'][GENERATED] = { 'at': datetime.utcnow().isoformat(), 'by': author, 'specifiedBy': { 'repo': git.repo_url(config.get_site_repo()), 'reference': config.get_site_rev() or 'master', 'path': catalog.catalog_path, }, } return doc @staticmethod def is_pegleg_managed_secret(secrets_document): """" Verify if the document is already a pegleg managed secrets document. :return: True if the document is a pegleg managed secrets document, False otherwise. :rtype: bool """ return PEGLEG_MANAGED_SCHEMA in secrets_document.get('schema') @property def embedded_document(self): """ parse the pegleg managed document, and return the embedded document :return: The original secrets document unwrapped from the pegleg managed document. :rtype: dict """ return self._embedded_document @property def name(self): return self._pegleg_document.get('metadata', {}).get('name') @property def data(self): return self._pegleg_document.get('data') @property def pegleg_document(self): return self._pegleg_document def is_encrypted(self): """If the document is already encrypted return True. False otherwise.""" return ENCRYPTED in self.data def is_generated(self): """If the document is already marked auto-generated return True. False otherwise.""" return GENERATED in self.data def is_storage_policy_encrypted(self): """If the document's storagePolicy is set to encrypted return True. False otherwise.""" return STORAGE_POLICY in self._embedded_document[METADATA] \ and ENCRYPTED in self._embedded_document[METADATA][STORAGE_POLICY] def set_encrypted(self, author=None): """Mark the pegleg managed document as encrypted.""" self.data[ENCRYPTED] = { 'at': datetime.utcnow().isoformat() } if author: self.data[ENCRYPTED]['by'] = author def set_decrypted(self): """Mark the pegleg managed document as un-encrypted.""" self.data.pop(ENCRYPTED) def set_secret(self, secret): self._embedded_document['data'] = secret def get_secret(self): return self._embedded_document.get('data')