ใช้ Confidential Space กับทรัพยากรที่มีการป้องกันซึ่งไม่ได้จัดเก็บไว้กับผู้ให้บริการคลาวด์

1. ภาพรวม

พื้นที่ทำงานที่ปลอดภัยมีการแชร์และทำงานร่วมกันกับหลายฝ่ายอย่างปลอดภัย ทั้งยังช่วยให้องค์กรรักษาความลับของข้อมูลได้ ซึ่งหมายความว่าองค์กรต่างๆ สามารถทำงานร่วมกันได้ในขณะที่ยังคงควบคุมข้อมูลและปกป้องข้อมูลจากการเข้าถึงที่ไม่ได้รับอนุญาต

พื้นที่ส่วนบุคคลจะปลดล็อกสถานการณ์ที่คุณต้องการรับคุณค่าร่วมกันจากการรวบรวมและวิเคราะห์ข้อมูลที่ละเอียดอ่อนซึ่งมักอยู่ภายใต้การควบคุมดูแลของรัฐ ขณะเดียวกันก็ยังคงควบคุมข้อมูลดังกล่าวได้อย่างเต็มที่ พื้นที่ทำงานที่ปลอดภัยช่วยให้องค์กรต่างๆ ได้รับคุณค่าร่วมกันจากการรวบรวมและวิเคราะห์ข้อมูลที่ละเอียดอ่อน เช่น ข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้ (PII) ข้อมูลสุขภาพที่ได้รับการคุ้มครอง (PHI) ทรัพย์สินทางปัญญา และข้อมูลลับที่เข้ารหัส ขณะเดียวกันก็ยังคงควบคุมข้อมูลดังกล่าวได้อย่างเต็มที่

สิ่งที่ต้องมี

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

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

Codelab นี้มุ่งเน้นที่วิธีใช้พื้นที่ทำงานที่ปลอดภัยกับทรัพยากรที่ได้รับการปกป้องซึ่งโฮสต์ไว้ที่อื่นที่ไม่ใช่ Google Cloud คุณจะได้เรียนรู้วิธีขอโทเค็นที่กําหนดเองแบบสําเร็จรูปจากบริการตรวจสอบสิทธิ์ของ Google โดยระบุ Nonce, กลุ่มเป้าหมาย และประเภทโทเค็น PKI

ในโค้ดแล็บนี้ คุณจะต้องสร้างพื้นที่ส่วนบุคคลระหว่างผลิตภัณฑ์สมมติอย่าง USleep ซึ่งเป็นแอปพลิเคชันที่ใช้คอนเทนเนอร์ และผลิตภัณฑ์สมมติอย่าง UWear ซึ่งเป็นอุปกรณ์ที่สวมใส่ได้แบบเชื่อมต่ออินเทอร์เน็ต เพื่อคำนวณคุณภาพการนอนหลับ UWear จะแชร์ข้อมูลสุขภาพที่ได้รับการคุ้มครอง (PHI) กับ USleep ในสภาพแวดล้อมที่ปลอดภัย แยกส่วน และเชื่อถือได้ (หรือที่เรียกว่า Trusted Execution Environment หรือ TEE) เพื่อให้เจ้าของข้อมูลรักษาความลับได้อย่างสมบูรณ์

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

USleep ใน Codelab นี้กําลังทำให้แอปพลิเคชันที่มีคอนเทนเนอร์ใช้งานได้ USleep ไม่มีสิทธิ์เข้าถึงข้อมูลที่มีความละเอียดอ่อน แต่เรียกใช้ภาระงานที่อนุมัติซึ่งได้รับอนุญาตให้เข้าถึงข้อมูลที่มีความละเอียดอ่อน

Codelab มีขั้นตอนต่อไปนี้

  • ขั้นตอนที่ 1: ตั้งค่าทรัพยากรในระบบคลาวด์ที่จําเป็นสําหรับ Codelab ตั้งค่าโปรเจ็กต์ การเรียกเก็บเงิน และสิทธิ์ ดาวน์โหลดซอร์สโค้ดของ Codelab และตั้งค่าตัวแปรสภาพแวดล้อม
  • ขั้นตอนที่ 2: ดาวน์โหลดใบรับรองรูทและจัดเก็บไว้กับซอร์สโค้ด UWear
  • ขั้นตอนที่ 3: สร้างบัญชีบริการของภาระงานแยกต่างหาก ซึ่ง VM ของภาระงานจะใช้สำหรับ USleep และ UWear
  • ขั้นตอนที่ 4: สร้างเวิร์กโหลด USleep ซึ่งให้โทเค็นการรับรอง
  • ขั้นตอนที่ 5: สร้างภาระงาน UWear ซึ่งจะตรวจสอบโทเค็นการรับรองและส่งข้อมูลที่ละเอียดอ่อนหากโทเค็นได้รับอนุมัติ
  • ขั้นตอนที่ 6: เรียกใช้เวิร์กโหลด USleep และ UWear UWear จะระบุข้อมูลที่ละเอียดอ่อน และ USleep จะเรียกใช้อัลกอริทึมการนอนหลับกับข้อมูลดังกล่าวและแสดงผลลัพธ์
  • ขั้นตอนที่ 7: (ไม่บังคับ) เรียกใช้ภาระงาน USleep ที่ไม่ได้รับอนุญาตและยืนยันว่าไม่ได้รับการข้อมูลที่มีความละเอียดอ่อนจาก UWear
  • ขั้นตอนที่ 8: ล้างข้อมูลทรัพยากรทั้งหมด

การทำความเข้าใจเวิร์กโฟลว์

USleep จะเรียกใช้ภาระงานในพื้นที่ทำงานที่ปลอดภัย และต้องเข้าถึง PHI ของ UWear เพื่อเรียกใช้เวิร์กโหลด เวิร์กโหลด USleep จะสร้างเซสชัน TLS ที่ปลอดภัยก่อนเพื่อให้ได้รับสิทธิ์เข้าถึง จากนั้น USleep จะขอโทเค็นการรับรองจากบริการการรับรองของ Google ด้วยเพย์โหลด

