Gérer et déployer les règles de sécurité Firebase

Firebase vous fournit plusieurs outils pour gérer vos Rules. Chacun d'eux est utile dans des cas particuliers et utilise la même API de gestion des règles de sécurité Firebase de backend.

Quel que soit l'outil utilisé pour l'appeler, l'API Management :

  • Ingère une source de règles : un ensemble de règles, généralement un fichier de code contenant des instructions Firebase Security Rules.
  • Stocke la source ingérée en tant que ensemble de règles immuable.
  • Suit le déploiement de chaque ensemble de règles dans une version. Les services compatibles avec les règles de sécurité Firebase recherchent la version d'un projet pour évaluer chaque demande de ressource sécurisée.
  • Permet d'exécuter des tests syntaxiques et sémantiques sur un ensemble de règles.

Utiliser la CLI Firebase

La CLI Firebase vous permet d'importer des sources locales et de déployer des versions. La CLI Firebase Local Emulator Suite vous permet d'effectuer des tests locaux complets des sources.

Si vous utilisez l'interface de ligne de commande, vous pouvez bénéficier du contrôle de version pour conserver vos règles comme le code de votre application et pour les déployer dans le cadre du processus de déploiement existant.

Générer un fichier de configuration

Lorsque vous configurez votre projet Firebase à l'aide de la CLI Firebase, vous créez un fichier de configuration .rules dans le répertoire de votre projet. Utilisez la commande suivante pour commencer à configurer votre projet Firebase :

Cloud Firestore

// Set up Firestore in your project directory, creates a .rules file
firebase init firestore

Realtime Database

// Set up Realtime Database in your project directory, creates a .rules file
firebase init database

Cloud Storage

// Set up Storage in your project directory, creates a .rules file
firebase init storage

Modifier et mettre à jour vos règles

Modifiez votre source de règles directement dans le fichier de configuration .rules.

Assurez-vous que toutes les modifications que vous apportez dans la CLI Firebase sont reflétées dans la console Firebase, ou que vous effectuez les mises à jour de manière cohérente à l'aide de la console Firebase ou de la CLI Firebase. Sinon, vous risquez d'écraser les modifications apportées dans la console Firebase.

Tester vos mises à jour

Local Emulator Suite fournit des émulateurs pour tous les produits compatibles avec les règles de sécurité. Le moteur des règles de sécurité de chaque émulateur effectue une évaluation syntaxique et sémantique des règles, ce qui dépasse les tests syntaxiques proposés par l'API Management des règles de sécurité.

Si vous utilisez la CLI, la suite est un excellent outil pour les tests Firebase Security Rules. Utilisez Local Emulator Suite pour tester vos mises à jour en local et vérifier que les Rules de votre application se comportent comme vous le souhaitez.

Déployer vos mises à jour

Une fois que vous avez mis à jour et testé votre Rules, déployez les sources en production.

Pour Cloud Firestore Security Rules, associez les fichiers .rules à vos bases de données par défaut et supplémentaires nommées en examinant et en mettant à jour votre fichier firebase.json.

Utilisez les commandes suivantes pour déployer vos Rules de manière sélective ou dans le cadre de votre processus de déploiement normal.

Cloud Firestore

// Deploy rules for all databases configured in your firebase.json
firebase deploy --only firestore:rules
// Deploy rules for the specified database configured in your firebase.json firebase deploy --only firestore:<databaseId>

Realtime Database

// Deploy your .rules file
firebase deploy --only database

Cloud Storage

// Deploy your .rules file
firebase deploy --only storage

Utiliser la console Firebase

Vous pouvez également modifier les sources et les déployer en tant que versions à partir de la console Firebase.Rules Les tests syntaxiques sont effectués lorsque vous modifiez le code dans l'interface utilisateur de la console Firebase. Les tests sémantiques sont disponibles dans l'atelier Rules.

Modifier et mettre à jour vos règles

  1. Ouvrez la console Firebase et sélectionnez votre projet.
  2. Sélectionnez ensuite Realtime Database, Cloud Firestore ou Stockage dans la navigation du produit, puis cliquez sur Règles pour accéder à l'éditeur Rules.
  3. Modifiez vos règles directement dans l'éditeur.

Tester vos mises à jour

