trivy-github-action

소개

Kubernetes 환경에서 Microservice 는 모두 image 기반으로 배포되고 운영이 됩니다. 그런만큼 image 보안에 대해 신경을 많이 써야하는데요.

image 보안을 위해서는 image 에 대한 보안 스캔을 통해 취약점을 최소화하고 안전한 이미지 기반으로 서비스를 배포 해야합니다.

Image Vulnerability Scanner 를 위한 오픈소스들은 여러가지가 존재합니다. AWS 를 사용하는 환경이라면 ECR 에서 제공해주는 Image Scan 기능도 많이들 사용을 하고 있는데요.

이번에는 AWS 환경에서 ECR 의 Image Scan 기능을 사용하는 것이 아닌 별도의 Trivy 이미지 스캐닝 툴을 CI/CD 에 녹이는 구성을 만들어 보려합니다.

AWS ECR 의 Image Scan 은 Clair 기반으로 동작하는데요. 이것이 싫거나 스캔을 돌릴때 좀더 디테일한 설정을 통해 스캔 설정을 하고 싶을때 사용하면 좋은 방법일 듯합니다.

Trivy

Trivy 는 Aqua Security에서 개발한 오픈 소스 image vulnerability scanner 입니다. 빠르고 광범위한 취약점 데이터베이스를 기반으로 스캐닝을 수행합니다.

Github Action 이나 kubernetes operator, VS Code 와도 통합이 가능한데요. 이번에는 Github Action 을 통해 CI/CD pipeline 에서 취약점 점검을 진행하고 결과를 확인해보도록 하겠습니다.

Github Action – Trivy 통합

구성은 아래와 같이 AWS 환경에서 구성하였습니다.

trivy-github-action

  1. Application 을 개발하여 Repository 에 Pull 하면,
  2. Github Action 을 통해 CI/CD 가 진행됩니다.
  3. Github Action 에서는 먼저 Image Build 를 하고,
  4. Build 된 Image 는 Trivy 를 통해 취약점 스캔이 진행됩니다.
  5. 스캔 결과를 출력하고,(soft fail, exit-code: "0" 설정하여 취약점 발견되어도 실패 안하도록)
  6. kustomaize 에 의해 image tag 를 수정하고,
  7. ECR 에 Image 최종 Push 하고, EKS 에 배포까지 하게 됩니다.

pipeline 절차는 위와 같습니다.

이제 Github Action workflow 코드를 보면, 위의 절차 그대로 확인이 가능합니다.

Github Action 에서는 trivy-action 패키지가 제공이 되고 있어, 참고하여 Pipeline 을 입맛에 맞게 구성하면 되겠습니다.

위 구성도와 같이 github secrets 에 secrets 값들을 미리 설정합니다. (DB 정보는 개인적으로 배포한 어플리케이션과 연동될 DB의 정보키이니 참고만 하면 될듯합니다.)

name: Build and Push Docker image to ECR

on:
  push:
    branches:
      - main

permissions:
  id-token: write
  contents: read

jobs:
  cd:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ap-northeast-2

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
        with:
          mask-password: "true"

      - name: Build, tag, and push docker image to Amazon ECR
        id: push-ecr
        env:
          REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: checkingress
          IMAGE_TAG: ${{ github.sha }}
        run: |
          echo "::set-output name=ecr_repository::$REPOSITORY"
          echo "::set-output name=image_tag::$IMAGE_TAG"
          echo "::set-output name=ecr_registry::$REGISTRY"
          docker build --build-arg DB_HOST=${{ secrets.DB_HOST }} \
            --build-arg DB_PORT=${{ secrets.DB_PORT }} \
            --build-arg DB_USER=${{ secrets.DB_USER }} \
            --build-arg DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
            --build-arg DB_DATABASE=${{ secrets.DB_DATABASE }} \
            -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
          docker images

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "${{ steps.login-ecr.outputs.ecr_registry}}/checkingress:${{ github.sha }}"
          format: "table"
          exit-code: "0"
          ignore-unfixed: true
          vuln-type: "os,library"
          severity: "CRITICAL,HIGH"

      - name: Push image to Amazon ECR
        run: |
          docker push ${{ steps.push-ecr.outputs.ecr_registry}}/${{ steps.push-ecr.outputs.ecr_repository }}:${{ steps.push-ecr.outputs.image_tag }}

      - name: Get image tag(verion)
        id: image
        run: |
          VERSION=$(echo \${{ github.sha }} | cut -c1-8)
          echo VERSION=\$VERSION
          echo "::set-output name=version::\$VERSION"

      - name: Install and configure kubectl
        run: |
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          chmod +x kubectl
          sudo mv kubectl /usr/local/bin/
          aws eks --region ap-northeast-2 update-kubeconfig --name service

      - name: Install Kustomize
        run: |
          curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
          sudo mv kustomize /usr/local/bin/

      - name: Deploy to EKS
        env:
          REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: checkingress
          IMAGE_TAG: ${{ github.sha }}
        run: |
          cd manifest/overlays
          kustomize edit set image $REGISTRY/$REPOSITORY=$REGISTRY/$REPOSITORY:$IMAGE_TAG
          kustomize build . | kubectl apply -f -

  1. code 를 check-out 하고,
  2. AWS ECR 를 assume role 기반으로 로그인 해놓습니다.
  3. Dockerfile 기반으로 Image Build 를 합니다.
  4. Build 된 Image 기반으로 Trivy vulnerability 스캐닝을 시작합니다.
  5. image 를 ECR 로 push 합니다.
  6. kustomize 로 tag 최신화 하고, eks 에 배포까지 하게됩니다.

개인적으로 eks 자동 배포까지 포함한 workflow 로 eks 배포까지는 크게 중요한 부분이 아닐듯하고, Trivty vulnerability 스캐닝 부분만 확인하면 될듯합니다.

steps 에서 Trivy 스캐너를 돌리는 부분만 집중적으로 살펴 보면,

- name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "${{ steps.login-ecr.outputs.registry}}/checkingress:${{ github.sha }}"
          format: "table"
          exit-code: "0"
          ignore-unfixed: true
          vuln-type: "os,library"
          severity: "CRITICAL,HIGH"

  • image-ref : 스캔할 image 참조로 build 결과 만들어진 image 입니다.
  • format : output format 으로 table 형식으로 지정하였습니다.
  • exit-code: "0" : soft-fail 로 취약점이 발견되더라도 workflow 실패를 일으키지 않습니다.
  • ignore-unfixed : true : 패치 fix 가 안된 취약점은 무시합니다.
  • vuln-type : "os,library" : 스캔 유형을 운영체제와 라이브러리로 지정합니다.
  • severity : "CRITICAL,HIGH" : high 이상의 심각도만 검사합니다.

만약 다른 설정으로 하고자 한다면 여기서 inputs key 를 확인하여 필요에 따라 사용을 하면 되겠습니다.

스캔 결과는..

trivy-scan-result

스캔이 잘 마무리 되어 결과를 확인할 수 있네요.

결론

Trivy 스캔 결과를 다른 로그 시스템과 통합하고 싶다면 step 을 추가하면 되고, Slack 이나 다른 SNS 로의 전달도 얼마든지 Action workflow 로 구성이 가능할 듯합니다.

위에서는 Trivy 스캔 결과가 Action workflow 흐름에 영향을 주지 않도록 exit-code: "0" 로 설정을 하였었는데요. 만약 실환경에서 스캔결과에 따라 이미지 배포를 강제하고 싶다면 1 로 설정하여 hard-scan 을 하면 안전한 이미지 배포를 강제화 할 수 있으니 참고하면 될듯합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Back To Top