Organiser un compartiment de documents

CloudflareBeginner
Pratiquer maintenant

Introduction

Votre équipe d’assistance a besoin d’un petit espace de stockage pour ses documents. Un objet contient les octets d’un fichier et ses métadonnées ; un compartiment regroupe les objets et une clé correspond au nom complet d’un objet. Les barres obliques dans les clés forment des préfixes utiles, mais elles ne créent pas de répertoires ordinaires comme dans un système de fichiers. Vous allez créer un compartiment privé, téléverser deux documents synthétiques, examiner leurs métadonnées, télécharger leurs octets exacts, puis supprimer uniquement le document sélectionné avant de procéder au nettoyage.

Commencez par terminer Connecter LabEx à votre compte Cloudflare. Ce laboratoire vous apprend à utiliser le terminal LabEx, l’autorisation de l’appareil, la confirmation du compte d’apprentissage et la configuration de l’ID de compte. Ce laboratoire démarre indépendamment dans /home/labex/project/r2-lab, avec Node.js 22.22.0, Wrangler 4.131.1 et AWS SDK 3.888.0 déjà préparés. Sur votre propre ordinateur, installez d’abord Node.js, puis installez Wrangler et AWS SDK comme dépendances du projet avec npm install.

Avant de commencer : votre compte d’apprentissage doit disposer d’un abonnement R2 actif. La page Configuration de R2 de Cloudflare inclut un parcours de paiement ; consultez-la vous-même si R2 n’est pas actif. Un compte Free n’active pas automatiquement R2. Consultez la page tarification pour connaître les frais de stockage et d’opération. Cet exercice utilise de petits fichiers synthétiques et aucun domaine acheté. Vous devez disposer de l’autorisation de gérer les compartiments et de créer un jeton R2 utilisateur limité à ce nouveau compartiment. Laissez l’accès public désactivé. Ne collez jamais d’identifiants dans cette leçon, dans une discussion ou dans des captures d’écran.

Créer votre compartiment privé de documents

Dans cette étape, vous autorisez cette VM et créez un compartiment temporaire. L’autorisation de l’appareil confirme votre compte d’apprentissage. La gestion des compartiments R2 utilise un jeton d’API distinct, limité à ce compte.

Lancez Bash pour utiliser la syntaxe des commandes présentées ci-dessous, puis accédez au projet préparé et vérifiez ses outils. Gardez ce même terminal ouvert afin que les variables contenant les noms de ressources restent disponibles :

bash
cd /home/labex/project/r2-lab
export PATH="$PWD/.tools/node-v22.22.0-linux-x64/bin:$PATH"
node --version
npx wrangler --version

Autorisez le code d’appareil affiché dans votre propre navigateur. Confirmez le compte d’apprentissage ainsi que les autorisations de lecture du compte et de l’utilisateur demandées avant d’accorder votre consentement :

npx wrangler login --device --browser=false --scopes account:read user:read
npx wrangler whoami --json

Vérifiez que loggedIn: true est présent. Lisez le nom du compte, même si un seul compte est répertorié. Remplacez YOUR_ACCOUNT_ID ci-dessous par l’ID réel de 32 caractères de ce compte. openssl rand -hex 6 génère douze caractères hexadécimaux aléatoires afin d’éviter tout conflit avec une exécution précédente. Le document here-doc crée un fichier de configuration standard ; le shell y remplace vos variables par leurs valeurs.

ACCOUNT_ID=YOUR_ACCOUNT_ID
RUN_ID=$(openssl rand -hex 6)
NAME="labex-c05-r01-$RUN_ID"
BUCKET="$NAME-docs"
cat > wrangler.jsonc <<JSON
{"name":"$NAME","account_id":"$ACCOUNT_ID","compatibility_date":"2026-07-30","r2_buckets":[{"binding":"DOCUMENTS","bucket_name":"$BUCKET"}]}
JSON

Pour gérer les compartiments, ouvrez la page API Tokens de votre profil Cloudflare et créez un jeton personnalisé portant un nom lié à ce laboratoire. Accordez l’autorisation Account → Workers R2 Storage → Edit, puis limitez Account Resources au compte d’apprentissage dont vous avez enregistré l’ID. Définissez une courte durée d’expiration. N’incluez aucun autre compte ni aucune autorisation sans rapport. Cette autorisation au niveau du compte permet de créer et de supprimer des compartiments ; le jeton limité aux objets de l’étape suivante ne le permet pas.

Copiez le jeton une seule fois dans cette invite masquée de la VM. umask 077 limite l’accès au fichier à votre utilisateur ; read -s masque la saisie. Le fichier utilise la variable de jeton standard de Wrangler et est exclu de Git.

umask 077
read -r -s -p 'R2 management API token: ' R2_MANAGEMENT_TOKEN; printf '\n'
printf 'CLOUDFLARE_API_TOKEN=%s\n' "$R2_MANAGEMENT_TOKEN" > .env.management
unset R2_MANAGEMENT_TOKEN

Utilisez --env-file=.env.management uniquement pour les commandes de gestion R2 ; la commande whoami ordinaire continue de vérifier l’autorisation de l’appareil de la VM.

