Event Information

  • The google.firestore.admin.v1.FirestoreAdmin.CreateIndex event in GCP for Firestore indicates that a new index has been created in the Firestore database.
  • This event is triggered when a user or an automated process creates an index to improve query performance in Firestore.
  • The event provides information about the index, such as the collection and field it is associated with, and any additional configuration options specified during the index creation.

Examples

  • Unauthorized access: If proper access controls are not implemented, an attacker may be able to gain unauthorized access to the Firestore database by exploiting the CreateIndex operation. This can lead to unauthorized reading, modifying, or deleting of sensitive data.

  • Data leakage: If the CreateIndex operation is misconfigured, it may inadvertently expose sensitive data to unauthorized users. For example, if an index is created on a field that contains sensitive information, such as personally identifiable information (PII), and the access controls are not properly set, the data may be exposed to unauthorized parties.

  • Denial of service (DoS) attacks: If the CreateIndex operation is abused or misused, it can potentially lead to a DoS attack. For example, an attacker may repeatedly create and delete indexes, causing excessive resource consumption and impacting the availability of the Firestore service for legitimate users. Proper rate limiting and monitoring should be implemented to mitigate such attacks.

Remediation

Using Console

To remediate the issues mentioned in the previous response for GCP Firestore using the GCP console, you can follow these step-by-step instructions:

  1. Enable VPC Service Controls:

    • Go to the GCP Console and navigate to the VPC Service Controls page.
    • Click on “Create Perimeter” and provide a name for the perimeter.
    • Select the project where your Firestore instance is located.
    • Choose the desired VPC network and subnetwork for the perimeter.
    • Click on “Create” to create the perimeter.
    • Once the perimeter is created, go to the Firestore instance settings and enable VPC Service Controls by selecting the created perimeter.
  2. Enable Audit Logging:

    • Go to the GCP Console and navigate to the Firestore instance settings.
    • Click on “Edit” to modify the settings.
    • Scroll down to the “Audit Logging” section and enable the “Data access” and “Admin activity” logs.
    • Choose the desired log sink destination, such as Cloud Storage or BigQuery.
    • Click on “Save” to save the changes.
  3. Implement IAM Best Practices:

    • Go to the GCP Console and navigate to the IAM & Admin page.
    • Review the existing IAM roles and permissions assigned to users and service accounts.
    • Remove any unnecessary or overly permissive roles.
    • Create custom IAM roles with the least privilege principle for specific tasks or responsibilities.
    • Assign the appropriate IAM roles to users and service accounts based on their requirements.
    • Regularly review and update the IAM roles and permissions as needed.

Note: These instructions assume that you have the necessary permissions and access to the GCP Console to perform these actions.

Using CLI

To remediate the issues in GCP Firestore using GCP CLI, you can follow these steps:

  1. Enable audit logging:

    • Use the following command to enable audit logging for Firestore:
      gcloud firestore databases patch [DATABASE_ID] --log-exclusion-names=cloudaudit.googleapis.com%2Factivity
      
  2. Implement VPC Service Controls:

    • Create a VPC Service Control perimeter using the following command:
      gcloud access-context-manager perimeters create [PERIMETER_ID] --resources=projects/[PROJECT_ID]/locations/[LOCATION]/buckets/[BUCKET_NAME] --restricted-services=firestore.googleapis.com
      
    • Associate the VPC Service Control perimeter with the project using the following command:
      gcloud access-context-manager perimeters update [PERIMETER_ID] --add-access-levels=[ACCESS_LEVEL_ID]
      
  3. Enable data encryption at rest:

    • Create a new Firestore instance with data encryption at rest enabled using the following command:
      gcloud firestore instances create [INSTANCE_ID] --location=[LOCATION] --encryption-key-name=[KEY_NAME]
      

Note: Replace the placeholders ([DATABASE_ID], [PROJECT_ID], [LOCATION], [BUCKET_NAME], [PERIMETER_ID], [ACCESS_LEVEL_ID], [INSTANCE_ID], [KEY_NAME]) with the actual values specific to your environment.

Using Python

