تأمين نظام رصد السلامة في محل العمل

1. مقدمة

في هذا الدرس التطبيقي حول الترميز، ستنشئ تطبيقًا توضيحيًا أساسيًا يوضّح كيفية دمج خدمات Google Cloud المختلفة في خدمة تقع في مشروع يتضمّن قيودًا متعلّقة بالامتثال. يستخدم هذا المشروع إمكانات الأمان التالية:

هذا الدرس العملي موجّه للمطوّرين من جميع المستويات، بما في ذلك المبتدئين. ستستخدم واجهة سطر الأوامر في Google Cloud Shell ورمز Python البرمجي. ليس عليك أن تكون خبيرًا في لغة Python، ولكنّ فهمًا أساسيًا لطريقة قراءة الرموز البرمجية سيساعدك في فهم المفاهيم.

ملاحظة: هذا نموذج مبسط لإثبات صحة الفكرة، وليس تطبيقًا جاهزًا للاستخدام. اتّخاذ احتياطات إضافية، مثل توفير وصول خارجي مصادَق عليه وآمن إلى هذه الخدمة في سيناريو فعلي

2. قبل البدء

إعداد المشروع

../shared/_project-setup.md

بدء Cloud Shell

Cloud Shell هي بيئة سطر أوامر تعمل في Google Cloud ومحمّلة مسبقًا بالأدوات اللازمة.

  1. انقر على تفعيل Cloud Shell في أعلى "وحدة تحكّم Google Cloud":

404e4cce0f23e5c5.png

  1. بعد الاتصال بـ Cloud Shell، شغِّل الأمر التالي للتحقّق من مصادقتك في Cloud Shell:
gcloud auth list
  1. نفِّذ الأمر التالي للتأكّد من إعداد مشروعك لاستخدامه مع gcloud:
gcloud config get project
  1. تأكَّد من أنّ المشروع هو ما تتوقّعه، ثم نفِّذ الأمر أدناه لضبط رقم تعريف مشروعك:
export PROJECT_ID=$(gcloud config get project)

أذونات "إدارة الهوية وإمكانية الوصول" المطلوبة

يجب أن يتضمّن الحساب الذي تستخدمه في هذا الدرس التطبيقي العملي أدوار "إدارة الهوية وإمكانية الوصول" التالية. هذه الأذونات ضرورية لإنشاء موارد Google Cloud المطلوبة (المشاريع والمجلدات ومجموعات GKE ومفاتيح KMS وحسابات الخدمة وما إلى ذلك) وإعداد Assured Workload.

على مستوى المؤسسة:

  • roles/assuredworkloads.admin (مشرف أحمال العمل المؤكّدة): لإنشاء مورد "أحمال العمل المؤكّدة" وإدارته، ما يضمن ضبط إعدادات التوافق

على مستوى حساب الفوترة (في حساب الفوترة):

  • roles/billing.accountUser (مستخدم حساب الفوترة): لربط حساب الفوترة المحدّد.

ضبط متغيّرات Codelab

لإنشاء البنية الأساسية اللازمة، يجب توفير متغيرات البيئة التالية:

# The ID of the Billing Account in the format (XXXXXX-XXXXXX-XXXXXX).
# This value will be used to attach in the projects created using Assured Workloads
export BILLING_ACCOUNT=

# The ID of a Google Cloud Platform organization
# Run `gcloud organizations list` to check all your available organizations
export GCP_ORGANIZATION=

# The numeric ID of a folder where the Assured Workloads will create the resources.
export FOLDER_ID=

# Region where the application will be deployed.
# Since you are using Assured Workloads, you MUST use one of the valid locations as described here: <https://docs.cloud.google.com/assured-workloads/docs/locations>
export REGION="us-central1"

# The ID of an existing Google Cloud project to be used for API quota and billing purposes.
# This project will only be used to enable the Assured Workloads API and create an Assured Workload.
export QUOTA_PROJECT_ID=

# Random suffix used to avoid naming collisions when creating the GCP projects.
export RANDOM_SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c 5 ; echo)

# The ID of the projects that will be created using Assured Workloads.
# You can modify this value if you want a custom id.
export PROJECT_ID="il5-gemini-vision-aw-${RANDOM_SUFFIX}"
export KMS_PROJECT_ID="il5-gemini-vision-kms-${RANDOM_SUFFIX}"

3- إنشاء أساس "أحمال العمل المؤكَّدة"

يمكنك الآن وضع الأساس لتطبيقك في بيئة منظَّمة. استخدِم Assured Workloads للمساعدة في فرض متطلبات الامتثال من خلال إنشاء بيئة خاضعة للرقابة لمواردك.

