Exemple #1
0
    def backup_restore_secret(self):
        """
        backs up a key vault secret and restores it to another key vault
        """
        # create a key vault
        first_vault = self.create_vault()

        # create a secret client
        credential = DefaultAzureCredential()
        first_secret_client = SecretClient(
            vault_url=first_vault.properties.vault_uri, credential=credential)

        # add a secret to the vault
        secret_name = get_name('secret')
        secret_value = 'this is a secret value to be migrated from one vault to another'

        secret = first_secret_client.set_secret(secret_name, secret_value)
        print('created secret {}'.format(secret.name))

        # list the secrets in the vault
        secret_properties = first_secret_client.list_properties_of_secrets()
        print("all of the secrets in the client's vault:")
        for secret_property in secret_properties:
            print(secret_property.name)

        # backup the secret
        backup = first_secret_client.backup_secret(secret_name)
        print('backed up secret {}'.format(secret_name))

        # create a second vault
        second_vault = self.create_vault()

        # create a secret client
        second_secret_client = SecretClient(
            vault_url=second_vault.properties.vault_uri, credential=credential)

        # restore the secret to the new vault
        restored = second_secret_client.restore_secret_backup(backup)
        print('restored secret {}'.format(restored.name))

        # list the secrets in the new vault
        secret_properties = second_secret_client.list_properties_of_secrets()
        print("all of the secrets in the new vault:")
        for secret_property in secret_properties:
            print(secret_property.name)
def test_managed_identity_live(live_managed_identity_config):
    credential = ManagedIdentityCredential(
        client_id=live_managed_identity_config["client_id"])

    # do something with Key Vault to verify the credential can get a valid token
    client = SecretClient(live_managed_identity_config["vault_url"],
                          credential,
                          logging_enable=True)
    for _ in client.list_properties_of_secrets():
        pass
Exemple #3
0
class KeyVaultManager(object):
    def __init__(self, vault_url: str) -> None:
        self.url = vault_url
        self.logger = cast(pylogrus.PyLogrus, logging.getLogger("keyvault2kube.keyvault")).withFields(
            {"vault": vault_url}
        )
        credential = cast("TokenCredential", DefaultAzureCredential())
        self._secret_client = SecretClient(vault_url=vault_url, credential=credential)

    def get_secrets(self) -> List[Secret]:
        secrets: Dict[str, Secret] = {}

        try:
            for secret in self._secret_client.list_properties_of_secrets():
                if not secret.tags:
                    continue
                if "k8s_secret_name" not in secret.tags:
                    continue

                try:
                    secret_value_obj = self._secret_client.get_secret(secret.name)
                except Exception as err:
                    self.logger.withFields({"secret": secret.name}).exception(
                        "Failed to get secret from KeyVault", exc_info=err
                    )
                    continue

                secret = Secret(
                    secret_value_obj.value,
                    secret_version=secret_value_obj.properties.version,
                    key_vault_secret_name=secret.name,
                    key_vault=secret.vault_url,
                    k8s_secret_name=secret.tags["k8s_secret_name"],
                    last_updated=secret.updated_on,
                    content_type=secret.content_type,
                    k8s_secret_key=secret.tags.get("k8s_secret_key"),
                    k8s_namespaces=secret.tags.get("k8s_namespaces"),
                    k8s_type=secret.tags.get("k8s_type"),
                    convert=secret.tags.get("k8s_convert"),
                )

                # Simple joining of secrets into 1 kube secret if needed
                if secret.k8s_secret_name in secrets:
                    secrets[secret.k8s_secret_name].add_key(secret)
                else:
                    secrets[secret.k8s_secret_name] = secret
        except azure.core.exceptions.ClientAuthenticationError as err:
            self.logger.exception("No credentials available", exc_info=err)
            sys.exit(1)

        except Exception as err:
            self.logger.exception("Failed to list secrets from KeyVault", exc_info=err)

        return list(secrets.values())
Exemple #4
0
class ListSecretsTest(PerfStressTest):

    def __init__(self, arguments):
        super().__init__(arguments)

        # Auth configuration
        self.credential = DefaultAzureCredential()
        self.async_credential = AsyncDefaultAzureCredential()

        # Create clients
        vault_url = self.get_from_env("AZURE_KEYVAULT_URL")
        self.client = SecretClient(vault_url, self.credential, **self._client_kwargs)
        self.async_client = AsyncSecretClient(vault_url, self.async_credential, **self._client_kwargs)
        self.secret_names = ["livekvtestlistperfsecret{}".format(i) for i in range(self.args.list_size)]

    async def global_setup(self):
        """The global setup is run only once."""
        await super().global_setup()
        create = [self.async_client.set_secret(name, "secret-value") for name in self.secret_names]
        await asyncio.wait(create)

    async def global_cleanup(self):
        """The global cleanup is run only once."""
        delete = [self.async_client.delete_secret(name) for name in self.secret_names]
        await asyncio.wait(delete)
        purge = [self.async_client.purge_deleted_secret(name) for name in self.secret_names]
        await asyncio.wait(purge)
        await super().global_cleanup()

    async def close(self):
        """This is run after cleanup."""
        await self.async_client.close()
        await self.async_credential.close()
        await super().close()

    def run_sync(self):
        """The synchronous perf test."""
        secret_properties = self.client.list_properties_of_secrets()
        # enumerate secrets to exercise paging code
        list(secret_properties)

    async def run_async(self):
        """The asynchronous perf test."""
        secret_properties = self.async_client.list_properties_of_secrets()
        # enumerate secrets to exercise paging code
        async for _ in secret_properties:
            pass

    @staticmethod
    def add_arguments(parser):
        super(ListSecretsTest, ListSecretsTest).add_arguments(parser)
        parser.add_argument(
            '--list-size', nargs='?', type=int, help='Number of secrets to list. Defaults to 10', default=10
        )
