ساخت امن & استقرار با Cloud Build، Artifact Registry و GKE

۱. مقدمه

تحلیل کانتینر، اسکن آسیب‌پذیری و ذخیره‌سازی فراداده برای کانتینرها را فراهم می‌کند. این سرویس اسکن، اسکن‌های آسیب‌پذیری را روی تصاویر موجود در Artifact Registry و Container Registry انجام می‌دهد، سپس فراداده‌های حاصل را ذخیره کرده و از طریق یک API برای استفاده در دسترس قرار می‌دهد. ذخیره‌سازی فراداده به شما امکان می‌دهد اطلاعات را از منابع مختلف، از جمله اسکن آسیب‌پذیری، سرویس‌های Google Cloud و ارائه‌دهندگان شخص ثالث، ذخیره کنید.

اسکن آسیب‌پذیری می‌تواند به صورت خودکار یا بر اساس تقاضا انجام شود:

  • وقتی اسکن خودکار فعال باشد، هر بار که یک تصویر جدید را به رجیستری مصنوعات یا رجیستری کانتینر اضافه می‌کنید، اسکن به طور خودکار شروع می‌شود. اطلاعات آسیب‌پذیری به طور مداوم با کشف آسیب‌پذیری‌های جدید به‌روزرسانی می‌شود.
  • وقتی اسکن بر اساس تقاضا فعال است، باید دستوری را برای اسکن یک تصویر محلی یا یک تصویر در Artifact Registry یا Container Registry اجرا کنید. اسکن بر اساس تقاضا به شما انعطاف‌پذیری در هنگام اسکن کانتینرها می‌دهد. به عنوان مثال، می‌توانید یک تصویر ساخته شده محلی را اسکن کرده و قبل از ذخیره آن در رجیستری، آسیب‌پذیری‌ها را برطرف کنید. نتایج اسکن تا ۴۸ ساعت پس از اتمام اسکن در دسترس هستند و اطلاعات آسیب‌پذیری پس از اسکن به‌روزرسانی نمی‌شود.

با ادغام تحلیل کانتینر در خط تولید CI/CD خود، می‌توانید بر اساس آن فراداده‌ها تصمیم‌گیری کنید. به عنوان مثال، می‌توانید از مجوز دودویی برای ایجاد سیاست‌های استقرار استفاده کنید که فقط امکان استقرار تصاویر سازگار از رجیستری‌های معتبر را فراهم می‌کنند.

آنچه یاد خواهید گرفت

  • نحوه فعال کردن اسکن خودکار
  • نحوه انجام اسکن بر اساس تقاضا
  • نحوه ادغام اسکن در خط لوله ساخت
  • نحوه امضای تصاویر تایید شده
  • نحوه استفاده از کنترل‌کننده‌های پذیرش GKE برای مسدود کردن تصاویر
  • نحوه پیکربندی GKE برای مجاز کردن فقط تصاویر امضا شده و تأیید شده

۲. تنظیمات و الزامات

تنظیم محیط خودتنظیم

  1. وارد کنسول گوگل کلود شوید و یک پروژه جدید ایجاد کنید یا از یک پروژه موجود دوباره استفاده کنید. اگر از قبل حساب جیمیل یا گوگل ورک اسپیس ندارید، باید یکی ایجاد کنید .

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • نام پروژه ، نام نمایشی برای شرکت‌کنندگان این پروژه است. این یک رشته کاراکتری است که توسط APIهای گوگل استفاده نمی‌شود. می‌توانید آن را در هر زمانی به‌روزرسانی کنید.
  • شناسه پروژه در تمام پروژه‌های گوگل کلود منحصر به فرد است و تغییرناپذیر است (پس از تنظیم، قابل تغییر نیست). کنسول کلود به طور خودکار یک رشته منحصر به فرد تولید می‌کند؛ معمولاً برای شما مهم نیست که چیست. در اکثر آزمایشگاه‌های کد، باید به شناسه پروژه ارجاع دهید (که معمولاً با عنوان PROJECT_ID شناخته می‌شود). اگر شناسه تولید شده را دوست ندارید، می‌توانید یک شناسه تصادفی دیگر ایجاد کنید. به عنوان یک جایگزین، می‌توانید شناسه خودتان را امتحان کنید و ببینید که آیا در دسترس است یا خیر. پس از این مرحله قابل تغییر نیست و در طول پروژه باقی خواهد ماند.
  • برای اطلاع شما، یک مقدار سوم، شماره پروژه ، وجود دارد که برخی از APIها از آن استفاده می‌کنند. برای کسب اطلاعات بیشتر در مورد هر سه این مقادیر، به مستندات مراجعه کنید.
  1. در مرحله بعد، برای استفاده از منابع/API های ابری، باید پرداخت صورتحساب را در کنسول ابری فعال کنید . اجرای این آزمایشگاه کد، اگر اصلاً هزینه‌ای نداشته باشد، هزینه زیادی نخواهد داشت. برای خاموش کردن منابع به طوری که پس از این آموزش متحمل پرداخت صورتحساب نشوید، می‌توانید منابعی را که ایجاد کرده‌اید یا کل پروژه را حذف کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان ۳۰۰ دلاری هستند.