إعداد مشروع الحصة

فعِّل واجهة برمجة التطبيقات Assured Workloads API في مشروع الحصة. هذه الواجهة مطلوبة لإنشاء "أحمال عمل مؤكَّدة" وإدارتها.

gcloud services enable assuredworkloads.googleapis.com \
  --project="${QUOTA_PROJECT_ID}"

إنشاء بيئة Assured Workloads

ينشئ الأمر التالي "منطقة هبوط" آمنة للعرض التوضيحي. يتم إنشاء مشروعَين جديدَين على Google Cloud ضمن المجلد وحساب الفوترة المحدّدَين.

  • يستضيف أحد المشاريع مجموعة GKE وتطبيقك.
  • يدير المشروع الآخر مفاتيح التشفير المُدارة من العميل (CMEK).

ويطبّق تلقائيًا عناصر التحكّم المحدّدة المتوافقة مع المستوى IL5 على كلا المشروعَين منذ لحظة إنشائهما.

نفِّذ ما يلي لإنشاء بيئة عبء العمل.

export ASSURED_WORKLOAD_ID=$(gcloud assured workloads create \
    --project="${QUOTA_PROJECT_ID}" \
    --display-name="DoD IL5 Gemini Vision Demo" \
    --compliance-regime="IL5" \
    --billing-account="billingAccounts/${BILLING_ACCOUNT}" \
    --location="${REGION}" \
    --organization="${GCP_ORGANIZATION}" \
    --provisioned-resources-parent="folders/${FOLDER_ID}" \
    --resource-settings="consumer-project-id=${PROJECT_ID},consumer-project-name=DoD IL5 Workloads,encryption-keys-project-id=${KMS_PROJECT_ID},encryption-keys-project-name=DoD IL5 KMS" \
    --labels="codelab=gemini-vision-demo" \
    --format="value(name)")

echo "Assured Workload created: ${ASSURED_WORKLOAD_ID}"

export WORKLOAD_FOLDER_ID=$(gcloud assured workloads describe ${ASSURED_WORKLOAD_ID} \
    --location="${REGION}" \
    --project="${QUOTA_PROJECT_ID}" \
    --format="json" | grep -B 1 "CONSUMER_FOLDER" | grep -oE "[0-9]{10,}")

echo "Assured Workload folder created: ${WORKLOAD_FOLDER_ID}"

gcloud projects create "${PROJECT_ID}" \
    --folder="${WORKLOAD_FOLDER_ID}" \
    --name="DoD IL5 Workloads"

gcloud billing projects link "${PROJECT_ID}" \
    --billing-account="${BILLING_ACCOUNT}"

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

تفعيل واجهات Google Cloud APIs المطلوبة

قبل الإنشاء، فعِّل واجهات برمجة التطبيقات المطلوبة للخدمات اللازمة.

يؤدي الأمر أدناه إلى تفعيل جميع الخدمات اللازمة لهذا الدرس التطبيقي حول الترميز ضمن مشروع حجم المعالجة الأساسي.

gcloud services enable \
    aiplatform.googleapis.com \
    artifactregistry.googleapis.com \
    cloudkms.googleapis.com \
    compute.googleapis.com \
    container.googleapis.com \
    iam.googleapis.com \
    logging.googleapis.com \
    monitoring.googleapis.com \
    --project="${PROJECT_ID}"

4. إعداد البنية الأساسية في GKE

أنشئ البنية الأساسية التي تتوافق مع مجموعة GKE. يتضمّن ذلك إعداد شبكة مخصّصة للمجموعة وتحديد مفاتيح التشفير الخاصة بك لحماية البيانات على العُقد.

إعداد شبكة VPC

أنشئ سحابة إلكترونية خاصة افتراضية (VPC) وشبكة فرعية مخصّصتَين. يمنحك هذا النهج التحكّم الكامل في نطاق عناوين IP ويضمن عزل مجموعتك على النحو المطلوب.

نفِّذ الأوامر التالية لإنشاء شبكة VPC وشبكة فرعية ضمن منطقتك المحدّدة.

export GKE_NETWORK_NAME="il5-gke-network"
export GKE_SUBNETWORK_NAME="il5-gke-subnet"

gcloud compute networks create "${GKE_NETWORK_NAME}" \
    --description="VPC network for GKE cluster in DoD IL5 Assured Workload" \
    --subnet-mode="custom" \
    --project="${PROJECT_ID}"