Exemple #5
0
    def grab_secrets_kubernetes_objects(self):
        """
        Gets secrets from KeyVault and creates them as Kubernetes secrets objects
        """
        vault_base_url = os.getenv('VAULT_BASE_URL')
        secrets_keys = os.getenv('SECRETS_KEYS')
        self._secrets_namespace = os.getenv('SECRETS_NAMESPACE', 'default')

        credential = self._get_credential()
        secret_client = SecretClient(vault_url=vault_base_url,
                                     credential=credential,
                                     timeout=TIMEOUT)
        _logger.info('Using vault: %s', vault_base_url)

        # Retrieving all secrets from Key Vault if specified by user
        if secrets_keys is None:
            _logger.info('Retrieving all secrets from Key Vault.')

            all_secrets = list(secret_client.list_properties_of_secrets())
            secrets_keys = ';'.join(
                [secret.id.split('/')[-1] for secret in all_secrets])

        if secrets_keys is not None:
            for key_info in filter(None, secrets_keys.split(';')):
                key_name, key_version, cert_filename, key_filename = self._split_keyinfo(
                    key_info)
                _logger.info(
                    'Retrieving secret name:%s with version: %s output certFileName: %s keyFileName: %s',
                    key_name, key_version, cert_filename, key_filename)
                secret = secret_client.get_secret(key_name, key_version)

                secret_type_env_key = key_name.upper() + "_SECRET_TYPE"
                secret_type = os.getenv(secret_type_env_key,
                                        os.getenv("SECRETS_TYPE", 'Opaque'))
                if secret_type == 'kubernetes.io/tls':
                    if secret.properties.key_id is not None:
                        _logger.info('Secret is backing certificate.')
                        if secret.properties.content_type == 'application/x-pkcs12':
                            self._create_kubernetes_secret_objects(
                                key_name, secret.value, secret_type)
                        else:
                            _logger.error('Secret is not in pkcs12 format')
                            sys.exit(1)
                    elif (key_name != cert_filename):
                        _logger.error(
                            'Cert filename provided for secret %s not backing a certificate.',
                            key_name)
                        sys.exit((
                            'Error: Cert filename provided for secret {0} not backing a certificate.'
                        ).format(key_name))
                else:
                    self._create_kubernetes_secret_objects(
                        key_name, secret.value, secret_type)
Exemple #6
0
class keyVaultInstance:
    def __init__(self):
        self.__setattr__("Dan", "test")

    '''
        Obtain a KeyVaultManagementClient so we can retrieve vault names. 
    '''

    def getClient(self):
        self._kvmgmtClient = get_client_from_cli_profile(
            KeyVaultManagementClient)
        return self._kvmgmtClient

    def getVaultNames(self):
        vaultName = []
        if self._kvmgmtClient is not None:
            for vlt in self._kvmgmtClient.vaults.list():
                vaultName.append(vlt.name)

        return vaultName

    '''
        Get a SecretClient so we can get/set secrets to a specific vault. 

        To do this, the SP has to have been added with secret access to the individual 
        KeyVault itself. THIS IS IMPORTANT OTHERWISE YOU WILL NOT GAIN ACCESS TO SECRETS
    '''

    def getKeyVltClient(self, vaultName, cl, sct, tnt):
        credential = ClientSecretCredential(tnt, cl, sct)
        vaultAddress = "https://{}.vault.azure.net/".format(vaultName)
        self._vaultClient = SecretClient(vault_url=vaultAddress,
                                         credential=credential)
        return self._vaultClient

    def listVaultSecrets(self):
        returnSecrets = {}
        if self._vaultClient is not None:
            secret_properties = self._vaultClient.list_properties_of_secrets()
            for prop in secret_properties:
                print(prop.name)
                sct = self._vaultClient.get_secret(prop.name)
                print(sct.name)
                returnSecrets[sct.name] = sct.value

        return returnSecrets

    def setVaultSecret(self, secretName, secretValue):
        if self._vaultClient is not None:
            print("setting secret")
            self._vaultClient.set_secret(secretName, secretValue)
Exemple #7
0
import os
import sys
from azure.identity import AuthenticationRequiredError, InteractiveBrowserCredential
from azure.keyvault.secrets import SecretClient

# This sample uses Key Vault only for demonstration. Any client accepting azure-identity credentials will work the same.
VAULT_URL = os.environ.get("VAULT_URL")
if not VAULT_URL:
    print(
        "This sample expects environment variable 'VAULT_URL' to be set with the URL of a Key Vault."
    )
    sys.exit(1)

# If it's important for your application to prompt for authentication only at certain times,
# create the credential with disable_automatic_authentication=True. This configures the credential to raise
# when interactive authentication is required, instead of immediately beginning that authentication.
credential = InteractiveBrowserCredential(
    disable_automatic_authentication=True)
client = SecretClient(VAULT_URL, credential)

try:
    secret_names = [s.name for s in client.list_properties_of_secrets()]
