Firebase provides you with several tools to manage your Rules, each one useful in particular cases, and each one using the same backend Firebase Security Rules management API.
No matter which tool is used to invoke it, the management API:
- Ingests a Rules source: a set of rules, typically a code file containing Firebase Security Rules statements.
- Stores ingested source as an immutable ruleset.
- Tracks deployment of each ruleset in a release. Firebase Security Rules-enabled services lookup the release for a project to evaluate each request for a secured resource.
- Provides the capability to run syntactic and semantic tests of a ruleset.
Use the Firebase CLI
With the Firebase CLI, you can upload local sources and deploy releases. The CLI's Firebase Local Emulator Suite lets you perform full local testing of sources.
Using the CLI allows you to keep your rules under version control with your application code and deploy rules as part of your existing deployment process.
Generate a configuration file
When you configure your Firebase project using the Firebase CLI, you create
a .rules
configuration file in your project directory. Use the following
command to start configuring your Firebase project:
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
Edit and update your rules
Edit your rules source directly in the .rules
configuration file.
Make sure that any edits you make in the Firebase CLI are reflected in the Firebase console, or that you consistently make updates using either the Firebase console or the Firebase CLI. Otherwise, you might overwrite any updates made in the Firebase console.
Test your updates
The Local Emulator Suite provides emulators for all Security Rules-enabled products. The Security Rules engine for each emulator performs both syntactic and semantic evaluation of rules, thus exceeding the syntactic testing the Security Rules management API offers.
If you're working with the CLI, the Suite is an excellent tool for Firebase Security Rules testing. Use the Local Emulator Suite to test your updates locally and confirm that your app's Rules exhibit the behavior you want.
Deploy your updates
Once you've updated and tested your Rules, deploy the sources to production.
For Cloud Firestore Security Rules, associate .rules
files with your default and
additional named databases by reviewing and updating your
firebase.json
file.
Use the following commands to selectively deploy your Rules alone or deploy them as part of your normal deployment process.
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
Use the Firebase console
You can also edit Rules sources and deploy them as releases from the Firebase console. Syntactic testing is performed as you edit in the Firebase console UI, and semantic testing is available using the Rules Playground.
Edit and update your rules
- Open the Firebase console and select your project.
- Then, select Realtime Database, Cloud Firestore or Storage from the product navigation, then click Rules to navigate to the Rules editor.
- Edit your rules directly in the editor.
Test your updates
In addition to testing syntax in the editor UI, you can test semantic Rules behavior, using your project's database and storage resources, directly in the Firebase console, using the Rules Playground. Open the Rules Playground screen in the Rules editor, modify the settings and click Run. Look for the confirmation message at the top of the editor.
Deploy your updates
Once you're satisfied that your updates are what you expect, click Publish.
Use the Admin SDK
You can use the Admin SDK for Node.js rulesets. With this programmatic access, you can:
- Implement custom tools, scripts, dashboards and CI/CD pipelines for managing rules.
- Manage rules more easily across multiple Firebase projects.
When updating rules programmatically, it is very important to avoid making unintended changes to the access control for your app. Write your Admin SDK code with security foremost in mind, especially when updating or deploying rules.
Another important thing to keep in mind is that Firebase Security Rules releases take a period of several minutes to fully propagate. When using the Admin SDK to deploy rules, make sure to avoid race conditions in which your app immediately relies on rules whose deployment is not yet complete. If your use case requires frequent updates to access control rules, consider solutions using Cloud Firestore, which is designed to reduce race conditions despite frequent updates.
Also note these limits:
- Rules must be smaller than 256 KiB of UTF-8 encoded text when serialized.
- A project can have at most 2500 total deployed rulesets. Once this limit is reached, you must delete some old rulesets before creating new ones.
Create and deploy Cloud Storage or Cloud Firestore rulesets
A typical workflow for managing security rules with the Admin SDK could include three discrete steps:
- Create a rules file source (optional)
- Create a ruleset
- Release, or deploy, the new ruleset
The SDK provides a method to combine these steps into a single API call for Cloud Storage and Cloud Firestore security rules. For example:
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);
This same pattern works for Cloud Storage rules with releaseFirestoreRulesetFromSource()
.
Alternatively, you can create the rules file as an in-memory object, create the ruleset, and deploy the ruleset separately for closer control of these events. For example:
const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
const rs = await admin.securityRules().createRuleset(rf);
await admin.securityRules().releaseFirestoreRuleset(rs);
Update Realtime Database rulesets
To update Realtime Database rulesets with the Admin SDK, use the getRules()
and
setRules()
methods of admin.database
. You can retrieve rulesets in JSON
format, or as a string with comments included.
To update a ruleset:
const source = `{
"rules": {
"scores": {
".indexOn": "score",
"$uid": {
".read": "$uid == auth.uid",
".write": "$uid == auth.uid"
}
}
}
}`;
await admin.database().setRules(source);
Manage rulesets
To help manage large rulesets, the Admin SDK lets you list all existing rules
with admin.securityRules().listRulesetMetadata
. For example:
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;
}
}
For very large deployments that reach the 2500 ruleset limit over time, you can create logic to delete the oldest rules on a fixed time cycle. For example, to delete all rulesets deployed for longer than 30 days:
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.`);
Use the REST API
The tools described above are well suited to various workflows, including Firebase Security Rules management for multiple Cloud Firestore databases in your project, but you may want to manage and deploy Firebase Security Rules using the management API itself. The management API gives you the greatest flexibility.
Also note these limits:
- Rules must be smaller than 256 KiB of UTF-8 encoded text when serialized.
- A project can have at most 2500 total deployed rulesets. Once this limit is reached, you must delete some old rulesets before creating new ones.
Create and deploy Cloud Firestore or Cloud Storage rulesets with REST
The examples in this section use Firestore Rules, though they apply to Cloud Storage Rules as well.
The examples also use cURL to make API calls. Steps to set up and pass authentication tokens are omitted. You can experiment with this API using the API Explorer integrated with the reference documentation.
Typical steps for creating and deploying a ruleset using the management API are:
- Create rules file sources
- Create a ruleset
- Release (deploy) the new ruleset.
Create a source
Let's assume you're working on your secure_commerce
Firebase project and want
to deploy locked-down Cloud Firestore Rules to a database in your
project named east_store
.
You can implement these rules in a firestore.rules
file.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Create a ruleset
Now, generate a base64-encoded fingerprint for this file. You can then use the
source in this file to populate the payload needed to create a ruleset with the
projects.rulesets.create
REST call. Here, use the cat
command to insert
the contents of firestore.rules
into the REST payload.
For tracking, to associate this with your east_store
database, set the attachment_point
to 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'
The API returns a validation response and a ruleset name, for example
projects/secure_commerce/rulesets/uuid123
.
Release (deploy) a ruleset
If the ruleset is valid, the final step is to deploy the new ruleset in a named release.
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'
Be aware that Firebase Security Rules releases take a period of several minutes to fully propagate. When using the management REST API to deploy, make sure to avoid race conditions in which your app immediately relies on rules whose deployment is not yet complete.
Update Realtime Database rulesets with REST
Realtime Database provides its own REST interface for managing Rules. See Managing Firebase Realtime Database Rules via REST.
Manage rulesets with REST
To help manage large rules deployments, in addition to a REST method for creating rulesets and releases, the management API provides methods to:
- list, get, and delete rulesets
- list, get, and delete rules releases
For very large deployments that reach the 2500 ruleset limit over time, you can
create logic to delete the oldest rules on a fixed time cycle. For example, to
delete all rulesets deployed for longer than 30 days, you can call the
projects.rulesets.list
method, parse the JSON list of Ruleset
objects on
their createTime
keys, then call project.rulesets.delete
on the
corresponding rulesets by ruleset_id
.
Test your updates with REST
Finally, the management API allows you to run syntactic and semantic tests on Cloud Firestore and Cloud Storage resources in your production projects.
Testing with this component of the API consists of:
- Defining a
TestSuite
JSON object to represent a set ofTestCase
objects - Submitting the
TestSuite
- Parsing returned
TestResult
objects
Let's define a TestSuite
object with a single TestCase
in a
testcase.json
file. In this example, we pass the Rules
language source inline with the REST payload, alongside the test suite to run
on those rules. We specify a Rules evaluation expectation, and the client
request against which the ruleset is to be tested. You can also specify how
complete the test report is, using value "FULL" to indicate results for all
Rules language expressions should be included in the report, including
expressions that were not matched to the request.
{ "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"}}} } ] } ] } }
We can then submit this TestSuite
for evalution with the projects.test
method.
curl -X POST -d '{
' $(cat testcase.json) '
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets/uuid123:test'
The returned TestReport
(containing test SUCCESS/FAILURE status, lists of
debug messages, lists of visited Rules expressions and their evaluation reports)
would confirm with status SUCCESS that access is properly allowed.
Manage permissions for cross-service Cloud Storage Security Rules
If you create Cloud Storage Security Rules that use Cloud Firestore document contents to evaluate security conditions, you'll be prompted in the Firebase console or Firebase CLI to enable permissions to connect the two products.
If you decide to disable such cross-service security:
First, before disabling the feature, edit your rules, removing all statements that use Rules functions to access Cloud Firestore. Otherwise, after the feature is disabled, Rules evaluations will cause your Storage requests to fail.
Use the IAM page in the Google Cloud Console to delete the "Firebase Rules Firestore Service Agent" role by following the Cloud guide for revoking roles.
You will be prompted to re-enable the feature the next time you save cross-service Rules from the Firebase CLI or the Firebase console.