Elastic Beanstalk에서 Secret Manager 사용하기

September 22, 2023

logo-eb-asm.png

Elastic Beanstalk?

우선 AWS 문서를 보자:

Elastic Beanstalk를 사용하면 애플리케이션을 실행하는 인프라에 대해 자세히 알지 못해도 AWS 클라우드에서 애플리케이션을 신속하게 배포하고 관리할 수 있습니다. Elastic Beanstalk를 사용하면 선택 또는 제어에 대한 제한 없이 관리 복잡성을 줄일 수 있습니다. 애플리케이션을 업로드하기만 하면 Elastic Beanstalk에서 용량 프로비저닝, 로드 밸런싱, 조정, 애플리케이션 상태 모니터링에 대한 세부 정보를 자동으로 처리합니다.

위에서 말한 것 처럼, 적당히 세팅만 해 주면 AWS쪽에서 웹 서비스에서 필요한 기능들을 알아서 관리해 주기 때문에 처음 웹 서비스를 만들거나 MVP를 만들 때 사용하기 매우 편하다. Heroku 같은 서비스보다는 더 많은 부분을 컨트롤할 수 있고, ECS나 EKS처럼 컨테이너를 사용하는 서비스보다는 훨씬 관리해 주는 게 많은 서비스다. 위에 말한 두 서비스의 적당한 절충안을 원하는 사람이라면 좋아할만한 서비스라고 생각한다.

나는 개인적으로 Elastic Beanstalk(이하 EB)을 사용하는 걸 좋아한다. 간단한 웹 서비스를 배포하는 데에 편리하고 적당히 중요한 기능들 다 있어서, 생각보다 더 쓸만하고 사용하면서 치명적인 단점을 발견한 적은 딱히 없었다.

그러던 어느날, 그동안 EB를 쓰면서 ASM(AWS Secrets Manager)을 사용할 일이 없었는데, 마침 사용하게 될 일이 생겨서 설정법을 찾아보던 도중 중요한 사실을 하나 깨달았다.

Elastic Beanstalk과 ASM을 연결하는 기능은 없다

그렇다. 같은 AWS 서비스임에도 불구하고 EB에서 ASM에 있는 시크릿 키를 받아와 사용할 수 있는 방법이 딱히 없다! EB 외부에서 값을 넣는 방법이 몇 가지 있는데, GUI에서 할 수 있는 방법은 Enviornment 값을 넣는 것이 전부이다.

문서를 뒤져봐도 개인 리포지토리를 호스팅하는 온라인 레지스트리를 사용하여 인증 하는 방법에 대해서만 이야기할 뿐, EB env안에 ASM 값을 넣는 방법은 나오지 않았고, 내 혈압도 같이 올라갔다.

그래도 넣어봅시다.

stack overflow를 뒤져보면서 얻은 결론은 "awscli로 커맨드 받아서 직접 넣기" 였다. awscli를 사용하는 거야 쉽다. 이런 식으로 ASM에서 secret key를 받아올 수 있다:

aws secretsmanager get-secret-value --secret-id ${AWS_SECRET_ID} | jq ".SecretString | fromjson | to_entries[] | [.key,.value] | join(\"=\")"

이렇게 하면 json 형태로 받아온 secret key를 .env에서 사용하는 AAA=BBB 형태로 가져올 수 있고, 파일로 저장하면 된다. 다만 받아온 키를 어디에 넣어야 하는지가 문제인데, 여러가지 방법을 써 본 결과 docker-compose를 이용해 값을 가져오는게 제일 괜찮은 방법이었다.

Dockerfile 직접 넣기보다 docker-compose.yml를 사용하자

이전에 나는 주로 Dockerfile을 직접 넣어서 빌드를 하는 방식을 주로 사용했다. 소스 코드와 Dockerfile을 넣으면 EB에서 알아서 docker build를 하고 배포를 하는데, 몇 가지 불편한 점이 있다.

  • 인스턴스 스펙이 낮으면 빌드 시 램 부족으로 터질 수 있다.

    • EB에서는 docker build도 해당 인스턴스로 하기 때문에, Frontend 배포 할 때 npm build 등으로 큰 소스들을 빌드하다 보면 OOM이 발생하는 경우가 생각보다 많다.
  • secret key 넣는 과정에 애로사항이 생긴다.

    • Dockerfile만을 사용할 경우 /var/app/current/.env 값에 secret key를 넣어야 하는데, EB에서 env 값을 바꿀 떄 .env 파일을 수정하기 때문에 값이 덮어씌워질 일이 생긴다.