USleep จะขอโทเค็นการรับรองที่มีเพย์โหลด JSON ซึ่งประกอบด้วย 3 สิ่งต่อไปนี้

  1. โทเค็นการรับรองที่เชื่อมโยงกับเซสชัน TLS หากต้องการเชื่อมโยงโทเค็นการรับรองกับเซสชัน TLS ค่า Nonce จะเป็นแฮชของข้อมูลการเข้ารหัสที่ส่งออกของ TLS การเชื่อมโยงโทเค็นกับเซสชัน TLS ช่วยให้มั่นใจได้ว่าจะไม่มีการใช้เครื่องกลางในการโจมตี เนื่องจากมีเพียง 2 ฝ่ายที่มีส่วนร่วมในเซสชัน TLS เท่านั้นที่จะสร้างค่า Nonce ได้
  2. ระบบจะสร้างกลุ่มเป้าหมาย "uwear" ให้ UWear จะยืนยันว่าเป็นกลุ่มเป้าหมายที่ต้องการสำหรับโทเค็นการรับรอง
  3. โทเค็นประเภท "PKI" โทเค็นประเภท "PKI" หมายความว่า USleep ต้องการขอโทเค็นแบบรวมทุกอย่าง คุณสามารถยืนยันได้ว่าโทเค็นแบบรวมอยู่ในตัวเองได้รับการรับรองโดย Google โดยใช้รูทที่ดาวน์โหลดจากปลายทาง PKI ที่รู้จักของพื้นที่ทำงานที่ปลอดภัย ซึ่งแตกต่างจากโทเค็น OIDC ประเภทเริ่มต้นที่จะมีการยืนยันลายเซ็นโดยใช้คีย์สาธารณะที่เปลี่ยนเป็นประจำ

bb013916a3222ce7.png

เวิร์กโหลด USleep ได้รับโทเค็นการรับรอง จากนั้น UWear จะเข้าร่วมการเชื่อมต่อ TLS กับ USleep และดึงข้อมูลโทเค็นการรับรองของ USleep UWear จะตรวจสอบความถูกต้องของโทเค็นโดยตรวจสอบการอ้างสิทธิ์ x5c กับใบรับรองรูท

UWear จะอนุมัติเวิร์กโหลด USleep ในกรณีต่อไปนี้

  1. โทเค็นผ่านตรรกะการตรวจสอบ PKI
  2. UWear จะตรวจสอบโทเค็นโดยตรวจสอบการอ้างสิทธิ์ x5c กับใบรับรองรูท ตรวจสอบว่าโทเค็นได้รับการลงนามโดยใบรับรองใบแจ้งยอด และสุดท้ายตรวจสอบว่าใบรับรองรูทที่ดาวน์โหลดมานั้นเป็นรูทเดียวกับในการอ้างสิทธิ์ x5c
  3. การอ้างสิทธิ์การวัดภาระงานในโทเค็นตรงกับเงื่อนไขแอตทริบิวต์ที่ระบุไว้ในนโยบาย OPA OPA เป็นเครื่องมือนโยบายแบบโอเพนซอร์สอเนกประสงค์ที่รวมการบังคับใช้นโยบายในแพลตฟอร์มต่างๆ OPA ใช้เอกสารที่มีไวยากรณ์คล้ายกับ JSON เพื่อตั้งค่าพื้นฐานที่ระบบจะใช้ตรวจสอบนโยบาย ดูตัวอย่างค่าที่นโยบายจะตรวจสอบได้ที่ค่าพื้นฐานของ OPA
  4. หมายเลขที่ไม่ซ้ำกันตรงกับ หมายเลขที่ไม่ซ้ำกันที่คาดไว้ (เนื้อหาการกุญแจที่ส่งออกของ TLS) ข้อมูลนี้ได้รับการยืนยันในนโยบาย OPA ด้านบน

เมื่อการตรวจสอบทั้งหมดเสร็จสิ้นและผ่านแล้ว UWear จะยืนยันได้ว่าระบบจะส่งและประมวลผลข้อมูลอย่างปลอดภัย จากนั้น UWear จะตอบกลับด้วย PHI ที่มีความละเอียดอ่อนผ่านเซสชัน TLS เดียวกัน และ USleep จะใช้ข้อมูลดังกล่าวเพื่อคำนวณคุณภาพการนอนหลับของลูกค้าได้

2. ตั้งค่าทรัพยากรระบบคลาวด์

ก่อนเริ่มต้น

  1. สร้างโปรเจ็กต์ Google Cloud 2 รายการ โปรเจ็กต์หนึ่งสำหรับ USleep และอีกโปรเจ็กต์สำหรับ UWear ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้างโปรเจ็กต์ Google Cloud ได้ที่ "ตั้งค่าและไปยังส่วนต่างๆ ของโปรเจ็กต์ Google โปรเจ็กต์แรก" ใน Codelab โปรดดูรายละเอียดเกี่ยวกับวิธีเรียกข้อมูลรหัสโปรเจ็กต์และความแตกต่างระหว่างรหัสโปรเจ็กต์กับชื่อโปรเจ็กต์และหมายเลขโปรเจ็กต์ที่หัวข้อการสร้างและจัดการโปรเจ็กต์
  2. เปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์
  3. ใน Cloud Shell ของโปรเจ็กต์ Google ให้ตั้งค่าตัวแปรสภาพแวดล้อมโปรเจ็กต์ที่จำเป็นตามที่แสดงด้านล่าง
export UWEAR_PROJECT_ID=<Google Cloud project id of UWear>
export USLEEP_PROJECT_ID=<Google Cloud project id of USleep>
  1. เปิดใช้ Confidential Computing API และ API ต่อไปนี้สําหรับโปรเจ็กต์ทั้ง 2 รายการ
gcloud config set project $UWEAR_PROJECT_ID
gcloud services enable \
    cloudapis.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    confidentialcomputing.googleapis.com

gcloud config set project $USLEEP_PROJECT_ID
gcloud services enable \
    cloudapis.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    confidentialcomputing.googleapis.com
  1. เรียกข้อมูลตัวระบุหลักโดยใช้
gcloud auth list

# Output should contain
# ACCOUNT: <Principal Identifier>

# Set your member variable
export MEMBER='user:<Principal Identifier>'
  1. เพิ่มสิทธิ์สำหรับโปรเจ็กต์ 2 รายการนี้ คุณสามารถเพิ่มสิทธิ์ได้โดยทำตามรายละเอียดในหน้าเว็บการให้สิทธิ์บทบาท IAM
gcloud config set project $UWEAR_PROJECT_ID

# Add Artifact Registry Administrator role
gcloud projects add-iam-policy-binding $UWEAR_PROJECT_ID --member=$MEMBER --role='roles/iam.serviceAccountAdmin'

# Add Service Account Administrator role
gcloud projects add-iam-policy-binding $UWEAR_PROJECT_ID --member=$MEMBER --role='roles/artifactregistry.admin'
gcloud config set project $USLEEP_PROJECT_ID

