1. Présentation
Vous souhaitez améliorer la sécurité et la confidentialité de vos charges de travail accélérées par GPU ? Cet atelier de programmation vous présentera les fonctionnalités de Trusted Space, une offre qui fournit une isolation forte des opérateurs et une compatibilité avec les accélérateurs pour vos charges de travail d'IA/de ML sensibles.
Il est plus que jamais essentiel de protéger les données, les modèles et les clés importants. Trusted Space offre une solution en veillant à ce que vos charges de travail fonctionnent dans un environnement sécurisé et de confiance auquel même l'opérateur de charge de travail n'a pas accès.
Voici ce que propose Trusted Space :
- Confidentialité et sécurité renforcées : Trusted Space fournit un environnement d'exécution sécurisé dans lequel vos actifs sensibles (par exemple, les modèles, les données et les clés importantes) restent protégés grâce à une preuve cryptographique.
- Isolation des opérateurs : éliminez les problèmes liés aux interférences des opérateurs. Avec Trusted Space, même vos opérateurs de charge de travail n'ont pas accès, ce qui les empêche de se connecter via SSH, d'accéder aux données, d'installer des logiciels ou de falsifier votre code.
- Compatibilité avec les accélérateurs : Trusted Space est conçu pour fonctionner de manière transparente avec un large éventail d'accélérateurs matériels, y compris les GPU tels que H100, A100, T4 et L4. Cela garantit le bon fonctionnement de vos applications d'IA/de ML critiques pour les performances.
Points abordés
- Découvrez les principales offres de Trusted Space.
- Découvrez comment déployer et configurer un environnement Trusted Space pour sécuriser les actifs importants de votre charge de travail d'IA/de ML.
Prérequis
- Un projet Google Cloud Platform
- Connaissances de base sur Google Compute Engine et les accélérateurs.
- Connaissances de base sur les comptes de service, la gestion des clés, la fédération d'identité de charge de travail et les conditions d'attribut.
- Connaissances de base sur les conteneurs et Artifact Registry
Protection des requêtes sensibles de génération de code avec Primus Company
Dans cet atelier de programmation, nous nous mettrons à la place de Primus, une entreprise qui accorde la priorité à la confidentialité et à la sécurité des données de ses employés. Primus souhaite déployer un modèle de génération de code pour aider ses développeurs dans leurs tâches de codage. Toutefois, l'entreprise craint de ne pas pouvoir protéger la confidentialité des requêtes envoyées par ses employés, car elles contiennent souvent des extraits de code sensibles, des détails de projet internes ou des algorithmes propriétaires.
Pourquoi Primus Company ne fait-elle pas confiance à l'opérateur ?
Primus Corp opère sur un marché très concurrentiel. Sa base de code contient une propriété intellectuelle précieuse, y compris des algorithmes propriétaires et des extraits de code sensibles qui lui offrent un avantage concurrentiel. L'entreprise craint l'espionnage industriel par les opérateurs de charge de travail. De plus, les requêtes des employés peuvent inclure des parties de code confidentielles que Primus Corp souhaite protéger.
Pour répondre à cette préoccupation, Primus Corp utilisera Trusted Space afin d'isoler le serveur d'inférence exécutant le modèle de génération de code. Voici comment cela fonctionne :
- Chiffrement des requêtes : avant d'envoyer une requête au serveur d'inférence, chaque employé la chiffrera à l'aide d'une clé KMS gérée par Primus Corp dans Google Cloud. Cela garantit que seul l'environnement Trusted Space, où la clé de déchiffrement correspondante est disponible, peut la déchiffrer et accéder à la requête en texte brut. Dans un scénario réel, le chiffrement côté client peut être géré par les bibliothèques disponibles (par exemple, Tink). Dans le cadre de cet atelier de programmation, nous utiliserons cet exemple d'application cliente avec le chiffrement encapsulé.
- Isolation des opérateurs : seul le serveur d'inférence, exécuté dans un environnement Trusted Space, aura accès à la clé utilisée pour le chiffrement et pourra déchiffrer la requête dans un environnement de confiance. L'accès à la clé de chiffrement sera protégé par le pool d'identités de charge de travail. Grâce aux garanties d'isolation de Trusted Space, même l'opérateur de charge de travail ne peut pas accéder à la clé utilisée pour le chiffrement ni au contenu déchiffré.
- Inférence sécurisée à l'aide d'un ou de plusieurs accélérateurs : le serveur d'inférence sera lancé sur une VM protégée (dans le cadre de la configuration de Trusted Space), ce qui garantira que l'instance de charge de travail n'a pas été compromise par un logiciel malveillant ou un rootkit opérant au niveau des secteurs de démarrage et du noyau. Ce serveur déchiffre la requête dans l'environnement Trusted Space, effectue l'inférence à l'aide du modèle de génération de code et renvoie le code généré à l'employé.
2. Configurer les ressources cloud
Avant de commencer
- Clone ce dépôt à l'aide de la commande ci-dessous pour obtenir les scripts requis utilisés dans cet atelier de programmation.
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
- Modifiez le répertoire de cet atelier de programmation.
cd confidential-space/codelabs/trusted_space_codelab/scripts
- Assurez-vous d'avoir défini les variables d'environnement de projet requises, comme indiqué ci-dessous. Pour en savoir plus sur la configuration d'un projet GCP, consultez cet atelier de programmation. Vous pouvez vous y référer pour obtenir des informations sur la récupération de l'ID de projet et sur la différence entre le nom, l'ID et le numéro de projet.
export PRIMUS_PROJECT_ID=<GCP project id of Primus>
- Activez la facturation pour vos projets.
- Activez l'API Confidential Computing et les API suivantes pour les deux projets.
gcloud services enable \
cloudapis.googleapis.com \
cloudresourcemanager.googleapis.com \
cloudkms.googleapis.com \
cloudshell.googleapis.com \
container.googleapis.com \
containerregistry.googleapis.com \
iam.googleapis.com \
confidentialcomputing.googleapis.com
- Attribuez des valeurs aux variables pour les noms de ressources spécifiés ci-dessus à l'aide de la commande suivante. Ces variables vous permettent de personnaliser les noms de ressources selon vos besoins et d'utiliser des ressources existantes si elles ont déjà été créées. (par exemple,
export PRIMUS_SERVICE_ACCOUNT='my-service-account')
- Vous pouvez définir les variables suivantes avec les noms de ressources cloud existants dans le projet Primus. Si la variable est définie, la ressource cloud existante correspondante du projet Primus est utilisée. Si la variable n'est pas définie, le nom de la ressource cloud est généré à partir du nom du projet, et une nouvelle ressource cloud est créée avec ce nom. Voici les variables compatibles pour les noms de ressources :
| Région dans laquelle les ressources régionales seront créées pour Primus Company. |
| Emplacement où les ressources seront créées pour Primus Company. |
| Zone dans laquelle les ressources zonales seront créées pour Primus Company. |
| Pool d'identités de charge de travail de Primus Company pour protéger les ressources cloud. |
| Fournisseur de pool d'identités de charge de travail de Primus Company, qui inclut la condition d'autorisation à utiliser pour les jetons signés par le service de validation d'attestation. |
| Compte de service de Primus Company que |
| La clé KMS est utilisée pour chiffrer les requêtes fournies par les employés de Primus Company. |
| Le trousseau de clés KMS qui sera utilisé pour créer la clé de chiffrement |
| Version de la clé KMS de la clé de chiffrement |
| Dépôt d'artefacts dans lequel l'image Docker de la charge de travail sera transférée. |
| Région du dépôt d'artefacts qui contiendra l'image Docker de la charge de travail publiée. |
| Nom de la VM de charge de travail. |
| Nom de l'image Docker de la charge de travail. |
| Tag de l'image de conteneur de la charge de travail. |
| Compte de service autorisé à accéder à la VM confidentielle qui exécute la charge de travail. |
| Nom de la VM cliente qui exécutera l'application cliente du serveur d'inférence. |
| Compte de service utilisé par |
- Vous aurez besoin des rôles Administrateur de l'espace de stockage, Administrateur d'Artifact Registry, Administrateur Cloud KMS, Administrateur de compte de service et Administrateur de pool d'identités de charge de travail IAM pour le projet
$PRIMUS_PROJECT_ID. Consultez ce guide pour savoir comment attribuer des rôles IAM à l'aide de la console GCP. - Pour le
$PRIMUS_PROJECT_ID, exécutez le script suivant afin de définir les noms de variables restants sur des valeurs basées sur l'ID de votre projet pour les noms de ressources.
source config_env.sh
Configurer les ressources de Primus Company
Au cours de cette étape, vous allez configurer les ressources cloud requises pour Primus. Exécutez le script suivant pour configurer les ressources de Primus. Les ressources suivantes seront créées lors de l'exécution du script :
- Clé de chiffrement (
$PRIMUS_ENC_KEY) et trousseau de clés ($PRIMUS_ENC_KEYRING) dans KMS pour chiffrer le fichier de données client de Primus Company. - Pool d'identités de charge de travail (
$PRIMUS_WORKLOAD_IDENTITY_POOL) pour valider les revendications en fonction des conditions d'attribut configurées sous son fournisseur. - Le compte de service (
$PRIMUS_SERVICE_ACCOUNT) associé au pool d'identités de charge de travail mentionné ci-dessus ($PRIMUS_WORKLOAD_IDENTITY_POOL) est autorisé à déchiffrer les données à l'aide de la clé KMS (à l'aide du rôleroles/cloudkms.cryptoKeyDecrypter), à chiffrer les données à l'aide de la clé KMS (à l'aide du rôleroles/cloudkms.cryptoKeyEncrypter), à lire les données du bucket Cloud Storage (à l'aide du rôleobjectViewer) et à connecter le compte de service au pool d'identités de charge de travail (à l'aide du rôleroles/iam.workloadIdentityUser).
./setup_primus_resources.sh
3. Créer une charge de travail
Créer un compte de service de charge de travail
Vous allez maintenant créer un compte de service pour la charge de travail avec les rôles et autorisations requis. Exécutez le script suivant pour créer un compte de service de charge de travail dans le projet Primus. Ce compte de service sera utilisé par la VM qui exécute le serveur d'inférence.
Ce compte de service de charge de travail ($WORKLOAD_SERVICEACCOUNT) disposera des rôles suivants :
confidentialcomputing.workloadUserpour obtenir un jeton d'attestationlogging.logWriterpour écrire des journaux dans Cloud Logging.
./create_workload_service_account.sh
Créer une charge de travail
Au cours de cette étape, vous allez créer une image Docker de charge de travail. La charge de travail sera créée par Primus Company. La charge de travail utilisée dans cet atelier de programmation est un code Python qui utilise le modèle codegemma à partir du bucket GCS disponible publiquement (du Vertex Model Garden). La charge de travail chargera le modèle codegemma et lancera le serveur d'inférence qui traitera les requêtes de génération de code des développeurs de Primus.
Dans la requête de génération de code, la charge de travail recevra la DEK encapsulée ainsi qu'une requête chiffrée. La charge de travail effectuera ensuite l'appel d'API KMS pour déchiffrer la DEK, puis déchiffrera la requête à l'aide de cette DEK. Les clés de chiffrement (pour la DEK) seront protégées via le pool d'identités de charge de travail, et l'accès sera accordé aux charges de travail qui répondent aux conditions d'attribut. Ces conditions d'attribut sont décrites plus en détail dans la section suivante sur l'autorisation de la charge de travail. Une fois que le serveur d'inférence dispose de la requête déchiffrée, il génère le code à l'aide d'un modèle chargé et renvoie la réponse.
Exécutez le script suivant pour créer une charge de travail dans laquelle les étapes suivantes sont effectuées :
- Créez un dépôt d'artefacts(
$PRIMUS_ARTIFACT_REGISTRY) appartenant à Primus. - Mettez à jour le code de la charge de travail avec les noms de ressources requis.
- Créez la charge de travail du serveur d'inférence et créez un Dockerfile pour créer une image Docker du code de la charge de travail. Voici le Dockerfile utilisé pour cet atelier de programmation.
- Créez et publiez l'image Docker dans Artifact Registry (
$PRIMUS_ARTIFACT_REGISTRY) appartenant à Primus. - Accordez à
$WORKLOAD_SERVICEACCOUNTl'autorisation de lecture pour$PRIMUS_ARTIFACT_REGISTRY. Cela est nécessaire pour que le conteneur de charge de travail puisse extraire l'image Docker de la charge de travail d'Artifact Registry.
./create_workload.sh
Pour référence, voici la méthode generate() de la charge de travail créée et utilisée dans cet atelier de programmation (vous trouverez l'intégralité du code de la charge de travail ici).
def generate():
try:
data = request.get_json()
ciphertext = base64.b64decode(data["ciphertext"])
wrapped_dek = base64.b64decode(data["wrapped_dek"])
unwrapped_dek_response = kms_client.decrypt(
request={"name": key_name, "ciphertext": wrapped_dek}
)
unwrapped_dek = unwrapped_dek_response.plaintext
f = Fernet(unwrapped_dek)
plaintext = f.decrypt(ciphertext)
prompt = plaintext.decode("utf-8")
tokens = tokenizer(prompt, return_tensors="pt")
outputs = model.generate(**tokens, max_new_tokens=128)
generated_code = tokenizer.decode(outputs[0])
generated_code_bytes = generated_code.encode("utf-8")
response = f.encrypt(generated_code_bytes)
ciphertext_base64 = base64.b64encode(response).decode("utf-8")
response = {"generated_code_ciphertext": ciphertext_base64}
return jsonify(response)
except (ValueError, TypeError, KeyError) as e:
return jsonify({"error": str(e)}), 500
4. Autoriser et exécuter la charge de travail
Autoriser la charge de travail
Primus souhaite autoriser les charges de travail à accéder à sa clé KMS utilisée pour le chiffrement des requêtes en fonction des attributs des ressources suivantes :
- _Quoi_ : code vérifié
- Où : environnement sécurisé
- Qui : opérateur de confiance
Primus utilise la fédération d'identité de charge de travail pour appliquer une stratégie d'accès basée sur ces exigences. La fédération d'identité de charge de travail vous permet de spécifier des conditions d'attribut. Ces conditions limitent les identités qui peuvent s'authentifier auprès du pool d'identités de charge de travail (WIP). Vous pouvez ajouter le service de validation d'attestation au pool d'identités de charge de travail en tant que fournisseur de pool d'identités de charge de travail pour présenter les mesures et appliquer la stratégie.
Le pool d'identités de charge de travail a déjà été créé lors de l'étape de configuration des ressources cloud. Primus va maintenant créer un fournisseur de pool d'identités de charge de travail OIDC. Le --attribute-condition spécifié autorise l'accès au conteneur de charge de travail. Cela nécessite :
- Quoi : dernière
$WORKLOAD_IMAGE_NAMEimportée dans le dépôt$PRIMUS_ARTIFACT_REPOSITORY. - Où : l'environnement d'exécution sécurisé Confidential Space s'exécute sur l'image de VM Confidential Space entièrement compatible.
- Qui : compte de service
$WORKLOAD_SERVICE_ACCOUNTde Primus.
export WORKLOAD_IMAGE_DIGEST=$(gcloud artifacts docker images describe ${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG --format="value(image_summary.digest)" --project ${PRIMUS_PROJECT_ID})
gcloud iam workload-identity-pools providers create-oidc $PRIMUS_WIP_PROVIDER \
--location="global" \
--project="$PRIMUS_PROJECT_ID" \
--workload-identity-pool="$PRIMUS_WORKLOAD_IDENTITY_POOL" \
--issuer-uri="https://confidentialcomputing.googleapis.com/" \
--allowed-audiences="https://sts.googleapis.com" \
--attribute-mapping="google.subject='assertion.sub'" \
--attribute-condition="assertion.swname == 'HARDENED_SHIELDED' && assertion.hwmodel == 'GCP_SHIELDED_VM' &&
assertion.submods.container.image_digest == '${WORKLOAD_IMAGE_DIGEST}' &&
assertion.submods.container.image_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' &&
'$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"
La commande ci-dessus vérifie que la charge de travail s'exécute dans un environnement Trusted Space en vérifiant que hwmodel est défini sur "GCP_SHIELDED_VM" et que swname est défini sur "HARDENED_SHIELDED". De plus, elle inclut des assertions spécifiques à la charge de travail, telles que image_digest et image_reference, pour renforcer la sécurité et garantir l'intégrité de la charge de travail en cours d'exécution.
Exécuter la charge de travail
Au cours de cette étape, nous allons exécuter la charge de travail dans la VM Trusted Space à laquelle un accélérateur sera associé. Les arguments TEE requis sont transmis à l'aide de l'indicateur de métadonnées. Les arguments du conteneur de charge de travail sont transmis à l'aide de la partie "tee-cmd" de l'indicateur. Pour équiper la VM de charge de travail d'un GPU Nvidia Tesla T4, nous utiliserons l'indicateur --accelerator=type=nvidia-tesla-t4,count=1. Cela associera un GPU à la VM. Nous devrons également inclure tee-install-gpu-driver=true dans les indicateurs de métadonnées pour déclencher l'installation du pilote de GPU approprié.
gcloud compute instances create ${WORKLOAD_VM} \
--accelerator=type=nvidia-tesla-t4,count=1 \
--machine-type=n1-standard-16 \
--shielded-secure-boot \
--image-project=conf-space-images-preview \
--image=confidential-space-0-gpupreview-796705b \
--zone=${PRIMUS_PROJECT_ZONE} \
--maintenance-policy=TERMINATE \
--boot-disk-size=40 \
--scopes=cloud-platform \
--service-account=${WORKLOAD_SERVICEACCOUNT}@${PRIMUS_PROJECT_ID}.iam.gserviceaccount.com \
--metadata="^~^tee-image-reference=${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_ARTIFACT_REPOSITORY}/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}~tee-install-gpu-driver=true~tee-restart-policy=Never"
Exécuter une requête d'inférence
Une fois le serveur d'inférence de la charge de travail lancé, les employés de Primus Company peuvent envoyer les requêtes de génération de code au serveur d'inférence.
Dans le cadre de cet atelier de programmation, nous utiliserons le script suivant pour configurer l'application cliente qui interagira avec le serveur d'inférence. Exécutez ce script pour configurer la VM cliente.
./setup_client.sh
Les étapes suivantes montrent comment se connecter à la VM cliente via SSH et exécuter un exemple d'application cliente dans un environnement virtuel Python. Cet exemple d'application utilise le chiffrement encapsulé avec la bibliothèque Fernet, mais n'oubliez pas que les bibliothèques de chiffrement spécifiques peuvent être adaptées à différents cas d'utilisation.
gcloud compute ssh ${CLIENT_VM} --zone=${PRIMUS_PROJECT_ZONE}
Exécutez les commandes suivantes pour activer l'environnement virtuel Python dans la VM cliente et exécuter l'application cliente.
source venv/bin/activate
python3 inference_client.py
La sortie de cet exemple d'application cliente affiche les requêtes de chiffrement et de texte brut, ainsi que leurs réponses chiffrées et déchiffrées correspondantes.
5. Effectuer un nettoyage
Voici le script qui peut être utilisé pour nettoyer les ressources que nous avons créées dans le cadre de cet atelier de programmation. Lors de ce nettoyage, les ressources suivantes seront supprimées :
- Compte de service Primus (
$PRIMUS_SERVICEACCOUNT). - Clé de chiffrement Primus (
$PRIMUS_ENC_KEY). - Dépôt d'artefacts de Primus (
$PRIMUS_ARTIFACT_REPOSITORY). - Pool d'identités de charge de travail Primus (
$PRIMUS_WORKLOAD_IDENTITY_POOL) avec son fournisseur. - Compte de service de charge de travail Primus (
$WORKLOAD_SERVICEACCOUNT). - VM de charge de travail (
$WORKLOAD_VM) et VM cliente ($CLIENT_VM).
./cleanup.sh
Si vous avez terminé votre exploration, veuillez envisager de supprimer votre projet.
- Accédez à la console Cloud Platform.
- Sélectionnez le projet que vous souhaitez arrêter, puis cliquez sur "Supprimer" en haut de la page. Le projet sera alors programmé pour être supprimé.