그럼 어떻게 하는 게 좋을까? 쉽다. docker-compose도 지원하기 때문에, CD 단계에서 docker build를 하고, ECR(Elastic Container Registry)에 docker 이미지를 올려둔 뒤 가져오면 된다.


여기서 잠깐, 왜 /var/app/current/.env 일까?

그걸 알기 위해선 EB가 어떤 구조로 돌아가는지 알 필요가 있다. EB는 ELB + EC2 + ASG 등을 AWS에서 미리 만들어 둔 CloudFormation 템플릿을 이용해서 배포를 하는 시스템이다. 그래서 EB 자체는 사용료가 부가되지 않지만, EB에서 배포하면서 만들어지는 다른 서비스들에서 비용이 부과가 된다.

EB에서 생성한 EC2 안으로 들어가 보면, 소스를 받고 가공을 하는 동안은 /var/app/staging/에서 작업을 하고, 그 후 실행할 땐 /var/app/current/에서 돌아간다는 것을 알 수 있다. 그러니 빌드 전에 secret key를 해당 디렉토리 안에 넣어서 돌아가게 할 수 있는 것이다.

.platform/ script 사용하기

EB에서는 코드 배포 전/후에 스크립트를 따로 돌릴 수 있는 방법들을 제공하고 있다.

eb_steps.png (출처: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html)

위 사진과 같이 EB는 배포 시 총 3가지 step을 진행하는데, 중간 중간에 스크립트를 실행할 수 있다. .platform/ 디렉토리 안에 넣으면 해당 스크립트를 실행할 수 있는데, 우리는 prebuild 단계에서 secret key를 만들어 넣을 예정이다.

다음과 같은 위치에 파일 두 개를 만들어야 한다.

.platform/hooks/prebuild/get_secret_key.sh .platform/confighooks/prebuild/get_secret_key.sh

confighooks는 무엇인가? 배포 뿐만 아니라 인스턴스 구성을 바꿀 때(env 값 변경 등)에도 스크립트를 돌릴 수 있다. confighooks/ 디렉토리에 넣으면 실행 가능하다.

그럼 스크립트 안에는 어떤 값을 넣어야 하는가? 실행하는 EB 위치에 .secret 파일을 넣어주면 된다.

#!/bin/bash $( echo "$(/opt/elasticbeanstalk/bin/get-config environment)" | jq -r 'keys[] as $k | "export \($k)=\(.[$k])"' ) # load ElasticBeanstalk env aws secretsmanager get-secret-value --secret-id ${AWS_SECRET_ID} | jq ".SecretString | fromjson | to_entries[] | [.key,.value] | join(\"=\")" -r > /var/app/staging/.secret aws secretsmanager get-secret-value --secret-id ${AWS_SECRET_ID} | jq ".SecretString | fromjson | to_entries[] | [.key,.value] | join(\"=\")" -r > /var/app/current/.secret

이 스크립트를 실행하게 되면 /var/app/staging/.secret, /var/app/current/.secret 두 곳에 .secret 파일을 만들게 된다. 두 곳 모두 만들어야 한다. 그렇지 않으면 배포 시 에러가 발생한다.

그리고 docker-compose에는 다음과 같이 .secret 파일을 읽도록 설정하면 끝.

version: '3.1' services: app: image: {docker image} # ECR에 올린 도커 이미지 env_file: - .env # Elastic Beanstalk에서 Environment 값을 넣으면 들어가는 파일 - .secret # 아까 만들었던 ASM으로 로드한 secret key ... # 나머지 기타등등 설정

이렇게 하면 EB + ECR + ASM 조합으로 애플리케이션을 간단하게 배포할 수 있다.

Reference

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/single-container-docker-configuration.html

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html

https://stackoverflow.com/questions/35788499/what-is-the-difference-between-commands-and-container-commands-configuration-key


Profile picture

Written by Mingyu Kim who works as a front-end engineer.