# Add Service Account Administrator role
gcloud projects add-iam-policy-binding $USLEEP_PROJECT_ID --member=$MEMBER --role='roles/iam.serviceAccountAdmin'

# Add Artifact Registry Administrator role
gcloud projects add-iam-policy-binding $USLEEP_PROJECT_ID --member=$MEMBER --role='roles/artifactregistry.admin'

# Add Compute Administrator role
gcloud projects add-iam-policy-binding $USLEEP_PROJECT_ID --member=$MEMBER --role='roles/compute.admin'

# Add Storage Administrator role
gcloud projects add-iam-policy-binding $USLEEP_PROJECT_ID --member=$MEMBER --role='roles/compute.storageAdmin'
  1. ใน Cloud Shell ของโปรเจ็กต์ Google Cloud รายการใดรายการหนึ่ง ให้โคลนที่เก็บ GitHub ของ Codelab พื้นที่ทำงานที่ปลอดภัยโดยใช้คำสั่งด้านล่างเพื่อรับสคริปต์ที่จำเป็นซึ่งใช้ใน Codelab นี้
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  1. เปลี่ยนไดเรกทอรีเป็นไดเรกทอรีสคริปต์สําหรับโค้ดแล็บข้อมูลสุขภาพ
cd confidential-space/codelabs/health_data_analysis_codelab/scripts
  1. อัปเดตบรรทัดเหล่านี้2 บรรทัดในสคริปต์ config_env.sh ซึ่งอยู่ในไดเรกทอรี codelabs/health_data_analysis_codelab/scripts อัปเดตรหัสโปรเจ็กต์ด้วยรหัสโปรเจ็กต์สำหรับ USleep และ UWear อย่าลืมนำสัญลักษณ์ความคิดเห็น "#" ที่ขึ้นต้นบรรทัดออก
# TODO: Populate UWear and USleep Project IDs
export UWEAR_PROJECT_ID=your-uwear-project-id
export USLEEP_PROJECT_ID=your-usleep-project-id
  1. ไม่บังคับ: ตั้งค่าตัวแปรที่มีอยู่ก่อน คุณสามารถลบล้างชื่อทรัพยากรได้โดยใช้ตัวแปรเหล่านี้ (เช่น export UWEAR_ARTIFACT_REPOSITORY='my-artifact-repository')
  • คุณสามารถตั้งค่าตัวแปรต่อไปนี้ด้วยชื่อทรัพยากรระบบคลาวด์ที่มีอยู่ หากตั้งค่าตัวแปร ระบบจะใช้ทรัพยากรระบบคลาวด์ที่มีอยู่ที่เกี่ยวข้องจากโปรเจ็กต์ หากไม่ได้ตั้งค่าตัวแปร ระบบจะสร้างชื่อทรัพยากรระบบคลาวด์จากค่าในสคริปต์ config_env.sh
  1. เรียกใช้สคริปต์ config_env.sh เพื่อตั้งค่าชื่อตัวแปรที่เหลือเป็นค่าตามรหัสโปรเจ็กต์สำหรับชื่อทรัพยากร
# Navigate to the scripts folder
cd ~/confidential-space/codelabs/health_data_analysis_codelab/scripts

# Run the config_env script
source config_env.sh

# Verify the variables were set
# Expected output for default variable should be `workload-sa`
echo $USLEEP_WORKLOAD_SERVICE_ACCOUNT

3. ดาวน์โหลดใบรับรองรูท

  1. UWear จะต้องตรวจสอบลายเซ็นกับใบรับรองรูทของพื้นที่ส่วนบุคคลเพื่อตรวจสอบโทเค็นแบบรวมทั้งหมดที่ส่งคืนจากบริการยืนยัน UWear จะต้องดาวน์โหลดใบรับรองรูท และจัดเก็บไว้ในเครื่อง ในคอนโซลของโปรเจ็กต์ Google Cloud ให้เรียกใช้คําสั่งต่อไปนี้
cd ~/confidential-space/codelabs/health_data_analysis_codelab/src/uwear

wget https://confidentialcomputing.googleapis.com/.well-known/confidential_space_root.crt -O confidential_space_root.pem
  1. สร้างลายนิ้วมือของใบรับรองรูทที่ดาวน์โหลด
openssl x509 -fingerprint -in confidential_space_root.pem -noout
  1. ตรวจสอบว่าลายนิ้วมือตรงกับข้อมูลสรุป SHA-1 ต่อไปนี้
B9:51:20:74:2C:24:E3:AA:34:04:2E:1C:3B:A3:AA:D2:8B:21:23:21

4. สร้างบัญชีบริการของ Workload

ตอนนี้คุณจะต้องสร้างบัญชีบริการ 2 บัญชี บัญชีหนึ่งสำหรับ USleep และอีกบัญชีสำหรับ UWear เรียกใช้สคริปต์ create_service_accounts.sh เพื่อสร้างบัญชีบริการสำหรับเวิร์กโหลดในโปรเจ็กต์ USleep และ UWear VM ที่เรียกใช้เวิร์กโหลดจะใช้บัญชีบริการเหล่านี้

# Navigate to the scripts folder
cd ~/confidential-space/codelabs/health_data_analysis_codelab/scripts

# Run the create_service_accounts script
./create_service_accounts.sh

สคริปต์

  • ให้บทบาท iam.serviceAccountUser ซึ่งจะแนบบัญชีบริการกับภาระงาน
  • มอบบทบาท confidentialcomputing.workloadUser ให้กับบัญชีบริการของภาระงาน ซึ่งจะช่วยให้บัญชีผู้ใช้สร้างโทเค็นการรับรองได้
  • มอบสิทธิ์บทบาท logging.logWriter ให้กับบัญชีบริการของภาระงาน ซึ่งจะช่วยให้สภาพแวดล้อมของพื้นที่ทำงานที่ปลอดภัยเขียนบันทึกไปยังการบันทึกในระบบคลาวด์ได้นอกเหนือจากคอนโซลอนุกรม เพื่อให้บันทึกพร้อมใช้งานหลังจากที่ VM สิ้นสุดการทำงานแล้ว สร้างเวิร์กโหลด

5. สร้างภาระงาน USleep

ในขั้นตอนนี้ คุณจะต้องสร้างอิมเมจ Docker สำหรับเวิร์กโหลดที่ใช้ในโค้ดแล็บนี้ เวิร์กโหลด USleep เป็นแอปพลิเคชัน Golang ง่ายๆ ที่ใช้ข้อมูลสุขภาพส่วนบุคคลในอุปกรณ์ที่สวมใส่ได้เพื่อพิจารณาคุณภาพการนอนหลับของลูกค้า