except AuthenticationRequiredError as ex:
    # Interactive authentication is necessary to authorize the client's request. The exception carries the
    # requested authentication scopes. If you pass these to 'authenticate', it will cache an access token
    # for those scopes.
    credential.authenticate(scopes=ex.scopes)

# the client operation should now succeed
secret_names = [s.name for s in client.list_properties_of_secrets()]
class ListSecretsTest(PerfStressTest):
    def __init__(self, arguments):
        super().__init__(arguments)

        # Auth configuration
        self.credential = DefaultAzureCredential()
        self.async_credential = AsyncDefaultAzureCredential()

        # Create clients
        vault_url = self.get_from_env("AZURE_KEYVAULT_URL")
        self.client = SecretClient(vault_url, self.credential,
                                   **self._client_kwargs)
        self.async_client = AsyncSecretClient(vault_url, self.async_credential,
                                              **self._client_kwargs)
        self.secret_names = [
            "livekvtestlistperfsecret{}".format(i)
            for i in range(self.args.count)
        ]

    async def global_setup(self):
        """The global setup is run only once."""
        # Validate that vault contains 0 secrets (including soft-deleted secrets), since additional secrets
        # (including soft-deleted) impact performance.
        async for secret in self.async_client.list_properties_of_secrets():
            raise Exception(
                "KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test"
                % self.async_client.vault_url)
        async for secret in self.async_client.list_deleted_secrets():
            raise Exception(
                "KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test"
                % self.async_client.vault_url)

        await super().global_setup()
        create = [
            self.async_client.set_secret(name, "secret-value")
            for name in self.secret_names
        ]
        await asyncio.wait(create)

    async def global_cleanup(self):
        """The global cleanup is run only once."""
        delete = [
            self.async_client.delete_secret(name) for name in self.secret_names
        ]
        await asyncio.wait(delete)
        purge = [
            self.async_client.purge_deleted_secret(name)
            for name in self.secret_names
        ]
        await asyncio.wait(purge)
        await super().global_cleanup()

    async def close(self):
        """This is run after cleanup."""
        await self.async_client.close()
        await self.async_credential.close()
        await super().close()

    def run_sync(self):
        """The synchronous perf test."""
        secret_properties = self.client.list_properties_of_secrets()
        # enumerate secrets to exercise paging code
        list(secret_properties)

    async def run_async(self):
        """The asynchronous perf test."""
        secret_properties = self.async_client.list_properties_of_secrets()
        # enumerate secrets to exercise paging code
        async for _ in secret_properties:
            pass

    @staticmethod
    def add_arguments(parser):
        super(ListSecretsTest, ListSecretsTest).add_arguments(parser)
        parser.add_argument("--count",
                            nargs="?",
                            type=int,
                            help="Number of secrets to list. Defaults to 10",
                            default=10)
Exemple #9
0
class AzureSecrets:
    """
    Azure secrets object that can be used for CLI and as a module.
    """

    def __init__(self, vault_base_url: str = None, client_id: str = None, secret: str = None,
                 tenant: str = None):

        self.vault_base_url = vault_base_url
        self.client_id = client_id
        self.secret = secret
        self.tenant = tenant

        try:
            if self.vault_base_url is None:
                self.vault_base_url = os.environ["AZURE_VAULT_BASE_URL"]
            if self.client_id is None:
                self.client_id = os.environ['AZURE_CLIENT_ID']
            if self.secret is None:
                self.secret = os.environ['AZURE_SECRET_KEY']
            if self.tenant is None:
                self.tenant = os.environ['AZURE_TENANT_ID']
        except KeyError as e:
            print("Did you forget to set the environment variable?", e)
            sys.exit(1)

        self.client = SecretClient(vault_url=self.vault_base_url, credential=ClientSecretCredential(
            client_id=self.client_id,
            client_secret=self.secret,
            tenant_id=self.tenant,
        ))

    def get_secret(self, secret_name: str, secret_version: str = None) -> str:
        """
        Get the value for the secret key.

        :param secret_name: Name of the secret key.
        :type secret_name: str
        :param secret_version: The version string of the secret key.
        :type secret_version: str
        :return: The secret value.
        :rtype: str

        >>> secrets = AzureSecrets('https://', 'client id', 'secret key', 'tenant id')
        >>> print(secrets.get_secret('secret-name'))
        secret-value
        """
        if secret_version is None:
            secret_version = None

        key_bundle = self.client.get_secret(secret_name, secret_version)

        return key_bundle.value

    def get_secrets(self, env_names: list = None) -> dict:
        """
        A dictionary of secret name and it's value.

        :param env_names: A list of secret names.
        :type env_names: list
        :rtype: dict
        :return: Dictionary of secrets.

        >>> secrets = AzureSecrets('https://', 'client id', 'secret key', 'tenant id')
        >>> print(secrets.get_secrets(['secret-name-1', 'secret-name-2']))
        {
            'secret-name-1' : 'secret-value-1',
            'secret-name-2': 'secret-value-2'
        }
        """
        secrets = {}

        try:
            if env_names is None:
                for secret_id in self.client.list_properties_of_secrets():
                    secrets.update({secret_id.name: self.get_secret(secret_name=secret_id.name)})
            else:
                for secret_name in env_names:
                    secrets.update({secret_name: self.get_secret(secret_name=secret_name)})
        except KeyVaultErrorException as e:
            print("Error:", e)
            sys.exit(1)

        return secrets

    def env_powershell(self, secret_names: list = None, except_names: list = None):
        """
        Prints environment variable for PowerShell
        """
        for key, value in self.get_secrets(secret_names).items():
            print('$Env:{0}="{1}"'.format(key.replace('-', "_"), value))
        print("# Run this command to configure your shell:")
        print("# & secrets env --shell powershell | Invoke-Expression")

    def env_cmd(self, secret_names: list = None, except_names: list = None):
        """
        Prints environment variable for CMD
        """
        for key, value in self.get_secrets(secret_names).items():
            print("SET {0}={1}".format(key.replace('-', "_"), value))
        print("REM Run this command to configure your shell:")
        print("REM @FOR /f \"tokens=*\" %i IN ('secrets env --shell cmd') DO @%i")

    def env_bash(self, secret_names: list = None, except_names: list = None):
        """
        Prints environment variable for Bash
        """
        for key, value in self.get_secrets(secret_names).items():
            print("export {0}='{1}'".format(key.replace('-', "_"), value))
        print("# Run this command to configure your shell:")
        print("# eval $(secrets env --shell bash)")
