AWS CDK 배포 Lambda 함수에서 비밀을 안전하게 사용

15270 단어 cdklambdaawspython
Lambda 함수의 로그인 세부 정보와 같은 항목에 대한 보안 액세스가 필요한 적이 있습니까? 데이터베이스 또는 기타 서비스에 연결해야 할 수 있지만 자격 증명을 하드 코딩할 필요는 없습니다. 글쎄, AWS Secrets Manager를 사용하여 로그인 세부 정보를 가져와 최상의 보안 방법을 사용합시다!
AWS CDK에 저장된 암호에 액세스할 수 있는 권한이 있는 Lambda 함수를 배포하기 위해 PythonSecrets Manager을 사용할 것입니다. 또한 람다 함수 내에서 이 비밀을 안전하게 검색하는 방법도 보여드리겠습니다.

GitHub 저장소here를 참조하십시오.

CDK 구성 요소에 들어가기 전에 AWS CLI를 사용하여 예제 암호를 생성해 보겠습니다.

aws secretsmanager create-secret --name secretsExample --secret-string "TestPass123"


스택 설계



cdk_lambda_secrets/cdk_lambda_secrets_stack.py



여기에서 우리는 람다 함수를 생성하고 비밀을 읽을 수 있는 권한을 부여하여 CDK 스택을 구축합니다. 비밀의 이름을 환경 변수로 람다 함수에 전달하여 반복을 줄일 수 있습니다.

import os

from aws_cdk import Stack
from aws_cdk import aws_lambda as _lambda
from aws_cdk import aws_secretsmanager as secrets
from constructs import Construct


class CdkLambdaSecretsStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        self.build_lambda_func()

    def build_lambda_func(self):
        secret_name = "secretsExample"
        self.secrets_lambda = _lambda.Function(
            scope=self,
            id="LambdaWithSecrets",
            runtime=_lambda.Runtime.PYTHON_3_9,
            function_name="LambdaWithSecretsExample",
            code=_lambda.Code.from_asset(
                path="lambda_funcs/lambda_with_secrets"
            ),
            handler="lambda_with_secrets.handler",
            # We need these env vars to access the secret inside the lambda
            environment={
                "secret_name": secret_name,
                "secret_region": os.environ["CDK_DEFAULT_REGION"],
            },
        )
        # Grant permission to the Lambda func to access the secret
        example_secret = secrets.Secret.from_secret_name_v2(
            scope=self, id="secretExample", secret_name=secret_name
        )
        example_secret.grant_read(grantee=self.secrets_lambda)



람다 함수



lambda_funcs/lambda_with_secrets/lambda_with_secrets.py



여기서 우리는 헬퍼 함수get_secrets()로 람다 함수를 정의합니다. AWS Console에서 시크릿을 볼 때 AWS에서 제안하는 '샘플 코드' 기능을 아주 약간 수정한 버전입니다. ARN를 사용하여 암호에 액세스하는 대신 단순히 암호 이름을 사용할 수 있습니다. 나는 CDK를 사용하여 비밀의 full ARN를 얻을 수 없다는 것을 알았지만 운 좋게도 get_secret_value()SecretId 매개변수에 대한 비밀 이름을 받아들입니다.

import base64
import json
import os

import boto3
from botocore.exceptions import ClientError


def get_secret():
    """
    Gets the secret
    """
    # Get env vars we passed in the stack.
    secret_name = os.getenv("secret_name")
    region_name = os.getenv("secret_region")

    # Create a Secrets Manager client
    session = boto3.session.Session()
    client = session.client(
        service_name="secretsmanager", region_name=region_name
    )

    # In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
    # See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
    # We rethrow the exception by default.

    try:
        # We need only the name of the secret
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        if e.response["Error"]["Code"] == "DecryptionFailureException":
            # Secrets Manager can't decrypt the protected secret text using the provided KMS key.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response["Error"]["Code"] == "InternalServiceErrorException":
            # An error occurred on the server side.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response["Error"]["Code"] == "InvalidParameterException":
            # You provided an invalid value for a parameter.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response["Error"]["Code"] == "InvalidRequestException":
            # You provided a parameter value that is not valid for the current state of the resource.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response["Error"]["Code"] == "ResourceNotFoundException":
            # We can't find the resource that you asked for.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        else:
            raise e
    else:
        # Decrypts secret using the associated KMS key.
        # Depending on whether the secret is a string or binary, one of these fields will be populated.
        if "SecretString" in get_secret_value_response:
            secret = get_secret_value_response["SecretString"]
            # If you have multiple secret values, you will need to json.loads(secret) here and then access the values using dict keys
            return secret
        else:
            decoded_binary_secret = base64.b64decode(
                get_secret_value_response["SecretBinary"]
            )
            return decoded_binary_secret


def handler(event, context):
    secret = get_secret()
    # Don't do this in production!!!
    return secret


cdk deploy 이 스택과 작업 예제가 있어야 합니다.

Lambda 함수 테스트





Lambda 함수가 AWS Secrets Manager에서 암호 값을 성공적으로 검색했습니다!

분해



우리가 만든 비밀을 삭제하려면:

aws secretsmanager delete-secret --secret-id secretsExample


스택 파괴:

cdk destroy


즐기다!

좋은 웹페이지 즐겨찾기