เกี่ยวกับภาระงาน USleep

USleep workload เป็นแอปพลิเคชัน Golang ง่ายๆ ที่ใช้ข้อมูลสุขภาพส่วนตัวในอุปกรณ์ที่สวมใส่ได้เพื่อพิจารณาคุณภาพการนอนหลับของลูกค้า เวิร์กโหลด USleep ประกอบด้วย 3 ส่วนหลักๆ ดังนี้

  1. การตั้งค่าเซสชัน TLS และดึงข้อมูลวัสดุการเข้ารหัสที่ส่งออก
func handleConnectionRequest(w http.ResponseWriter, r *http.Request) {
  // Upgrade HTTP Connection to a websocket.
  conn, err := upgrader.Upgrade(w, r, nil)
  if err != nil {
    fmt.Printf("failed to upgrade connection to a websocket with err: %v\n", err)
    return
  }
  defer conn.Close()

  // Get EKM
  hash, err := getEKMHashFromRequest(r)
  if err != nil {
    fmt.Printf("Failed to get EKM: %v", err)
  }
  ...
}

func getEKMHashFromRequest(r *http.Request) (string, error) {
  ekm, err := r.TLS.ExportKeyingMaterial("testing_nonce", nil, 32)
  if err != nil {
    err := fmt.Errorf("failed to get EKM from inbound http request: %w", err)
    return "", err
  }

  sha := sha256.New()
  sha.Write(ekm)
  hash := base64.StdEncoding.EncodeToString(sha.Sum(nil))

  fmt.Printf("EKM: %v\nSHA hash: %v", ekm, hash)
  return hash, nil
}
  1. การขอโทเค็นจากบริการยืนยันโดยมีกลุ่มเป้าหมาย, Nonce และประเภทโทเค็น PKI
func handleConnectionRequest(w http.ResponseWriter, r *http.Request) {
  ...

  // Request token with TLS Exported Keying Material (EKM) hashed.
  token, err := getCustomToken(hash)
  if err != nil {
    fmt.Printf("failed to get custom token from token endpoint: %v", err)
    return
  }

  // Respond to the client with the token.
  conn.WriteMessage(websocket.TextMessage, token)

  ...
}

var (
        socketPath    = "/run/container_launcher/teeserver.sock"
        tokenEndpoint = "http://localhost/v1/token"
        contentType   = "application/json"
)


func getCustomToken(nonce string) ([]byte, error) {
  httpClient := http.Client{
    Transport: &http.Transport{
      // Set the DialContext field to a function that creates
      // a new network connection to a Unix domain socket
      DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
        return net.Dial("unix", socketPath)
      },
    },
  }

  body := fmt.Sprintf(`{
    "audience": "uwear",
    "nonces": ["%s"],
    "token_type": "PKI"
  }`, nonce)

  resp, err := httpClient.Post(tokenEndpoint, contentType, strings.NewReader(body))
  if err != nil {
    return nil, err
  }

  fmt.Printf("Response from launcher: %v\n", resp)
  text, err := io.ReadAll(resp.Body)
  if err != nil {
    return nil, fmt.Errorf("Failed to read resp.Body: %w", err)
  }
  fmt.Printf("Token from the attestation service: %s\n", text)

  return text, nil
}
  1. การรับข้อมูลที่ละเอียดอ่อนและคำนวณคุณภาพการนอนหลับของผู้ใช้
func handleConnectionRequest(w http.ResponseWriter, r *http.Request) {
  ...

  // Read the sensitive data
  _, content, err := conn.ReadMessage()
  if err != nil {
    fmt.Printf("failed to read message from the connection: %v\n", err)
  }
  fmt.Printf("Received content from other side, %v\n", string(content))

 // TODO: Handle sensitive data
  ...
}

ขั้นตอนการสร้างเวิร์กโหลด USleep

  1. เรียกใช้สคริปต์ create_usleep_workload.sh เพื่อสร้างเวิร์กโหลด USleep สคริปต์นี้
  • สร้าง Artifact Registry ($USLEEP_ARTIFACT_REPOSITORY) ที่เป็นของ UWear ซึ่งจะเผยแพร่เวิร์กโหลด
  • สร้างโค้ด usleep/workload.go และแพ็กเกจไว้ในอิมเมจ Docker ดูการกําหนดค่า Dockerfile สําหรับ USleep
  • เผยแพร่อิมเมจ Docker ไปยัง Artifact Registry ($USLEEP_ARTIFACT_REPOSITORY) ของ UWear
  • ให้สิทธิ์บัญชีบริการ $USLEEP_WORKLOAD_SERVICE_ACCOUNT อ่านสำหรับ Artifact Registry ($USLEEP_ARTIFACT_REPOSITORY)
./create_usleep_workload.sh
  1. สำคัญ: ในบันทึกเอาต์พุต ให้ดึงข้อมูลสรุปรูปภาพสำหรับ USleep
latest: digest: sha256:<USLEEP_IMAGE_DIGEST> size: 945
  1. ไปที่ไดเรกทอรี UWear
cd ~/confidential-space/codelabs/health_data_analysis_codelab/src/uwear
  1. แทนที่ค่าในส่วน "allowed_submods_container_image_digest" ใน opa_validation_values.json ด้วย USLEEP_IMAGE_DIGEST
# Replace the image digest
sed -i 's/sha256:bc4c32cb2ca046ba07dcd964b07a320b7d0ca88a5cf8e979da15cae68a2103ee/sha256:<USLEEP_IMAGE_DIGEST>/' ~/confidential-space/codelabs/health_data_analysis_codelab/src/uwear/opa_validation_values.json

6. สร้างภาระงาน UWear

เกี่ยวกับภาระงาน UWear

ปริมาณงาน UWear ประกอบด้วย 4 ส่วนหลักๆ ดังนี้

  1. เข้าร่วมเซสชัน TLS เดียวกันกับที่สร้างไว้ในเวิร์กโหลดของ USleep และดึงข้อมูลโทเค็นการรับรองจาก USleep ผ่านเซสชัน TLS ที่ปลอดภัย
