การสร้างที่ปลอดภัย ทำให้ใช้งานได้ด้วย Cloud Build, Artifact Registry และ GKE

1. บทนำ

Container Analysis มีการสแกนช่องโหว่และพื้นที่เก็บข้อมูลเมตาสำหรับคอนเทนเนอร์ บริการสแกนจะสแกนช่องโหว่ในอิมเมจใน Artifact Registry และ Container Registry จากนั้นจัดเก็บข้อมูลเมตาที่ได้และทำให้พร้อมใช้งานผ่าน API พื้นที่เก็บข้อมูลเมตาช่วยให้คุณจัดเก็บข้อมูลจากแหล่งที่มาต่างๆ รวมถึงการสแกนช่องโหว่, บริการของ Google Cloud และผู้ให้บริการบุคคลที่สาม

การสแกนช่องโหว่อาจเกิดขึ้นโดยอัตโนมัติหรือแบบออนดีมานด์โดยดำเนินการดังนี้

  • เมื่อเปิดใช้การสแกนอัตโนมัติ การสแกนจะทริกเกอร์โดยอัตโนมัติทุกครั้งที่คุณพุชอิมเมจใหม่ไปยัง Artifact Registry หรือ Container Registry ข้อมูลช่องโหว่จะได้รับการอัปเดตอย่างต่อเนื่องเมื่อพบช่องโหว่ใหม่ๆ
  • เมื่อเปิดใช้การสแกนแบบออนดีมานด์ คุณต้องเรียกใช้คำสั่งเพื่อสแกนอิมเมจในเครื่องหรืออิมเมจใน Artifact Registry หรือ Container Registry การสแกนแบบออนดีมานด์ช่วยให้คุณสแกนคอนเทนเนอร์ได้อย่างยืดหยุ่น เช่น สแกนอิมเมจที่สร้างขึ้นในเครื่องและแก้ไขช่องโหว่ก่อนจัดเก็บไว้ในรีจิสทรี ผลการสแกนจะใช้ได้นานถึง 48 ชั่วโมงหลังจากสแกนเสร็จแล้ว และจะไม่มีการอัปเดตข้อมูลช่องโหว่หลังการสแกน

ด้วย Container Analysis ที่ผสานรวมอยู่ในไปป์ไลน์ CI/CD ของคุณ คุณจึงสามารถตัดสินใจโดยอิงตามข้อมูลเมตานั้นได้ ตัวอย่างเช่น คุณสามารถใช้การให้สิทธิ์แบบไบนารีเพื่อสร้างนโยบายการติดตั้งใช้งานที่อนุญาตให้ติดตั้งใช้งานเฉพาะอิมเมจที่เป็นไปตามข้อกำหนดจากรีจิสทรีที่เชื่อถือได้

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเปิดใช้การสแกนอัตโนมัติ
  • วิธีสแกนแบบออนดีมานด์
  • วิธีผสานรวมการสแกนในไปป์ไลน์บิลด์
  • วิธีเซ็นชื่อกำกับรูปภาพที่ได้รับอนุมัติ
  • วิธีใช้ตัวควบคุมการเข้าร่วม GKE เพื่อบล็อกรูปภาพ
  • วิธีกำหนดค่า GKE เพื่ออนุญาตเฉพาะอิมเมจที่อนุมัติที่ลงนามแล้ว

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Google Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • ชื่อโครงการคือชื่อที่แสดงของผู้เข้าร่วมโปรเจ็กต์นี้ เป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ โดยคุณจะอัปเดตได้ทุกเมื่อ
  • รหัสโปรเจ็กต์จะไม่ซ้ำกันในทุกโปรเจ็กต์ของ Google Cloud และจะเปลี่ยนแปลงไม่ได้ (เปลี่ยนแปลงไม่ได้หลังจากตั้งค่าแล้ว) Cloud Console จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ปกติแล้วคุณไม่สนว่าอะไรเป็นอะไร ใน Codelab ส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยปกติจะระบุเป็น PROJECT_ID) หากคุณไม่ชอบรหัสที่สร้างขึ้น คุณสามารถสร้างรหัสแบบสุ่มอื่นได้ หรือคุณจะลองดำเนินการเองแล้วดูว่าพร้อมให้บริการหรือไม่ และไม่สามารถเปลี่ยนแปลงได้หลังจากขั้นตอนนี้และจะยังคงอยู่ตลอดระยะเวลาของโปรเจ็กต์
  • สำหรับข้อมูลของคุณ ค่าที่ 3 คือหมายเลขโปรเจ็กต์ที่ API บางตัวใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 ค่าได้ในเอกสารประกอบ
  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของระบบคลาวด์ การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี หากต้องการปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่คุณสร้างหรือลบทั้งโปรเจ็กต์ได้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

