Server

[Docker, AWS, Spring] docker-compose시 환경변수 전달하고 스프링부트 application.yaml에서 사용하기

Sean 션 2023. 10. 6. 16:33

저는 보안 전문가가 아닙니다.

하지만 개발자라면 보안을 고려하지 않을 수 없겠죠.

제가 사용했던 기존의 방법입니다.

application.yaml파일을 github repository secret으로 두었기 때문에 언뜻 보면 안전해 보입니다.

하지만 잘 보시면 application.yaml을 만든 후 도커 푸시를 진행하죠..

 

private docker를 사용하지 않는다면, repo 와 image 이름을 아는 누구나 제 image를 pull하고 열어볼 수 있습니다.

그렇기 때문에 저는 완전히 public한 장소에 저의 모든 환경변수를 넣은 것이죠.

 

 

저희가 수정할 방법입니다.

ec2에 .env 파일을 만들고, docker-compose up 시에 env를 설정하여 받으면 됩니다.

 

그림을 보시면 image에는 환경변수가 들어가질 않았죠.

.env를 docker-compose up 시에 넣어준 뒤에 사용할 수 있습니다.

자 그럼 어떻게 할 수 있을까요?

 

 

 

1. application.yaml

spring:
    servlet:
        multipart:
            max-request-size: 30MB
            max-file-size: 30MB
    jpa:
        show-sql: true
        generate-ddl: true
        hibernate:
            ddl-auto: update
            default_batch_fetch_size: 100
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: ${DB_URL}
        username: ${DB_USERNAME}
        password: ${DB_PASSWORD}
        hikari:
            maximum-pool-size: 10
    properties:
        hibernate:
            format-sql: true
            dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    mvc:
        pathmatch:
            matching-strategy: ant-path-matcher
    main:
        allow-bean-definition-overriding: true
    redis:
        host: ${REDIS_HOST}
        port: 6379

레포지토리에 public하게 push되는 application.yaml입니다.

중요한 환경변수들은 ${}의 포맷으로 가려져있죠.

 

2. .env

DB_URL=imnotgonnaleakthis
DB_USERNAME=mydbusernameisprivate
DB_PASSWORD=thisismyprivatedbpassword

.env에는 실제로 사용하는 중요한 환경변수들을 key-value쌍으로 저장해둡니다.

위의 application.yaml에서 변수를 불러오는 소스입니다.

(이 파일은 당연히 노출시키지 않습니다. gitignore 처리 하세요)

 

그리고 .env 파일은 깃헙 레포지토리 시크릿에 ENV_VARS로 등록해줍니다.

 

 

 

3. docker-compose.yaml

version: '3'
services:

  web:
    container_name: web
    image: repick/repick-web
    env_file:		# 이부분 추가 바랍니다
      - .env        # 이부분 추가 바랍니다
    expose:
      - 8080
    ports:
      - 8080:8080
    tty: true
    environment:
      - TZ=Asia/Seoul
    logging:
      driver: awslogs
      options:
        awslogs-group: "repickLogGroup"
        awslogs-region: "ap-northeast-2"
        awslogs-stream: "repickLogStream"

  nginx:
    container_name: nginx
    image: repick/repick-nginx
    ports:
      - 80:80
    depends_on:
      - web

docker-compose.yaml에서 env_file : -.env 부분을 추가해줍니다!

그래야 환경변수를 인식하고 넣어준답니다.

 

4. gradle.yml ( 여러분의 워크플로우 )

name: Deploy Development Server

## develop 브랜치에 push가 되면 실행됩니다
on:
  push:
    branches: [ "develop" ]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

      - name: checkout
        uses: actions/checkout@v3

      ## 여러분이 사용하는 버전을 사용하세요
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      ## gradle build
      - name: Build with Gradle
        run: ./gradlew bootJar


      ## 웹 이미지 빌드 및 도커허브에 push
      - name: web docker build and push
        run: |
          docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          docker build -t my-repo/my-web-image .
          docker push my-repo/my-web-image
          docker build -f dockerfile-nginx -t my-repo/my-nginx-image .
          docker push my-repo/my-nginx-image

      - name: executing remote ssh commands using password
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ubuntu
          key: ${{ secrets.KEY }}
          script: |
          
          ## 여러분이 원하는 경로로 이동합니다.
            cd /home/ubuntu/
            
          ## .env 파일을 생성합니다.
            sudo touch .env
            echo "${{ secrets.ENV_VARS }}" | sudo tee .env > /dev/null
          
          ## docker-compose.yaml 파일을 생성합니다.
            sudo touch docker-compose.yaml
            echo "${{ vars.DOCKER_COMPOSE }}" | sudo tee docker-compose.yaml > /dev/null
            
          ## docker-compose를 실행합니다.
            sudo chmod 666 /var/run/docker.sock
            sudo docker rm -f $(docker ps -qa)
            sudo docker pull my-repo/my-web-image
            sudo docker pull my-repo/my-nginx-image
            docker-compose -f docker-compose.yaml --env-file ./.env up -d
            docker image prune -f

이렇게 워크플로우를 작성하였는데요, 보다시피 ENV_VARS를 읽어서 .env에 저장해줍니다.

그런 후 docker-compose -f docker-compose.yaml --env-file ./.env up -d 로 env파일을 읽어서 실행시키도록 합니다.

(현재 디렉토리의 .env파일을 default로 읽는다고 합니다. 하지만 명시적으로 적어주었습니다)

 

자 이렇게 해서 docker image에 환경변수를 노출시키지 않았습니다!

여러분들도 안전한 코딩 되시기 바랍니다.