Exemple #10
0
class AzureKeyVault:
    headers = None
    kvName = None
    token = None
    tracer = None
    uri = None

    def __init__(self,
                 tracer: logging.Logger,
                 kvName: str,
                 msiClientId: Optional[str] = None):
        self.tracer = tracer
        self.tracer.info("initializing KeyVault %s" % kvName)
        self.kvName = kvName
        self.uri = "https://%s.vault.azure.net" % kvName
        self.token = ManagedIdentityCredential(client_id=msiClientId)
        self.kv_client = SecretClient(vault_url=self.uri,
                                      credential=self.token)

    # Set a secret in the KeyVault
    def setSecret(self, secretName: str, secretValue: str) -> bool:
        self.tracer.info("setting KeyVault secret for secretName=%s" %
                         secretName)
        try:
            self.kv_client.set_secret(secretName, secretValue)
        except Exception as e:
            self.tracer.critical("could not set KeyVault secret (%s)" % e)
            sys.exit(ERROR_SETTING_KEYVAULT_SECRET)
        return True

    # Delete a secret from the KeyVault
    def deleteSecret(self, secretName: str) -> bool:
        self.tracer.info("deleting KeyVault secret %s" % secretName)
        try:
            self.kv_client.begin_delete_secret(secretName)
        except Exception as e:
            self.tracer.critical("could not delete KeyVault secret (%s)" % e)
            return False
        return True

    # Get the current version of a specific secret in the KeyVault
    def getSecret(self,
                  secretId: str,
                  version: Optional[str] = None) -> KeyVaultSecret:
        self.tracer.info("getting KeyVault secret for secretId=%s" % secretId)
        secret = None
        try:
            secret = self.kv_client.get_secret(secretId, version)
        except Exception as e:
            self.tracer.error(
                "could not get KeyVault secret for secretId=%s (%s)" %
                (secretId, e))
        return secret

    # Get the current versions of all secrets inside the customer KeyVault
    def getCurrentSecrets(self) -> Dict[str, str]:
        self.tracer.info("getting current KeyVault secrets")
        secrets = {}
        try:
            kvSecrets = self.kv_client.list_properties_of_secrets()
            for k in kvSecrets:
                secrets[k.name] = self.kv_client.get_secret(k.name).value
        except Exception as e:
            self.tracer.error("could not get current KeyVault secrets (%s)" %
                              e)
        return secrets

    # Check if a KeyVault with a specified name exists
    def exists(self) -> bool:
        self.tracer.info("checking if KeyVault %s exists" % self.kvName)
        try:
            kvSecrets = self.kv_client.list_properties_of_secrets(
                max_page_size=1)
            if kvSecrets:
                self.tracer.info("KeyVault %s exists" % self.kvName)
                return True
        except Exception as e:
            self.tracer.error(
                "could not determine is KeyVault %s exists (%s)" %
                (self.kvName, e))
        self.tracer.info("KeyVault %s does not exist" % self.kvName)
        return False
