1. บทนำ
Container Analysis ให้บริการสแกนหาช่องโหว่และพื้นที่เก็บข้อมูลเมตาสำหรับคอนเทนเนอร์ บริการสแกนจะทำการสแกนหาช่องโหว่ในรูปภาพใน Artifact Registry และ Container Registry จากนั้นจัดเก็บข้อมูลเมตาที่ได้และทำให้พร้อมใช้งานผ่าน API พื้นที่เก็บข้อมูลเมตาช่วยให้คุณจัดเก็บข้อมูลจากแหล่งที่มาต่างๆ ซึ่งรวมถึงการสแกนหาช่องโหว่ บริการ Google Cloud และผู้ให้บริการบุคคลที่สาม
การสแกนช่องโหว่อาจเกิดขึ้นโดยอัตโนมัติหรือตามคําขอ ดังนี้
- เมื่อเปิดใช้การสแกนอัตโนมัติ ระบบจะเรียกใช้การสแกนโดยอัตโนมัติทุกครั้งที่คุณพุชอิมเมจใหม่ไปยัง Artifact Registry หรือ Container Registry ข้อมูลช่องโหว่จะอัปเดตอย่างต่อเนื่องเมื่อมีการตรวจพบช่องโหว่ใหม่ๆ
- เมื่อเปิดใช้การสแกนเมื่อต้องการ คุณต้องเรียกใช้คำสั่งเพื่อสแกนรูปภาพในเครื่องหรือรูปภาพใน Artifact Registry หรือ Container Registry การสแกนตามคําขอช่วยให้คุณมีความยืดหยุ่นในการสแกนคอนเทนเนอร์ เช่น คุณสามารถสแกนอิมเมจที่สร้างขึ้นในพื้นที่และแก้ไขช่องโหว่ก่อนที่จะจัดเก็บไว้ในรีจิสทรี ผลการสแกนจะพร้อมใช้งานสูงสุด 48 ชั่วโมงหลังจากการสแกนเสร็จสมบูรณ์ และระบบจะไม่อัปเดตข้อมูลช่องโหว่หลังการสแกน
เมื่อผสานรวมการวิเคราะห์คอนเทนเนอร์เข้ากับไปป์ไลน์ CI/CD แล้ว คุณจะตัดสินใจตามข้อมูลเมตานั้นได้ เช่น คุณสามารถใช้การให้สิทธิ์แบบไบนารีเพื่อสร้างนโยบายการทำให้ใช้งานได้ที่อนุญาตให้มีเฉพาะการทำให้ใช้งานได้สำหรับอิมเมจที่เป็นไปตามข้อกำหนดจากรีจิสทรีที่เชื่อถือเท่านั้น
สิ่งที่คุณจะได้เรียนรู้
- วิธีเปิดใช้การสแกนอัตโนมัติ
- วิธีทำการสแกนตามคำขอ
- วิธีผสานรวมการสแกนในไปป์ไลน์การสร้าง
- วิธีลงนามในรูปภาพที่อนุมัติแล้ว
- วิธีใช้ Admission Controller ของ GKE เพื่อบล็อกรูปภาพ
- วิธีกำหนดค่า GKE ให้อนุญาตเฉพาะอิมเมจที่อนุมัติและลงนามแล้ว
2. การตั้งค่าและข้อกําหนด
การตั้งค่าสภาพแวดล้อมด้วยตนเอง
- ลงชื่อเข้าใช้ Google Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี
- ชื่อโปรเจ็กต์คือชื่อที่แสดงสำหรับผู้เข้าร่วมโปรเจ็กต์นี้ ซึ่งเป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ โดยคุณจะอัปเดตได้ทุกเมื่อ
- รหัสโปรเจ็กต์จะต้องไม่ซ้ำกันสำหรับโปรเจ็กต์ Google Cloud ทั้งหมดและจะเปลี่ยนแปลงไม่ได้ (เปลี่ยนแปลงไม่ได้หลังจากตั้งค่าแล้ว) คอนโซล Cloud จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ซึ่งปกติแล้วคุณไม่จำเป็นต้องสนใจว่าสตริงนั้นจะเป็นอะไร ในโค้ดแล็บส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยปกติจะระบุเป็น
PROJECT_ID
) หากไม่ชอบรหัสที่สร้างขึ้น คุณก็สร้างรหัสอื่นแบบสุ่มได้ หรือจะลองใช้อุปกรณ์ของคุณเองเพื่อดูว่าฟีเจอร์นี้พร้อมใช้งานหรือไม่ก็ได้ คุณจะเปลี่ยนแปลงชื่อหลังจากขั้นตอนนี้ไม่ได้ และชื่อจะยังคงอยู่ตลอดระยะเวลาของโปรเจ็กต์ - โปรดทราบว่ามีค่าที่ 3 ซึ่งเป็นหมายเลขโปรเจ็กต์ที่ API บางรายการใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 รายการนี้ได้ในเอกสารประกอบ
- ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของ Cloud การทำตามโค้ดแล็บนี้ไม่น่าจะเสียค่าใช้จ่ายมากนัก หากต้องการปิดใช้ทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินหลังจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่สร้างไว้หรือลบทั้งโปรเจ็กต์ได้ ผู้ใช้ใหม่ของ Google Cloud มีสิทธิ์เข้าร่วมโปรแกรมช่วงทดลองใช้ฟรีมูลค่า$300 USD
เริ่มเครื่องมือแก้ไข Cloudshell
ห้องทดลองนี้ได้รับการออกแบบและทดสอบเพื่อใช้กับเครื่องมือแก้ไข Google Cloud Shell วิธีเข้าถึงเครื่องมือแก้ไข
- เข้าถึงโปรเจ็กต์ Google ที่ https://console.cloud.google.com
- คลิกไอคอนเครื่องมือแก้ไข Cloud Shell ที่มุมขวาบน
- แผงใหม่จะเปิดขึ้นที่ด้านล่างของหน้าต่าง
การตั้งค่าสภาพแวดล้อม
ใน 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
ในชั้นเรียนนี้ คุณจะใช้ Artifact Registry เพื่อจัดเก็บและสแกนรูปภาพ สร้างที่เก็บด้วยคำสั่งต่อไปนี้
gcloud artifacts repositories create artifact-scanning-repo \
--repository-format=docker \
--location=us-central1 \
--description="Docker repository"
กำหนดค่า Docker ให้ใช้ข้อมูลเข้าสู่ระบบ gcloud เมื่อเข้าถึง Artifact Registry
gcloud auth configure-docker us-central1-docker.pkg.dev
3. การสแกนอัตโนมัติ
การสแกนอาร์ติแฟกต์จะทริกเกอร์โดยอัตโนมัติทุกครั้งที่คุณพุชอิมเมจใหม่ไปยัง Artifact Registry หรือ Container Registry ข้อมูลช่องโหว่จะอัปเดตอย่างต่อเนื่องเมื่อมีการตรวจพบช่องโหว่ใหม่ๆ ในส่วนนี้ คุณจะต้องพุชรูปภาพไปยัง Artifact Registry และสำรวจผลลัพธ์
สร้างและเปลี่ยนเป็นไดเรกทอรีงาน
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
- เปิด Artifact Registry ใน Cloud Console
- คลิกที่ artifact-scanning-repo เพื่อดูเนื้อหา
- คลิกดูรายละเอียดรูปภาพ
- คลิกข้อมูลสรุปล่าสุดของรูปภาพ
- เมื่อสแกนเสร็จแล้ว ให้คลิกแท็บช่องโหว่ของรูปภาพ
จากแท็บช่องโหว่ คุณจะเห็นผลการสแกนอัตโนมัติสำหรับรูปภาพที่คุณเพิ่งสร้าง
ระบบจะเปิดใช้การสแกนอัตโนมัติโดยค่าเริ่มต้น สำรวจการตั้งค่ารีจิสทรีอาร์ติแฟกต์เพื่อดูวิธีปิด/เปิดการสแกนอัตโนมัติ
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
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 เพื่อใช้อิมเมจฐานที่ไม่มีช่องโหว่ร้ายแรง
เขียนทับ Dockerfile เพื่อใช้อิมเมจ Debian 10 ด้วยคำสั่งต่อไปนี้
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
- เปิด Artifact Registry ใน Cloud Console
- คลิกที่ artifact-scanning-repo เพื่อดูเนื้อหา
- คลิกดูรายละเอียดรูปภาพ
- คลิกข้อมูลสรุปล่าสุดของรูปภาพ
- คลิกแท็บช่องโหว่ของรูปภาพ
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
ในโปรเจ็กต์โดยอัตโนมัติเมื่อคุณเรียกใช้บิลด์ที่สร้างรูปภาพ ดังนั้นคําสั่งข้างต้นจะแสดงผู้รับรอง 2 ราย ได้แก่ 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
ผู้รับรองต้องมีคีย์การเข้ารหัสเพื่อแนบหมายเหตุและให้ลายเซ็นที่ตรวจสอบได้ ในขั้นตอนนี้ คุณจะต้องสร้างและจัดเก็บคีย์ไว้ใน 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 Console
ตอนนี้ให้เชื่อมโยงคีย์กับผู้ตรวจสอบผ่านคําสั่ง 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}"
ในการวิเคราะห์คอนเทนเนอร์ การดำเนินการนี้จะสร้างรายการใหม่และแนบไปกับหมายเหตุของผู้รับรอง คุณสามารถแสดงรายการการรับรองเพื่อให้มั่นใจว่าทุกอย่างทำงานได้ตามที่คาดไว้
gcloud container binauthz attestations list \
--attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}
7. การรับรองด้วย Cloud Build
คุณได้เปิดใช้การรับรองเนื้อหาของรูปภาพและใช้โปรแกรมตรวจสอบเพื่อรับรองรูปภาพตัวอย่างด้วยตนเอง ในทางปฏิบัติ คุณควรใช้การรับรองในระหว่างกระบวนการอัตโนมัติ เช่น ไปป์ไลน์ CI/CD
ในส่วนนี้ คุณจะต้องกำหนดค่า Cloud Build ให้ตรวจสอบอิมเมจโดยอัตโนมัติ
บทบาท
เพิ่มบทบาทผู้ดูผู้รับรองการให้สิทธิ์แบบไบนารีลงในบัญชีบริการ Cloud Build โดยทำดังนี้
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
--role roles/binaryauthorization.attestorsViewer
เพิ่มบทบาทผู้ลงนาม/ผู้รับรอง Cloud KMS CryptoKey ลงในบัญชีบริการ Cloud Build (การรับรองตาม KMS)
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
--role roles/cloudkms.signerVerifier
เพิ่มบทบาทผู้แนบบันทึก Container Analysis ไปยังบัญชีบริการ 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 เพื่อลดความซับซ้อนของกระบวนการรับรอง 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
ในขั้นตอนนี้ คุณจะต้องเพิ่มขั้นตอนการตรวจสอบลงในไปป์ไลน์ Cloud Build ที่สร้างไว้ก่อนหน้านี้
- ตรวจสอบขั้นตอนใหม่ที่จะเพิ่ม
ตรวจสอบเท่านั้น ไม่คัดลอก
#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'
- เขียนทับไฟล์ 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
ตรวจสอบบิลด์ในประวัติ Cloud Build
เปิด Cloud Console ไปที่หน้าประวัติการสร้างในระบบคลาวด์ และตรวจสอบบิลด์ล่าสุดและการดำเนินการขั้นตอนการสร้างที่สำเร็จ
8. นโยบายการควบคุมการเข้าชม
การให้สิทธิ์แบบไบนารีเป็นฟีเจอร์ใน 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"
นโยบายอนุญาตทั้งหมด
ก่อนอื่น ให้ยืนยันสถานะนโยบายเริ่มต้นและความสามารถในการทำให้ภาพใช้งานได้
- ตรวจสอบนโยบายที่มีอยู่
gcloud container binauthz policy export
- โปรดทราบว่ามีการตั้งค่านโยบายการบังคับใช้เป็น
ALWAYS_ALLOW
evaluationMode: ALWAYS_ALLOW
- ติดตั้งใช้งานตัวอย่างเพื่อยืนยันว่าคุณทำให้ทุกอย่างใช้งานได้
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
- ยืนยันว่าการทําให้การเผยแพร่ใช้งานได้
kubectl get pods
คุณจะเห็นเอาต์พุตต่อไปนี้
- ลบการทำให้ใช้งานได้
kubectl delete pod hello-server
นโยบายปฏิเสธทั้งหมด
จากนั้นอัปเดตนโยบายเพื่อไม่อนุญาตให้ใช้รูปภาพทั้งหมด
- ส่งออกนโยบายปัจจุบันไปยังไฟล์ที่แก้ไขได้
gcloud container binauthz policy export > policy.yaml
- เปลี่ยนนโยบาย
ในเครื่องมือแก้ไขข้อความ ให้เปลี่ยน 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
- เปิด Terminal แล้วใช้นโยบายใหม่ แล้วรอ 2-3 วินาทีเพื่อให้การเปลี่ยนแปลงมีผล
gcloud container binauthz policy import policy.yaml
- พยายามทำให้ภาระงานตัวอย่างใช้งานได้
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
- ทำให้ใช้งานได้ไม่สำเร็จพร้อมข้อความต่อไปนี้
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
เปลี่ยนนโยบายกลับไปเป็นอนุญาตทั้งหมด
โปรดเปลี่ยนนโยบายกลับก่อนไปยังส่วนถัดไป
- เปลี่ยนนโยบาย
ในเครื่องมือแก้ไขข้อความ ให้เปลี่ยน 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
- ใช้นโยบายที่เปลี่ยนกลับ
gcloud container binauthz policy import policy.yaml
9. บล็อกช่องโหว่ใน GKE
ในส่วนนี้ คุณจะได้รวมสิ่งที่ได้เรียนรู้มาจนถึงตอนนี้ด้วยการใช้ไปป์ไลน์ CI/CD กับ Cloud Build ที่สแกนรูปภาพ จากนั้นตรวจสอบช่องโหว่ก่อนที่จะเซ็นชื่อรูปภาพและพยายามทำให้ใช้งานได้ GKE จะใช้การให้สิทธิ์แบบไบนารีเพื่อตรวจสอบว่าอิมเมจมีลายเซ็นจากการสแกนหาช่องโหว่ก่อนที่จะอนุญาตให้อิมเมจทำงาน
อัปเดตนโยบาย 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. ยินดีด้วย
ยินดีด้วย คุณทำ Codelab เสร็จแล้ว
สิ่งที่เราได้พูดถึง
- วิธีเปิดใช้การสแกนอัตโนมัติ
- วิธีทำการสแกนตามคำขอ
- วิธีผสานรวมการสแกนในไปป์ไลน์การสร้าง
- วิธีลงนามในรูปภาพที่อนุมัติแล้ว
- วิธีใช้ Admission Controller ของ GKE เพื่อบล็อกรูปภาพ
- วิธีกำหนดค่า GKE ให้อนุญาตเฉพาะอิมเมจที่อนุมัติและลงนามแล้ว
ขั้นตอนต่อไปที่ทำได้
- การรักษาความปลอดภัยให้กับการสร้างใช้งานอิมเมจใน Cloud Run และ Google Kubernetes Engine | เอกสารประกอบ Cloud Build
- เริ่มต้นใช้งานอย่างรวดเร็ว: กำหนดค่านโยบายการให้สิทธิ์แบบไบนารีด้วย GKE | Google Cloud
ล้างข้อมูล
โปรดลบโปรเจ็กต์ที่มีทรัพยากรดังกล่าวหรือเก็บโปรเจ็กต์ไว้และลบทรัพยากรแต่ละรายการเพื่อเลี่ยงไม่ให้เกิดการเรียกเก็บเงินกับบัญชี Google Cloud สำหรับทรัพยากรที่ใช้ในบทแนะนำนี้
การลบโปรเจ็กต์
วิธีที่ง่ายที่สุดในการหยุดการเรียกเก็บเงินคือการลบโปรเจ็กต์ที่คุณสร้างสำหรับบทแนะนำ