Comment on page
Develop a Custom Secrets Manager
How to develop a custom secrets manager
This is an older version of the ZenML documentation. To read and view the latest version please visit this up-to-date URL.
The secret manager acts as the one-stop shop for all the secrets to which your pipeline or stack components might need access.
- 1.As it is the base class for a specific type of
StackComponent
, it inherits from the StackComponent class. This sets theTYPE
variable to the secrets manager . TheFLAVOR
class variable needs to be set in the specific subclass. - 2.The
BaseSecretsManager
implements the interface for a set of CRUD operations asabstractmethod
s:register_secret
,get_secret
,get_all_secret_keys
,update_secret
,delete_secret
,delete_all_secrets
. In the implementation of everySecretsManager
flavor, it is required to define these methods with respect to the flavor at hand.
from abc import ABC, abstractmethod
from typing import ClassVar, List
from zenml.enums import StackComponentType
from zenml.secret.base_secret import BaseSecretSchema
from zenml.stack import StackComponent
class BaseSecretsManager(StackComponent, ABC):
"""Base class for all ZenML secrets managers."""
# Class configuration
TYPE: ClassVar[StackComponentType] = StackComponentType.SECRETS_MANAGER
FLAVOR: ClassVar[str]
@abstractmethod
def register_secret(self, secret: BaseSecretSchema) -> None:
"""Registers a new secret."""
@abstractmethod
def get_secret(self, secret_name: str) -> BaseSecretSchema:
"""Gets the value of a secret."""
@abstractmethod
def get_all_secret_keys(self) -> List[str]:
"""Get all secret keys."""
@abstractmethod
def update_secret(self, secret: BaseSecretSchema) -> None:
"""Update an existing secret."""
@abstractmethod
def delete_secret(self, secret_name: str) -> None:
"""Delete an existing secret."""
@abstractmethod
def delete_all_secrets(self) -> None:
"""Delete all existing secrets."""
This is a slimmed-down version of the base implementation which aims to highlight the abstraction layer. In order to see the full implementation and get the complete docstrings, please check the API docs.
If you want to create your own custom flavor for a secrets manager, you can follow the following steps:
- 1.Create a class which inherits from the
BaseSecretsManager
. - 2.Define the
FLAVOR
class variable. - 3.Implement the
abstactmethod
s based on the API of your desired secrets manager
Once you are done with the implementation, you can register it through the CLI as:
zenml secrets-manager flavor register <THE-SOURCE-PATH-OF-YOUR-SECRETS-MANAGER>
Different providers in the space of secrets manager have different definitions of what constitutes a secret. While some providers consider a single key-value pair a secret: (
'secret_name': 'secret_value'
), other providers have a slightly different definition. For them, a secret is a collection of key-value pairs: {'some_username': 'user_name_1', 'some_pwd': '1234'}
.ZenML falls into the second category. The implementation of the different methods should reflect this convention. In case the specific implementation interfaces with a secrets manager that uses the other definition of a secret, working with tags can be helpful. See the
GCPSecretsManager
for inspiration.One way that ZenML expands on the notion of secrets as dictionaries is the secret schema. A secret schema allows the user to create and use a specific template. A schema could, for example, require the combination of a username, password and token. All schemas must sub-class from the
BaseSecretSchema
.- 1.All Secret Schemas will need to have a defined
TYPE
. - 2.The required and optional keys of the secret need to be defined as class variables.
class BaseSecretSchema(BaseModel, ABC):
name: str
TYPE: ClassVar[str]
@property
def content(self) -> Dict[str, Any]:
...
One such schema could look like this.
from typing import ClassVar, Optional
from zenml.secret import register_secret_schema_class
from zenml.secret.base_secret import BaseSecretSchema
EXAMPLE_SECRET_SCHEMA_TYPE = "example"
@register_secret_schema_class
class ExampleSecretSchema(BaseSecretSchema):
TYPE: ClassVar[str] = EXAMPLE_SECRET_SCHEMA_TYPE
username: str
password: str
token: Optional[str]
Last modified 1mo ago