ویرایشگر Cloudshell را شروع کنید

این آزمایشگاه برای استفاده با ویرایشگر پوسته ابری گوگل (Google Cloud Shell Editor) طراحی و آزمایش شده است. برای دسترسی به ویرایشگر،

  1. برای دسترسی به پروژه گوگل خود به آدرس https://console.cloud.google.com مراجعه کنید.
  2. در گوشه بالا سمت راست، روی آیکون ویرایشگر پوسته ابری کلیک کنید.

8560cc8d45e8c112.png

  1. یک پنل جدید در پایین پنجره شما باز خواهد شد

تنظیمات محیط

در Cloud Shell، شناسه پروژه و شماره پروژه خود را تنظیم کنید. آنها را به عنوان متغیرهای PROJECT_ID و PROJECT_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 

ایجاد مخزن رجیستری مصنوعات

در این آزمایش شما از Artifact Registry برای ذخیره و اسکن تصاویر خود استفاده خواهید کرد. مخزن را با دستور زیر ایجاد کنید.

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

داکر را طوری پیکربندی کنید که هنگام دسترسی به رجیستری مصنوعات، از اعتبارنامه‌های gcloud شما استفاده کند.

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

۳. اسکن خودکار

اسکن مصنوعات هر بار که یک تصویر جدید را به رجیستری مصنوعات یا رجیستری کانتینر اضافه می‌کنید، به طور خودکار فعال می‌شود. اطلاعات آسیب‌پذیری به طور مداوم با کشف آسیب‌پذیری‌های جدید به‌روزرسانی می‌شود. در این بخش، یک تصویر را به رجیستری مصنوعات اضافه می‌کنید و نتایج را بررسی می‌کنید.

ایجاد و تغییر به یک دایرکتوری کاری

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

تصویر را بسازید و به AR منتقل کنید

از Cloud Build برای ساخت و انتقال خودکار کانتینر خود به Artifact Registry استفاده کنید. به برچسب bad روی تصویر توجه کنید. این به شما کمک می‌کند تا آن را برای مراحل بعدی شناسایی کنید.

gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad

جزئیات تصویر را بررسی کنید

پس از اتمام فرآیند ساخت، نتایج مربوط به تصویر و آسیب‌پذیری را در داشبورد Artifact Registry بررسی کنید.

  1. رجیستری مصنوعات را در کنسول ابری باز کنید
  2. برای مشاهده محتوا، روی مخزن اسکن مصنوعات کلیک کنید
  3. روی جزئیات تصویر کلیک کنید
  4. روی آخرین خلاصه تصویر خود کلیک کنید
  5. پس از اتمام اسکن، روی برگه آسیب‌پذیری‌ها برای تصویر کلیک کنید.

از تب آسیب‌پذیری‌ها، نتایج اسکن خودکار برای ایمیجی که تازه ساخته‌اید را مشاهده خواهید کرد.

361be7b3bf293fca.png

اسکن خودکار به طور پیش‌فرض فعال است. تنظیمات رجیستری مصنوعات را بررسی کنید تا ببینید چگونه می‌توانید اسکن خودکار را خاموش/روشن کنید.

۴. اسکن بر اساس تقاضا

سناریوهای مختلفی وجود دارد که در آنها ممکن است لازم باشد قبل از ارسال تصویر به مخزن، اسکن را اجرا کنید. به عنوان مثال، یک توسعه‌دهنده کانتینر ممکن است قبل از ارسال کد به کنترل منبع، یک تصویر را اسکن کرده و مشکلات را برطرف کند. در مثال زیر، قبل از اقدام بر اساس نتایج، تصویر را به صورت محلی ایجاد و تجزیه و تحلیل خواهید کرد.

