컨테이너 빌드 보호

1. 소개

ead1609267034bf7.png

소프트웨어 취약점은 우발적인 시스템 장애를 일으키거나 악의적인 행위자가 소프트웨어를 손상시킬 수 있는 수단을 제공하는 약점을 말합니다. Container Analysis는 컨테이너의 취약점을 찾기 위해 두 종류의 OS 스캔을 제공합니다.

  • On-Demand Scanning API를 사용하면 컴퓨터에서 로컬로 또는 Container Registry 또는 Artifact Registry에서 원격으로 컨테이너 이미지를 수동으로 스캔하여 OS 취약점을 확인할 수 있습니다.
  • Container Scanning API를 사용하면 Container Registry 또는 Artifact Registry에 이미지를 푸시할 때마다 자동으로 OS 취약점을 감지하고 스캔할 수 있습니다. 이 API를 사용 설정하면 Go 및 Java 취약점에 대한 언어 패키지 스캔도 사용 설정됩니다.

On-Demand Scanning API를 사용하면 컴퓨터에 로컬로 저장된 이미지 또는 Container Registry 또는 Artifact Registry에 원격으로 저장된 이미지를 스캔할 수 있습니다. 이렇게 하면 취약점을 스캔할 컨테이너를 세밀하게 제어할 수 있습니다. On-Demand Scanning을 사용하면 CI/CD 파이프라인에서 이미지를 스캔한 후 이를 레지스트리에 저장할지 여부를 결정할 수 있습니다.

학습할 내용

이 실습에서는 다음 작업을 수행하는 방법을 배웁니다.

  • Cloud Build로 이미지 빌드
  • 컨테이너에 Artifact Registry 사용
  • 자동 취약점 스캔 활용
  • On-Demand Scanning 구성
  • Cloud Build의 CI/CD에 이미지 스캔 추가

2. 설정 및 요구사항

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름 은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID 는 모든 Google Cloud 프로젝트에서 고유하며, 변경할 수 없습니다 (설정된 후에는 변경할 수 없음). Cloud 콘솔은 고유한 문자열을 자동으로 생성합니다. 일반적으로는 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 다른 임의 ID를 생성할 수 있습니다. 또는 직접 지정해서 사용할 수 있는지 확인하세요. 이 단계 후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호 입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스 또는 전체 프로젝트를 삭제하면 됩니다. Google Cloud 새 사용자에게는 미화$300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

환경 설정

Cloud Shell에서 프로젝트 ID와 프로젝트의 프로젝트 번호를 설정합니다. 이러한 변수를 PROJECT_IDPROJECT_ID 변수로 저장합니다.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

서비스 사용 설정

필요한 모든 서비스를 사용 설정합니다.

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

3. Cloud Build로 이미지 빌드

이 섹션에서는 컨테이너 이미지를 빌드하고 스캔한 후 결과를 평가하는 자동화된 빌드 파이프라인을 만듭니다. '심각(CRITICAL)' 등급 취약점이 발견되지 않으면 이미지가 저장소로 푸시됩니다. '심각' 등급 취약점이 발견되는 경우 빌드가 실패하고 종료됩니다.

Cloud Build 서비스 계정에 대한 액세스 권한 제공

Cloud Build에는 On-Demand Scanning API에 액세스할 권한이 필요합니다. 다음 명령어를 사용하여 액세스 권한을 제공합니다.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

작업 디렉터리를 만들고 해당 디렉터리로 변경

mkdir vuln-scan && cd vuln-scan

샘플 이미지 정의

다음 콘텐츠로 Dockerfile이라는 파일을 만듭니다.

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

EOF

다음 콘텐츠로 main.py라는 파일을 만듭니다.

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

Cloud Build 파이프라인 만들기

다음 명령어를 사용하면 자동화된 프로세스에 사용될 cloudbuild.yaml 파일이 디렉터리에 생성됩니다. 이 예시에서는 단계가 컨테이너 빌드 프로세스로 제한됩니다. 하지만 실제로는 컨테이너 단계 외에도 애플리케이션별 안내와 테스트가 포함됩니다.

다음 명령어를 사용하여 파일을 만듭니다.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']


EOF

CI 파이프라인 실행

처리를 위해 빌드를 제출합니다.

gcloud builds submit

빌드 세부정보 검토

빌드 프로세스가 시작되면 Cloud Build 대시보드에서 진행 상황을 검토합니다.

  1. Cloud 콘솔에서 Cloud Build를 엽니다.
  2. 빌드를 클릭하여 콘텐츠를 확인합니다.

4. 컨테이너용 Artifact Registry

Artifact Registry 저장소 만들기

이 실습에서는 Artifact Registry를 사용하여 이미지를 저장하고 스캔합니다. 다음 명령어를 사용하여 저장소를 만듭니다.

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

Artifact Registry에 액세스할 때 gcloud 사용자 인증 정보를 활용하도록 Docker를 구성합니다.

gcloud auth configure-docker us-central1-docker.pkg.dev

Cloud Build 파이프라인 업데이트

빌드 파이프라인을 수정하여 결과 이미지를 Artifact Registry로 푸시합니다.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

# push to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

CI 파이프라인 실행

처리를 위해 빌드를 제출합니다.

gcloud builds submit

5. 자동 취약점 스캔

Artifact Registry 또는 Container Registry에 새 이미지를 푸시할 때마다 Artifact 스캔이 자동으로 트리거됩니다. 취약점 정보는 새로운 취약점이 발견될 때 지속적으로 업데이트됩니다. 이 섹션에서는 방금 빌드하여 Artifact Registry에 푸시한 이미지를 검토하고 취약점 결과를 살펴봅니다.