Exemple #11
0
def run_sample():
    # Instantiate a secret client that will be used to call the service. Notice that the client is using default Azure
    # credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID',
    # 'AZURE_CLIENT_SECRET' and 'AZURE_TENANT_ID' are set with the service principal credentials.
    VAULT_ENDPOINT = os.environ["VAULT_ENDPOINT"]
    credential = DefaultAzureCredential()
    client = SecretClient(vault_endpoint=VAULT_ENDPOINT, credential=credential)
    try:
        # Let's create secrets holding storage and bank accounts credentials. If the secret
        # already exists in the Key Vault, then a new version of the secret is created.
        print("\n.. Create Secret")
        bank_secret = client.set_secret("listOpsBankSecretName", "listOpsSecretValue1")
        storage_secret = client.set_secret("listOpsStorageSecretName", "listOpsSecretValue2")
        print("Secret with name '{0}' was created.".format(bank_secret.name))
        print("Secret with name '{0}' was created.".format(storage_secret.name))

        # You need to check if any of the secrets are sharing same values.
        # Let's list the secrets and print their values.
        # List operations don 't return the secrets with value information.
        # So, for each returned secret we call get_secret to get the secret with its value information.
        print("\n.. List secrets from the Key Vault")
        secrets = client.list_properties_of_secrets()
        for secret in secrets:
            retrieved_secret = client.get_secret(secret.name)
            print(
                "Secret with name '{0}' and value {1} was found.".format(retrieved_secret.name, retrieved_secret.name)
            )

        # The bank account password got updated, so you want to update the secret in Key Vault to ensure it reflects the
        # new password. Calling set_secret on an existing secret creates a new version of the secret in the Key Vault
        # with the new value.
        updated_secret = client.set_secret(bank_secret.name, "newSecretValue")
        print(
            "Secret with name '{0}' was updated with new value '{1}'".format(updated_secret.name, updated_secret.value)
        )

        # You need to check all the different values your bank account password secret had previously. Lets print all
        # the versions of this secret.
        print("\n.. List versions of the secret using its name")
        secret_versions = client.list_secret_versions(bank_secret.name)
        for secret_version in secret_versions:
            print(
                "Bank Secret with name '{0}' has version: '{1}'.".format(
                    secret_version.name, secret_version.version
                )
            )

        # The bank account and storage accounts got closed. Let's delete bank and storage accounts secrets.
        client.delete_secret(bank_secret.name)
        client.delete_secret(storage_secret.name)

        # To ensure secret is deleted on the server side.
        print("Deleting secrets...")
        time.sleep(30)

        # You can list all the deleted and non-purged secrets, assuming Key Vault is soft-delete enabled.
        print("\n.. List deleted secrets from the Key Vault")
        deleted_secrets = client.list_deleted_secrets()
        for deleted_secret in deleted_secrets:
            print(
                "Secret with name '{0}' has recovery id '{1}'".format(deleted_secret.name, deleted_secret.recovery_id)
            )

    except HttpResponseError as e:
        if "(NotSupported)" in e.message:
            print("\n{0} Please enable soft delete on Key Vault to perform this operation.".format(e.message))
        else:
            print("\nrun_sample has caught an error. {0}".format(e.message))

    finally:
        print("\nrun_sample done")