To remediate the issues mentioned in the previous response for GCP Firestore using Python, you can follow these steps:

  1. Enable Firestore Audit Logs:

    • Use the Google Cloud Python SDK to enable Firestore Audit Logs for your project.
    • You can use the google-cloud-logging library to create a sink that exports Firestore Audit Logs to Cloud Logging.
    • Here’s an example Python script to enable Firestore Audit Logs:
    from google.cloud import logging_v2
    
    def enable_firestore_audit_logs(project_id, firestore_dataset):
        client = logging_v2.LoggingServiceV2Client()
        parent = f"projects/{project_id}"
        sink_name = f"{parent}/sinks/firestore-audit-logs"
        filter_expr = f'resource.type="cloud_firestore_database" AND log_name="projects/{project_id}/logs/cloudaudit.googleapis.com%2Factivity"'
        destination = f"bigquery.googleapis.com/projects/{project_id}/datasets/{firestore_dataset}"
    
        sink = {
            "name": sink_name,
            "filter": filter_expr,
            "destination": destination,
            "output_version_format": "V2",
        }
    
        response = client.create_sink(parent, sink)
        print(f"Enabled Firestore Audit Logs with sink name: {response.name}")
    
    enable_firestore_audit_logs("your-project-id", "your-firestore-dataset")
    
  2. Implement Access Controls:

    • Use the Google Cloud Python SDK to implement access controls for Firestore.
    • You can use the google-cloud-iam library to manage IAM policies for Firestore.
    • Here’s an example Python script to grant a user the roles/datastore.owner role for a Firestore database:
    from google.cloud import firestore
    from google.cloud.iam_v1 import Policy
    
    def grant_firestore_access(project_id, firestore_database, user_email):
        client = firestore.Client(project=project_id)
        database_path = f"projects/{project_id}/databases/{firestore_database}"
        policy = client.get_iam_policy(request={"resource": database_path})
    
        policy.bindings.add(
            role="roles/datastore.owner",
            members=[f"user:{user_email}"],
        )
    
        updated_policy = client.set_iam_policy(request={"resource": database_path, "policy": policy})
        print(f"Granted user {user_email} the roles/datastore.owner role for Firestore")
    
    grant_firestore_access("your-project-id", "your-firestore-database", "[email protected]")
    
  3. Implement Data Encryption:

    • Use the Google Cloud Python SDK to implement data encryption for Firestore.
    • You can use the google-cloud-kms library to encrypt and decrypt Firestore data using Cloud KMS.
    • Here’s an example Python script to encrypt and decrypt a Firestore document:
    from google.cloud import firestore
    from google.cloud import kms_v1
    
    def encrypt_firestore_document(project_id, firestore_database, document_path, kms_key_name):
        client = firestore.Client(project=project_id)
        document_ref = client.document(firestore_database, document_path)
        document_data = document_ref.get().to_dict()
    
        kms_client = kms_v1.KeyManagementServiceClient()
        key_name = f"projects/{project_id}/locations/global/keyRings/{kms_key_name}/cryptoKeys/{kms_key_name}"
        plaintext = str(document_data).encode("utf-8")
    
        response = kms_client.encrypt(request={"name": key_name, "plaintext": plaintext})
        encrypted_data = response.ciphertext
    
        document_ref.set({"encrypted_data": encrypted_data})
        print(f"Encrypted Firestore document at {document_path}")
    
    def decrypt_firestore_document(project_id, firestore_database, document_path, kms_key_name):
        client = firestore.Client(project=project_id)
        document_ref = client.document(firestore_database, document_path)
        document_data = document_ref.get().to_dict()
    
        kms_client = kms_v1.KeyManagementServiceClient()
        key_name = f"projects/{project_id}/locations/global/keyRings/{kms_key_name}/cryptoKeys/{kms_key_name}"
        ciphertext = document_data["encrypted_data"]
    
        response = kms_client.decrypt(request={"name": key_name, "ciphertext": ciphertext})
        decrypted_data = response.plaintext.decode("utf-8")
    
        print(f"Decrypted Firestore document at {document_path}: {decrypted_data}")
    
    encrypt_firestore_document("your-project-id", "your-firestore-database", "your-document-path", "your-kms-key-name")
    decrypt_firestore_document("your-project-id", "your-firestore-database", "your-document-path", "your-kms-key-name")
    

Please note that you need to replace the placeholders (your-project-id, your-firestore-dataset, your-firestore-database, [email protected], your-document-path, your-kms-key-name) with your actual values.