Cloud Resolvers
Each resolver uses the same interface but has unique features based on the service it connects to. The next sections will cover important examples for each resolver.
AWS
Prerequisites
The AWS resolvers in this package are built on top of the boto3
library, which is the
Amazon Web Services (AWS) SDK for Python.
If you are running this example from your local machine, ensure that you have configured your AWS credentials.
You might need to install the aws-cli if you don't have it yet.
After installing the AWS CLI, configure it with your credentials by running:
aws configure
This configuration is stored in the ~/.aws/credentials
and ~/.aws/config
files.
Secrets Manager
Create a secret
Policy Check
If you have problems creating or accessing your secrets, verify that you have the necessary permissions to access the AWS Secrets Manager. Review the policies needed and ensure that your IAM user or role has the appropriate permissions.
You can create a secret using the AWS CLI or the AWS Management Console. Below is an example of how to create a secret using the AWS CLI:
aws secretsmanager create-secret --name db_secret_1 --secret-string '{"user":"user1","password":"mypassword"}'
Using the Secrets Manager Resolver
In this example, the AWSSecretsManagerResolver
is used to fetch the secret named db_secret_1
from AWS Secrets Manager.
The infer_json
parameter is set to True
, which means the resolver will attempt to parse the secret string into a
dictionary. This is of interest when the secret stores key:values pairs.
If infer_json
is set to False
, the secret will be returned as a plain string, which is useful if you store a secret
string, like a JWT.
The following example shows how to use the AWS Secrets Manager resolver with default AWS credentials configuration.
from omegaconf import OmegaConf
from omegaconf_cloud_resolvers import register_custom_resolvers
from omegaconf_cloud_resolvers.resolvers.aws import AWSSecretsManagerResolver
resolvers = {
"aws_secretsmanager": AWSSecretsManagerResolver(infer_json=True),
}
register_custom_resolvers(**resolvers)
conf = OmegaConf.create({
"secret": "${aws_secretsmanager:db_secret_1}"
})
print(conf["user"]) # 'user1'
print(conf["password"]) # 'mypassword'
To check the class in depth, visit the reference page for AWSSecretsManagerResolver
.
SSM Parameter Store
Create parameters
Policy Check
If you have problems creating or accessing your parameters, verify that you have the necessary permissions to access the SSM Parameter Store. Review the policies needed and ensure that your IAM user or role has the appropriate permissions.
You can create secrets using either the AWS Command Line Interface (CLI) or the AWS Management Console. Below are the instructions for using the CLI:
aws ssm put-parameter --name "/project1/env1/sec" --value "MySecureParameterValue" --type "SecureString"
aws ssm put-parameter --name "/project1/env1/list" --value "Value1,Value2,1,1.2" --type "StringList"
aws ssm put-parameter --name "/project1/env1/famA/a" --value "ValueA" --type "String"
aws ssm put-parameter --name "/project1/env1/famA/b" --value "ValueB" --type "SecureString"
Using the SSM Parameter Store Resolver
The AWSParameterStoreResolver
is able to retrieve each one of the parameters types available:
String
: plain string, suitable for common values.StringList
: comma separated list of plain strings, suitable for a collection of non-encrypted values.SecureString
: encrypted string, suitable to store sensitive information. Use the argumentdecrypt=True
(defaults toTrue
) if you need the decrypted value stored, otherwise you will get the encrypted value.
Another feature of the class is its ability to retrieve nested parameters. The options are:
* /my/param
: retrieves one single value.
* /my/param/*
: retrieves /my/param
and the first level hanging from /my/param/
, i.e. /my/param/a
and
/my/param/b
, as a dictionary: {'param': ..., 'param/a': ...,'param/b': ...}
.
* /my/param/family
: retrieves /my/param/family
and the all the parameters hanging from /my/param/family
, i.e. /my/param/family/a
,
/my/param/family/a/beta
and /my/param/family/b
, as a dictionary:
{'family': ..., 'family/a': ..., family/a/beta: ..., 'family/b': ...}
.
Lastly, infer_types=True
will attempt to cast each value to the right type (). That could be of special interest when
the parameter type is StringList
.
The following case assumes that you have default configuration for your AWS credentials.
import boto3
from omegaconf import OmegaConf
from omegaconf_cloud_resolvers import register_custom_resolvers
from omegaconf_cloud_resolvers.resolvers.aws import AWSParameterStoreResolver
session = boto3.Session(profile_name="<my-profile>")
resolvers = {
# Decrypts and infer the parameter. It will return a single value.
"get_aws_param": AWSParameterStoreResolver(session=session, decrypt=True, infer_types=True),
# This parameter is a list of elements, that does not require decryption. It will return a list[any]
"get_aws_param_list": AWSParameterStoreResolver(session=session, decrypt=False, infer_types=True),
# This parameter is a list of elements, that does not require decryption. It will return a list[str]
"get_aws_param_list_str": AWSParameterStoreResolver(session=session, decrypt=False, infer_types=False),
}
register_custom_resolvers(**resolvers)
conf = OmegaConf.create({
"sec_param": "${get_aws_param:/project1/env1/sec}",
"collection_param": "${get_aws_param:/project1/env1/famA/*}",
"list_param": "${get_aws_param_list:/project1/env1/list}",
"list_param_str": "${get_aws_param_list_str:/project1/env1/list}",
})
print(conf["sec_param"])
print(conf["collection_param"])
print(conf["list_param"])
print(conf["list_param_str"])
To check the class in depth, visit the reference page for AWSParameterStoreResolver
.
Azure
Prerequisites
If you need to test locally your configuration you will need to install the Azure CLI.
Make sure as well that you are authenticated:
az login
Key Vault
Create a Secret
You need to point out to a secret. In case that you need to create a new one, you can create it using the console or through the web.
Key Vaults
Key Vault's secrets belong inside objects called Key Vaults. As anything in Azure, they must be linked to a resource group, so make sure that you have a resource group available. In case you don't, you can create a new one:
az group create --name <ResourceGroupName> --location germanywestcentral
az keyvault create --name <ConfigVaultName> --resource-group <ResourceGroupName> --location germanywestcentral
Let's create 2 versions for this secret, make sure that you replace
the fields between <>
by the proper strings.
az keyvault secret set --vault-name <ConfigVaulName> --name MySecret --value "This is a s3cr3t"
az keyvault secret set --vault-name <ConfigVaulName> --name MySecret --value "This is a s3cr3t v2"
Permission error creating a secret
If you get an error trying to create the secrets like: `
it is likely that you don't have the right set of permissions to create secrets.
For this example's sake, you can use the
Key Vault Administrator` role.
Add the previusly mentioned role in your ConfigResourceGroup/Access control (IAM)/Role Assigments
as described here.
Consider using a more restricted role in production.
Key Vault naming
Key Vault naming must be globally unique, so you can add some random string at the end of the name if you get any related error.
Using the Azure Key Vault Resolver
The Azure Key Vault resolver support the one name parameter.
The supported patterns are:
* keyvault/<keyvault-name>/secret/<secret-name>/version/<version-id>
: retrieves a given secret version.
* keyvault/<keyvault-name>/secret/<secret-name>
: retrieves the latest version of a secret.
Assuming that in my case I have access to
* Key Vault: ConfigVaultu31d
(in your case it will be different)
* Secret: MySecret
from omegaconf import OmegaConf
from omegaconf_cloud_resolvers import register_custom_resolvers
from omegaconf_cloud_resolvers.resolvers.az import AzureKeyVaultResolver
from azure.identity import DefaultAzureCredential
credentials = DefaultAzureCredential()
resolvers = {
"get_az_secret": AzureKeyVaultResolver(credentials=credentials),
}
register_custom_resolvers(**resolvers)
conf = OmegaConf.create({
"secret_01":"${get_az_secret:keyvault/ConfigVaultu31d/secret/MySecret}",
"secret_02":"${get_az_secret:keyvault/ConfigVaultu31d/secret/MySecret/version/339c8635b01644b2b6197588ef94a228}",
"secret_03":"${get_az_secret:keyvault/ConfigVaultu31d/secret/MySecret/version/ab9a2a6ae5b5420abd49a71628f368d8}",
})
print(conf["secret_01"])
print(conf["secret_02"])
print(conf["secret_03"])
GCP
Prerequisites
If you are working on your local environment, ensure that you have the necessary permissions and tools installed to interact with Google Cloud Platform services, in this case, the Secret Manager.
You will need the gcloud
CLI installed and authenticated to your GCP account.
Set-up the environment credentials and
make sure that you have the right access permissions.
If you want to set up Application Default Credentials (ADC), so your application automatically finds your environment credentials, review this link.
Secret Manager
Create a Secret
Create a secret through the web or using the gcloud
CLI, running the line below.
echo -n "This is a s3cr3t" | gcloud secrets create gcp-secret-001 --data-file=-
Also create a new version for this example.
echo -n "This is a s3cr3t v2" | gcloud secrets versions add gcp-secret-001 --data-file=-
Using the GCP Secret Manager Resolver
The typical way to access a GCP secret is providing a combination of the project_id, the secret id and, optionally, the secret's version. That is supported by the resolver, allowing you to retrieve the secret providing a name under the following format:
project/<project_id>/secrets/<secret_id>/versions/<version>
project/<project_id>/secrets/<secret_id>
: retrieve the latest versionsecrets/<secret_id>/versions/<version>
: infer the project_id based on the default configurationsecrets/<secret_id>
: infer the project_id based on the default configuration and retrieve the latest version<secret_id>
: infer the project_id based on the default configuration and retrieve the latest version
Assuming that you have the ADC, create a file main.py
like the following:
from omegaconf import OmegaConf
from omegaconf_cloud_resolvers import register_custom_resolvers
from omegaconf_cloud_resolvers.resolvers.gcp import GCPSecretManagerResolver
resolvers = {
"get_gcp_secret": GCPSecretManagerResolver(), # if you don't have the ADC, or you need to override the,
# provide: credentials and project_id
}
register_custom_resolvers(**resolvers)
conf = OmegaConf.create({
"secret_01": "${get_gcp_secret:secrets/gcp-secret-001/versions/1}",
"secret_02": "${get_gcp_secret:secrets/gcp-secret-001}",
"secret_03": "${get_gcp_secret:gcp-secret-001}",
})
print(conf["secret_01"])
print(conf["secret_02"])
print(conf["secret_03"])