python - aws秘密经理:远程env vars
#aws #python #env #secretsmanager

环境变量在配置和自定义软件应用程序中起着至关重要的作用。它们允许开发人员安全地存储敏感信息并调整其代码的行为,而无需修改基础源文件。在Python中,检索环境变量通常是一个简单的过程。

但是,在处理远程环境或秘密管理时,该过程可能会变得更加复杂。本文提供了一种检索环境变量的方法,特别关注与AWS Secrets Manager集成。

内容

要讨论的代码

下面提供的代码包括三个主要功能:envget_envremote_environment_variable,仔细阅读每个函数的实现,尝试了解其目的及其在检索环境变量中的作用。

import json
import os
from base64 import b64decode

from botocore.exceptions import (ClientError, NoCredentialsError,
                                 ParamValidationError)

from configs import aws
from configs.logging import logger

"""
Retrieves the value of an env variable from a remote source or a .env file.

:type key: str
:type default_value: str
:return: str
"""


def env(key: str, default_value: str = ""):
    value = get_env(key, default_value)

    if value.lower() == "true":
        return True
    if value.lower() == "false":
        return False

    return value


"""
Retrieves env variable from .env and AWS Secrets Manager, giving precedence to
remote value. If both sources exist, the remote value is returned; otherwise,
.env value or default_value is used.

:type key: str
:type default_value: str
:return: str
"""


def get_env(key: str, default_value: str = "") -> str:
    local_value = str(os.getenv(key, default_value))
    remote_value = str(remote_environment_variable(key))
    return remote_value if remote_value else local_value


"""
Retrieves env variable from AWS Secrets Manager.

:type key: str
:return: str
"""


def remote_environment_variable(key: str) -> str:
    secret_id = os.getenv("AWS_SECRETS_MANAGER_SECRET_ID")

    if not secret_id:
        return ""

    try:
        response = aws.secrets_manager.get_secret_value(SecretId=secret_id)
    except (ClientError, NoCredentialsError, ParamValidationError) as error:
        if isinstance(error, (NoCredentialsError, ParamValidationError)):
            logger.debug("AWS Secrets Manager: %s", error)
        else:
            message = f"{error.response['Error']['Code']} to secret"
            logger.error(f"{message} {secret_id}: {error}")

        return ""

    if "SecretString" in response:
        secret_dictionary = json.loads(response["SecretString"])
    else:
        secret_dictionary = json.loads(b64decode(response["SecretBinary"]))

    return secret_dictionary.get(key)

现在,已读取代码,让我们详细探讨代码。

env函数

此功能旨在从远程源或.env文件中检索环境变量的值。它为访问环境变量提供了一个实用的接口,并为布尔值提供了其他处理。通过在内部利用get_env函数,它可以确保从适当源的变量稳定地检索。

def env(key: str, default_value: str = "") -> str:
    value = get_env(key, default_value)

    if value.lower() == "true":
        return True
    if value.lower() == "false":
        return False

    return value

env函数采用两个参数:代表要检索的环境变量名称的key,如果找不到变量,则使用的可选default_value

在该函数中,它调用get_env函数,传递键和default_value参数。返回值分配给value变量。

提供额外的灵活性,该功能检查检索值是true或false。如果该值为真(对案例不敏感),则返回一个布尔True。如果该值是错误的(不敏感的),则返回一个布尔False。这允许对布尔环境变量进行更实际的处理。

如果该值不是布尔值,则该函数将原始值返回为字符串。

总体而言,env函数通过内部利用get_env函数并提供一个一致且灵活的接口来访问和解释其值。

,可以简化环境变量的检索。

get_env函数

此功能是检索环境变量的中心部分。它处理逻辑以从本地.env文件或AWS Secrets Manager获取变量。可用时,它给出了远程值的优先级,并在必要时落后于本地值或默认值。

def get_env(key: str, default_value: str = "") -> str:
    local_value = str(os.getenv(key, default_value))
    remote_value = str(remote_environment_variable(key))
    return remote_value if remote_value else local_value

get_env函数负责从本地.env文件或AWS Secrets Manager检索环境变量。它需要两个参数:key,代表要检索的环境变量的名称,如果找不到变量,则使用的可选default_value

在该功能中,它首先尝试使用os.getenv(key, default_value)从本地环境中检索值。 os.getenv()功能通过提供的key检索环境变量的值。如果找不到变量,它将返回到default_value。然后,无论是从环境还是默认值中检索的值,都使用str()函数转换为字符串,并存储在local_value变量中。