이미지 세부정보 검토

이전 빌드 프로세스가 완료되면 Artifact Registry 대시보드에서 이미지 및 취약점 결과를 검토합니다.

  1. Cloud 콘솔에서 Artifact Registry를 엽니다.
  2. artifact-scanning-repo를 클릭하여 콘텐츠를 확인합니다.
  3. 이미지 세부정보를 클릭합니다.
  4. 이미지의 최신 다이제스트를 클릭합니다.
  5. 스캔이 완료되면 이미지의 취약점 탭을 클릭합니다.

취약점 탭에는 방금 빌드한 이미지의 자동 스캔 결과가 표시됩니다.

361be7b3bf293fca.png

자동 스캔은 기본적으로 사용 설정되어 있습니다. Artifact Registry 설정을 살펴보고 자동 스캔을 사용 중지/사용 설정하는 방법을 알아보세요.

6. On-Demand Scanning

저장소에 이미지를 푸시하기 전에 스캔을 실행해야 하는 다양한 시나리오가 있습니다. 예를 들어 컨테이너 개발자는 소스 제어에 코드를 푸시하기 전에 이미지를 스캔하고 문제를 해결할 수 있습니다. 아래 예시에서는 이미지를 로컬로 빌드하고 분석한 후 결과를 바탕으로 조치를 취합니다.

이미지 빌드

이 단계에서는 로컬 Docker를 사용하여 이미지를 로컬 캐시에 빌드합니다.

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

이미지 스캔

이미지가 빌드되면 이미지 스캔을 요청합니다. 스캔 결과는 메타데이터 서버에 저장됩니다. 작업이 완료되면 메타데이터 서버에 저장된 결과 위치가 표시됩니다.

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

출력 파일 검토

scan_id.txt 파일에 저장된 이전 단계의 출력을 검토합니다. 메타데이터 서버에서 스캔 결과의 보고서 위치를 확인합니다.

cat scan_id.txt

세부 스캔 결과 검토

스캔의 실제 결과를 보려면 출력 파일에 표시된 보고서 위치에서 list-vulnerabilities 명령어를 사용하세요.

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

출력에는 이미지의 모든 취약점에 관한 상당한 양의 데이터가 포함되어 있습니다.

심각한 문제 신고

보고서에 저장된 데이터를 사람이 직접 사용하는 경우는 거의 없습니다. 일반적으로 자동화된 프로세스에서 결과를 사용합니다. 아래 명령어를 사용하여 보고서 세부정보를 읽고 '심각' 등급 취약점이 발견된 경우 로깅합니다.

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

이 명령어의 출력은 다음과 같습니다.

Failed vulnerability check for CRITICAL level

7. Cloud Build를 사용한 CI/CD 스캔

Cloud Build 서비스 계정에 대한 액세스 권한 제공

Cloud Build에는 On-Demand Scanning API에 액세스할 권한이 필요합니다. 다음 명령어를 사용하여 액세스 권한을 제공합니다.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

Cloud Build 파이프라인 업데이트

다음 명령어를 사용하면 자동화된 프로세스에 사용될 cloudbuild.yaml 파일이 디렉터리에 생성됩니다. 이 예시에서는 단계가 컨테이너 빌드 프로세스로 제한됩니다. 하지만 실제로는 컨테이너 단계 외에도 애플리케이션별 안내와 테스트가 포함됩니다.

다음 명령어를 사용하여 파일을 만듭니다.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

CI 파이프라인 실행

빌드를 처리하도록 제출하여 심각도가 '심각' 등급인 취약점이 발견될 때 빌드가 중단되는지 확인합니다.

gcloud builds submit

빌드 실패 검토

이미지에 '심각' 등급 취약점이 포함되어 있으므로 방금 제출한 빌드가 실패합니다.

Cloud Build 기록 페이지에서 빌드 실패를 검토합니다.

취약점 해결

'심각' 등급 취약점이 포함되지 않은 기본 이미지를 사용하도록 Dockerfile을 업데이트합니다.

다음 명령어를 사용하여 Debian 10 이미지를 사용하도록 Dockerfile을 덮어씁니다.

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

정상 이미지를 사용하여 CI 프로세스 실행

빌드를 처리하도록 제출하여 심각도가 '심각' 등급인 취약점이 발견되지 않을 때 빌드가 성공하는지 확인합니다.

gcloud builds submit

빌드 성공 검토

업데이트된 이미지에 '심각' 등급 취약점이 포함되어 있지 않으므로 방금 제출한 빌드가 성공합니다.

Cloud Build 기록 페이지에서 빌드 성공을 검토합니다.

스캔 결과 검토

Artifact Registry에서 정상 이미지를 검토합니다.

  1. Cloud 콘솔에서 Artifact Registry를 엽니다.
  2. artifact-scanning-repo를 클릭하여 콘텐츠를 확인합니다.
  3. 이미지 세부정보를 클릭합니다.
  4. 이미지의 최신 다이제스트를 클릭합니다.
  5. 이미지의 취약점 탭을 클릭합니다.

8. 축하합니다.

축하합니다. Codelab을 완료했습니다.

학습한 내용

  • Cloud Build로 이미지 빌드
  • 컨테이너용 Artifact Registry
  • 자동 취약점 스캔
  • On-Demand Scanning
  • Cloud Build를 사용한 CI/CD 스캔

다음 단계:

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

프로젝트 삭제

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

최종 업데이트: 2023년 3월 21일