1. Présentation
Prêt à améliorer la sécurité et la confidentialité de vos charges de travail accélérées par GPU ? Cet atelier de programmation vous guidera à travers les fonctionnalités de Trusted Space, une offre qui fournit une isolation des opérateurs et une compatibilité avec les accélérateurs renforcées pour vos charges de travail d'IA/de ML sensibles.
Il est plus important que jamais de protéger les données, les modèles et les clés de valeur. Trusted Space offre une solution en veillant à ce que vos charges de travail fonctionnent dans un environnement sécurisé et fiable auquel même l'opérateur de charge de travail n'a pas accès.
Voici ce que propose l'espace vérifié :
- Confidentialité et sécurité renforcées : Trusted Space fournit un environnement d'exécution sécurisé où vos composants sensibles (par exemple, les modèles, les données précieuses et les clés) restent protégés grâce à des preuves cryptographiques.
- Isolation de l'opérateur : éliminez les problèmes d'interférence de l'opérateur. Avec Trusted Space, même vos opérateurs de charge de travail n'ont pas accès à vos données. Ils ne peuvent donc pas utiliser SSH, accéder aux données, installer des logiciels ni altérer votre code.
- Compatibilité avec les accélérateurs : Trusted Space est conçu pour fonctionner de manière fluide avec un large éventail d'accélérateurs matériels, y compris les GPU tels que H100, A100, T4 et L4. Cela permet de s'assurer que vos applications d'IA/de ML critiques pour les performances s'exécutent sans problème.
Points abordés
- Comprendre les principales offres de Trusted Space.
- Découvrez comment déployer et configurer un environnement Trusted Space pour sécuriser les ressources précieuses de votre charge de travail d'IA/ML.
Prérequis
- Un projet Google Cloud Platform
- Connaissances de base sur Google Compute Engine et les accélérateurs.
- Connaissances de base des comptes de service, de la gestion des clés, de la fédération d'identité de charge de travail et des conditions d'attributs.
- Connaissances de base sur les conteneurs et Artifact Registry
Protéger les requêtes de génération de code sensibles avec Primus Company
Dans cet atelier de programmation, nous allons nous mettre dans la peau 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, ils souhaitent protéger la confidentialité des requêtes envoyées par leurs employés, car elles contiennent souvent des extraits de code sensibles, des détails de projets internes ou des algorithmes propriétaires.
Pourquoi la société Primus ne fait-elle pas confiance à l'opérateur ?
Primus Corp opère sur un marché très concurrentiel. Leur base de code contient une propriété intellectuelle précieuse, y compris des algorithmes propriétaires et des extraits de code sensibles qui leur offrent un avantage concurrentiel. Ils craignent 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 "à connaître" que Primus Corp souhaite protéger.
Pour résoudre ce problème, 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 chiffre à 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 le 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 cet atelier de programmation, nous allons utiliser cet exemple d'application cliente avec le chiffrement d'enveloppe.
- Isolation de l'opérateur : 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 l'invite dans un environnement de confiance. L'accès à la clé de chiffrement serait 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 plusieurs accélérateurs : le serveur d'inférence est lancé sur une VM protégée (dans le cadre de la configuration de l'espace de confiance), ce qui garantit que l'instance de charge de travail n'a pas été compromise par des logiciels malveillants ou des rootkits au niveau du démarrage ou 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 des ressources cloud
Avant de commencer
- Clonez 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
- Accédez au 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 du projet requises, comme indiqué ci-dessous. Pour en savoir plus sur la configuration d'un projet GCP, consultez cet atelier de programmation. Pour savoir comment récupérer l'ID d'un projet et en quoi il diffère du nom et du numéro du projet, consultez cette page.
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 les 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 acceptées pour les noms de ressources :
| Région dans laquelle les ressources régionales seront créées pour l'entreprise Primus. |
| Emplacement où les ressources seront créées pour l'entreprise Primus. |
| Zone dans laquelle les ressources zonales seront créées pour l'entreprise Primus. |
| Pool d'identités de charge de travail de l'entreprise Primus pour protéger les ressources cloud. |
| Fournisseur de pool d'identités de charge de travail de l'entreprise Primus, qui inclut la condition d'autorisation à utiliser pour les jetons signés par le service de validation d'attestation. |
| Compte de service de l'entreprise Primus utilisé par |
| La clé KMS est utilisée pour chiffrer les requêtes fournies par les employés de l'entreprise Primus. |
| 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 contenant 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 du conteneur de 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 Storage, Administrateur 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. Pour savoir comment attribuer des rôles IAM à l'aide de la console GCP, consultez ce guide. - Pour
$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 l'entreprise Primus
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 l'entreprise Primus. - Pool d'identités de charge de travail (
$PRIMUS_WORKLOAD_IDENTITY_POOL) pour valider les revendications en fonction des conditions d'attributs 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) a accès au déchiffrement des données à l'aide de la clé KMS (avec le rôleroles/cloudkms.cryptoKeyDecrypter), au chiffrement des données à l'aide de la clé KMS (avec le rôleroles/cloudkms.cryptoKeyEncrypter), à la lecture des données du bucket Cloud Storage (avec le rôleobjectViewer) et à la connexion du compte de service au pool d'identités de charge de travail (avec le 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 serait créée par l'entreprise Primus. La charge de travail utilisée dans cet atelier de programmation est un code Python qui utilise le modèle codegemma du bucket GCS disponible publiquement (de Vertex Model Garden). La charge de travail chargera le modèle codegemma et lancera le serveur d'inférence qui répondra aux demandes 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 obtient la clé DEK encapsulée ainsi qu'une invite chiffrée. La charge de travail effectue ensuite l'appel d'API KMS pour déchiffrer la DEK, puis déchiffre l'invite à l'aide de cette DEK. Les clés de chiffrement (pour les DEK) seraient protégées par le biais du pool d'identités de charge de travail, et l'accès serait accordé aux charges de travail qui remplissent les 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 a reçu 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 Artifact Registry(
$PRIMUS_ARTIFACT_REGISTRY) appartenant à Primus. - Mettez à jour le code de la charge de travail avec les noms des ressources requises.
- Créez la charge de travail du serveur d'inférence et le 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 le registre Artifact Registry (
$PRIMUS_ARTIFACT_REGISTRY) appartenant à Primus. - Accordez l'autorisation de lecture
$WORKLOAD_SERVICEACCOUNTpour$PRIMUS_ARTIFACT_REGISTRY. Cela est nécessaire pour que le conteneur de charge de travail puisse extraire l'image Docker de charge de travail à partir d'Artifact Registry.
./create_workload.sh
Pour votre information, 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 validé
- Où : un environnement sécurisé
- Qui : un opérateur de confiance
Primus utilise la fédération d'identité de charge de travail pour appliquer une règle 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 avec le pool d'identités de charge de travail. 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 pools 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 :
- Description : la dernière version de
$WORKLOAD_IMAGE_NAMEa été importé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 Primus
$WORKLOAD_SERVICE_ACCOUNT.
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". Il inclut également 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
Dans 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. Un GPU sera alors associé à 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 charge de travail lancé, les employés de Primus peuvent envoyer des requêtes de génération de code au serveur d'inférence.
Dans 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 en SSH à la VM cliente et exécuter un exemple d'application cliente dans un environnement virtuel Python. Cette application exemple utilise le chiffrement d'enveloppe 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 affichera les demandes d'invite de chiffrement et en texte brut, ainsi que les 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 cet atelier de programmation. Dans le cadre 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 de Primus (
$WORKLOAD_SERVICEACCOUNT). - VM de charge de travail (
$WORKLOAD_VM) et VM cliente ($CLIENT_VM).
./cleanup.sh
Si vous avez terminé l'exploration, pensez à 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 est alors programmé pour suppression.