Placez --env-file à la fin de chaque commande Wrangler pour que sa liste de fichiers ne soit pas étendue au nom de la commande. Après la création de chaque compartiment, si Wrangler propose d’ajouter une liaison à la configuration, saisissez n et appuyez sur Entrée. La configuration contient déjà la liaison prévue.

npx wrangler r2 bucket create "$BUCKET" --env-file=.env.management

Répertoriez vos compartiments et repérez le nom généré exact. Les autres compartiments appartiennent à d’autres travaux ; ne les modifiez pas.

npx wrangler r2 bucket list --env-file=.env.management

Dans le tableau de bord, ouvrez Storage & databases → R2 → Overview, sélectionnez ce compartiment précis et vérifiez que la liste des objets est vide. Dans ses paramètres, laissez l’URL de développement publique et les domaines personnalisés désactivés. Le nom du compartiment dans le tableau de bord confirme son identité ; les vérifications de téléchargement ultérieures prouveront que les octets stockés sont corrects.

Bucket privé Standard sans objets

Cet exemple montre le stockage Standard et Public Access Disabled. Le nom de votre bucket généré sera différent.

Téléverser des documents avec des métadonnées

Dans cette étape, vous donnez au SDK un accès limité à ce compartiment et vous y stockez deux documents. Le type de contenu indique à un client comment interpréter les octets ; les métadonnées personnalisées stockent vos propres étiquettes courtes avec l’objet. Ni l’un ni l’autre ne constitue une règle de contrôle d’accès.

L’API compatible S3 permet aux SDK de stockage standard d’accéder à R2. Elle utilise une paire de clés d’accès distincte du jeton d’appareil de Wrangler. Dans R2 Overview, utilisez Account Details → Manage API Tokens, puis créez un User API token portant un nom lié au nom de ressource généré pour ce laboratoire. Choisissez Object Read & Write, limitez-le à ce nouveau compartiment précis et sélectionnez une courte durée d’expiration si le formulaire le propose. Ne choisissez ni tous les compartiments ni l’accès Admin. Gardez cette page de jeton ouverte jusqu’à ce que vous ayez enregistré le secret affiché une seule fois.

Utilisez les invites Bash suivantes dans la VM. read -s masque la saisie ; umask 077 rend le fichier d’identifiants lisible uniquement par votre utilisateur. Ces noms correspondent aux variables d’environnement standard de l’AWS SDK. Collez l’Access Key ID et la Secret Access Key dans les invites correspondantes, puis appuyez sur Entrée. Ne collez pas la valeur du jeton d’API général.

Dans le formulaire du jeton, choisissez 24 hours sous TTL, puis vérifiez le compartiment exact et l’autorisation Object Read & Write avant de créer le jeton. Révoquez-le à la fin du laboratoire ; l’expiration n’est qu’une mesure de secours.

umask 077
read -r -s -p 'Access Key ID: ' AWS_ACCESS_KEY_ID; printf '\n'
read -r -s -p 'Secret Access Key: ' AWS_SECRET_ACCESS_KEY; printf '\n'
printf 'AWS_ACCESS_KEY_ID=%s\nAWS_SECRET_ACCESS_KEY=%s\n' "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" > .env.s3
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY

Écrivez un client réutilisable du SDK standard. Le SDK nécessite une chaîne de région ; R2 utilise auto. La lecture de la configuration existante permet de diriger les opérations de l’interface de ligne de commande et du SDK vers le même compte et le même compartiment.