func main() {
  fmt.Println("Initializing client...")

  tlsconfig := &tls.Config{
    // Skipping client verification of the server's certificate chain and host name since we are
    // doing custom verification using the attestation token.
    InsecureSkipVerify: true,
  }

  dialer := websocket.Dialer{
    TLSClientConfig:  tlsconfig,
    HandshakeTimeout: 5 * time.Second,
  }

  ipAddress := os.Getenv(ipAddrEnvVar)
  url := fmt.Sprintf("wss://%s:8081/connection", ipAddress)

  fmt.Printf("Attempting to dial to url %v...\n", url)
  conn, _, err := dialer.Dial(url, nil)
  if err != nil {
    fmt.Printf("Failed to dial to url %s, err %v\n", url, err)
    return
  }

  defer conn.Close()

  tokenString, ekm, err := retrieveTokenAndEKMFromConn(conn)
  if err != nil {
    fmt.Printf("Failed to retrieve token and EKM from connection: %v\n", err)
    return
  }

  fmt.Printf("token: %v\n", tokenString)

  ...
}
  1. ตรวจสอบโทเค็นแบบรวมในตัวโดยทำดังนี้
  • ตรวจสอบการอ้างสิทธิ์ x5c มีเชนใบรับรองที่เชื่อมโยงจากใบรับรองใบแจ้งหนี้ไปยังใบรับรองสื่อกลางและไปยังใบรับรองรูทอย่างถูกต้อง
  • ตรวจสอบว่าโทเค็นได้รับการรับรองโดยใบรับรองใบสุดท้ายที่อยู่ในการอ้างสิทธิ์ x5c
  • ตรวจสอบว่าใบรับรองรูทที่ดาวน์โหลด / จัดเก็บไว้เป็นรูทเดียวกับในคํากล่าวอ้าง x5c
func main() {
  ...

  token, err := validatePKIToken(tokenString)
  if err != nil {
    fmt.Printf("Failed to validate PKI token, err: %v\n.", err)
    return
  }
  fmt.Println("PKI token validated successfully")
 
  ...
}

// validatePKIToken validates the PKI token returned from the attestation service.
// It verifies the token the certificate chain and that the token is signed by Google
// Returns a jwt.Token or returns an error if invalid.
func validatePKIToken(attestationToken string) (jwt.Token, error) {
  // IMPORTANT: The attestation token should be considered untrusted until the certificate chain and
  // the signature is verified.
  rawRootCertificate, err := readFile(rootCertificateFile)
  if err != nil {
    return jwt.Token{}, fmt.Errorf("readFile(%v) - failed to read root certificate: %w", rootCertificateFile, err)
  }

  storedRootCert, err := decodeAndParsePEMCertificate(string(rawRootCertificate))
  if err != nil {
    return jwt.Token{}, fmt.Errorf("DecodeAndParsePEMCertificate(string) - failed to decode and parse root certificate: %w", err)
  }

  jwtHeaders, err := extractJWTHeaders(attestationToken)
  if err != nil {
    return jwt.Token{}, fmt.Errorf("ExtractJWTHeaders(token) - failed to extract JWT headers: %w", err)
  }

  if jwtHeaders["alg"] != "RS256" {
    return jwt.Token{}, fmt.Errorf("ValidatePKIToken(attestationToken, ekm) - got Alg: %v, want: %v", jwtHeaders["alg"], "RS256")
  }

  // Additional Check: Validate the ALG in the header matches the certificate SPKI.
  // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7
  // This is included in Golang's jwt.Parse function

  x5cHeaders := jwtHeaders["x5c"].([]any)
  certificates, err := extractCertificatesFromX5CHeader(x5cHeaders)
  if err != nil {
    return jwt.Token{}, fmt.Errorf("ExtractCertificatesFromX5CHeader(x5cHeaders) returned error: %w", err)
  }

  // Verify the leaf certificate signature algorithm is an RSA key
  if certificates.LeafCert.SignatureAlgorithm != x509.SHA256WithRSA {
    return jwt.Token{}, fmt.Errorf("leaf certificate signature algorithm is not SHA256WithRSA")
  }

  // Verify the leaf certificate public key algorithm is RSA
  if certificates.LeafCert.PublicKeyAlgorithm != x509.RSA {
    return jwt.Token{}, fmt.Errorf("leaf certificate public key algorithm is not RSA")
  }

  // Verify the storedRootCertificate is the same as the root certificate returned in the token
  // storedRootCertificate is downloaded from the confidential computing well known endpoint
  // https://confidentialcomputing.googleapis.com/.well-known/attestation-pki-root
  err = compareCertificates(*storedRootCert, *certificates.RootCert)
  if err != nil {
    return jwt.Token{}, fmt.Errorf("failed to verify certificate chain: %w", err)
  }

  err = verifyCertificateChain(certificates)
  if err != nil {
    return jwt.Token{}, fmt.Errorf("VerifyCertificateChain(CertificateChain) - error verifying x5c chain: %v", err)
  }

  keyFunc := func(token *jwt.Token) (any, error) {
    return certificates.LeafCert.PublicKey, nil
  }

  verifiedJWT, err := jwt.Parse(attestationToken, keyFunc)
  return *verifiedJWT, err
}



// verifyCertificateChain verifies the certificate chain from leaf to root.
// It also checks that all certificate lifetimes are valid.
func verifyCertificateChain(certificates CertificateChain) error {
    // Additional check: Verify that all certificates in the cert chain are valid.
    // Note: The *x509.Certificate Verify method in Golang already validates this but for other coding
    // languages it is important to make sure the certificate lifetimes are checked.
    if isCertificateLifetimeValid(certificates.LeafCert) {
        return fmt.Errorf("leaf certificate is not valid")
    }

    if isCertificateLifetimeValid(certificates.IntermediateCert) {
        return fmt.Errorf("intermediate certificate is not valid")
    }
    interPool := x509.NewCertPool()
    interPool.AddCert(certificates.IntermediateCert)

    if isCertificateLifetimeValid(certificates.RootCert) {
        return fmt.Errorf("root certificate is not valid")
    }
    rootPool := x509.NewCertPool()
    rootPool.AddCert(certificates.RootCert)

    _, err := certificates.LeafCert.Verify(x509.VerifyOptions{
        Intermediates: interPool,
        Roots:         rootPool,
        KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
    })

    if err != nil {
        return fmt.Errorf("failed to verify certificate chain: %v", err)
    }

    return nil
}
  1. จากนั้นภาระงาน UWear จะตรวจสอบว่าการอ้างสิทธิ์การวัดภาระงานในโทเค็นตรงกับเงื่อนไขแอตทริบิวต์ที่ระบุไว้ในนโยบาย OPA หรือไม่ OPA เป็นเครื่องมือนโยบายแบบโอเพนซอร์สอเนกประสงค์ที่รวมการบังคับใช้นโยบายในแพลตฟอร์มต่างๆ OPA ใช้เอกสารที่มีไวยากรณ์คล้ายกับ JSON เพื่อตั้งค่าพื้นฐานที่ระบบจะใช้ตรวจสอบนโยบาย