Exemple #12
0
class AzureKeyVaultConfiguration(Configuration):
    """
    Azure Configuration class.

    The Azure Configuration class takes Azure KeyVault credentials and
    behaves like a drop-in replacement for the regular Configuration class.

    The following limitations apply to the Azure KeyVault Configurations:
        - keys must conform to the pattern '^[0-9a-zA-Z-]+$'. In particular,
          there is no support for levels and nested values as there are no
          natural key separators for the pattern above.
        - values must be strings.
    """
    def __init__(
        self,
        az_client_id: str,
        az_client_secret: str,
        az_tenant_id: str,
        az_vault_name: str,
        cache_expiration: int = 5 * 60,
        interpolate: InterpolateType = False,
    ) -> None:
        """
        Constructor.

        :param az_client_id: Client ID
        :param az_client_secret: Client Secret
        :param az_tenant_id: Tenant ID
        :param az_vault_name: Vault Name
        :param cache_expiration: Cache expiration (in seconds)
        """
        credentials = ClientSecretCredential(
            client_id=az_client_id,
            client_secret=az_client_secret,
            tenant_id=az_tenant_id,
        )
        vault_url = "https://{az_vault_name}.vault.azure.net/".format(
            az_vault_name=az_vault_name)
        self._kv_client = SecretClient(vault_url=vault_url,
                                       credential=credentials)
        self._cache_expiration = cache_expiration
        self._cache: Dict[str, Cache] = {}
        self._interpolate = {} if interpolate is True else interpolate
        self._default_levels = None

    def _get_secret(self, key: str) -> Optional[str]:
        key = key.replace("_", "-")  # Normalize for Azure KeyVault
        now = time.time()
        from_cache = self._cache.get(key)
        if from_cache and from_cache.ts + self._cache_expiration > now:
            return from_cache.value
        try:
            secret = self._kv_client.get_secret(key)
            self._cache[key] = Cache(value=secret.value, ts=now)
            return cast(str, secret.value)
        except ResourceNotFoundError:
            if key in self._cache:
                del self._cache[key]
            return None

    def __getitem__(self, item: str) -> Any:  # noqa: D105
        secret = self._get_secret(item)
        if secret is None:
            raise KeyError(item)
        else:
            return secret

    def __getattr__(self, item: str) -> Any:  # noqa: D105
        secret = self._get_secret(item)
        if secret is None:
            raise KeyError(item)
        else:
            return secret

    def get(self, key: str, default: Any = None) -> Union[dict, Any]:
        """
        Get the configuration values corresponding to :attr:`key`.

        :param key: key to retrieve
        :param default: default value in case the key is missing
        :return: the value found or a default
        """
        secret = self._get_secret(key)
        if secret is None:
            return default
        else:
            return secret

    def keys(
        self,
        levels: Optional[int] = None
    ) -> Union["Configuration", Any, KeysView[str]]:
        """Return a set-like object providing a view on the configuration keys."""
        assert not levels  # Azure Key Vaults don't support separators
        return cast(
            KeysView[str],
            (k.name for k in self._kv_client.list_properties_of_secrets()),
        )

    def values(
        self,
        levels: Optional[int] = None
    ) -> Union["Configuration", Any, ValuesView[Any]]:
        """Return a set-like object providing a view on the configuration values."""
        assert not levels  # Azure Key Vaults don't support separators
        return cast(
            ValuesView[str],
            (self._get_secret(k.name)
             for k in self._kv_client.list_properties_of_secrets()),
        )

    def items(
        self,
        levels: Optional[int] = None
    ) -> Union["Configuration", Any, ItemsView[str, Any]]:
        """Return a set-like object providing a view on the configuration items."""
        assert not levels  # Azure Key Vaults don't support separators
        return cast(
            ItemsView[str, Any],
            ((k.name, self._get_secret(k.name))
             for k in self._kv_client.list_properties_of_secrets()),
        )

    def reload(self) -> None:
        """Reload the configuration."""
        self._cache.clear()

    def __repr__(self) -> str:  # noqa: D105
        return "<AzureKeyVaultConfiguration: %r>" % self._kv_client.vault_url

    @property
    def _config(self) -> Dict[str, Any]:  # type: ignore
        return dict(self.items())
    # Let's create secrets holding storage and bank accounts credentials. If the secret
    # already exists in the Key Vault, then a new version of the secret is created.
    print("\n.. Create Secret")
    bank_secret = client.set_secret("listOpsBankSecretName",
                                    "listOpsSecretValue1")
    storage_secret = client.set_secret("listOpsStorageSecretName",
                                       "listOpsSecretValue2")
    print("Secret with name '{0}' was created.".format(bank_secret.name))
    print("Secret with name '{0}' was created.".format(storage_secret.name))

    # You need to check if any of the secrets are sharing same values.
    # Let's list the secrets and print their values.
    # List operations don 't return the secrets with value information.
    # So, for each returned secret we call get_secret to get the secret with its value information.
    print("\n.. List secrets from the Key Vault")
    secrets = client.list_properties_of_secrets()
    for secret in secrets:
        retrieved_secret = client.get_secret(secret.name)
        print("Secret with name '{0}' and value {1} was found.".format(
            retrieved_secret.name, retrieved_secret.name))

    # The bank account password got updated, so you want to update the secret in Key Vault to ensure it reflects the
    # new password. Calling set_secret on an existing secret creates a new version of the secret in the Key Vault
    # with the new value.
    updated_secret = client.set_secret(bank_secret.name, "newSecretValue")
    print("Secret with name '{0}' was updated with new value '{1}'".format(
        updated_secret.name, updated_secret.value))

    # You need to check all the different values your bank account password secret had previously. Lets print all
    # the versions of this secret.
    print("\n.. List versions of the secret using its name")
    def deleted_secret_recovery(self):
        """
        a sample of enumerating, retrieving, recovering and purging deleted secrets from a key vault
        """
        # create a vault enabling the soft delete feature
        vault = self.create_vault()

        # create a secret client
        credential = DefaultAzureCredential()
        secret_client = SecretClient(vault_url=vault.properties.vault_uri,
                                     credential=credential)

        # create secrets in the vault
        secret_to_recover = get_name('secret')
        secret_to_purge = get_name('secret')

        secret = secret_client.set_secret(secret_to_recover,
                                          "secret to restore")
        print('created secret {}'.format(secret.name))

        secret = secret_client.set_secret(secret_to_purge, "secret to purge")
        print('created secret {}'.format(secret.name))

        # list the name of all of the secrets in the client's vault
        secret_properties = secret_client.list_properties_of_secrets()
        print("all of the secrets in the client's vault:")
        for secret_property in secret_properties:
            print(secret_property.name)

        # delete the secrets
        delete_secret_poller = secret_client.begin_delete_secret(
            secret_to_recover)
        deleted_secret = delete_secret_poller.result()
        delete_secret_poller.wait()
        print('deleted secret {}'.format(deleted_secret.name))

        delete_secret_poller = secret_client.begin_delete_secret(
            secret_to_purge)
        deleted_secret = delete_secret_poller.result()
        delete_secret_poller.wait()
        print('deleted secret {}'.format(deleted_secret.name))

        # list the deleted secrets
        deleted_secrets = secret_client.list_deleted_secrets()
        print("all of the deleted secrets in the client's vault:")
        for deleted_secret in deleted_secrets:
            print(deleted_secret.name)

        # recover a deleted secret
        recover_secret_poller = secret_client.begin_recover_deleted_secret(
            secret_to_recover)
        recovered_secret = recover_secret_poller.result()
        print('recovered secret {}'.format(recovered_secret.name))

        # purge a deleted secret
        secret_client.purge_deleted_secret(secret_to_purge)
        time.sleep(50)
        print('purged secret {}'.format(secret_to_purge))

        # list the name of all of the secrets in the client's vault
        secret_properties = secret_client.list_properties_of_secrets()
        print("all of the secrets in the client's vault:")
        for secret_property in secret_properties:
            print(secret_property.name)
    if c.name.startswith("livekvtest")
]
for certificate in deleted_test_certificates:
    cert_client.purge_deleted_certificate(certificate.name)

test_keys = [
    k for k in key_client.list_properties_of_keys()
    if k.name.startswith("livekvtest")
]
for key in test_keys:
    key_client.begin_delete_key(key.name).wait()
deleted_test_keys = [
    k for k in key_client.list_deleted_keys()
    if k.name.startswith("livekvtest")
]
for key in deleted_test_keys:
    key_client.purge_deleted_key(key.name)

test_secrets = [
    s for s in secret_client.list_properties_of_secrets()
    if s.name.startswith("livekvtest")
]
for secret in test_secrets:
    secret_client.begin_delete_secret(secret.name).wait()