gcloud compute networks subnets create "${GKE_SUBNETWORK_NAME}" \
    --network="${GKE_NETWORK_NAME}" \
    --range="10.10.0.0/20" \
    --region="${REGION}" \
    --description="Subnet for GKE cluster nodes in DoD IL5 Assured Workload" \
    --project="${PROJECT_ID}"

ضبط التشفير باستخدام Cloud KMS

لاستيفاء متطلبات الامتثال الصارمة للبيانات غير النشطة، استخدِم مفاتيح التشفير التي يديرها العميل (CMEK). يتيح لك ذلك التحكّم المباشر في المفاتيح المستخدَمة لتشفير أقراص التمهيد لعُقد GKE.

export KMS_KEYRING_NAME="il5_gke_key_ring"
export KMS_KEY_NAME="il5_gke_key"

gcloud kms keyrings create "${KMS_KEYRING_NAME}" \
    --location="$REGION" \
    --project="${KMS_PROJECT_ID}"

gcloud kms keys create "${KMS_KEY_NAME}" \
    --keyring="${KMS_KEYRING_NAME}" \
    --location="${REGION}" \
    --purpose="encryption" \
    --project="${KMS_PROJECT_ID}"

بما أنّ مفتاح التشفير متوفّر في مشروع KMS منفصل عن الخدمة التي تحتاج إلى استخدامه، يجب أن يتمكّن وكيل خدمة Google Compute Engine في مشروع عبء العمل من الوصول إلى المفتاح.

يجب منح إذن استخدام هذا المفتاح صراحةً لوكيل خدمة GCE من مشروع عبء العمل. يضيف الأمر أدناه ربط سياسة "إدارة الهوية وإمكانية الوصول" بالمفتاح، ما يمنح وكيل الخدمة الدور اللازم.

gcloud kms keys add-iam-policy-binding "${KMS_KEY_NAME}" \
    --location="${REGION}" \
    --keyring="${KMS_KEYRING_NAME}" \
    --member="serviceAccount:service-${PROJECT_NUMBER}@compute-system.iam.gserviceaccount.com" \
    --role="roles/cloudkms.cryptoKeyEncrypterDecrypter" \
    --project="${KMS_PROJECT_ID}"

ضبط حساب خدمة لعُقدة GKE

export GKE_NODE_SA=gke-node-sa

gcloud iam service-accounts create "${GKE_NODE_SA}" \
    --display-name="GKE Node Service Account" \
    --project="${PROJECT_ID}"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/monitoring.metricWriter"

5- إنشاء مجموعة GKE وإعدادها

يمكنك الآن إنشاء مجموعة GKE. يوفّر الأمر التالي مجموعة GKE مع تفعيل العديد من ميزات الأمان.

يستغرق إكمال هذه العملية عدة دقائق لأنّ Google Cloud يوفّر العُقد ولوحة التحكّم.

export GKE_CLUSTER=ppe-app

gcloud beta container clusters create "${GKE_CLUSTER}" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --service-account="${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --release-channel="regular" \
    --machine-type="n2d-standard-4" \
    --image-type="COS_CONTAINERD" \
    --disk-type="pd-ssd" \
    --disk-size="50" \
    --boot-disk-kms-key="projects/${KMS_PROJECT_ID}/locations/${REGION}/keyRings/${KMS_KEYRING_NAME}/cryptoKeys/${KMS_KEY_NAME}" \
    --metadata disable-legacy-endpoints=true \
    --num-nodes="1" \
    --network="projects/${PROJECT_ID}/global/networks/${GKE_NETWORK_NAME}" \
    --subnetwork="projects/${PROJECT_ID}/regions/${REGION}/subnetworks/${GKE_SUBNETWORK_NAME}" \
    --security-posture="standard" \
    --workload-vulnerability-scanning="disabled" \
    --workload-pool="${PROJECT_ID}.svc.id.goog" \
    --workload-metadata=GKE_METADATA \
    --addons="HorizontalPodAutoscaling,HttpLoadBalancing,NodeLocalDNS,GcePersistentDiskCsiDriver" \
    --max-surge-upgrade=1 \
    --max-unavailable-upgrade=0 \
    --binauthz-evaluation-mode="DISABLED" \
    --no-enable-basic-auth \
    --enable-autoupgrade \
    --enable-autorepair \
    --enable-confidential-nodes \
    --confidential-node-type=sev \
    --enable-ip-access \
    --enable-ip-alias \
    --enable-managed-prometheus \
    --enable-dns-access \
    --enable-shielded-nodes \
    --shielded-integrity-monitoring \
    --shielded-secure-boot