ساخت یک تصویر

در این مرحله از داکر محلی برای ساخت ایمیج در حافظه پنهان محلی خود استفاده خواهید کرد.

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

۵. اسکن خط لوله را بسازید

در این بخش، شما یک خط لوله ساخت خودکار ایجاد خواهید کرد که تصویر کانتینر شما را می‌سازد، آن را اسکن می‌کند و سپس نتایج را ارزیابی می‌کند. اگر هیچ آسیب‌پذیری بحرانی پیدا نشود، تصویر را به مخزن ارسال می‌کند. اگر آسیب‌پذیری‌های بحرانی پیدا شود، ساخت با شکست مواجه شده و خاتمه می‌یابد.

دسترسی به حساب سرویس ساخت ابری (Cloud Build Service Account) را فراهم کنید

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

در صورت یافتن آسیب‌پذیری با شدت بحرانی، نسخه را برای پردازش ارسال کنید تا نقص‌های نسخه تأیید شود.

gcloud builds submit

بررسی شکست ساخت

ساختاری که ارسال کردید با شکست مواجه خواهد شد زیرا تصویر حاوی آسیب‌پذیری‌های بحرانی است.

شکست ساخت را در صفحه تاریخچه ساخت ابری بررسی کنید

رفع آسیب‌پذیری

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

بررسی ایجاد موفقیت

ساختاری که شما ارسال کردید با موفقیت انجام خواهد شد زیرا تصویر به‌روزرسانی‌شده حاوی هیچ آسیب‌پذیری بحرانی نیست.

موفقیت ساخت را در صفحه تاریخچه ساخت ابری بررسی کنید

نتایج اسکن را بررسی کنید

تصویر خوب را در رجیستری مصنوعات بررسی کنید

  1. رجیستری مصنوعات را در کنسول ابری باز کنید
  2. برای مشاهده محتوا، روی مخزن اسکن مصنوعات کلیک کنید
  3. روی جزئیات تصویر کلیک کنید
  4. روی آخرین خلاصه تصویر خود کلیک کنید
  5. برای مشاهده تصویر، روی تب آسیب‌پذیری‌ها کلیک کنید

۶. تصاویر امضا

ایجاد یادداشت گواهی دهنده

یادداشت گواهی‌دهنده صرفاً بخش کوچکی از داده است که به عنوان برچسبی برای نوع امضای اعمال‌شده عمل می‌کند. به عنوان مثال، یک یادداشت ممکن است نشان‌دهنده اسکن آسیب‌پذیری باشد، در حالی که دیگری ممکن است برای تأیید QA استفاده شود. این یادداشت در طول فرآیند امضا مورد ارجاع قرار خواهد گرفت.

ایجاد یادداشت

cat > ./vulnz_note.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "Container Vulnerabilities attestation authority"
    }
  }
}
EOM

یادداشت را ذخیره کنید

NOTE_ID=vulnz_note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./vulnz_note.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"

یادداشت را تأیید کنید

curl -vvv  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"

ایجاد یک گواهی دهنده

گواهی‌دهندگان برای انجام فرآیند امضای تصویر واقعی استفاده می‌شوند و برای تأیید بعدی، وقوع یادداشت را به تصویر پیوست می‌کنند. گواهی‌دهنده را برای استفاده‌های بعدی ایجاد کنید.

ایجاد گواهی‌دهنده

ATTESTOR_ID=vulnz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

تأییدکننده را تأیید کنید

gcloud container binauthz attestors list

توجه داشته باشید که خط آخر نشان دهنده NUM_PUBLIC_KEYS: 0 است. کلیدها را در مرحله بعد ارائه خواهید کرد.

همچنین توجه داشته باشید که Cloud Build هنگام اجرای یک build که تصاویر را تولید می‌کند، به طور خودکار گواهی built-by-cloud-build را در پروژه شما ایجاد می‌کند. بنابراین دستور بالا دو گواهی vulnz-attestor و built-by-cloud-build را برمی‌گرداند. پس از ساخت موفقیت‌آمیز تصاویر، Cloud Build به طور خودکار گواهی‌ها را برای آنها امضا و ایجاد می‌کند.

افزودن نقش IAM

حساب کاربری سرویس احراز هویت دودویی (Binary Authorization) برای مشاهده یادداشت‌های تأیید به دسترسی نیاز دارد. با فراخوانی API زیر، این دسترسی را فراهم کنید.

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")

BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"


cat > ./iam_request.json << EOM
{
  'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
  'policy': {
    'bindings': [
      {
        'role': 'roles/containeranalysis.notes.occurrences.viewer',
        'members': [
          'serviceAccount:${BINAUTHZ_SA_EMAIL}'
        ]
      }
    ]
  }
}
EOM

از فایل برای ایجاد سیاست IAM استفاده کنید

curl -X POST  \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @./iam_request.json \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"

افزودن کلید KMS

گواهی‌دهنده برای پیوست کردن یادداشت و ارائه امضاهای قابل تأیید به کلیدهای رمزنگاری نیاز دارد. در این مرحله، شما کلیدها را در KMS ایجاد و ذخیره خواهید کرد تا Cloud Build بتواند بعداً به آنها دسترسی داشته باشد.

ابتدا چند متغیر محیطی برای توصیف کلید جدید اضافه کنید

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

یک جاکلیدی برای نگه داشتن دسته کلیدها بسازید

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

یک جفت کلید امضای نامتقارن جدید برای گواهی‌دهنده ایجاد کنید

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing   \
    --default-algorithm="ec-sign-p256-sha256"

باید کلید خود را در صفحه KMS کنسول Google Cloud مشاهده کنید.

اکنون، کلید را از طریق دستور gcloud binauthz به گواهی‌دهنده خود مرتبط کنید:

gcloud beta container binauthz attestors public-keys add  \
    --attestor="${ATTESTOR_ID}"  \
    --keyversion-project="${PROJECT_ID}"  \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

اگر دوباره لیست مراجع را چاپ کنید، اکنون باید یک کلید ثبت شده را ببینید:

gcloud container binauthz attestors list

ایجاد گواهی امضا شده

در این مرحله، ویژگی‌هایی که به شما امکان امضای تصاویر را می‌دهند، پیکربندی شده‌اند. از Attestor که قبلاً ایجاد کرده‌اید، برای امضای تصویر کانتینری که با آن کار می‌کردید، استفاده کنید.

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

DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
    --format='get(image_summary.digest)')

اکنون می‌توانید از gcloud برای ایجاد گواهی خود استفاده کنید. این دستور به سادگی جزئیات کلیدی را که می‌خواهید برای امضا استفاده کنید و تصویر کانتینر خاصی را که می‌خواهید تأیید کنید، دریافت می‌کند.

gcloud beta container binauthz attestations sign-and-create  \
    --artifact-url="${CONTAINER_PATH}@${DIGEST}" \
    --attestor="${ATTESTOR_ID}" \
    --attestor-project="${PROJECT_ID}" \
    --keyversion-project="${PROJECT_ID}" \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

به زبان تحلیل کانتینر، این یک رخداد جدید ایجاد می‌کند و آن را به یادداشت گواهی‌دهنده شما پیوست می‌کند. برای اطمینان از اینکه همه چیز طبق انتظار پیش می‌رود، می‌توانید گواهی‌های خود را فهرست کنید.

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

۷. ثبت نام با Cloud Build

شما امضای تصویر را فعال کرده‌اید و به صورت دستی از Attestor برای امضای تصویر نمونه خود استفاده کرده‌اید. در عمل، شما می‌خواهید Attestationها را در طول فرآیندهای خودکار مانند CI/CD pipelines اعمال کنید.

در این بخش ، Cloud Build را طوری پیکربندی می‌کنید که تصاویر را به طور خودکار تأیید کند.

نقش‌ها

نقش Binary Authorization Attestor Viewer را به حساب سرویس Cloud Build اضافه کنید:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/binaryauthorization.attestorsViewer

نقش امضاکننده/تأییدکننده‌ی کلید رمزنگاری‌شده‌ی Cloud KMS را به حساب سرویس ساخت ابری (امضای مبتنی بر KMS) اضافه کنید:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/cloudkms.signerVerifier

نقش Attacher مربوط به یادداشت‌های تحلیل کانتینر را به حساب سرویس Cloud Build اضافه کنید:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/containeranalysis.notes.attacher

آماده‌سازی مرحله ساخت ابری سفارشی