En plus de tester la syntaxe dans l'interface utilisateur de l'éditeur, vous pouvez tester le comportement sémantique Rules en utilisant les ressources de base de données et de stockage de votre projet directement dans la console Firebase à l'aide de l'bac à sable Rules. Ouvrez l'écran Rules Playground (Espace de test dédié aux règles) dans l'éditeur Rules, modifiez les paramètres, puis cliquez sur Run (Exécuter). Recherchez le message de confirmation en haut de l'éditeur.

Déployer vos mises à jour

Une fois que vous êtes sûr que les modifications apportées sont celles que vous souhaitez, cliquez sur Publier.

Utiliser le SDK Admin

Vous pouvez utiliser les ensembles de règles Admin SDK pour Node.js. Cet accès programmatique vous permet de :

  • Implémenter des outils, des scripts, des tableaux de bord et des pipelines CI/CD personnalisés pour gérer les règles.
  • Gérez plus facilement les règles dans plusieurs projets Firebase.

Lorsque vous mettez à jour des règles de manière programmatique, il est très important d'éviter d'apporter des modifications involontaires au contrôle d'accès de votre application. Écrivez votre code Admin SDK en gardant la sécurité à l'esprit, en particulier lorsque vous mettez à jour ou déployez des règles.

Une autre chose importante à garder à l'esprit est que la propagation complète des versions Firebase Security Rules prend plusieurs minutes. Lorsque vous utilisez Admin SDK pour déployer des règles, veillez à éviter les conditions de concurrence dans lesquelles votre application s'appuie immédiatement sur des règles dont le déploiement n'est pas encore terminé. Si votre cas d'utilisation nécessite des mises à jour fréquentes des règles de contrôle des accès, envisagez d'utiliser des solutions avec Cloud Firestore, qui est conçu pour réduire les conditions de concurrence malgré les mises à jour fréquentes.

Notez également les limites suivantes :

  • Les règles doivent être inférieures à 256 kio de texte encodé au format UTF-8 lorsqu'elles sont sérialisées.
  • Un projet peut comporter au maximum 2 500 ensembles de règles déployés au total. Une fois cette limite atteinte, vous devez supprimer d'anciens ensembles de règles avant d'en créer d'autres.

Créer et déployer des ensembles de règles Cloud Storage ou Cloud Firestore

Un workflow typique de gestion des règles de sécurité avec Admin SDK peut inclure trois étapes distinctes :

  1. Créer une source de fichier de règles (facultatif)
  2. Créer un ensemble de règles
  3. Publier ou déployer le nouveau règlement

Le SDK fournit une méthode permettant de combiner ces étapes en un seul appel d'API pour les règles de sécurité Cloud Storage et Cloud Firestore. Exemple :

    const source = `service cloud.firestore {
      match /databases/{database}/documents {
        match /carts/{cartID} {
          allow create: if request.auth != null && request.auth.uid == request.resource.data.ownerUID;
          allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.ownerUID;
        }
      }
    }`;
    // Alternatively, load rules from a file
    // const fs = require('fs');
    // const source = fs.readFileSync('path/to/firestore.rules', 'utf8');

    await admin.securityRules().releaseFirestoreRulesetFromSource(source);

Ce même schéma fonctionne pour les règles Cloud Storage avec releaseFirestoreRulesetFromSource().

Vous pouvez également créer le fichier de règles en tant qu'objet en mémoire, créer l'ensemble de règles et le déployer séparément pour mieux contrôler ces événements. Exemple :

    const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
    const rs = await admin.securityRules().createRuleset(rf);
    await admin.securityRules().releaseFirestoreRuleset(rs);

Mettre à jour les ensembles de règles Realtime Database

Pour mettre à jour les ensembles de règles Realtime Database avec Admin SDK, utilisez les méthodes getRules() et setRules() de admin.database. Vous pouvez récupérer les ensembles de règles au format JSON ou sous forme de chaîne avec des commentaires inclus.

Pour mettre à jour un ensemble de règles :

    const source = `{
      "rules": {
        "scores": {
          ".indexOn": "score",
          "$uid": {
            ".read": "$uid == auth.uid",
            ".write": "$uid == auth.uid"
          }
        }
      }
    }`;
    await admin.database().setRules(source);

Gérer les ensembles de règles

Pour vous aider à gérer les grands ensembles de règles, Admin SDK vous permet de lister toutes les règles existantes avec admin.securityRules().listRulesetMetadata. Exemple :

    const allRulesets = [];
    let pageToken = null;
    while (true) {
      const result = await admin.securityRules().listRulesetMetadata(pageToken: pageToken);
      allRulesets.push(...result.rulesets);
      pageToken = result.nextPageToken;
      if (!pageToken) {
        break;
      }
    }