deleted_test_secrets = [
    s for s in secret_client.list_deleted_secrets()
    if s.name.startswith("livekvtest")
]
for secret in deleted_test_secrets:
    secret_client.purge_deleted_secret(secret.name)
    print("\n.. Restore the secret using the backed up secret bytes")
    secret = dest_client.restore_secret_backup(secret_backup)
    print("Restored secret with name '{0}'".format(secret.name))
    return True

  except HttpResponseError as e:
    # print("\nDestination AKV has caught an error. {0}".format(e.message))
    print("\nDestination AKV has caught an error. Secret Exixts")
    return False

# COMMAND ----------

delete_dups = False
update_version = True

secret_properties = source_client.list_properties_of_secrets()

for secret_property in secret_properties:
    # the list doesn't include values or versions of the secrets
    print(secret_property.name)
    print("---------------------------")
    backup = backup_secret(secret_property.name)
    if restore_secret(backup) :
      print(secret_property.name + " has been migrated")
    else:
      if delete_dups :
        delete_dest_secret(secret_property.name)
        restore_secret(backup)
      else :
        if update_version : 
          try:
Exemple #17
0
    def grab_secrets(self):
        """
        Gets secrets from KeyVault and stores them in a folder
        """
        vault_base_url = os.getenv('VAULT_BASE_URL')
        secrets_keys = os.getenv('SECRETS_KEYS')
        certs_keys = os.getenv('CERTS_KEYS')
        output_folder = os.getenv('SECRETS_FOLDER')
        self._secrets_output_folder = os.path.join(output_folder, "secrets")
        self._certs_output_folder = os.path.join(output_folder, "certs")
        self._keys_output_folder = os.path.join(output_folder, "keys")
        self._cert_keys_output_folder = os.path.join(output_folder,
                                                     "certs_keys")

        for folder in (self._secrets_output_folder, self._certs_output_folder,
                       self._keys_output_folder,
                       self._cert_keys_output_folder):
            if not os.path.exists(folder):
                os.makedirs(folder)

        credential = self._get_credential()
        secret_client = SecretClient(vault_url=vault_base_url,
                                     credential=credential,
                                     timeout=TIMEOUT)
        certificate_client = CertificateClient(vault_url=vault_base_url,
                                               credential=credential,
                                               timeout=TIMEOUT)
        _logger.info('Using vault: %s', vault_base_url)

        # Retrieving all secrets from Key Vault if specified by user
        if secrets_keys is None:
            _logger.info('Retrieving all secrets from Key Vault.')

            all_secrets = list(secret_client.list_properties_of_secrets())
            secrets_keys = ';'.join(
                [secret.id.split('/')[-1] for secret in all_secrets])

        if secrets_keys is not None:
            for key_info in filter(None, secrets_keys.split(';')):
                # Secrets are not renamed. They will have same name
                # Certs and keys can be renamed
                key_name, key_version, cert_filename, key_filename = self._split_keyinfo(
                    key_info)
                _logger.info(
                    'Retrieving secret name:%s with version: %s output certFileName: %s keyFileName: %s',
                    key_name, key_version, cert_filename, key_filename)
                secret = secret_client.get_secret(key_name, key_version)

                if secret.properties.key_id is not None:
                    _logger.info(
                        'Secret is backing certificate. Dumping private key and certificate.'
                    )
                    if secret.properties.content_type == 'application/x-pkcs12':
                        self._dump_pfx(secret.value, cert_filename,
                                       key_filename, key_name)
                    else:
                        _logger.error('Secret is not in pkcs12 format')
                        sys.exit(1)
                elif (key_name != cert_filename):
                    _logger.error(
                        'Cert filename provided for secret %s not backing a certificate.',
                        key_name)
                    sys.exit((
                        'Error: Cert filename provided for secret {0} not backing a certificate.'
                    ).format(key_name))

                # secret has same name as key_name
                output_path = os.path.join(self._secrets_output_folder,
                                           key_name)
                _logger.info('Dumping secret value to: %s', output_path)
                with open(output_path, 'w') as secret_file:
                    secret_file.write(self._dump_secret(secret))

        if certs_keys is not None:
            for key_info in filter(None, certs_keys.split(';')):
                # only cert_filename is needed, key_filename is ignored with _
                key_name, key_version, cert_filename, _ = self._split_keyinfo(
                    key_info)
                _logger.info(
                    'Retrieving cert name:%s with version: %s output certFileName: %s',
                    key_name, key_version, cert_filename)
                cert = certificate_client.get_certificate_version(
                    key_name, key_version)
                output_path = os.path.join(self._certs_output_folder,
                                           cert_filename)
                _logger.info('Dumping cert value to: %s', output_path)
                with open(output_path, 'w') as cert_file:
                    cert_file.write(self._cert_to_pem(cert.cer))