شما از یک مرحله ساخت سفارشی در Cloud Build برای ساده‌سازی فرآیند گواهی استفاده خواهید کرد. گوگل این مرحله ساخت سفارشی را ارائه می‌دهد که شامل توابع کمکی برای ساده‌سازی فرآیند است. قبل از استفاده، کد مرحله ساخت سفارشی باید در یک کانتینر ساخته شده و به Cloud Build منتقل شود. برای انجام این کار، دستورات زیر را اجرا کنید:

git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/binauthz-attestation
gcloud builds submit . --config cloudbuild.yaml
cd ../..
rm -rf cloud-builders-community

یک مرحله امضا به cloudbuild.yaml خود اضافه کنید

در این مرحله، مرحله‌ی تأیید را به خط تولید ابری خود که قبلاً ساخته‌اید، اضافه خواهید کرد.

  1. مرحله جدیدی که اضافه خواهید کرد را مرور کنید.

فقط نقد. کپی نکنید

#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
  1. فایل 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']


#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'



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

اجرای ساخت

gcloud builds submit

بررسی ساخت در تاریخچه ساخت ابری

کنسول ابری را باز کنید و به صفحه تاریخچه ساخت ابری بروید و آخرین ساخت و اجرای موفقیت‌آمیز مراحل ساخت را بررسی کنید.

۸. سیاست‌های کنترل پذیرش

احراز هویت دودویی (Binary Authorization) قابلیتی در GKE و Cloud Run است که امکان اعتبارسنجی قوانین را قبل از اجازه اجرای یک تصویر کانتینر فراهم می‌کند. اعتبارسنجی بر اساس هر درخواستی برای اجرای یک تصویر، چه از یک خط لوله CI/CD قابل اعتماد و چه از سوی کاربری که به صورت دستی سعی در استقرار یک تصویر دارد، اجرا می‌شود. این قابلیت به شما امکان می‌دهد محیط‌های زمان اجرا را به طور مؤثرتری نسبت به بررسی‌های خط لوله CI/CD به تنهایی، ایمن کنید.

برای درک این قابلیت، شما سیاست پیش‌فرض GKE را برای اعمال یک قانون مجوزدهی سختگیرانه تغییر خواهید داد.

ایجاد خوشه GKE

خوشه GKE را ایجاد کنید:

gcloud beta container clusters create binauthz \
    --zone us-central1-a  \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE

به Cloud Build اجازه دهید تا در این کلاستر مستقر شود:

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

اجازه دادن به همه سیاست‌ها

ابتدا وضعیت پیش‌فرض سیاست و توانایی خود را برای استقرار هر تصویری بررسی کنید

  1. بررسی سیاست‌های موجود
gcloud container binauthz policy export
  1. توجه داشته باشید که سیاست اعمال قانون روی ALWAYS_ALLOW تنظیم شده است.

evaluationMode: ALWAYS_ALLOW

  1. نمونه را مستقر کنید تا تأیید کنید که می‌توانید هر چیزی را مستقر کنید
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. تأیید کنید که استقرار کار کرده است
kubectl get pods

خروجی زیر را مشاهده خواهید کرد

۱۶۱db370d99ffb13.png

  1. حذف استقرار
kubectl delete pod hello-server

رد کردن همه سیاست‌ها

اکنون خط‌مشی را به‌روزرسانی کنید تا همه تصاویر را مجاز نکنید.

  1. سیاست فعلی را به یک فایل قابل ویرایش صادر کنید
gcloud container binauthz policy export  > policy.yaml
  1. تغییر سیاست

در یک ویرایشگر متن، evaluationMode را از ALWAYS_ALLOW به ALWAYS_DENY تغییر دهید.

edit policy.yaml

فایل YAML مربوط به سیاست باید به شکل زیر باشد:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_DENY
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. ترمینال را باز کنید و سیاست جدید را اعمال کنید و چند ثانیه صبر کنید تا تغییر اعمال شود.
gcloud container binauthz policy import policy.yaml
  1. نمونه‌ای از استقرار حجم کار را امتحان کنید
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. نصب با پیغام زیر با شکست مواجه می‌شود
Error from server (VIOLATES_POLICY): admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image gcr.io/google-samples/hello-app:1.0 denied by Binary Authorization default admission rule. Denied by always_deny admission rule

سیاست را برگردانید تا همه مجاز باشند

قبل از رفتن به بخش بعدی، حتماً تغییرات سیاست را به حالت اولیه برگردانید

  1. تغییر سیاست

در یک ویرایشگر متن، evaluationMode را از ALWAYS_DENY به ALWAYS_ALLOW تغییر دهید.