الاتصال بالمجموعة الجديدة

للتفاعل مع مجموعتك الجديدة، عليك إعداد أداة سطر الأوامر kubectl المحلية.

يجلب هذا الأمر بيانات اعتماد المجموعة ونقطة النهاية، ويضبط ملف kubeconfig المحلي تلقائيًا. بعد تنفيذ هذا الأمر، سيتم توجيه أي أوامر kubectl تنفّذها إلى مجموعة GKE الجديدة.

gcloud container clusters get-credentials "${GKE_CLUSTER}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --dns-endpoint

6. إعدادات هوية التطبيق

لربط حساب خدمة Kubernetes بحساب خدمة Cloud IAM في Google Cloud، عليك إعداد Workload Identity.

إنشاء حسابات خدمة

أنشئ حساب خدمة Kubernetes (KSA) مخصّصًا داخل مجموعتك.

export GKE_NAMESPACE=default
export GKE_SA=ppe-sa

kubectl create sa "${GKE_SA}" --namespace="${GKE_NAMESPACE}"

بعد ذلك، يحتاج تطبيقك إلى هوية ضمن Google Cloud. أنشئ حساب خدمة على Cloud IAM في Google Cloud للتطبيق. بعد إنشاء حساب الخدمة، امنحه الأدوار اللازمة.

# Create GCP service account
gcloud iam service-accounts create "${GKE_SA}" \
    --project="${PROJECT_ID}"
# Grant necessary roles
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/aiplatform.user"

السماح لحساب خدمة Kubernetes بانتحال هوية حساب إدارة الهوية وإمكانية الوصول

بعد إنشاء حسابَي الخدمة، الخطوة الأخيرة هي إنشاء الرابط بينهما. تتألف هذه العملية من جزأين. أولاً، أضِف سياسة "إدارة الهوية وإمكانية الوصول" إلى حساب الخدمة على Google Cloud.

# Allow the Kubernetes service account to act as GCP service account by using Workload Identity
gcloud iam service-accounts add-iam-policy-binding "${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --project="${PROJECT_ID}" \
    --role="roles/iam.workloadIdentityUser" \
    --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${GKE_NAMESPACE}/${GKE_SA}]"

ثانيًا، أضِف تعليقًا توضيحيًا إلى حساب الخدمة في Kubernetes.

kubectl annotate --namespace="${GKE_NAMESPACE}" serviceaccount "$GKE_SA" \
    iam.gke.io/gcp-service-account="${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com"

بعد إكمال هذه الخطوة، يمكن لأي حاوية تعمل في مجموعتك باستخدام حساب خدمة Kubernetes الوصول إلى Vertex API.

ملاحظة: من الممكن إلغاء انتحال هوية حساب الخدمة لتبسيط عملية الإعداد هذه. يمكنك الاطّلاع هنا على التفاصيل والقيود.

7. إنشاء التطبيق ونشره

حان الوقت لتعبئة تطبيقك وتخزينه ونشره في مجموعة GKE.

إنشاء مستودع Artifact Registry

قبل أن تتمكّن من تشغيل التطبيق، عليك تجميع حزمة له كحاوية Docker وتخزينها داخل مستودع Artifact Registry. استخدِم الأمر أدناه لإنشاء هذا المستودع.

export REPOSITORY_ID=ppe-repo

gcloud artifacts repositories create "${REPOSITORY_ID}" \
  --repository-format=docker \
  --location="${REGION}" \
  --project="${PROJECT_ID}" \
  --description="Regional Docker repo for PPE App"

يجب منح حساب الخدمة المستخدَم من قِبل عُقد GKE صراحةً إذن القراءة من المستودع الجديد.

gcloud artifacts repositories add-iam-policy-binding "${REPOSITORY_ID}" \
    --location="${REGION}" \
    --role="roles/artifactregistry.reader" \
    --project="${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com"

إنشاء صورة Docker ونشرها

أنشئ صورة Docker وادفعها إلى المستودع. أولاً، استنسِخ رمز المصدر وأنشئ صورة الحاوية. بعد ذلك، ضع علامة على الصورة باستخدام مسار Artifact Registry الكامل، وادفعها إلى المستودع الذي أنشأته سابقًا.

git clone https://github.com/GoogleCloudPlatform/next-26-sessions.git

cd BRK3-034-workplace-safety

cd ppe

export IMAGE_TAG="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_ID}/ppe-app:v15"
docker build -t "${IMAGE_TAG}" .
docker push "${IMAGE_TAG}"