接下来,该函数调用remote_environment_variable(key)函数,该功能从AWS Secrets Manager中检索值。结果存储在remote_value变量中,也转换为字符串表示。

最后,该函数如果存在(即,不是一个空字符串),则返回remote_value,或者如果远程值不可用,则返回回到local_value。这确保了当两个源都存在时函数优先于远程值。

总而言之,get_env函数提供了一种统一的方法来检索环境变量,结合了本地.env文件和AWS Secrets Manager的值。它在可用时优先考虑远程值,在处理环境可变检索中提供灵活性和一致性。

远程_environment_variable函数

此功能负责从AWS Secrets Manager检索环境变量。它使用AWS_SECRETS_MANAGER_SECRET_ID环境变量来识别AWS Secrets Manager中的秘密并获取相应的值。

def remote_environment_variable(key: str) -> str:
    secret_id = os.getenv("AWS_SECRETS_MANAGER_SECRET_ID")

    if not secret_id:
        return ""

    try:
        response = aws.secrets_manager.get_secret_value(SecretId=secret_id)
    except (ClientError, NoCredentialsError, ParamValidationError) as error:
        if isinstance(error, (NoCredentialsError, ParamValidationError)):
            logger.debug("AWS Secrets Manager: %s", error)
        else:
            message = f"{error.response['Error']['Code']} to secret"
            logger.error(f"{message} {secret_id}: {error}")

        return ""

    if "SecretString" in response:
        secret_dictionary = json.loads(response["SecretString"])
    else:
        secret_dictionary = json.loads(b64decode(response["SecretBinary"]))

    return secret_dictionary.get(key)

remote_environment_variable函数从AWS Secrets Manager中检索环境变量的值。它采用一个参数,键,代表环境变量的名称。

首先,该函数使用os.getenv()检索AWS_SECRETS_MANAGER_SECRET_ID环境变量的值。此值代表包含所需环境变量的AWS Secrets Manager中的秘密ID。

如果找不到或空的secret_id,表明所需的环境变量不可用,则该功能返回一个空字符串。

接下来,该函数尝试使用aws.secrets_manager.get_secret_value()方法来获取秘密值,并使用检索到的secret_id传递SecretId参数。在except街区中捕获并处理任何潜在的例外,例如ClientErrorNoCredentialsErrorParamValidationError

如果检索成功,则该函数检查响应是否包含秘密弹簧键。如果存在,它假设秘密值是字符串格式,并使用json.loads()解析,将结果字典存储在secret_dictionary变量中。否则,如果响应包含一个秘密键,则假设秘密值是在基本64编码的二进制格式中,并在将其解析为字典之前使用b64decode()对其进行解码。

最后,该函数尝试使用get()方法检索与secret_dictionary提供的key关联的值。如果在字典中找到key,则返回相应的值。如果找不到,返回None

总而言之,remote_environment_variable函数通过利用AWS_SECRETS_MANAGER_SECRET_ID环境变量来识别秘密,提供了一种从AWS Secrets Manager检索环境变量的方法。它在检索过程中处理潜在的错误和例外,确保稳健性并可靠地访问敏感配置值。

用法示例

此功能在不同的情况下演示了ENV函数的用法。

from example_module import env

def example_function():
    # Example 1
    database_url = env('DATABASE_URL')
    print(f"The database URL is: {database_url}")

    # Example 2
    api_key = env('API_KEY', default_value='DEFAULT_API_KEY')
    print(f"The API key is: {api_key}")

    # Example 3
    debug_mode = env('DEBUG_MODE')
    if debug_mode:
        print("Debug mode is enabled.")
    else:
        print("Debug mode is disabled.")

在第一个示例中,可以看到基本的环境变量检索,它可以检索“ database_url”环境变量的值并打印它。在第二个示例中,用默认值检索“ API_KEY”环境变量的值并打印它。第三个也是最后一个示例处理布尔环境变量,它将“ debug_mode”环境变量的值检索为布尔值,并相应地打印了调试模式。

最后的想法

使用这种方法与适当的AWS EC2 aws IAM配置相结合,可以将所有环境变量集中到AWS Secrets Manager中,消除了在部署期间处理.ENV文件的必要性。

因此,该解决方案为应用程序生命周期提供了两个效果。 1)简化了由于消除本地环境之外的.ENV文件而导致的部署; 2)更好的安全性,因为您可以以团队的特定成员可以添加和修改Secrets Manager条目的方式建立IAM访问策略。


我是巴西工程师杰克·米拉斯

快乐编码!