name: Deploy to Amazon ECR
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
AWS_REGION: ap-northeast-2
ECR_REPOSITORY: users
ECS_SERVICE: race-user-sv
ECS_CLUSTER: race-cluster
ECS_TASK_DEFINITION: ./aws/task-definition.json
CONTAINER_NAME: race-user
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
working-directory: ./backend/user-backend
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . || true
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG || true
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
위의 git actions yml을 이용해서 CI/CD 파이프라인을 구축하려면 아래의 task-definition 파일이 필요했다.
하지만 taskDefinition에 환경변수로 access key가 필요한 상황이였는데 json에 해당 값이 그대로 노출이 됐었다.
git action을 사용하기 위해서 해당 파일을 gitignore에 추가할 수도 없어서 Secrets Manager 사용이 필요했다.
{
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-2:648098991845:task-definition/race-user-task:11",
"containerDefinitions": [
{
"name": "race-user",
"image": "IMAGE_URL",
"cpu": 0,
"portMappings": [
{
"name": "race-user-3000-tcp",
"containerPort": 3000,
"hostPort": 3000,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"environment": [
{
"name": "AWS_ACCESS_KEY",
"value": "AWS_ACCESS_KEY_VALUE"
},
{
"name": "AWS_SECRET_ACCESS_KEY",
"value": "AWS_SECRET_ACCESS_KEY_VALUE"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/race-user-task",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"family": "race-user-task",
"taskRoleArn": "arn:aws:iam::648098991845:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::648098991845:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"revision": 11,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "ecs.capability.task-eni"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2",
"FARGATE"
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "1024",
"memory": "3072",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"registeredAt": "2023-06-19T06:54:22.345Z",
"registeredBy": "arn:aws:iam::648098991845:root",
"tags": []
}
- 환경 변수의 값 유형을 ValueFrom으로 지정한다.
- 값 부분에 (보안 암호 ARN):(보안 암호 키):: 으로 작성 해준다.
이제 테스크 정의 JSON에서 access key값의 노출을 방지할 수 있게 되었다.
Secrets Manager의 보안암호는 그밖에 DB의 username과 password값을 숨기거나 코드에 노출될 수 있는 중요한 정보들을 가리는데 사용할 수 있다.
위의 사진은 한달간 사용하면서 100만건의 요청을 처리했을 때의 예상 비용이다.
5.40 USD로 매우 저렴하게 사용가능 하다
Secrets Manager은 분명 간편하고 요금도 적게나오는 좋은 서비스라고 위에서 설명한대로 생각하고있다.
하지만 이걸 terraform과 git action을 같이 사용하는곳에서 문제를 직면했다.
resource "aws_ecs_task_definition" "app_task" {
family = "tf-race-user-task" # Name your task
container_definitions = <<DEFINITION
[
{
"name": "race-user-task",
"image": "648098991845.dkr.ecr.ap-northeast-2.amazonaws.com/users:4775dbd4b152757ad366d4dc23f57b00904eabdd",
"essential": true,
"portMappings": [
{
"containerPort": 3000,
"hostPort": 3000
}
],
"cpu": 0,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "app-logstream",
"awslogs-group": "${aws_cloudwatch_log_group.my_ecs_service_log_group.name}"
}
},
"environment": [
{
"name": "AWS_ACCESS_KEY_ID",
"value": "${var.AWS_ACCESS_KEY}"
},
{
"name": "AWS_SECRET_ACCESS_KEY",
"value": "${var.AWS_SECRET_ACCESS_KEY}"
}
]
}
]
DEFINITION
requires_compatibilities = ["FARGATE"] # use Fargate as the launch type
network_mode = "awsvpc" # add the AWS VPN network mode as this is required for Fargate
memory = 3072 # Specify the memory the container requires
cpu = 1024 # Specify the CPU the container requires
execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn
}
위의 코드는 terraform 코드중에 task definition부분이다.
environment 부분을 보면 value라고 되어있는곳을 Secrets manager를 사용하기 위해서 valueFrom이라고 변경해서 terraform을 실행시키면 환경변수가 테스크 정의에서 없어진채로 배포가 된다.
terraform 공식문서와 chatGPT등 여러 방면으로 검색해 보았지만 해당 valueFrom을 사용하는 부분은 지원해주지 않는것 같았다.
해서 결국 목적은 코드에 access key 값을 숨기기 위함이니 git action yml 부분에서 환경변수를 숨겨서 추가해기로 결정했다.
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
environment-variables: |
AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
environment-variables 부분을 추가해서 테스크 정의 json 파일에 환경변수를 github secret을 활용하여 숨겨서 추가해준다.