AWS Amplify Function 에서 Secrets Manager 사용하기

김현성·2021년 1월 16일
0
post-thumbnail

Secrets Manger를 왜 사용해야하는가?

이전에는 데이터에 엑세스 하기 위한 인증키를 애플리케이션에 직접적으로 포함시키거나 환경변수를 사용하여 관리 하였으나, 직접적인 인증키의 사용은 외부에 유출되기가 쉬웠으며 또한 공통의 인증키를 사용하는 여러 애플리케이션의 경우 인증키가 만료시 혹은 인증키를 변경시 각각의 인증키를 변경해줘야하는 관리 측면에서의 불편함이 존재했습니다.

Secrets Manger는 이러한 불편함을 프로그래밍 방식으로 암호의 관리 및 코드에 인증키가 직접적으로 노출되지 않게 도와줍니다.

Secrets Manager 생성

  • 암호 유형 선택 및 암호 입력
    이 글에서는 일반적인 용도의 키-값 방식을 사용합니다.

  • 암호 이름 입력
    코드에서 이름을 가지고 불러옵니다.

  • 암호 변경 자동화
    암호를 자동으로 교체해줄지 여부를 선택합니다.
    암호의 교체는 람다를 통하여 진행됩니다.

  • 입력한 내용 검토 및 예제 코드
    마지막 단계로 입력한 내용의 검토 및 예제 코드를 확인 할 수 있습니다.

Amplify Function CloudFormation Template변경

Amplify를 통하여 Deploy된 Function(Lambda) 에서 사용하기 위하여 CloudFormation 파일을 변경하여 권한을 추가해 줘야 합니다.

amplify/backend/function/FUNCTION_NAME/FUNCTION_NAME-cloudformation-template.json

PolicyDocument 의 Statement에 다음과 같이 권한을 허용해줍니다.

MY_KEY 대신 arn에 있는 동일한 값을 넣어주시면 됩니다.

"PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            ...
            {
              "Effect": "Allow",
              "Action": [
                "secretsmanager:GetSecretValue"
              ],
              "Resource": {
                "Fn::Sub": [
                  "arn:aws:secretsmanager:${region}:${account}:secret:MY_KEY",
                  {
                    "region": {
                      "Ref": "AWS::Region"
                    },
                    "account": {
                      "Ref": "AWS::AccountId"
                    }
                  }
                ]
              }
            }

          ]
}

코드에서의 사용(Golang)

위에서 권한 추가가 정상적으로 되었으면 함수에서의 접근은 쉬운편입니다.
기본 제공되는 샘플 코드로 접근이 가능합니다.

import (
	"encoding/json"
	"fmt"
    
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/secretsmanager"
)

...

func getSecret() (map[string]interface{}, error) {

	secretName := "SAMPLE_APP"
	region := "ap-northeast-2"

	// Create Client
	svc := secretsmanager.New(session.New(),
		aws.NewConfig().WithRegion(region))
	input := &secretsmanager.GetSecretValueInput{
		SecretId:     aws.String(secretName),
		VersionStage: aws.String("AWSCURRENT"),
	}

	// Get Key Value
	result, err := svc.GetSecretValue(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case secretsmanager.ErrCodeDecryptionFailure:
				return nil, fmt.Errorf("[%s] %s", secretsmanager.ErrCodeDecryptionFailure, aerr.Error())

			case secretsmanager.ErrCodeInternalServiceError:
				return nil, fmt.Errorf("[%s] %s", secretsmanager.ErrCodeInternalServiceError, aerr.Error())
			case secretsmanager.ErrCodeInvalidParameterException:
				return nil, fmt.Errorf("[%s] %s", secretsmanager.ErrCodeInvalidParameterException, aerr.Error())

			case secretsmanager.ErrCodeInvalidRequestException:
				return nil, fmt.Errorf("[%s] %s", secretsmanager.ErrCodeInvalidRequestException, aerr.Error())

			case secretsmanager.ErrCodeResourceNotFoundException:
				return nil, fmt.Errorf("[%s] %s", secretsmanager.ErrCodeResourceNotFoundException, aerr.Error())
			}
		} else {
			fmt.Println(err.Error())
		}
		return nil, err
	}

	resp := make(map[string]interface{})
	if err := json.Unmarshal([]byte(aws.StringValue(result.SecretString)), &resp); err != nil {
		return nil, err
	}

	return resp, nil
}

...
// 키값 출력
fmt.Printf("%s", resp["SAMPLE_KEY"].(string)) // output: SAMPLE_VALUE

결론

Secrets Manger를 사용해서 보안을 높이고 편하게 관리하자.
Amplify 에서 사용하기 위해서는 CloudFormation Template에서 권한을 추가해주면 사용이 가능하다.

0개의 댓글