컨테이너 빌드 보호

1. 소개

ead1609267034bf7.png

소프트웨어 취약점은 우발적인 시스템 장애를 일으키거나 악의적인 행위자가 소프트웨어를 손상시킬 수 있는 약점입니다. 컨테이너 분석은 컨테이너의 취약점을 찾기 위해 두 가지 종류의 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에 원격으로 저장된 이미지를 스캔할 수 있습니다. 이렇게 하면 취약점을 스캔할 컨테이너를 세부적으로 제어할 수 있습니다. 주문형 스캔을 사용하여 CI/CD 파이프라인에서 이미지를 스캔한 후에 이미지를 레지스트리에 저장할지 결정할 수 있습니다.

학습할 내용

이 실습에서는 다음을 수행합니다.

  • Cloud Build로 이미지 빌드
  • 컨테이너에 Artifact Registry 사용
  • 자동 취약점 스캔 활용
  • 주문형 스캔 구성
  • Cloud Build의 CICD에 이미지 스캔 추가

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 취약점이 발견되지 않으면 이미지가 저장소에 푸시됩니다. CRITICAL 취약점이 발견되면 빌드가 실패하고 종료됩니다.

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

Cloud Build에 주문형 스캐닝 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 Registry로 푸시한 이미지를 검토하고 취약점 결과를 살펴봅니다.

이미지 세부정보 검토

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

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

취약점 탭에서 방금 빌드한 이미지에 대한 자동 스캔 결과를 확인할 수 있습니다.

361be7b3bf293fca.png

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

6. 주문형 스캔

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

이미지 빌드

이 단계에서는 로컬 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

출력 파일 검토

잠시 시간을 내어 스캔_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로 CICD 스캔

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

Cloud Build에 주문형 스캐닝 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 파이프라인 실행

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

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
  • 취약점을 자동으로 스캔
  • 온디맨드 스캐닝
  • Cloud Build를 사용한 CI/CD에서 스캔

다음 단계:

삭제

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

프로젝트 삭제

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

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