Skip to content

Commit

Permalink
Azure Key Vault provider (#131)
Browse files Browse the repository at this point in the history
* add Azure secret provider

* -- fix mistakenly upgraded nautobot dependency version

* Updates to azure.oy and poetry

* Change fragment

* Formatting

* Additional minor formatting

* Update lock file

* Update docs/admin/install.md

Co-authored-by: Gary Snider <75227981+gsnider2195@users.noreply.github.com>

---------

Co-authored-by: Jonathan Nathanson <jonathan.nathanson@layereight.io>
Co-authored-by: Gary Snider <75227981+gsnider2195@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 25, 2024
1 parent d6a8d7f commit 8db834f
Show file tree
Hide file tree
Showing 19 changed files with 1,385 additions and 973 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ This app publishes secrets providers that are not included in the Nautobot core

This app supports the following popular secrets backends:

| Secrets Backend | Supported Secret Types | Supported Authentication Methods |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) | [Other: Key/value pairs](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) | [AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html) (see Usage section below) |
| [AWS Systems Manager Parameter Store](https://aws.amazon.com/secrets-manager/) | [Other: Key/value pairs](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) | [AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html) (see Usage section below) |
| [HashiCorp Vault](https://www.vaultproject.io) | [K/V Version 2](https://www.vaultproject.io/docs/secrets/kv/kv-v2)<br/>[K/V Version 1](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1) | [Token](https://www.vaultproject.io/docs/auth/token)<br/>[AppRole](https://www.vaultproject.io/docs/auth/approle)<br/>[AWS](https://www.vaultproject.io/docs/auth/aws)<br/>[Kubernetes](https://www.vaultproject.io/docs/auth/kubernetes) |
| [Delinea/Thycotic Secret Server](https://delinea.com/products/secret-server) | [Secret Server Cloud](https://github.com/DelineaXPM/python-tss-sdk#secret-server-cloud)<br/>[Secret Server (on-prem)](https://github.com/DelineaXPM/python-tss-sdk#initializing-secretserver)| [Access Token Authorization](https://github.com/DelineaXPM/python-tss-sdk#access-token-authorization)<br/>[Domain Authorization](https://github.com/DelineaXPM/python-tss-sdk#domain-authorization)<br/>[Password Authorization](https://github.com/DelineaXPM/python-tss-sdk#password-authorization)<br/> |
| Secrets Backend | Supported Secret Types | Supported Authentication Methods |
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) | [Other: Key/value pairs](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) | [AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html) (see Usage section below) |
| [AWS Systems Manager Parameter Store](https://aws.amazon.com/secrets-manager/) | [Other: Key/value pairs](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) | [AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html) (see Usage section below) |
| [HashiCorp Vault](https://www.vaultproject.io) | [K/V Version 2](https://www.vaultproject.io/docs/secrets/kv/kv-v2)<br/>[K/V Version 1](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1) | [Token](https://www.vaultproject.io/docs/auth/token)<br/>[AppRole](https://www.vaultproject.io/docs/auth/approle)<br/>[AWS](https://www.vaultproject.io/docs/auth/aws)<br/>[Kubernetes](https://www.vaultproject.io/docs/auth/kubernetes) |
| [Delinea/Thycotic Secret Server](https://delinea.com/products/secret-server) | [Secret Server Cloud](https://github.com/DelineaXPM/python-tss-sdk#secret-server-cloud)<br/>[Secret Server (on-prem)](https://github.com/DelineaXPM/python-tss-sdk#initializing-secretserver) | [Access Token Authorization](https://github.com/DelineaXPM/python-tss-sdk#access-token-authorization)<br/>[Domain Authorization](https://github.com/DelineaXPM/python-tss-sdk#domain-authorization)<br/>[Password Authorization](https://github.com/DelineaXPM/python-tss-sdk#password-authorization)<br/> |
| [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/) | [Key Vault Secrets](https://learn.microsoft.com/en-us/azure/key-vault/secrets/about-secrets) | [Entra ID Service Principal](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.environmentcredential?view=azure-python) |

## Screenshots

Expand Down
1 change: 1 addition & 0 deletions changes/131.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a secrets provider for Azure Key Vault.
1 change: 1 addition & 0 deletions development/app_config_schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""App Config Schema Generator and Validator."""

import json
from importlib import import_module
from os import getenv
Expand Down
20 changes: 19 additions & 1 deletion development/creds.example.env
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ MYSQL_PASSWORD=${NAUTOBOT_DB_PASSWORD}
# NAUTOBOT_REDIS_HOST=localhost
# NAUTOBOT_CONFIG=development/nautobot_config.py

#############################################################################
################################################################################
# Settings for Delinea/Thycotic Secret-Server-Reader
# https://github.com/DelineaXPM/python-tss-sdk

Expand Down Expand Up @@ -56,3 +56,21 @@ SECRET_SERVER_PASSWORD='my_thycotic_password'
#REQUESTS_CA_BUNDLE='/etc/ssl/certs/ca-bundle.trust.crt'

VAULT_TOKEN=nautobot

################################################################################
# Azure Key Vault Settings
# https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python
# https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.environmentcredential?view=azure-python
#
# TLDR; Set up a Service Principal, grant it "Key Vault Secrets User" role, add service principal
# details to the environment variables below.

AZURE_TENANT_ID=''
AZURE_CLIENT_ID=''

AZURE_CLIENT_SECRET=''

# AZURE_CLIENT_CERTIFICATE_PATH=''
# AZURE_CLIENT_CERTIFICATE_PASSWORD=''

################################################################################
1 change: 1 addition & 0 deletions development/nautobot_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Nautobot development configuration file."""

import os
import sys

Expand Down
16 changes: 16 additions & 0 deletions docs/admin/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ The Delinea/Thycotic Secret Server provider requires the `python-tss-sdk` librar
pip install nautobot-secrets-providers[thycotic]
```

#### Azure Key Vault

The Azure Key Vault provider requires the `azure-identity` and `azure-keyvault-secrets` libraries. This can be easily installed along with the app using the following command:

```no-highlight
pip install nautobot-secrets-providers[azure]
```

### Access Requirements

There are no special access requirements to install the app.
Expand Down Expand Up @@ -210,3 +218,11 @@ PLUGINS_CONFIG = {
- `tenant` - (optional) Required for 'Domain Authorization'.
- `token` - (optional) Required for 'Access Token Authorization'.
- `username` - (optional) Required for 'Secret Server Cloud', 'Password Authorization', 'Domain Authorization'.

### Azure Key Vault

#### Authentication

No configuration is required within Nautobot for this provider to work. You must provide [Azure Service Principal credentials in one of the formats supported by the azure-identity library](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.environmentcredential?view=azure-python). The credential variables should be injected into Nautobot's environment via your preferred method.

The recommended method is to use a Service Principal with Secret, for which creds.example.env has an example. [More information on how to set up the SP in Azure in the Azure docs](https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide?tabs=azure-cli).
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This app supports the following popular secrets backends:
| [AWS Systems Manager Parameter Store](https://aws.amazon.com/secrets-manager/) | [Other: Key/value pairs](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) | [AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html) (see Usage section below) |
| [HashiCorp Vault](https://www.vaultproject.io) | [K/V Version 2](https://www.vaultproject.io/docs/secrets/kv/kv-v2)<br/>[K/V Version 1](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1) | [Token](https://www.vaultproject.io/docs/auth/token)<br/>[AppRole](https://www.vaultproject.io/docs/auth/approle)<br/>[AWS](https://www.vaultproject.io/docs/auth/aws)<br/>[Kubernetes](https://www.vaultproject.io/docs/auth/kubernetes) |
| [Delinea/Thycotic Secret Server](https://delinea.com/products/secret-server) | [Secret Server Cloud](https://github.com/DelineaXPM/python-tss-sdk#secret-server-cloud)<br/>[Secret Server (on-prem)](https://github.com/DelineaXPM/python-tss-sdk#initializing-secretserver)| [Access Token Authorization](https://github.com/DelineaXPM/python-tss-sdk#access-token-authorization)<br/>[Domain Authorization](https://github.com/DelineaXPM/python-tss-sdk#domain-authorization)<br/>[Password Authorization](https://github.com/DelineaXPM/python-tss-sdk#password-authorization)<br/> |
| [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/) | [Key Vault Secrets](https://learn.microsoft.com/en-us/azure/key-vault/secrets/about-secrets) | [Entra ID Service Principal](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.environmentcredential?view=azure-python) |

## Audience (User Personas) - Who should use this App?

Expand Down
1 change: 1 addition & 0 deletions nautobot_secrets_providers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""App declaration for nautobot_secrets_providers."""

# Metadata is inherited from Nautobot. If not including Nautobot in the environment, this should be added
from importlib import metadata

Expand Down
2 changes: 2 additions & 0 deletions nautobot_secrets_providers/providers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Nautobot Secrets Providers."""

from .aws import AWSSecretsManagerSecretsProvider, AWSSystemsManagerParameterStore
from .azure import AzureKeyVaultSecretsProvider
from .hashicorp import HashiCorpVaultSecretsProvider
from .delinea import ThycoticSecretServerSecretsProviderId, ThycoticSecretServerSecretsProviderPath

__all__ = ( # type: ignore
AWSSecretsManagerSecretsProvider, # pylint: disable=invalid-all-object
AWSSystemsManagerParameterStore, # pylint: disable=invalid-all-object
AzureKeyVaultSecretsProvider, # pylint: disable=invalid-all-object
HashiCorpVaultSecretsProvider, # pylint: disable=invalid-all-object
ThycoticSecretServerSecretsProviderId, # pylint: disable=invalid-all-object
ThycoticSecretServerSecretsProviderPath, # pylint: disable=invalid-all-object
Expand Down
62 changes: 62 additions & 0 deletions nautobot_secrets_providers/providers/azure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Secrets Provider for Azure Key Vault."""

try:
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

azure_available = True # pylint: disable=invalid-name
except ImportError:
azure_available = False # pylint: disable=invalid-name

from django import forms
from nautobot.core.forms import BootstrapMixin
from nautobot.extras.secrets import exceptions, SecretsProvider

__all__ = ("AzureKeyVaultSecretsProvider",)


class AzureKeyVaultSecretsProvider(SecretsProvider):
"""A secrets provider for Azure Key Vault."""

slug = "azure-key-vault"
name = "Azure Key Vault"
is_available = azure_available

# pylint: disable-next=nb-incorrect-base-class
class ParametersForm(BootstrapMixin, forms.Form):
"""Required parameters for Azure Key Vault."""

vault_url = forms.CharField(
required=True,
help_text="The URL of the Azure Key Vault",
)
secret_name = forms.CharField(
required=True,
help_text="The name of the secret in the Azure Key Vault",
)

@classmethod
def get_value_for_secret(cls, secret, obj=None, **kwargs):
"""Return the secret value by name from Azure Key Vault."""
# Extract the parameters from the Secret.
parameters = secret.rendered_parameters(obj=obj)
vault_url = parameters.get("vault_url")
secret_name = parameters.get("secret_name")

# Authenticate with Azure Key Vault using default credentials.
# This assumes that environment variables for Azure authentication are set.
credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_url, credential=credential)

try:
# Retrieve the secret from Azure Key Vault.
response = client.get_secret(secret_name)
except Exception as err:
# Handle exceptions from the Azure SDK.
raise exceptions.SecretProviderError(secret, cls, str(err))

# The value is in the 'value' attribute of the response.
secret_value = response.value

# Return the secret value.
return secret_value
1 change: 1 addition & 0 deletions nautobot_secrets_providers/providers/choices.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Choices for Thycotic Secret Server Plugin."""

from nautobot.core.choices import ChoiceSet


Expand Down
1 change: 1 addition & 0 deletions nautobot_secrets_providers/providers/delinea.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Secrets Provider for Thycotic Secret Server."""

import os
from pathlib import Path

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ <h1>{% block title %}Secrets Providers Home{% endblock %}</h1>
<a href="https://github.com/DelineaXPM/python-tss-sdk#domain-authorization" rel="nofollow">Domain Authorization</a><br/>
<a href="https://github.com/DelineaXPM/python-tss-sdk#access-token-authorization" rel="nofollow">Access Token Authorization</a></td>
</tr>
<tr>
<td><a href="https://learn.microsoft.com/en-us/azure/key-vault/" rel="nofollow">Azure Key Vault</a></td>
<td><a href="https://learn.microsoft.com/en-us/azure/key-vault/secrets/about-secrets" rel="nofollow">Secrets</a><br/>
<td><a href="https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.environmentcredential?view=azure-python" rel="nofollow">Entra ID Service Principal</a><br/>
</tr>
</tbody>
</table>
</div>
Expand Down
1 change: 1 addition & 0 deletions nautobot_secrets_providers/tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Basic tests that do not require Django."""

import unittest
import os
import toml
Expand Down
1 change: 1 addition & 0 deletions nautobot_secrets_providers/tests/test_providers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Unit tests for Secrets Providers."""

import os
from unittest.mock import patch, mock_open

Expand Down
1 change: 1 addition & 0 deletions nautobot_secrets_providers/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Django urlpatterns declaration for nautobot_secrets_providers app."""

from django.urls import path

from nautobot_secrets_providers import views
Expand Down
Loading

0 comments on commit 8db834f

Please sign in to comment.