func main() {
  ...

  err = validateClaimsAgainstOPAPolicy(token, ekm)
  if err != nil {
    fmt.Printf("Failed to validate claims against OPA policy: %v\n", err)
  return
  }

  fmt.Println("Validated token and claims. Sending sensitive data")

  ...
}

// validateClaimsAgainstOPAPolicy validates the claims in the JWT token against the OPA policy.
func validateClaimsAgainstOPAPolicy(token jwt.Token, ekm string) error {
        data, err := os.ReadFile("opa_validation_values.json")
        authorized, err := evaluateOPAPolicy(context.Background(), token, ekm, string(data))
        if err != nil {
                fmt.Println("Error evaluating OPA policy:", err)
                return fmt.Errorf("failed to evaluate OPA policy: %w", err)
        }
        if !authorized {
                fmt.Println("Remote TEE's JWT failed policy check.")
                return fmt.Errorf("remote TEE's JWT failed policy check")
        }
        fmt.Println("JWT is authorized.")
        return nil
}


// evaluateOPAPolicy returns boolean indicating if OPA policy is satisfied or not, or error if occurred
func evaluateOPAPolicy(ctx context.Context, token jwt.Token, ekm string, policyData string) (bool, error) {
        var claims jwt.MapClaims
        var ok bool
        if claims, ok = token.Claims.(jwt.MapClaims); !ok {
                return false, fmt.Errorf("failed to get the claims from the JWT")
        }

        module := fmt.Sprintf(opaPolicy, ekm)

        var json map[string]any
        err := util.UnmarshalJSON([]byte(policyData), &json)
        store := inmem.NewFromObject(json)

        // Bind 'allow' to the value of the policy decision
        // Bind 'hw_verified', 'image_verified', 'audience_verified, 'nonce_verified' to their respective policy evaluations
        query, err := rego.New(
                rego.Query(regoQuery),                          // Argument 1 (Query string)
                rego.Store(store),                              // Argument 2 (Data store)
                rego.Module("confidential_space.rego", module), // Argument 3 (Policy module)
        ).PrepareForEval(ctx)

        if err != nil {
                fmt.Printf("Error creating query: %v\n", err)
                return false, err
        }

        fmt.Println("Performing OPA query evaluation...")
        results, err := query.Eval(ctx, rego.EvalInput(claims))

        if err != nil {
                fmt.Printf("Error evaluating OPA policy: %v\n", err)
                return false, err
        } else if len(results) == 0 {
                fmt.Println("Undefined result from evaluating OPA policy")
                return false, err
        } else if result, ok := results[0].Bindings["allow"].(bool); !ok {
                fmt.Printf("Unexpected result type: %v\n", ok)
                fmt.Printf("Result: %+v\n", result)
                return false, err
        }

        fmt.Println("OPA policy evaluation completed.")

        fmt.Println("OPA policy result values:")
        for key, value := range results[0].Bindings {
                fmt.Printf("[ %s ]: %v\n", key, value)
        }
        result := results[0].Bindings["allow"]
        if result == true {
                fmt.Println("Policy check PASSED")
                return true, nil
        }
        fmt.Println("Policy check FAILED")
        return false, nil
}
{
  "allowed_submods_container_image_digest": [
    "sha256:<USLEEP_IMAGE_DIGEST>"
  ],
  "allowed_hwmodel": [
    "GCP_INTEL_TDX",
    "GCP_SHIELDED_VM",
    "GCP_AMD_SEV_ES",
    "GCP_AMD_SEV"
  ],
  "allowed_aud": [
    "uwear"
  ],
  "allowed_issuer": [
    "https://confidentialcomputing.googleapis.com"
  ],
  "allowed_secboot": [
    true
  ],
  "allowed_sw_name": [
    "CONFIDENTIAL_SPACE"
  ]
}
package confidential_space

import rego.v1

default allow := false
default hw_verified := false
default image_digest_verified := false
default audience_verified := false
default nonce_verified := false
default issuer_verified := false
default secboot_verified := false
default sw_name_verified := false

allow if {
  hw_verified
  image_digest_verified
  audience_verified
  nonce_verified
  issuer_verified
  secboot_verified
  sw_name_verified
}

hw_verified if input.hwmodel in data.allowed_hwmodel
image_digest_verified if input.submods.container.image_digest in data.allowed_submods_container_image_digest
audience_verified if input.aud in data.allowed_aud
issuer_verified if input.iss in data.allowed_issuer
secboot_verified if input.secboot in data.allowed_secboot
sw_name_verified if input.swname in data.allowed_sw_name
nonce_verified if {
  input.eat_nonce == "%s"
}
  • ตัวอย่างการค้นหา Rego
regoQuery = "
    allow = data.confidential_space.allow;
    hw_verified = data.confidential_space.hw_verified;
    image__digest_verified = data.confidential_space.image_digest_verified;
    audience_verified = data.confidential_space.audience_verified;
    nonce_verified = data.confidential_space.nonce_verified;
    issuer_verified = data.confidential_space.issuer_verified;
    secboot_verified = data.confidential_space.secboot_verified;
    sw_name_verified = data.confidential_space.sw_name_verified
"

ตัวอย่างโค้ดสําหรับการเรียกใช้แฮช EKM

func getEKMHashFromConn(c *websocket.Conn) (string, error) {
  conn, ok := c.NetConn().(*tls.Conn)
  if !ok {
    return "", fmt.Errorf("failed to cast NetConn to *tls.Conn")
  }

  state := conn.ConnectionState()
  ekm, err := state.ExportKeyingMaterial("testing_nonce", nil, 32)
  if err != nil {
    return "", fmt.Errorf("failed to get EKM from TLS connection: %w", err)
  }

  sha := sha256.New()
  sha.Write(ekm)
  hash := base64.StdEncoding.EncodeToString(sha.Sum(nil))

  return hash, nil
}
  1. เมื่อการตรวจสอบทั้งหมดเสร็จสิ้นและผ่านแล้ว UWear จะยืนยันได้ว่าระบบจะส่งและประมวลผลข้อมูลอย่างปลอดภัย จากนั้น UWear จะตอบกลับด้วย PHI ที่มีความละเอียดอ่อนผ่านเซสชัน TLS เดียวกัน และ USleep จะใช้ข้อมูลดังกล่าวเพื่อคำนวณคุณภาพการนอนหลับของลูกค้าได้
