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

1. مقدمه

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

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

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

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

چیزی که یاد خواهید گرفت

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

2. راه اندازی و الزامات

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

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

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

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

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

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

  1. به پروژه Google خود در 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

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

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

ایجاد و تبدیل به فهرست کاری

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. رجیستری Artifact را در Cloud Console باز کنید
  2. برای مشاهده مطالب روی artifact-scanning-repo کلیک کنید
  3. روی جزئیات تصویر کلیک کنید
  4. روی آخرین خلاصه تصویر خود کلیک کنید
  5. پس از پایان اسکن، روی تب آسیب پذیری تصویر کلیک کنید

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

361be7b3bf293fca.png

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

4. اسکن درخواستی

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

یک تصویر بسازید

در این مرحله از 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

5. ساخت خط لوله اسکن

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

دسترسی برای حساب خدمات ساخت ابری فراهم کنید

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 را ایجاد کنید

دستور زیر یک فایل 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 History مرور کنید

آسیب پذیری را برطرف کنید

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 History مرور کنید

نتایج اسکن را مرور کنید

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

  1. رجیستری Artifact را در Cloud Console باز کنید
  2. برای مشاهده مطالب روی artifact-scanning-repo کلیک کنید
  3. روی جزئیات تصویر کلیک کنید
  4. روی آخرین خلاصه تصویر خود کلیک کنید
  5. برای تصویر روی تب آسیب پذیری ها کلیک کنید

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

یک یادداشت تأیید کننده ایجاد کنید

یادداشت تأیید کننده به سادگی یک بیت کوچک از داده است که به عنوان یک برچسب برای نوع امضای اعمال شده عمل می کند. به عنوان مثال، یک یادداشت ممکن است نشان دهنده اسکن آسیب پذیری باشد، در حالی که یکی دیگر ممکن است برای علامت 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 به طور خودکار گواهی built-by-cloud-build در پروژه شما ایجاد می کند. بنابراین دستور بالا دو گواهی‌دهنده، vulnz-attestor و built-by-cloud-build برمی‌گرداند. پس از اینکه تصاویر با موفقیت ساخته شدند، Cloud Build به طور خودکار امضا می کند و برای آنها گواهی ایجاد می کند.

اضافه کردن نقش IAM

حساب سرویس مجوز باینری برای مشاهده یادداشت‌های گواهی نیاز به حقوق دارد. دسترسی را با فراخوانی 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

Attestor برای پیوست کردن یادداشت و ارائه امضاهای قابل تأیید به کلیدهای رمزنگاری نیاز دارد. در این مرحله کلیدهایی را در 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 ظاهر می شود.

اکنون، کلید را از طریق دستور 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

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

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

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}"

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

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

7. امضا با Cloud Build

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

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

نقش ها

نقش نمایشگر تأیید کننده مجوز باینری را به حساب سرویس ساخت ابری اضافه کنید:

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

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

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

نقش Attacher Notes Analysis Container را به حساب سرویس Cloud Build اضافه کنید:

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

مرحله ساخت ابر سفارشی را آماده کنید

شما از یک مرحله ساخت سفارشی در Cloud Build برای ساده کردن فرآیند تأیید استفاده خواهید کرد. Google این مرحله ساخت سفارشی را ارائه می‌کند که شامل توابع کمکی برای ساده‌سازی فرآیند است. قبل از استفاده، کد مرحله ساخت سفارشی باید در یک کانتینر ساخته شود و به 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

Build را اجرا کنید

gcloud builds submit

ساخت را در Cloud Build History مرور کنید

Cloud Console را به صفحه Cloud Build History باز کنید و آخرین ساخت و اجرای موفقیت آمیز مراحل ساخت را مرور کنید.

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

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"

Allow All Policy

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

  1. سیاست موجود را مرور کنید
gcloud container binauthz policy export
  1. توجه داشته باشید که خط مشی اجرایی روی ALWAYS_ALLOW تنظیم شده است

evaluationMode: ALWAYS_ALLOW

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

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

161db370d99ffb13.png

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

همه خط مشی ها را رد کنید

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

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

در یک ویرایشگر متن، ارزیابی حالت را از 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. سیاست را تغییر دهید

در یک ویرایشگر متن، ارزیابی حالت را از 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

9. آسیب پذیری ها را در 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)')

از خلاصه در پیکربندی 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)')

از خلاصه در پیکربندی 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

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

10. تبریک می گویم!

تبریک می گویم، شما نرم افزار کد را تمام کردید!

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

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

بعدش چیه:

تمیز کردن

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

حذف پروژه

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