เริ่มผู้แก้ไข Cloudshell

ห้องทดลองนี้ออกแบบและทดสอบเพื่อใช้กับ Google Cloud Shell Editor วิธีเข้าถึงเครื่องมือแก้ไข

  1. เข้าถึงโปรเจ็กต์ Google ที่ https://console.cloud.google.com
  2. คลิกไอคอนตัวแก้ไข Cloud Shell ที่มุมขวาบน

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

ในห้องทดลองนี้ คุณจะใช้ 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

  1. เปิด Artifact Registry ใน Cloud Console
  2. คลิกที่เก็บการสแกนอาร์ติแฟกต์เพื่อดูเนื้อหา
  3. คลิกดูรายละเอียดของรูปภาพ
  4. คลิกเข้าไปในสรุปล่าสุดของรูปภาพของคุณ
  5. เมื่อสแกนเสร็จแล้ว ให้คลิกแท็บช่องโหว่ของรูปภาพ

จากแท็บช่องโหว่ คุณจะเห็นผลลัพธ์ของการสแกนอัตโนมัติสำหรับอิมเมจที่คุณเพิ่งสร้างขึ้น

361be7b3bf293fca.png

ระบบจะเปิดใช้การสแกนอัตโนมัติโดยค่าเริ่มต้น สำรวจการตั้งค่า Artifact Registry เพื่อดูวิธีปิด/เปิดการสแกนอัตโนมัติ

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 ต้องมีสิทธิ์เข้าถึง 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 ให้ใช้อิมเมจฐานที่ไม่มีช่องโหว่ CRITICAL

เขียนทับ 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

ตรวจสอบผลการสแกน

ตรวจสอบรูปภาพที่ดีในรีจิสทรีอาร์ติแฟกต์

  1. เปิด Artifact Registry ใน Cloud Console
  2. คลิกที่เก็บการสแกนอาร์ติแฟกต์เพื่อดูเนื้อหา
  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 ในโปรเจ็กต์ของคุณโดยอัตโนมัติเมื่อคุณเรียกใช้บิลด์ที่สร้างอิมเมจ ดังนั้นคำสั่งด้านบนจะแสดงผลผู้รับรอง 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}"

ในข้อกำหนดของ Container Analysis การดำเนินการนี้จะสร้างรายการใหม่ และแนบกับบันทึกของผู้รับรอง คุณระบุเอกสารรับรองได้เพื่อให้แน่ใจว่าทุกอย่างทำงานตามที่คาดไว้

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 ที่คุณสร้างก่อนหน้านี้

  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

ตรวจสอบบิลด์ในประวัติ Cloud Build

เปิด Cloud Console ไปที่หน้าประวัติ Cloud Build แล้วตรวจสอบบิลด์ล่าสุดและการดำเนินการตามขั้นตอนของบิลด์ได้สำเร็จ

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"

อนุญาตนโยบายทั้งหมด

ก่อนอื่นให้ยืนยันสถานะนโยบายเริ่มต้นและความสามารถในการทำให้อิมเมจใดก็ได้ใช้งานได้

  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

คุณจะเห็นเอาต์พุตต่อไปนี้

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 เพื่อต้องมีเอกสารรับรอง

ผู้รับรองต้องลงชื่ออิมเมจโดยการเพิ่มคลัสเตอร์AdmissionRules ต่างๆ ในนโยบาย 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 จบแล้ว

สิ่งที่เราได้พูดคุยกันมีดังนี้

  • วิธีเปิดใช้การสแกนอัตโนมัติ
  • วิธีสแกนแบบออนดีมานด์
  • วิธีผสานรวมการสแกนในไปป์ไลน์บิลด์
  • วิธีเซ็นชื่อกำกับรูปภาพที่ได้รับอนุมัติ
  • วิธีใช้ตัวควบคุมการเข้าร่วม GKE เพื่อบล็อกรูปภาพ
  • วิธีกำหนดค่า GKE เพื่ออนุญาตเฉพาะอิมเมจที่อนุมัติที่ลงนามแล้ว

ขั้นตอนต่อไปที่ทำได้

ล้างข้อมูล

เพื่อหลีกเลี่ยงไม่ให้เกิดการเรียกเก็บเงินกับบัญชี Google Cloud สำหรับทรัพยากรที่ใช้ในบทแนะนำนี้ โปรดลบโปรเจ็กต์ที่มีทรัพยากรดังกล่าวหรือเก็บโปรเจ็กต์ไว้และลบทรัพยากรแต่ละรายการ

กำลังลบโปรเจ็กต์

วิธีที่ง่ายที่สุดในการยกเลิกการเรียกเก็บเงินคือการลบโปรเจ็กต์ที่คุณสร้างไว้สำหรับบทแนะนำ