func main() {
  ...

  fmt.Println("Validated token and claims. Sending sensitive data")

  data, err := readFile(mySensitiveDataFile)
  if err != nil {
    fmt.Printf("Failed to read data from the file: %v\n", err)
  }

  conn.WriteMessage(websocket.BinaryMessage, data)
  fmt.Println("Sent payload. Closing the connection")
  conn.Close()
  
  ...
}

ขั้นตอนการสร้างเวิร์กโหลด USleep

  1. ไปที่ไดเรกทอรีสคริปต์
cd ~/confidential-space/codelabs/health_data_analysis_codelab/scripts
  1. เรียกใช้สคริปต์ create_uwear_workload.sh เพื่อสร้างภาระงาน UWear
  • สร้าง Artifact Registry ($UWEAR_ARTIFACT_REPOSITORY) ที่เป็นของ UWear ซึ่งจะเผยแพร่เวิร์กโหลด
  • สร้างโค้ด uwear/workload.go และแพ็กเกจไว้ในอิมเมจ Docker ดูการกําหนดค่า Dockerfile สําหรับ USleep
  • เผยแพร่อิมเมจ Docker ไปยัง Artifact Registry ($UWEAR_ARTIFACT_REPOSITORY) ของ UWear
  • ให้สิทธิ์บัญชีบริการ $UWEAR_WORKLOAD_SERVICE_ACCOUNT อ่านสำหรับ Artifact Registry ($UWEAR_ARTIFACT_REPOSITORY)
./create_uwear_workload.sh

7. เรียกใช้ภาระงาน USleep และ UWear

เรียกใช้เวิร์กโหลด USleep

gcloud config set project $USLEEP_PROJECT_ID