Pour les déploiements très volumineux qui atteignent la limite de 2 500 ensembles de règles au fil du temps, vous pouvez créer une logique pour supprimer les règles les plus anciennes selon un cycle temporel fixe. Par exemple, pour supprimer tous les ensembles de règles déployés depuis plus de 30 jours :

    const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS);
    const promises = [];
    allRulesets.forEach((rs) => {
      if (new Date(rs.createTime) < thirtyDays) {
        promises.push(admin.securityRules().deleteRuleset(rs.name));
      }
    });
    await Promise.all(promises);
    console.log(`Deleted ${promises.length} rulesets.`);

Utiliser l'API REST

Les outils décrits ci-dessus conviennent à différents workflows, y compris la gestion Firebase Security Rules pour plusieurs bases de données Cloud Firestore dans votre projet. Toutefois, vous pouvez gérer et déployer Firebase Security Rules à l'aide de l'API de gestion elle-même. L'API Management vous offre la plus grande flexibilité.

Notez également les limites suivantes :

  • Les règles doivent être inférieures à 256 kio de texte encodé au format UTF-8 lorsqu'elles sont sérialisées.
  • Un projet peut comporter au maximum 2 500 ensembles de règles déployés au total. Une fois cette limite atteinte, vous devez supprimer d'anciens ensembles de règles avant d'en créer d'autres.

Créer et déployer des ensembles de règles Cloud Firestore ou Cloud Storage avec REST

Les exemples de cette section utilisent Rules Firestore, mais ils s'appliquent également à Cloud Storage Rules.

Les exemples utilisent également cURL pour effectuer des appels d'API. Les étapes de configuration et de transmission des jetons d'authentification sont omises. Vous pouvez tester cette API à l'aide de l'explorateur d'API intégré à la documentation de référence.

Voici les étapes types pour créer et déployer un ensemble de règles à l'aide de l'API Management :

  1. Créer des sources de fichier de règles
  2. Créer un ensemble de règles
  3. Déployez le nouveau règlement.

Créer une source

Supposons que vous travailliez sur votre projet Firebase secure_commerce et que vous souhaitiez déployer des Cloud Firestore Rules verrouillés dans une base de données de votre projet nommée east_store.

Vous pouvez implémenter ces règles dans un fichier firestore.rules.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

Créer un ensemble de règles

Générez maintenant une empreinte digitale encodée en base64 pour ce fichier. Vous pouvez ensuite utiliser la source de ce fichier pour remplir le payload nécessaire à la création d'un ensemble de règles avec l'appel REST projects.rulesets.create. Ici, utilisez la commande cat pour insérer le contenu de firestore.rules dans la charge utile REST.

Pour le suivi, associez-le à votre base de données east_store en définissant attachment_point sur east_store.

curl -X POST -d '{
  "source": {
    "files": [
      {
        "content": "' $(cat storage.rules) '",
        "name": "firestore.rules",
        "fingerprint": <sha fingerprint>
      },
    "attachment_point": "firestore.googleapis.com/databases/east_store"
    ]
  }
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets'

L'API renvoie une réponse de validation et un nom de règles, par exemple projects/secure_commerce/rulesets/uuid123.

Publier (déployer) un ensemble de règles

Si l'ensemble de règles est valide, la dernière étape consiste à le déployer dans une version nommée.

curl -X POST -d '{
  "name": "projects/secure_commerce/releases/cloud.firestore/east_store"  ,
  "rulesetName": "projects/secure_commerce/rulesets/uuid123"
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/releases'

Sachez que la propagation complète des versions Firebase Security Rules prend plusieurs minutes. Lorsque vous utilisez l'API REST de gestion pour le déploiement, veillez à éviter les conditions de concurrence dans lesquelles votre application s'appuie immédiatement sur des règles dont le déploiement n'est pas encore terminé.

Mettre à jour les ensembles de règles Realtime Database avec REST

Realtime Database fournit sa propre interface REST pour gérer Rules. Consultez Gérer Firebase Realtime Database Rules via REST.

Gérer les ensembles de règles avec REST