cat > storage.mjs <<'JS'
import { S3Client } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
const config = JSON.parse(readFileSync("wrangler.jsonc", "utf8"));
export const Bucket = config.r2_buckets[0].bucket_name;
export const s3 = new S3Client({
  region: "auto",
  endpoint: `https://${config.account_id}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
  }
});
JS

Créez maintenant le programme de téléversement. PutObjectCommand stocke les octets à la clé indiquée. Les deux documents sont synthétiques ; le manuel conservé prouvera qu’une suppression sélective ultérieure n’efface pas les autres clés.

cat > upload.mjs <<'JS'
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new PutObjectCommand({
  Bucket, Key: "documents/report.txt", Body: readFileSync("document.txt"),
  ContentType: "text/plain", Metadata: { team: "blue", revision: "1" }
}));
await s3.send(new PutObjectCommand({
  Bucket, Key: "retained/handbook.txt", Body: readFileSync("retained.txt"),
  ContentType: "text/plain"
}));
console.log("Uploaded two synthetic documents");
JS

--env-file charge les valeurs des identifiants sans les afficher :

node --env-file=.env.s3 upload.mjs

La ligne de réussite s’affiche uniquement après la fin des deux appels d’API attendus. La vérification de la plateforme lit séparément les vrais objets et leurs métadonnées.

Répertorier les métadonnées et comparer les octets téléchargés

Dans cette étape, vous examinez les clés sans télécharger chaque objet, puis vous récupérez le rapport. ListObjectsV2 répertorie les clés, tandis que HeadObject récupère uniquement les métadonnées. Ce petit compartiment tient sur une seule page de résultats ; en production, les listes doivent suivre les jetons de continuation lorsque IsTruncated vaut true.

cat > inspect.mjs <<'JS'
import { ListObjectsV2Command, HeadObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { writeFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log(page.Contents.map(object => object.Key));
const metadata = await s3.send(new HeadObjectCommand({ Bucket, Key: "documents/report.txt" }));
console.log({ contentType: metadata.ContentType, metadata: metadata.Metadata });
const object = await s3.send(new GetObjectCommand({ Bucket, Key: "documents/report.txt" }));
writeFileSync("download.txt", await object.Body.transformToByteArray());
JS
node --env-file=.env.s3 inspect.mjs

La liste contient documents/report.txt et retained/handbook.txt. Le rapport possède le type text/plain, ainsi que les métadonnées team: blue et revision: 1. L’ordre d’affichage des métadonnées peut varier.

cmp compare les octets et n’affiche rien lorsque les fichiers correspondent. Le message suivant apparaît uniquement si la comparaison réussit :

cmp document.txt download.txt && printf "Downloaded bytes match\n"

Actualisez la liste des objets du même compartiment dans le tableau de bord et ouvrez les détails du rapport. Comparez sa clé et son type de contenu avec la sortie du SDK. Si le tableau de bord actuel n’affiche pas les métadonnées personnalisées, utilisez la sortie de la CLI comme preuve concernant les métadonnées.

Type, métadonnées personnalisées et aperçu du rapport

Cet exemple montre text/plain, revision 1, team blue et un aperçu du rapport synthétique. Le nom du bucket et la date de création seront différents.

Supprimer uniquement le rapport sélectionné

Dans cette étape, vous supprimez une clé d’objet complète tout en conservant le manuel. Un préfixe n’est pas un répertoire que l’on peut supprimer récursivement ; transmettez exactement la clé du rapport à l’API.

cat > remove-report.mjs <<'JS'
import { DeleteObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new DeleteObjectCommand({ Bucket, Key: "documents/report.txt" }));
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log(page.Contents.map(object => object.Key));
JS
node --env-file=.env.s3 remove-report.mjs

Il ne reste que retained/handbook.txt. La vérification de la plateforme télécharge également le manuel afin de confirmer que son contenu reste inchangé. Exécutez cette vérification avant de procéder au nettoyage complet.

Nettoyer le compartiment dont vous êtes propriétaire

Dans cette étape, vous supprimez l’objet restant, puis son compartiment vide. Gardez vos identifiants actifs jusqu’à la confirmation de la suppression distante.

cat > cleanup.mjs <<'JS'
import { DeleteObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new DeleteObjectCommand({ Bucket, Key: "retained/handbook.txt" }));
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log("Remaining objects:", page.KeyCount);
JS
node --env-file=.env.s3 cleanup.mjs

Vérifiez que Remaining objects: 0 s’affiche. Si vous avez ouvert un nouveau terminal, lisez le nom généré du compartiment dans la configuration ; node -p affiche ce seul champ.

BUCKET=$(node -p "JSON.parse(require('fs').readFileSync('wrangler.jsonc')).r2_buckets[0].bucket_name")
npx wrangler r2 bucket delete "$BUCKET" --env-file=.env.management

Lorsque vous y êtes invité, confirmez uniquement le compartiment exact du laboratoire. Répertoriez à nouveau les compartiments ; la liste obtenue avec succès ne doit plus contenir ce nom. Une erreur d’authentification ou de réseau ne prouve pas que la suppression a réussi.

npx wrangler r2 bucket list --env-file=.env.management

Actualisez la même liste dans le tableau de bord, puis exécutez la vérification de la plateforme de cette étape tout en restant connecté.

Révoquer l’identifiant du laboratoire et se déconnecter

Dans cette étape, vous fermez les accès laissés par cet exercice. Dans la page R2 API Tokens, révoquez uniquement le jeton d’objet portant le nom de ce laboratoire. Dans la page API Tokens de votre profil, révoquez le jeton de gestion R2 distinct que vous avez créé pour ce laboratoire. La suppression d’un compartiment ne révoque pas un jeton, et la déconnexion de Wrangler ne révoque pas les identifiants S3.

Après la révocation, supprimez le fichier d’identifiants local et déconnectez cette VM :

rm .env.s3 .env.management
npx wrangler logout

Examinez l’identité structurée. Son code de sortie différent de zéro est attendu lorsque vous êtes déconnecté :

npx wrangler whoami --json || true

Vérifiez que loggedIn: false est présent ; conservez votre session ordinaire dans le tableau de bord. Les vérifications de la plateforme contrôlent la suppression des identifiants locaux et la déconnexion de Wrangler. Les deux révocations de jetons sont des vérifications manuelles dans le tableau de bord pour ce laboratoire ; elles ne sont pas déduites de la suppression des fichiers.

Résumé

Vous avez créé un compartiment R2 privé, stocké des octets et des métadonnées d’objets, répertorié et téléchargé des documents, vérifié une suppression sélective, puis nettoyé les accès au compartiment.