gcloud compute instances create \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${USLEEP_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
--service-account=${USLEEP_WORKLOAD_SERVICE_ACCOUNT}@${USLEEP_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata ^~^tee-image-reference=${USLEEP_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${USLEEP_PROJECT_ID}/${USLEEP_ARTIFACT_REPOSITORY}/${USLEEP_WORKLOAD_IMAGE_NAME}:${USLEEP_WORKLOAD_IMAGE_TAG}~tee-restart-policy=Never~tee-container-log-redirect=true usleep

การตอบกลับควรแสดงผลเป็น STATUS: RUNNING และควรแสดงผล EXTERNAL_IP คล้ายกับตัวอย่างนี้ด้วย

NAME: usleep
ZONE: us-west1-b
MACHINE_TYPE: n2d-standard-2
PREEMPTIBLE:
INTERNAL_IP: 10.138.0.6
EXTERNAL_IP: 34.168.56.10
STATUS: RUNNING

จัดเก็บ IP ภายนอกไว้ในตัวแปร

export USLEEP_EXTERNAL_IP=<add your external IP> 

ยืนยันว่า USleep Workload ทำงานอย่างถูกต้อง

หากต้องการตรวจสอบว่าเวิร์กโหลด USleep ทํางานอย่างถูกต้อง ให้ไปที่หน้าอินสแตนซ์ VM ในโปรเจ็กต์ USleep คลิกอินสแตนซ์ "usleep" แล้วกด "พอร์ตซีเรียล 1(คอนโซล)" ในส่วนบันทึก เมื่อเซิร์ฟเวอร์พร้อมใช้งานแล้ว บันทึกควรแสดงข้อมูลคล้ายกับต่อไปนี้ที่ด้านล่างของบันทึก

2024/09/13 17:00:00 workload task started
#####----- Local IP Address is <YOUR-LOCAL-IP> -----#####
Starting Server..

เรียกใช้ภาระงาน UWear

gcloud config set project $UWEAR_PROJECT_ID

gcloud compute instances create \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${UWEAR_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
--service-account=${UWEAR_WORKLOAD_SERVICE_ACCOUNT}@${UWEAR_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata ^~^tee-image-reference=${UWEAR_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${UWEAR_PROJECT_ID}/${UWEAR_ARTIFACT_REPOSITORY}/${UWEAR_WORKLOAD_IMAGE_NAME}:${UWEAR_WORKLOAD_IMAGE_TAG}~tee-restart-policy=Never~tee-container-log-redirect=true~tee-env-remote_ip_addr=$USLEEP_EXTERNAL_IP uwear

ยืนยันว่าเวิร์กโหลด UWear ทำงานอย่างถูกต้อง

หากต้องการดูบันทึกของภาระงาน UWear ให้ไปที่หน้าอินสแตนซ์ VM ในโปรเจ็กต์ UWear คลิกอินสแตนซ์ "uwear" แล้วกด "พอร์ตอนุกรม 1(คอนโซล)" ในส่วนบันทึก

เอาต์พุตบันทึกเมื่ออินสแตนซ์เริ่มต้นขึ้นอย่างสมบูรณ์แล้วควรมีลักษณะดังนี้

ในโปรเจ็กต์ UWear บันทึกซีเรียลควรแสดงข้อมูลคล้ายกับ

token: eyJ[...]MrXUg
PKI token validated successfully
Performing OPA query evaluation...
OPA policy evaluation completed.
OPA policy result values:
[ hw_verified ]: true
[ image__digest_verified ]: true
[ audience_verified ]: true
[ nonce_verified ]: true
[ issuer_verified ]: true
[ secboot_verified ]: true
[ sw_name_verified ]: true
[ allow ]: true
Policy check PASSED
JWT is authorized.
Validated token and claims. Sending sensitive data
Sent payload. Closing the connection

หากปริมาณงาน UWear ของคุณไม่มีลักษณะเช่นนี้ โปรดดูวิธีการในหมายเหตุด้านล่าง

ดูผลลัพธ์ของ USleep

หากต้องการดูผลลัพธ์ ให้กลับไปที่หน้าอินสแตนซ์ VM ในโปรเจ็กต์ USleep คลิกอินสแตนซ์ "usleep" แล้วกด "พอร์ตซีเรียล 1(คอนโซล)" ในส่วนบันทึก ดูผลลัพธ์ของปริมาณงานที่ด้านล่างของบันทึก โดยควรมีลักษณะคล้ายกับตัวอย่างด้านล่าง

Token from the attestation service: eyJhbGci...Ii5A3CJBuDM2o5Q
Received content from other side, {
  "name": "Amy",
  "age": 29,
  "sleep": {
      "light": {
          "minutes": 270
      },
      "deep": {
          "minutes": 135
      },
      "rem": {
          "minutes": 105
      }
  }
}
Sleep quality result: total sleep time is less than 8 hours

ผลลัพธ์ควรเป็น "total sleep time is less than 8 hours".

ยินดีด้วย คุณสร้างพื้นที่ที่ปลอดภัยระหว่าง UWear กับ USleep เพื่อแชร์ข้อมูลที่ละเอียดอ่อนเรียบร้อยแล้ว

8. (ไม่บังคับ) เรียกใช้ภาระงานที่ไม่ได้รับอนุญาต

ในสถานการณ์ถัดไป USleep จะอัปเดตโค้ดและเรียกใช้เวิร์กโหลดอื่นกับข้อมูลการนอนหลับจาก UWear UWear ยังไม่ได้ยอมรับภาระงานใหม่นี้และยังไม่ได้อัปเดตนโยบาย OPA เพื่ออนุญาตข้อมูลสรุปรูปภาพใหม่ เราจะยืนยันว่า UWear จะไม่ส่งข้อมูลที่ละเอียดอ่อนไปยังเวิร์กโหลดที่ไม่ได้รับอนุญาต

USleep แก้ไขภาระงาน

  1. ตั้งค่าโปรเจ็กต์เป็น $USLEEP_PROJECT_ID
gcloud config set project $USLEEP_PROJECT_ID
  1. ลบอินสแตนซ์ VM ของ USleep
gcloud compute instances delete usleep --zone $USLEEP_PROJECT_ZONE
  1. ไปที่ไดเรกทอรี usleep/workload.go
cd ~/confidential-space/codelabs/health_data_analysis_codelab/src/usleep
  1. ในไฟล์ usleep/workload.go อัปเดตบรรทัด "audience": "uwear". ในตัวอย่างนี้ หากต้องการเปลี่ยนข้อมูลสรุปรูปภาพ เราจะอัปเดตกลุ่มเป้าหมายเป็นค่าอื่นที่ UWear ยังไม่ได้อนุมัติ ดังนั้น UWear จึงควรปฏิเสธด้วยเหตุผล 2 ข้อ ได้แก่ ข้อมูลสรุปรูปภาพไม่ได้รับอนุมัติและกลุ่มเป้าหมายไม่ถูกต้อง
"audience": "anotherCompany.com",
  1. สร้างเวิร์กโหลด USleep ใหม่
cd ~/confidential-space/codelabs/health_data_analysis_codelab/scripts

./create_usleep_workload.sh
  1. สร้างอินสแตนซ์ VM ของ USleep ใหม่และเรียกใช้เวิร์กโหลด
gcloud compute instances create \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${USLEEP_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
--service-account=${USLEEP_WORKLOAD_SERVICE_ACCOUNT}@${USLEEP_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata ^~^tee-image-reference=${USLEEP_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${USLEEP_PROJECT_ID}/${USLEEP_ARTIFACT_REPOSITORY}/${USLEEP_WORKLOAD_IMAGE_NAME}:${USLEEP_WORKLOAD_IMAGE_TAG}~tee-restart-policy=Never~tee-container-log-redirect=true usleep
  1. ดึงข้อมูล IP ภายนอกของ USleep ใหม่เพื่อใช้ภายหลัง
export USLEEP_EXTERNAL_IP=<add your external IP>

เรียกใช้ภาระงานอีกครั้ง

  1. ลบอินสแตนซ์ VM ของ UWear
gcloud config set project $UWEAR_PROJECT_ID

gcloud compute instances delete uwear --zone $UWEAR_PROJECT_ZONE
  1. สร้างอินสแตนซ์ UWear VM อีกครั้งโดยใช้ IP ภายนอกใหม่
gcloud compute instances create \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${UWEAR_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
--service-account=${UWEAR_WORKLOAD_SERVICE_ACCOUNT}@${UWEAR_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata ^~^tee-image-reference=${UWEAR_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${UWEAR_PROJECT_ID}/${UWEAR_ARTIFACT_REPOSITORY}/${UWEAR_WORKLOAD_IMAGE_NAME}:${UWEAR_WORKLOAD_IMAGE_TAG}~tee-restart-policy=Never~tee-container-log-redirect=true~tee-env-remote_ip_addr=$USLEEP_EXTERNAL_IP uwear
  1. ในบันทึกซีเรียลของ UWear ข้อความต่อไปนี้ควรปรากฏขึ้น และ VM ของ USleep ไม่ควรได้รับข้อมูลที่ละเอียดอ่อน
OPA policy result values:
[ nonce_verified ]: true
[ issuer_verified ]: true
[ secboot_verified ]: true
[ sw_name_verified ]: true
[ allow ]: false
[ hw_verified ]: true
[ image__digest_verified ]: false
[ audience_verified ]: false
Policy check FAILED
Remote TEE's JWT failed policy check.
Failed to validate claims against OPA policy: remote TEE's JWT failed policy check

9. ล้าง

คุณสามารถใช้สคริปต์ล้างข้อมูลเพื่อล้างทรัพยากรที่เราสร้างขึ้นซึ่งเป็นส่วนหนึ่งของ Codelab นี้ ในการล้างข้อมูลนี้ ระบบจะลบทรัพยากรต่อไปนี้

  • บัญชีบริการ UWear ($UWEAR_SERVICE_ACCOUNT)
  • รีจิสทรีอาร์ติแฟกต์ UWear ($UWEAR_ARTIFACT_REPOSITORY)
  • อินสแตนซ์ Compute ของ UWear
  • บัญชีบริการ USleep ($USLEEP_SERVICE_ACCOUNT)
  • รีจิสทรีอาร์ติแฟกต์ USleep ($USLEEP_ARTIFACT_REPOSITORY)
  • อินสแตนซ์ Compute ของ USleep
./cleanup.sh

หากสำรวจเสร็จแล้ว โปรดพิจารณาลบโปรเจ็กต์โดยทำตามวิธีการเหล่านี้

ยินดีด้วย

ยินดีด้วย คุณทำ Codelab เสร็จเรียบร้อยแล้ว

คุณได้เรียนรู้วิธีแชร์ข้อมูลอย่างปลอดภัยโดยยังคงรักษาความลับของข้อมูลไว้โดยใช้พื้นที่ทำงานที่ปลอดภัย

ขั้นตอนถัดไป

ลองดู Codelab ที่คล้ายกันเหล่านี้...

อ่านเพิ่มเติม