Pour vous aider à gérer les déploiements de règles à grande échelle, l'API Management fournit des méthodes permettant de créer des ensembles de règles et des versions, ainsi que :

  • Lister, obtenir et supprimer des ensembles de règles
  • releases list, get, and delete rules

Pour les déploiements très volumineux qui atteignent la limite de 2 500 ensembles de règles au fil du temps, vous pouvez créer une logique pour supprimer les règles les plus anciennes selon un cycle temporel fixe. Par exemple, pour supprimer tous les ensembles de règles déployés depuis plus de 30 jours, vous pouvez appeler la méthode projects.rulesets.list, analyser la liste JSON des objets Ruleset sur leurs clés createTime, puis appeler project.rulesets.delete sur les ensembles de règles correspondants par ruleset_id.

Tester vos mises à jour avec REST

Enfin, l'API Management vous permet d'exécuter des tests syntaxiques et sémantiques sur les ressources Cloud Firestore et Cloud Storage dans vos projets de production.

.

Les tests avec ce composant de l'API comprennent les éléments suivants :

  1. Définir un objet JSON TestSuite pour représenter un ensemble d'objets TestCase
  2. Envoyer le TestSuite
  3. Analyser les objets TestResult renvoyés

Définissons un objet TestSuite avec un seul TestCase dans un fichier testcase.json. Dans cet exemple, nous transmettons la source de langue Rules en ligne avec la charge utile REST, ainsi que la suite de tests à exécuter sur ces règles. Nous spécifions une attente d'évaluation des règles et la requête client par rapport à laquelle l'ensemble de règles doit être testé. Vous pouvez également spécifier le niveau d'exhaustivité du rapport de test en utilisant la valeur "FULL" pour indiquer que les résultats de toutes les expressions linguistiques Rules doivent être inclus dans le rapport, y compris les expressions qui n'ont pas été mises en correspondance avec la requête.

 {
  "source":
  {
    "files":
    [
      {
        "name": "firestore.rules",
        "content": "service cloud.firestore {
          match /databases/{database}/documents {
            match /users/{userId}{
              allow read: if (request.auth.uid == userId);
            }
            function doc(subpath) {
              return get(/databases/$(database)/documents/$(subpath)).data;
            }
            function isAccountOwner(accountId) {
              return request.auth.uid == accountId 
                  || doc(/users/$(request.auth.uid)).accountId == accountId;
            }
            match /licenses/{accountId} {
              allow read: if isAccountOwner(accountId);
            }
          }
        }"
      }
    ]
  },
  "testSuite":
  {
    "testCases":
    [
      {
        "expectation": "ALLOW",
        "request": {
           "auth": {"uid": "123"},
           "path": "/databases/(default)/documents/licenses/abcd",
           "method": "get"},
        "functionMocks": [
            {
            "function": "get",
            "args": [{"exact_value": "/databases/(default)/documents/users/123"}],
            "result": {"value": {"data": {"accountId": "abcd"}}}
            }
          ]
      }
    ]
  }
}

Nous pouvons ensuite envoyer ce TestSuite pour évaluation avec la méthode projects.test.

curl -X POST -d '{
    ' $(cat testcase.json) '
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets/uuid123:test'

L'TestReport renvoyé (contenant l'état de réussite/d'échec du test, des listes de messages de débogage, des listes d'expressions de règles visitées et leurs rapports d'évaluation) confirmerait avec l'état SUCCESS que l'accès est correctement autorisé.

Gérer les autorisations pour Cloud Storage Security Rules multiservices

Si vous créez des Cloud Storage Security Rules qui utilisent le contenu du document Cloud Firestore pour évaluer les conditions de sécurité, vous serez invité dans la console Firebase ou la CLI Firebase à activer les autorisations pour connecter les deux produits.

Si vous décidez de désactiver cette sécurité multiservice :

  1. Avant de désactiver la fonctionnalité, commencez par modifier vos règles en supprimant toutes les instructions qui utilisent des fonctions Rules pour accéder à Cloud Firestore. Sinon, une fois la fonctionnalité désactivée, les évaluations Rules entraîneront l'échec de vos requêtes de stockage.

  2. Accédez à la page IAM de la console Google Cloud et supprimez le rôle "Agent de service Firestore pour les règles Firebase" en suivant le guide Cloud pour révoquer des rôles.

Vous serez invité à réactiver la fonctionnalité la prochaine fois que vous enregistrerez des règles multiservices à partir de la CLI Firebase ou de la console Firebase.