النشر على GKE

بعد توفّر صورة الحاوية في Artifact Registry، تتمثّل الخطوة الأخيرة في توجيه GKE لسحبها وتشغيلها. ويتم تحقيق ذلك من خلال تحديد موارد تطبيقك في ملف بيان Kubernetes وتطبيقه على المجموعة. ينشئ هذا الأمر كائنَي Deployment وService المحدَّدَين في الملف.

export GKE_DEPLOY=ppe-detector

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${GKE_DEPLOY}
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ${GKE_DEPLOY}
  template:
    metadata:
      labels:
        app: ${GKE_DEPLOY}
    spec:
      serviceAccountName: ${GKE_SA}
      containers:
      - name: ${GKE_DEPLOY}
        image: ${IMAGE_TAG}
        env:
        - name: PROJECT_ID
          value: ${PROJECT_ID}
        - name: LOCATION
          value: ${REGION}
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "500m"
            memory: "1Gi"
---
apiVersion: v1
kind: Service
metadata:
  name: ${GKE_DEPLOY}
spec:
  type: LoadBalancer
  selector:
    app: ${GKE_DEPLOY}
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
EOF

8. اختبار التطبيق

الخطوة الأخيرة هي الوصول إلى التطبيق التجريبي واختباره. يتضمّن ذلك استرداد عنوان IP الخارجي المخصّص للخدمة والتفاعل معه من خلال واجهة أمامية بسيطة.

استرداد عنوان IP الخارجي للخدمة

الحصول على عنوان IP خارجي للخدمة المعروضة (يستغرق توفيره حوالي 30 ثانية)

export IP_ADDRESS=$(kubectl get service "${GKE_DEPLOY}" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $IP_ADDRESS

تشغيل الواجهة الأمامية محليًا

في هذا العرض التوضيحي، الواجهة الأمامية هي صفحة بسيطة بتنسيق HTML/JavaScript لا تشكّل جزءًا من عملية النشر على GKE. وهي مصمَّمة للعمل على جهازك المحلي.

يجب عرض الواجهة الأمامية من Google Cloud Platform في تطبيق إنتاج. على الجهاز المحلي:

# Update the index.html file with the server IP address
cd frontend

# For Linux
sed -i "s#\(const BACKEND_URL = \"http://\)[^/]\+\(\/analyze\";\)#\1${IP_ADDRESS}\2#g" "index.html"

# For MacOS
#sed -i '' "s#\(const BACKEND_URL = #\"http://\)[^/]*\(\/analyze\";\)#\1${IP_ADDRESS}\2#g" "index.html"

python3 -m http.server 8001

افتح http://localhost:8001/index.html في Chrome.

9. تنظيف

لتجنُّب الرسوم المستمرة، احذف الموارد التي تم إنشاؤها في هذا الدرس البرمجي.

إتلاف مجموعة GKE

لحذف التطبيق بأكمله، ما عليك سوى حذف مجموعة GKE. لإجراء ذلك، نفِّذ الأمر التالي:

gcloud container clusters delete "${GKE_CLUSTER}" \
    --region="$REGION" \
    --project="${PROJECT_ID}"

حذف أحمال العمل المؤكّدة

نفِّذ الأوامر التالية لحذف جميع الموارد ذات الصلة بـ "أحمال العمل المؤكّدة".

# Workload project deletion
gcloud billing projects unlink "${PROJECT_ID}"
gcloud projects delete "${PROJECT_ID}"

# KMS project deletion
gcloud billing projects unlink "${KMS_PROJECT_ID}"
gcloud projects delete "${KMS_PROJECT_ID}"

# Assured Workload folder deletion
gcloud resource-manager folders delete ${WORKLOAD_FOLDER_ID} --quiet

# Assured Workload deletion
gcloud assured workloads delete "${ASSURED_WORKLOAD_ID}" \
    --location="${REGION}" \
    --organization="${GCP_ORGANIZATION}" \
    --project="${QUOTA_PROJECT_ID}"

10. تهانينا

مهمة مكتملة! لقد أنشأت بنجاح نظامًا لرصد السلامة في مكان العمل في الصناعات الخاضعة للرقابة، ويستخدم هذا النظام Gemini لرصد قبعات السلامة.

الإنجازات:

  • حماية البيانات والخصوصية: وفّرت عقدة Confidential GKE باستخدام مفاتيح التشفير المُدارة من العميل (CMEK)
  • حدود البيانات: فعّلت عناصر التحكّم في الامتثال للمنصّة في بيئة خاضعة للرقابة

المستندات المرجعية