edit policy.yaml

فایل YAML مربوط به سیاست باید به شکل زیر باشد:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. اعمال سیاست برگشتی
gcloud container binauthz policy import policy.yaml

۹. مسدود کردن آسیب‌پذیری‌ها در GKE

در این بخش، آنچه تاکنون آموخته‌اید را با پیاده‌سازی یک خط لوله CI/CD با Cloud Build ترکیب خواهید کرد که تصاویر را اسکن می‌کند، سپس قبل از امضای تصویر و تلاش برای استقرار، آسیب‌پذیری‌ها را بررسی می‌کند. GKE قبل از اجازه دادن به اجرای تصویر، از مجوز دودویی برای اعتبارسنجی تصویر دارای امضایی از اسکن آسیب‌پذیری استفاده می‌کند.

d5c41bb89e22fd61.png

به‌روزرسانی سیاست GKE برای الزام به اخذ گواهی

با اضافه کردن clusterAdmissionRules به خط‌مشی GKE BinAuth خود، الزام کنید که تصاویر توسط گواهی‌دهنده شما امضا شوند.

با استفاده از دستور زیر، پالیسی را با پیکربندی به‌روز شده بازنویسی کنید.

COMPUTE_ZONE=us-central1-a

cat > binauth_policy.yaml << EOM
defaultAdmissionRule:
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  evaluationMode: ALWAYS_DENY
globalPolicyEvaluationMode: ENABLE
clusterAdmissionRules:
  ${COMPUTE_ZONE}.binauthz:
    evaluationMode: REQUIRE_ATTESTATION
    enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
    requireAttestationsBy:
    - projects/${PROJECT_ID}/attestors/vulnz-attestor
EOM

اعمال سیاست

gcloud beta container binauthz policy import binauth_policy.yaml

تلاش برای استقرار تصویر امضا نشده

با استفاده از دستور زیر، یک توصیف‌گر استقرار برای برنامه‌ای که قبلاً ساخته‌اید ایجاد کنید. تصویری که در اینجا استفاده شده، تصویری است که قبلاً ساخته‌اید و حاوی آسیب‌پذیری‌های بحرانی است و حاوی گواهی امضا شده نیست.

کنترل‌کننده‌های پذیرش GKE برای اعتبارسنجی مداوم امضا، باید تصویر دقیقی که قرار است مستقر شود را بدانند. برای انجام این کار، باید از خلاصه تصویر و یک برچسب ساده استفاده کنید.

خلاصه تصویر بد را دریافت کنید

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


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:bad \
    --format='get(image_summary.digest)')

از digest در پیکربندی Kubernetes استفاده کنید

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

تلاش برای استقرار برنامه در GKE

kubectl apply -f deploy.yaml

حجم کار را در کنسول بررسی کنید و به خطایی که می‌گوید استقرار رد شده است توجه کنید:

No attestations found that were valid and signed by a key trusted by the attestor

یک تصویر امضا شده را مستقر کنید

خلاصه تصویر بد را دریافت کنید

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


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:good \
    --format='get(image_summary.digest)')

از digest در پیکربندی Kubernetes استفاده کنید

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

برنامه را روی GKE مستقر کنید

kubectl apply -f deploy.yaml

حجم کار را در کنسول بررسی کنید و به استقرار موفقیت‌آمیز تصویر توجه کنید.

۱۰. تبریک می‌گویم!

تبریک می‌گویم، شما codelab را تمام کردید!

آنچه ما پوشش داده‌ایم:

  • نحوه فعال کردن اسکن خودکار
  • نحوه انجام اسکن بر اساس تقاضا
  • نحوه ادغام اسکن در خط لوله ساخت
  • نحوه امضای تصاویر تایید شده
  • نحوه استفاده از کنترل‌کننده‌های پذیرش GKE برای مسدود کردن تصاویر
  • نحوه پیکربندی GKE برای مجاز کردن فقط تصاویر امضا شده و تأیید شده

قدم بعدی چیست؟

تمیز کردن

برای جلوگیری از تحمیل هزینه به حساب گوگل کلود خود برای منابع استفاده شده در این آموزش، یا پروژه‌ای که شامل منابع است را حذف کنید، یا پروژه را نگه دارید و منابع تکی را حذف کنید.

حذف پروژه

ساده‌ترین راه برای حذف هزینه‌ها، حذف پروژه‌ای است که برای آموزش ایجاد کرده‌اید.