Exemple #18
0
def main(req: func.HttpRequest) -> func.HttpResponse:
    logger = logging.getLogger(__name__)
    formatter = logging.Formatter(
        '%(asctime)s %(name)s %(levelname)s: %(message)s')
    func_context = os.environ['FUNCTION_CONTEXT']
    logger.debug(f"Function context --> {func_context}")

    credentials = None
    subscription_id = None
    kv_credentials = None
    kv_subscription_id = None
    if func_context == 'local':
        filehandler = logging.FileHandler('func.log')
        filehandler.setFormatter(formatter)
        logger.addHandler(filehandler)
        logger.setLevel(logging.DEBUG)
        credentials, kv_credentials, subscription_id = get_local_credentials()
    else:
        console = logging.StreamHandler()
        console.setLevel(logging.INFO)
        console.setFormatter(formatter)
        credentials, kv_credentials, subscription_id = get_azure_credentials()

    logger.debug('Python HTTP trigger function processed a request.')
    logger.debug(f"method={req.method}, url={req.url}, params={req.params}")
    logger.debug(f"body={req.get_json()}")

    # Handle WebHook
    webhook = req.get_json()
    # Get resource information specifically tags if this is an alert
    resource_id = None
    if "azureMonitorCommonAlertSchema" in webhook["schemaId"]:
        if check_keys(webhook, 'data', 'essentials', 'alertTargetIDs'):
            resource_id = webhook["data"]["essentials"]["alertTargetIDs"]

    if resource_id:
        resource_client = ResourceManagementClient(credentials,
                                                   subscription_id)
        try:
            resource = resource_client.resources.get_by_id(
                resource_id[0], api_version='2018-06-01')
            if resource.tags:
                #                webhook['resource_tags'] = resource.tags
                logger.info(f"found resource tags {resource.tags}")
            else:
                logger.info(f"no tags found in resource {resource_id}")
        except:
            logger.error(
                f"received exception from ResourceManagementClient for {resource_id}"
            )
    else:
        logger.info("no resource_id found in webhook")

    subscription_client = SubscriptionClient(credentials)
    subscription = next(subscription_client.subscriptions.list())
    webhook['additionalData'] = {}
    if 'motsID' in subscription.tags.keys():
        webhook['additionalData']['motsID'] = subscription.tags['motsID']

    logger.info(f"added subscription tags={subscription.tags}")

    # Key Vault stuff
    kv_mgmt_client = KeyVaultManagementClient(credentials, subscription_id)
    #    kv_client = KeyVaultClient(credentials)
    kv_client = SecretClient(vault_url=os.environ['KEY_VAULT_URI'],
                             credential=kv_credentials)
    namespace = kv_client.get_secret('EventHubNamespace').value
    event_hub = kv_client.get_secret('EventHub').value
    user = kv_client.get_secret('EventHubKeyName').value
    key = kv_client.get_secret('EventHubKey').value
    # Check whether connection string exists in Key Vault
    kv_prop = kv_client.list_properties_of_secrets()
    if 'EventHubConnectionString' in [prop.name for prop in kv_prop]:
        conn_string = get_kv_secret(kv_client,
                                    'EventHubConnectionString').value
    else:
        conn_string = f"Endpoint=sb://{namespace}.servicebus.windows.net/;SharedAccessKeyName={user};SharedAccessKey={key}"

    eh_prod_client = EventHubProducerClient.from_connection_string(
        conn_string, eventhub_name=event_hub)
    event_data_batch = eh_prod_client.create_batch()
    event_data_batch.add(EventData(json.dumps(webhook)))
    eh_prod_client.send_batch(event_data_batch)
    logger.info(f"sending event to {namespace}, {json.dumps(webhook)}")
    date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
    return func.HttpResponse(json.dumps({'date': date, 'status': 'SUCCESS'}))
Exemple #19
0
class AzureVaultStore:
    def __init__(self, vault_name):

        try:
            from azure.identity import EnvironmentCredential
            from azure.keyvault.secrets import SecretClient
        except ImportError as exc:
            raise ImportError(
                f"Azure key-vault libraries not installed, run pip install mlrun[azure-key-vault], {exc}"
            )

        self._vault_name = vault_name
        self._url = mlconf.secret_stores.azure_vault.url.format(name=vault_name)
        self._client = None

        tenant_id = self._get_secret_file_contents("tenant_id")
        client_id = self._get_secret_file_contents("client_id")

        if not tenant_id or not client_id:
            logger.info(
                "both tenant_id and client_id must be configured to use Azure vault"
            )
            return

        client_secret = self._get_secret_file_contents("secret")
        if client_secret:
            os.environ["AZURE_CLIENT_SECRET"] = client_secret

        if "AZURE_CLIENT_SECRET" not in os.environ:
            logger.info("Azure client secret could not be found")
            return

        # Azure EnvironmentCredential uses these environment variables. Populate them
        os.environ["AZURE_TENANT_ID"] = tenant_id
        os.environ["AZURE_CLIENT_ID"] = client_id

        credential = EnvironmentCredential()
        self._client = SecretClient(vault_url=self._url, credential=credential)

    @staticmethod
    def _get_secret_file_contents(file_name):
        full_path = expanduser(
            mlconf.secret_stores.azure_vault.secret_path + "/" + file_name
        )
        if os.path.isfile(full_path):
            with open(full_path, "r") as secret_file:
                contents = secret_file.read()
            return contents
        return None

    def get_secrets(self, keys):
        # We're not checking this import, since azure-core is automatically installed by other
        # libs. Assuming we passed the checks on __init__, this is expected to work.
        from azure.core.exceptions import HttpResponseError, ResourceNotFoundError

        secrets = {}
        if not self._client:
            return secrets

        if len(keys) == 0:
            secret_details = self._client.list_properties_of_secrets()
            keys = [secret.name for secret in secret_details if secret.enabled]

        for secret in keys:
            try:
                secrets[secret] = self._client.get_secret(secret).value
            except ResourceNotFoundError:
                logger.warning(f"Secret '{secret}' is not available in Azure key vault")
            except HttpResponseError as exc:
                logger.warning(f"Exception retrieving secret '{secret}': {exc.error}")
        return secrets