Configura y administra proyectos y productos de Firebase con Terraform

1. Introducción

Objetivos

Puedes usar Terraform para configurar y administrar un proyecto de Firebase, incluida la configuración programática de la infraestructura y los productos de Firebase.

En este codelab, primero se describe cómo compilar un archivo de configuración de Terraform para crear un nuevo proyecto de Firebase y, luego, cómo configurar las apps y los productos de Firebase que quieres usar en ese proyecto. También abordaremos los conceptos básicos de la línea de comandos de Terraform, como obtener una vista previa de los cambios que se realizarán y, luego, implementarlos.

Si quieres aprender a configurar y administrar proyectos y productos de Firebase con Terraform, este codelab es para ti.

Qué aprenderás

  • Cómo crear un archivo de configuración de Terraform (*.tf)
  • Cómo usar los comandos de la CLI de Terraform para administrar tu infraestructura
  • Cómo modificar la configuración para actualizar los recursos y servicios
  • Cómo aplicar tu configuración en una app web real (llamada Friendly Chat)
  • Cómo definir parámetros de configuración en paralelo (y sincronizados) en diferentes entornos (producción, etapa de pruebas, etcétera)

Requisitos

Para tener éxito con este codelab, necesitas tener conocimientos básicos sobre Terraform y su terminología, incluidos los siguientes requisitos previos:

En este codelab, se proporciona una app de ejemplo real para que puedas probar lo que aprovisiones a través de Terraform y, además, interactuar con él. Para ello, necesitarás lo siguiente:

  • El código de muestra para una app web: Descarga este código en el siguiente paso del codelab
  • El administrador de paquetes npm (que suele incluirse con Node.js): Instala estas herramientas.
  • Firebase CLI: Instala esta CLI y accede

2. Obtén el código de partida

En este codelab, puedes probar lo que aprovisionas a través de Terraform con una app web real. Te recomendamos que lo hagas para comprender todos los pasos necesarios para usar los recursos aprovisionados por Terraform.

Clona el repositorio de GitHub del codelab desde la línea de comandos:

git clone https://github.com/firebase/codelab-friendlychat-web

Como alternativa, si no tienes git instalado, puedes descargar el repositorio como archivo ZIP.

3. Cómo crear una configuración de Terraform

Configuración de Terraform

  1. En la base de código de la app de ejemplo descargada, navega a la raíz del directorio web.
  2. En la raíz de ese directorio, crea un archivo de configuración de Terraform llamado main.tf con la siguiente configuración inicial:

    main.tf
    # Terraform configuration to set up providers by version.
    terraform {
      required_providers {
        google-beta = {
          source  = "hashicorp/google-beta"
          version = "~> 4.0"
        }
      }
    }
    
    # Configure the provider not to use the specified project for quota check.
    # This provider should only be used during project creation and initializing services.
    provider "google-beta" {
      alias                 = "no_user_project_override"
      user_project_override = false
    }
    
    # Configure the provider that uses the new project's quota.
    provider "google-beta" {
      user_project_override = true
    }
    

Cada uno de los proveedores de google-beta tiene un atributo llamado user_project_override que determina cómo se verificará la cuota de las operaciones de Terraform. Para aprovisionar la mayoría de los recursos, debes usar user_project_override = true, lo que significa que debes verificar la cuota en tu propio proyecto de Firebase. Sin embargo, si quieres que tu proyecto acepte verificaciones de cuotas, debes debes usar user_project_override=false. La sintaxis alias de Terraform te permite distinguir entre las dos configuraciones del proveedor en los próximos pasos de este codelab.

Inicializa Terraform en el directorio

Para crear una configuración nueva por primera vez, debes descargar el proveedor especificado en la configuración.

Para realizar esta inicialización, ejecuta el siguiente comando desde la raíz del mismo directorio que tu archivo de configuración main.tf:

terraform init

4. Crea un proyecto de Firebase mediante Terraform

Para "crear un proyecto de Firebase", es importante recordar que cada proyecto de Firebase es, en realidad, un proyecto de Google Cloud, solo que con los servicios de Firebase habilitados.

Agrega bloques para el proyecto y las APIs subyacentes de Google Cloud

  1. Primero, aprovisiona el proyecto subyacente de Google Cloud.

    Agrega el siguiente bloque de recursos a tu archivo de configuración main.tf.

    Debes especificar el nombre de tu proyecto (como "Terraform FriendlyChat Codelab") y el ID de tu proyecto (como "terraform-codelab-your-initials"). Ten en cuenta que el valor name solo se usa en las interfaces de Firebase y no es visible para los usuarios finales. Sin embargo, el valor project_id identifica de forma única tu proyecto para Google, así que asegúrate de especificar un valor único. main.tf
    ...
    
    # Create a new Google Cloud project.
    resource "google_project" "default" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_YOUR_PROJECT>"
      project_id      = "<PROJECT_ID_OF_YOUR_PROJECT>"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
  2. A continuación, debes habilitar las APIs subyacentes requeridas: la API de Service Usage y la API de Firebase Management.

    Por lo general, esta habilitación de API se controla en segundo plano cuando usas Firebase console para crear un proyecto de Firebase, pero se debe indicar explícitamente a Terraform que realice esta habilitación.

    En tu archivo de configuración main.tf (justo debajo del bloque que crea el nuevo proyecto de Cloud), agrega el siguiente bloque de recursos:

    main.tf
    ...
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "serviceusage" {
      provider = google-beta.no_user_project_override
    
      project = google_project.default.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "firebase" {
      provider = google-beta.no_user_project_override
    
      project = google_project.default.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    Si habilitas la API de Service Usage, tu proyecto nuevo podrá aceptar verificaciones de cuota. Por lo tanto, para todos los aprovisionamientos de recursos y habilitaciones de servicios posteriores, debes usar el proveedor con user_project_override (no se necesita alias).

Agrega un bloque para habilitar los servicios de Firebase

Lo último que se necesita para "crear un proyecto de Firebase" es habilitar los servicios de Firebase en el proyecto.

Continúa en tu archivo de configuración main.tf y agrega el siguiente bloque de recursos.

Como se mencionó anteriormente, ten en cuenta que este bloque de recursos usa el proveedor con user_project_override (no se necesita alias).

main.tf

...

# Enable Firebase services for the new project created above.
resource "google_firebase_project" "default" {
  provider = google-beta

  project = google_project.default.project_id

  # Wait until the required APIs are enabled.
  depends_on = [
    google_project_service.firebase,
    google_project_service.serviceusage,
  ]
}

En el bloque de recursos anterior, es posible que notes la cláusula depends_on, que le indica a Terraform que espere a que se habiliten las APIs subyacentes. Sin esta cláusula, Terraform no conoce la dependencia y puede encontrar errores cuando aprovisiona recursos en paralelo.

Aplica la configuración

  1. Para aprovisionar los recursos nuevos y habilitar las APIs especificadas en tu archivo de configuración, ejecuta el siguiente comando desde la raíz del mismo directorio que contiene el archivo main.tf (que debería ser web):
    terraform apply
    
  2. En la terminal, Terraform imprime un plan de acciones que realizará.

    Si todo parece como se espera, ingresa yes para aprobar las acciones.

    main.tf
    Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      # google_firebase_project.default will be created
      + resource "google_firebase_project" "default" {
          + display_name   = (known after apply)
          + id             = (known after apply)
          + project        = "terraform-friendlychat-codelab"
          + project_number = (known after apply)
        }
    
      # google_project.default will be created
      + resource "google_project" "default" {
          + auto_create_network = true
          + id                  = (known after apply)
          + labels              = {
              + "firebase" = "enabled"
            }
          + name                = "Terraform FriendlyChat Codelab"
          + number              = (known after apply)
          + project_id          = "terraform-friendlychat-codelab"
          + skip_delete         = (known after apply)
        }
    
      # google_project_service.firebase will be created
      + resource "google_project_service" "firebase" {
          + disable_on_destroy = false
          + id                 = (known after apply)
          + project            = "terraform-friendlychat-codelab"
          + service            = "firebase.googleapis.com"
        }
    
      # google_project_service.serviceusage will be created
      + resource "google_project_service" "serviceusage" {
          + disable_on_destroy = false
          + id                 = (known after apply)
          + project            = "terraform-friendlychat-codelab"
          + service            = "serviceusage.googleapis.com"
        }
    
    Plan: 4 to add, 0 to change, 0 to destroy.
    
    Do you want to perform these actions?
      Terraform will perform the actions described above.
      Only 'yes' will be accepted to approve.
    
      Enter a value: yes # <----
    

Ten en cuenta que, si solo necesitas obtener una vista previa de los cambios sin aplicarlos, puedes usar el comando terraform plan.

Valida los cambios

Cuando Terraform termine de ejecutarse, puedes ejecutar el siguiente comando para inspeccionar el estado de todos los recursos y servicios habilitados de Terraform aprovisionados:

terraform show

Este es un ejemplo de lo que deberías ver impreso. Tu estado contendrá valores específicos de tu proyecto.

# google_firebase_project.default:
resource "google_firebase_project" "default" {
    display_name   = "Terraform FriendlyChat Codelab"
    id             = "projects/terraform-friendlychat-codelab"
    project        = "terraform-friendlychat-codelab"
    project_number = "000000000"
}

# google_project.default:
resource "google_project" "default" {
    auto_create_network = true
    id                  = "projects/terraform-friendlychat-codelab"
    labels              = {
        "firebase" = "enabled"
    }
    name                = "Terraform FriendlyChat Codelab"
    number              = "000000000"
    project_id          = "terraform-friendlychat-codelab"
}

# google_project_service.firebase:
resource "google_project_service" "firebase" {
    disable_on_destroy = false
    id                 = "terraform-friendlychat-codelab/firebase.googleapis.com"
    project            = "terraform-friendlychat-codelab"
    service            = "firebase.googleapis.com"
}

# google_project_service.serviceusage:
resource "google_project_service" "serviceusage" {
    disable_on_destroy = false
    id                 = "terraform-friendlychat-codelab/serviceusage.googleapis.com"
    project            = "terraform-friendlychat-codelab"
    service            = "serviceusage.googleapis.com"
}

Como alternativa, puedes verificar que el proyecto se haya creado viéndolo en Firebase console.

El proyecto del codelab de Terraform FriendlyChat seleccionado en Firebase console

5. Registra tu app de Firebase con Terraform

Para usar Firebase, debes registrar cada variante de plataforma de tu app en tu proyecto de Firebase. En este codelab, usarás una app real para probar lo que aprovisiones a través de Terraform y, además, interactuar con él. Esta app es una app web, por lo que debes indicarle a Terraform que registre una app web de Firebase en el proyecto de Firebase que acabas de crear.

Agrega un bloque para registrar la app web

Para registrar tu app web en el proyecto de Firebase, agrega el archivo main.tf con el siguiente bloque de recursos.

Debes especificar tu propio display_name para tu app web. Ten en cuenta que este nombre solo se usa en las interfaces de Firebase y no es visible para los usuarios finales.

main.tf

...

# Create a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "default" {
  provider = google-beta

  project      = google_firebase_project.default.project
  display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
  deletion_policy = "DELETE"
}

Aplica la configuración

  1. Para aprovisionar el recurso nuevo, ejecuta el siguiente comando desde la raíz del mismo directorio que contiene el archivo main.tf (que debería ser web).
    terraform apply
    
    Ten en cuenta que este comando no volverá a crear un proyecto de Google Cloud nuevo. Terraform detectará que ya existe un proyecto con el ID especificado, comparará el estado actual del proyecto con el contenido del archivo .tf y realizará los cambios que encuentre.
  2. Revisa el plan de acciones impreso. Si todo está como se espera, escribe yes y presiona Intro para aprobar las acciones.

Valida los cambios

Para inspeccionar el estado del recurso aprovisionado recientemente, ejecuta el siguiente comando:

terraform show

Como alternativa, puedes verificar que la app se registró correctamente en tu proyecto. Para ello, ve a Firebase console. Ve a Configuración del proyecto y, luego, desplázate hasta la sección Tus apps.

6. Configura Firebase Authentication

La autenticación es una parte importante de cualquier app. Para permitir que los usuarios finales accedan a tu app web con sus Cuentas de Google, puedes habilitar Firebase Authentication y configurar el método de acceso con Google.

Ten en cuenta que, en este codelab, proporcionamos dos opciones diferentes para configurar Firebase Authentication:

  • Opción 1 (recomendada): Configura Firebase Authentication en la consola, que no requiere GCIP.
    • Si usas esta opción, no tendrás que asociar tu proyecto nuevo a una cuenta de Facturación de Cloud.
  • Opción 2: Configura Firebase Authentication a través de Terraform con las APIs de Google Cloud Identity Platform (GCIP).
    • Si usas esta opción, deberás asociar tu proyecto nuevo con una cuenta de Facturación de Cloud, ya que GCIP requiere que el proyecto esté en el plan de precios Blaze.

Opción 1: Configura Authentication con Firebase console

Para configurar Firebase Authentication con Firebase console, no es necesario que tu proyecto tenga el plan de precios Blaze.

Aquí te mostramos cómo configurar Firebase Authentication y acceder con Google:

  1. En Firebase console, busca la sección Build en el panel izquierdo.
  2. Haz clic en Authentication, en Comenzar y, luego, en la pestaña Método de acceso (o haz clic aquí para ir directamente a la página).
  3. Haz clic en Agregar proveedor nuevo y, en la sección Proveedores adicionales, selecciona Google.
  4. Activa la opción Habilitar.
  5. Establece el nombre público de tu app como FriendlyChat (no es necesario que sea único a nivel global).
  6. Elige un correo electrónico de asistencia del proyecto en el menú desplegable y, luego, haz clic en Guardar.Cómo configurar Firebase Auth en Firebase console
  7. Deberías ver a Google como un proveedor de acceso habilitado.Página Authentication de Firebase console: Acceso con Google habilitado

Opción 2: Configura la autenticación a través de Terraform con las APIs de Google Cloud Identity Platform (GCIP)

Para configurar Firebase Authentication mediante Terraform, debes usar las APIs de GCIP, lo que significa que el proyecto debe tener el plan de precios Blaze. Asocia una cuenta de Facturación de Cloud al proyecto para actualizar tu proyecto de Firebase y usar el plan Blaze.

Habilita la facturación con Terraform

  1. Si aún no tienes una cuenta de Facturación de Cloud, el primer paso es crear una nueva en la consola de Google Cloud. Cuando lo hagas, anota el ID de la cuenta de facturación. Puedes encontrar el ID de la cuenta de facturación en la página Facturación, en el ID de la cuenta de facturación asociado con tu proyecto.Habilita una cuenta de facturación con la consola de Google Cloud
  2. Para habilitar la facturación en tu proyecto a través de Terraform, agrega un atributo billing_account al recurso google_project existente en tu archivo main.tf:

    main.tf
    ...
    
    # Create a new Google Cloud project.
    resource "google_project" "default" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_YOUR_PROJECT>"
      project_id      = "<PROJECT_ID_OF_YOUR_PROJECT>"
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>" # Add this line with your Cloud Billing account ID
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    ...
    

Habilita Firebase Authentication y accede con Google mediante Terraform

  1. Para aprovisionar Firebase Authentication con GCIP, agrega tu archivo main.tf con los siguientes bloques de recursos:

    main.tf
    ...
    
    # Enable the Identity Toolkit API.
    resource "google_project_service" "auth" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      service =  "identitytoolkit.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Create an Identity Platform config.
    # Also, enable Firebase Authentication using Identity Platform (if Authentication isn't yet enabled).
    resource "google_identity_platform_config" "auth" {
      provider = google-beta
      project  = google_firebase_project.default.project
    
      # For example, you can configure to auto-delete anonymous users.
      autodelete_anonymous_users = true
    
      # Wait for identitytoolkit.googleapis.com to be enabled before initializing Authentication.
      depends_on = [
        google_project_service.auth,
      ]
    }
    
  2. Para habilitar el acceso con Google, debes tener un cliente de OAuth. Accede a la página de APIs y en la sección Servicios de la consola de Google Cloud para realizar esta configuración.
  3. Dado que esta es la primera vez que creas un ID de cliente para este proyecto, debes configurar la pantalla de consentimiento de OAuth.
    1. Abre la página Pantalla de consentimiento de OAuth y, luego, selecciona el proyecto que acabas de crear.
    2. Establece User Type en External y, luego, haz clic en Create.
    3. En la siguiente pantalla, completa lo siguiente y, luego, haz clic en Save and continue para guardar y continuar.
      • Establece el Nombre de la app público de tu app en algo como FriendlyChat (no es necesario que sea único a nivel global).
      • Elige un correo electrónico de asistencia al usuario en el menú desplegable.
      • Ingresa un correo electrónico para la Información de contacto del desarrollador.
    4. En las siguientes pantallas, completa lo siguiente:
      • Acepta los valores predeterminados en la página Permisos y, luego, haz clic en Guardar y continuar.
      • Acepta los valores predeterminados en la página Usuarios de prueba y, luego, haz clic en Guardar y continuar.
      • Revisa el resumen y, luego, haz clic en Volver al panel.
      Configura un cliente de OAuth2 con la consola de Google Cloud
  4. Para configurar un cliente de OAuth en la página Credenciales, haz lo siguiente:
    1. Haz clic en Crear credenciales y, luego, selecciona ID de cliente OAuth.
    2. En el menú desplegable Tipo de aplicación, selecciona Aplicación web.
    3. En el campo Nombre, ingresa el nombre de tu app, por ejemplo, FriendlyChat (no es necesario que sea único a nivel global).
    4. Para permitir que la URL de tu app use este cliente de OAuth, configura lo siguiente:
      • En Orígenes de JavaScript autorizados, haz clic en Agregar URI y, luego, ingresa
        https://<PROJECT_ID>.firebaseapp.com, donde <PROJECT_ID> es el ID del proyecto que configuraste en main.tf.
      • En URI de redireccionamiento autorizados, haz clic en Agregar URI y escribe
        https://<PROJECT_ID>.firebaseapp.com/__/auth/handler, donde <PROJECT_ID> es el ID de proyecto que configuraste en main.tf.
    5. Haz clic en Guardar.
    Cómo obtener el ID de cliente y el secreto de OAuth2 desde la página Credenciales de la consola de Google Cloud
  5. Para habilitar el acceso con Google con tu ID de cliente y secreto de cliente de OAuth, agrega el siguiente bloque a tu archivo main.tf:

    main.tf
    ...
    
    variable "oauth_client_secret" {
      type = string
    
      description = "OAuth client secret. For this codelab, you can pass in this secret through the environment variable TF_VAR_oauth_client_secret. In a real app, you should use a secret manager service."
    
      sensitive = true
    }
    
    resource "google_identity_platform_default_supported_idp_config" "google_sign_in" {
      provider = google-beta
      project  = google_firebase_project.default.project
    
      enabled       = true
      idp_id        = "google.com"
      client_id     = "<YOUR_OAUTH_CLIENT_ID>"
      client_secret = var.oauth_client_secret
    
      depends_on = [
         google_identity_platform_config.auth
      ]
    }
    

Aplica la configuración

  1. Para configurar Authentication según tu configuración, ejecuta los siguientes comandos desde la raíz del mismo directorio que tu archivo main.tf (que debería ser web):
    export TF_VAR_oauth_client_secret="<YOUR_OAUTH_CLIENT_SECRET>"
    
    terraform apply
    
    Ten en cuenta que ejecutar terraform apply no volverá a crear un proyecto nuevo de Google Cloud. Terraform detectará que ya existe un proyecto con el ID especificado y comparará el estado actual del proyecto con el contenido del archivo .tf. Luego, realizará los cambios que encuentre.
  2. Revisa el plan de acciones impreso. Si todo se ve como se espera, escribe yes y presiona Intro para aprobar las acciones.

Valida los cambios

  1. En Firebase console, busca la sección Build en el panel izquierdo.
  2. Haz clic en Authentication y, luego, en la pestaña Sign-in method (o haz clic aquí para ir directamente allí).
  3. Deberías ver a Google como un proveedor de acceso habilitado.Página Authentication de Firebase console: Acceso con Google habilitado

7. Configura una base de datos de Firestore y sus reglas de seguridad

En la app web de este codelab, almacenarás mensajes entre los usuarios finales en una base de datos de Firestore.

  1. Para habilitar las APIs requeridas y aprovisionar la instancia de la base de datos, agrega el archivo main.tf con los siguientes bloques de recursos:

    main.tf
    ...
    
    # Enable required APIs for Cloud Firestore.
    resource "google_project_service" "firestore" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      for_each = toset([
        "firestore.googleapis.com",
        "firebaserules.googleapis.com",
      ])
      service = each.key
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Provision the Firestore database instance.
    resource "google_firestore_database" "default" {
      provider                    = google-beta
    
      project                     = google_firebase_project.default.project
      name                        = "(default)"
      # See available locations:
      # https://firebase.google.com/docs/firestore/locations
      location_id                 = "<NAME_OF_DESIRED_REGION>"
      # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs,
      # authentication, and Firebase Security Rules.
      type                        = "FIRESTORE_NATIVE"
      concurrency_mode            = "OPTIMISTIC"
    
      depends_on = [
        google_project_service.firestore
      ]
    }
    
  2. Cambia <NAME_OF_DESIRED_REGION> a la región en la que quieres que resida la base de datos.

    Cuando desarrolles una app de producción, te recomendamos que esté en una región cercana a la mayoría de los usuarios y en común con otros servicios de Firebase, como Cloud Functions. En este codelab, puedes usar us-east1 (Carolina del Sur) o la región más cercana a ti (consulta Ubicaciones de Cloud Firestore).
  3. Cada instancia de base de datos de Firestore a la que Firebase pueda acceder debe estar protegida por las reglas de seguridad de Firebase.

    El código de muestra de este codelab proporciona un conjunto de reglas seguras de Firestore en el archivo firestore.rules, que puedes encontrar en la raíz del directorio web.
  4. Agrega el archivo main.tf con los siguientes bloques de recursos para hacer lo siguiente:
    • Crea un conjunto de reglas de reglas de seguridad de Firebase a partir del archivo local firestore.rules.
    • Publica el conjunto de reglas para la instancia de Firestore.
    Ten en cuenta que estos bloques de recursos realizan la acción equivalente a hacer clic en el botón Publish en Firebase console o a ejecutar firebase deploy --only firestore:rules.

    main.tf
    ...
    
    # Create a ruleset of Firestore Security Rules from a local file.
    resource "google_firebaserules_ruleset" "firestore" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      source {
        files {
          name = "firestore.rules"
          # Write security rules in a local file named "firestore.rules".
          # Learn more: https://firebase.google.com/docs/firestore/security/get-started
          content = file("firestore.rules")
        }
      }
    
      # Wait for Firestore to be provisioned before creating this ruleset.
      depends_on = [
        google_firestore_database.default,
      ]
    }
    
    # Release the ruleset for the Firestore instance.
    resource "google_firebaserules_release" "firestore" {
      provider     = google-beta
    
      name         = "cloud.firestore"  # must be cloud.firestore
      ruleset_name = google_firebaserules_ruleset.firestore.name
      project      = google_firebase_project.default.project
    
      # Wait for Firestore to be provisioned before releasing the ruleset.
      depends_on = [
        google_firestore_database.default,
      ]
    
      lifecycle {
        replace_triggered_by = [
          google_firebaserules_ruleset.firestore
        ]
      }
    }
    
  5. Ejecuta terraform apply para aprovisionar la base de datos de Firestore y, luego, implementar sus reglas de seguridad.
  6. Verifica que la base de datos esté aprovisionada y que se hayan implementado sus reglas de seguridad:
    1. En Firebase console, busca la sección Build en el panel izquierdo.
    2. Ve a la sección Base de datos de Firestore y, luego, haz clic en la pestaña Reglas.
    Cómo verificar las reglas de Cloud Firestore con Firebase console

8. Configura un bucket de Cloud Storage y sus reglas de seguridad

En la app web de este codelab, almacenarás las imágenes que comparten los usuarios finales en un bucket de Cloud Storage.

  1. Para habilitar las APIs requeridas y aprovisionar tu bucket predeterminado de Cloud Storage, agrega el archivo main.tf con los siguientes bloques de recursos.

    Ten en cuenta que el bucket predeterminado de Cloud Storage de tu proyecto se aprovisiona a través de Google App Engine y debe tener la misma ubicación que tu base de datos de Firestore. Consulta Ubicaciones de App Engine para obtener más información.

    Si quieres tener varios buckets en tu proyecto, aprovisionalos con el recurso google_storage_bucket (que no se muestra en este codelab).

    main.tf
    ...
    
    # Enable required APIs for Cloud Storage for Firebase.
    resource "google_project_service" "storage" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      for_each = toset([
        "firebasestorage.googleapis.com",
        "storage.googleapis.com",
      ])
      service = each.key
    
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Provision the default Cloud Storage bucket for the project via Google App Engine.
    resource "google_app_engine_application" "default" {
      provider    = google-beta
    
      project     = google_firebase_project.default.project
      # See available locations: https://firebase.google.com/docs/projects/locations#default-cloud-location
      # This will set the location for the default Storage bucket and the App Engine App.
      location_id = "<NAME_OF_DESIRED_REGION_FOR_DEFAULT_BUCKET>"  # Must be in the same location as Firestore (above)
    
      # Wait until Firestore is provisioned first.
      depends_on = [
        google_firestore_database.default
      ]
    }
    
    # Make the default Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
    resource "google_firebase_storage_bucket" "default-bucket" {
      provider  = google-beta
    
      project   = google_firebase_project.default.project
      bucket_id = google_app_engine_application.default.default_bucket
    }
    
  2. Cada bucket de Cloud Storage al que Firebase pueda acceder debe estar protegido por las reglas de seguridad de Firebase.

    El código de ejemplo de este codelab proporciona un conjunto de reglas seguras de Firestore en el archivo storage.rules, que puedes encontrar en la raíz del directorio web.
  3. Agrega tu archivo main.tf con los siguientes bloques de recursos para hacer lo siguiente:
    • Crea un conjunto de reglas de las reglas de seguridad de Firebase desde el archivo local.
    • Publica el conjunto de reglas para el bucket de Storage.
    Ten en cuenta que estos bloques de recursos logran el equivalente a hacer clic en el botón Publicar en Firebase console o ejecutar firebase deploy --only storage.

    main.tf
    ...
    
    # Create a ruleset of Cloud Storage Security Rules from a local file.
    resource "google_firebaserules_ruleset" "storage" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      source {
        files {
          # Write security rules in a local file named "storage.rules".
          # Learn more: https://firebase.google.com/docs/storage/security/get-started
          name    = "storage.rules"
          content = file("storage.rules")
        }
      }
    
      # Wait for the default Storage bucket to be provisioned before creating this ruleset.
      depends_on = [
        google_firebase_storage_bucket.default-bucket,
      ]
    }
    
    # Release the ruleset to the default Storage bucket.
    resource "google_firebaserules_release" "default-bucket" {
      provider     = google-beta
    
      name         = "firebase.storage/${google_app_engine_application.default.default_bucket}"
      ruleset_name = "projects/${google_firebase_project.default.project}/rulesets/${google_firebaserules_ruleset.storage.name}"
      project      = google_firebase_project.default.project
    
      lifecycle {
        replace_triggered_by = [
          google_firebaserules_ruleset.storage
        ]
      }
    }
    
  4. Ejecuta terraform apply para aprovisionar el bucket predeterminado de Cloud Storage y, luego, implementa sus reglas de seguridad.
  5. Verifica que el bucket esté aprovisionado y que se hayan implementado sus reglas de seguridad:
    1. En Firebase console, localiza la sección Compilación en el panel izquierdo.
    2. Ve a la sección Almacenamiento y, luego, haz clic en la pestaña Reglas.
    Verifica las reglas de seguridad con Firebase console

9. Ejecuta tu app de manera local

Ya está todo listo para que ejecutes tu app web por primera vez. Usarás el emulador de Firebase Hosting para entregar tu app de forma local.

  1. Abre una ventana de terminal nueva y, desde el directorio web, ejecuta el siguiente comando de Firebase CLI para iniciar el emulador:
    firebase emulators:start --project=<PROJECT_ID>
    
  2. En el navegador, abre la app web en la URL local que muestra la CLI (generalmente http://localhost:5000).

Deberías ver la IU de tu app de FriendlyChat, que (aún) no funciona. La app aún no está conectada a Firebase, pero lo estará cuando completes los siguientes pasos de este codelab.

Ten en cuenta que, cada vez que realices cambios en tu app web (como lo harás en los siguientes pasos de este codelab), actualiza el navegador para actualizar la URL local con esos cambios.

10. Instala, configura e inicializa Firebase

Para que una app funcione con Firebase, debes tener el SDK de Firebase y la configuración de Firebase de tu proyecto.

El código de muestra de este codelab ya es una app funcional con todas las dependencias y funciones necesarias para usar varios productos de Firebase en la app. Puedes consultar web/package.json y web/src/index.js si quieres ver lo que ya se hizo.

Si bien el código de muestra está casi completo, de todos modos debes hacer algunas cosas para poner en marcha tu app, entre ellas, instalar el SDK de Firebase, comenzar tu compilación, agregar la configuración de Firebase a tu app y, por último, inicializar Firebase.

Instala el SDK de Firebase y comienza la compilación de webpack.

Debes ejecutar algunos comandos para comenzar la compilación de tu app.

  1. Abre una nueva ventana de terminal.
  2. Asegúrate de estar en la raíz del directorio web.
  3. Ejecuta npm install para descargar el SDK de Firebase.
  4. Ejecuta npm update para actualizar las dependencias.
  5. Ejecuta npm run start para iniciar webpack.

Para el resto del codelab, webpack volverá a compilar tu código fuente de forma continua.

Agrega tu configuración de Firebase a la app

También debes agregar la configuración de Firebase a tu app para que los SDK de Firebase sepan qué proyecto de Firebase quieres que usen.

En este codelab, tienes dos opciones diferentes para obtener tu configuración de Firebase:

  • Opción 1: Obtén tu configuración de Firebase desde Firebase console.
  • Opción 2: Obtén la configuración de Firebase mediante Terraform.

Opción 1: Obtén la configuración de Firebase console y agrégala a tu base de código

  1. En Firebase console, ve a la configuración del proyecto.
  2. Desplázate hacia abajo hasta la tarjeta Tus apps y, luego, selecciona tu aplicación web.
  3. Selecciona Configuración en el panel de fragmentos del SDK de Firebase y, luego, copia el fragmento de configuración.
  4. Pega la configuración en el archivo web/src/firebase-config.js de la app, de la siguiente manera:

    firebase-config.js
    ...
    
    const config = {
      apiKey: "<API_KEY>",
      authDomain: "<PROJECT_ID>.firebaseapp.com",
      projectId: "<PROJECT_ID>",
      storageBucket: "<PROJECT_ID>.appspot.com",
      messagingSenderId: "<SENDER_ID>",
      appId: "<APP_ID>",
      measurementId: "<G-MEASUREMENT_ID>",
    };
    
    ...
    

Opción 2: Obtén la configuración a través de Terraform y agrégala a tu base de código

Como alternativa, puedes obtener tu configuración de Firebase a través de Terraform como un valor de salida en la CLI.

  1. En el archivo main.tf, busca el bloque de recursos google_firebase_web_app (el bloque que registró una app web con tu proyecto).
  2. Inmediatamente después de ese bloque, agrega los siguientes bloques:

    main.tf
    ...
    
    data "google_firebase_web_app_config" "default" {
      provider     = google-beta
      project      = google_firebase_project.default.project
      web_app_id   = google_firebase_web_app.default.app_id
    }
    
    output "friendlychat_web_app_config" {
      value = {
        projectId         = google_firebase_project.default.project
        appId             = google_firebase_web_app.default.app_id
        apiKey            = data.google_firebase_web_app_config.default.api_key
        authDomain        = data.google_firebase_web_app_config.default.auth_domain
        storageBucket     = lookup(data.google_firebase_web_app_config.default, "storage_bucket", "")
        messagingSenderId = lookup(data.google_firebase_web_app_config.default, "messaging_sender_id", "")
        measurementId     = lookup(data.google_firebase_web_app_config.default, "measurement_id", "")
      }
    }
    
    ...
    
  3. Dado que el bloque data y el bloque output no están diseñados para modificar la infraestructura de ninguna manera, solo debes ejecutar los siguientes comandos.
    1. Para cargar la configuración de Firebase de tu app web en el estado de Terraform de tu directorio, ejecuta este comando:
      terraform refresh
      
    2. Para imprimir los valores de configuración de Firebase, ejecuta este comando:
      terraform output –json
      
      El siguiente es un ejemplo de resultado de una configuración. El resultado impreso contendrá los valores de tu proyecto y tu app.
      {
        "friendlychat_web_app_config": {
          "sensitive": false,
          "type": [
            "object",
            {
              "apiKey": "string",
              "appId": "string",
              "authDomain": "string",
              "measurementId": "string",
              "messagingSenderId": "string",
              "projectId": "string",
              "storageBucket": "string"
            }
          ],
          "value": {
            "apiKey": "<API_KEY>",
            "appId": "<APP_ID>",
            "authDomain": "<PROJECT_ID>.firebaseapp.com",
            "measurementId": "<G-MEASUREMENT_ID>",
            "messagingSenderId": "<SENDER_ID>",
            "projectId": "<PROJECT_ID>",
            "storageBucket": "<PROJECT_ID>.appspot.com"
          }
        }
      }
      
  4. Copia los valores desde el mapa de value.
  5. Pega estos valores (tu configuración) en el archivo web/src/firebase-config.js de la app, de esta manera:

    firebase-config.js
    ...
    
    const config = {
      apiKey: "<API_KEY>",
      appId: "<APP_ID>",
      authDomain: "<PROJECT_ID>.firebaseapp.com",
      measurementId: "<G-MEASUREMENT_ID>",
      messagingSenderId: "<SENDER_ID>",
      projectId: "<PROJECT_ID>",
      storageBucket: "<PROJECT_ID>.appspot.com",
    };
    
    ...
    

Inicializa Firebase en la app

Por último, para inicializar Firebase, agrega el archivo web/src/index.js de tu app con lo siguiente:

index.js

...

const firebaseAppConfig = getFirebaseConfig();
initializeApp(firebaseAppConfig);

Prueba tu app

Ahora que todo está configurado para Firebase, puedes probar tu aplicación web funcional.

  1. Actualiza el navegador que entrega tu app.
  2. Ahora deberías poder acceder con Google y comenzar a publicar mensajes en el chat. Si tienes archivos de imagen, incluso puedes subirlos.

11. Replica tu configuración en todos los entornos

Terraform se destaca por administrar varias infraestructuras configuradas de manera similar (por ejemplo, configurar un proyecto de Firebase de etapa de pruebas similar a un proyecto de producción).

En este codelab, crearás un segundo proyecto de Firebase para que sea un entorno de etapa de pruebas.

Si quieres replicar una configuración existente para crear este proyecto de etapa de pruebas, tienes dos opciones:

  • Opción 1: Haz una copia de la configuración de Terraform.
    Esta opción ofrece la mayor flexibilidad en cuanto a la diferencia entre el proyecto replicado y el proyecto de origen.
  • Opción 2: Vuelve a usar la configuración con for_each.
    Esta opción ofrece más reutilización de código si cada proyecto no debe diferir de manera significativa y deseas propagar los cambios a todos los proyectos a la vez.

Opción 1: Haz una copia de la configuración de Terraform

Esta opción ofrece la mayor flexibilidad en cuanto a la diferencia que puede tener el proyecto replicado del proyecto de origen, como tener apps con diferentes nombres visibles y lanzamientos por etapas.

  1. En la raíz del directorio web, crea un nuevo archivo de configuración de Terraform llamado main_staging.tf.
  2. Copia todos los bloques de recursos de tu archivo main.tf (excepto los bloques terraform y provider) y, luego, pégalos en tu archivo main_staging.tf.
  3. Luego, debes modificar cada uno de tus bloques de recursos replicados en main_staging.tf para que funcionen con tu proyecto de pruebas:
    • Etiquetas de recursos: Usa un nombre nuevo para evitar conflictos. Por ejemplo, cambia el nombre de resource "google_project" "default" a resource "google_project" "staging".
    • Referencias de recursos: Actualiza cada una. Por ejemplo, actualiza google_firebase_project.default.project a google_firebase_project.staging.project.
    Puedes encontrar la configuración completa de un archivo main_staging.tf en el repositorio de GitHub de este codelab:

    web/terraform-checkpoints/replicate-config/main_staging-copypaste.tf

    Si quieres usar esta configuración, asegúrate de hacer lo siguiente:
    1. Copia la configuración de main_staging-copypaste.tf y, luego, pégala en tu archivo main_staging.tf.
    2. En el archivo main_staging.tf, haz lo siguiente:
      • En el bloque de recursos google_project, actualiza los atributos name, project-id y (si configuras Authentication a través de Terraform) el atributo billing_account con tus propios valores.
      • En el bloque de recursos google_firebase_web_app, actualiza el atributo display_name con tu propio valor.
      • En los bloques de recursos google_firestore_database y google_app_engine_application, actualiza los atributos location_id con tu propio valor.
    main_staging.tf
    # Create a new Google Cloud project.
    resource "google_project" "staging" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_STAGING_PROJECT>"
      project_id      = "<PROJECT_ID_OF_STAGING_PROJECT"
      # Required if you want to set up Authentication via Terraform
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "staging_serviceusage" {
      provider = google-beta.no_user_project_override
    
      project = google_project.staging.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "staging_firebase" {
      provider = google-beta.no_user_project_override
    
      project = google_project.staging.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable Firebase services for the new project created above.
    resource "google_firebase_project" "staging" {
      provider = google-beta
    
      project = google_project.staging.project_id
    
      # Wait until the required APIs are enabled.
      depends_on = [
        google_project_service.staging_serviceusage,
        google_project_service.staging_firebase,
      ]
    }
    
    # Create a Firebase Web App in the new project created above.
    resource "google_firebase_web_app" "staging" {
      provider = google-beta
    
      project      = google_firebase_project.staging.project
      display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
      deletion_policy = "DELETE"
    }
    
  4. Ejecuta terraform apply para aprovisionar tu nueva “etapa de pruebas” proyecto de Firebase y todos sus recursos, y habilitar sus servicios.
  5. Verifica que todo se haya aprovisionado y habilitado según lo esperado en Firebase console, igual que antes.

Opción 2: Reutiliza los parámetros de configuración con for_each

Esta opción ofrece más reutilización de código si cada proyecto no debería diferir de manera significativa y deseas propagar los cambios en todos los proyectos a la vez. Usa el metaargumento for_each en el lenguaje de Terraform.

  1. Abre el archivo main.tf.
  2. En cada bloque de recursos que quieras replicar, agrega un metaargumento for_each, de la siguiente manera:

    main.tf
    # Create new Google Cloud projects.
    resource "google_project" "default" {
      provider        = google-beta.no_user_project_override
      name            = each.value
      # Create a unique project ID for each project, with each ID starting with <PROJECT_ID>.
      project_id      = "<PROJECT_ID>-${each.key}"
      # Required if you want to set up Authentication via Terraform
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>"
    
      # Required for the projects to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    
      for_each = {
        prod    = "<PROJECT_NAME_OF_PROD_PROJECT>"
        staging = "<PROJECT_NAME_OF_STAGING_PROJECT>"
      }
    }
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "serviceusage" {
      provider = google-beta.no_user_project_override
      for_each = google_project.default
    
      project = each.value.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "firebase" {
      provider = google-beta.no_user_project_override
      for_each = google_project.default
    
      project = each.value.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable Firebase services for each of the new projects created above.
    resource "google_firebase_project" "default" {
      provider = google-beta
      for_each = google_project.default
    
      project = each.value.project_id
    
      depends_on = [
        google_project_service.serviceusage,
        google_project_service.firebase,
      ]
    }
    
    # Create a Firebase Web App in each of the new projects created above.
    resource "google_firebase_web_app" "default" {
      provider = google-beta
      for_each = google_firebase_project.default
    
      project      = each.value.project
      # The Firebase Web App created in each project will have the same display name.
      display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
      deletion_policy = "DELETE"
    }
    
    
    # NOTE: For this codelab, we recommend setting up Firebase Authentication
    # using the Firebase console. However, if you set up Firebase Authentication
    # using Terraform, copy-paste from your main.tf the applicable blocks.
    # Make sure to add the `for_each` meta-argument into each block.
    
    
    # Copy-paste from your main.tf file the applicable resource blocks
    # for setting up Cloud Firestore (including rules) and
    # for setting up Cloud Storage for Firebase (including rules).
    # Make sure to add the `for_each` meta-argument into each block.
    
    Puedes encontrar la configuración completa de un archivo main.tf que usa el metaargumento for_each en el repositorio de GitHub de este codelab:

    web/terraform-checkpoints/replicate-config/main-foreach.tf

    Si quieres usar esta configuración, asegúrate de hacer lo siguiente:
    1. Copia la configuración de main-foreach.tf y, luego, pégala en tu archivo main.tf.
    2. En el archivo main.tf, haz lo siguiente:
      • En el bloque de recursos google_project, actualiza los atributos name, project-id y (si configuras Authentication a través de Terraform) el atributo billing_account con tus propios valores.
      • En el bloque de recursos google_firebase_web_app, actualiza el atributo display_name con tu propio valor.
      • En los bloques de recursos google_firestore_database y google_app_engine_application, actualiza los atributos location_id con tu propio valor.
  3. En lugar de aplicar esta configuración de inmediato, es importante comprender y corregir algunos aspectos sobre cómo Terraform interpreta esta configuración en comparación con la infraestructura existente.
    1. En este momento, si aplicaras esta configuración que usa for_each, las direcciones de recursos se verían de la siguiente manera:
      google_project.default["prod"]
      google_project.default["staging"]
      google_firebase_project.default["prod"]
      google_firebase_project.default["staging"]
      google_firebase_web_app.default["prod"]
      google_firebase_web_app.default["staging"]
      
      Sin embargo, Terraform conoce el proyecto existente que creaste en la primera parte de este codelab de la siguiente manera:
      google_project.default
      google_firebase_project.default
      google_firebase_android_app.default
      
    2. Ejecuta terraform plan para ver qué acciones realizaría Terraform según el estado actual.

      El resultado debería mostrar que Terraform borraría el proyecto que creaste en la primera parte de este codelab y crearía dos proyectos nuevos. Esto se debe a que Terraform no sabe que el proyecto ubicado en la dirección google_project.default se movió a la nueva dirección google_project.default["prod"].
    3. Para solucionar esto, ejecuta el comando terraform state mv:
      terraform state mv "google_project.default" "google_project.default[\"prod\"]"
      
    4. Del mismo modo, para corregir todos los demás bloques de recursos, ejecuta terraform state mv para google_firebase_project, google_firebase_web_app y todos los demás bloques de recursos de tu archivo main.tf.
    5. Ahora, si vuelves a ejecutar terraform plan, no debería mostrar que Terraform borraría el proyecto que creaste en la primera parte de este codelab.
  4. Ejecuta terraform apply para aprovisionar tu nuevo proyecto de Firebase "de pruebas" y todos sus recursos, y habilitar sus servicios.
  5. Verifica que todo esté aprovisionado y habilitado como se esperaba. Para ello, búscalos en Firebase console como antes.

12. Paso adicional: Implementa tus apps de prueba y producción

  1. En la base de código de tu app, cambia el firebase-config.js para usar la configuración de Firebase de tu proyecto de etapa de pruebas.

    Para recordar cómo obtener tu configuración de Firebase y agregarla a tu app, consulta el paso anterior de este codelab, Agrega tu configuración de Firebase a tu app.
  2. En la raíz del directorio web, ejecuta el siguiente comando para implementar la app en el proyecto de Firebase de etapa de pruebas.
    firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
    
  3. Abre tu app de etapa de pruebas en el navegador a través de la URL que se imprime en el resultado de firebase deploy. Intenta acceder, enviar mensajes y subir imágenes.

    Cuando implementas una app en un proyecto de Firebase, se usan recursos reales de Firebase, no emulados. A medida que interactúas con la app de etapa de pruebas, deberías ver imágenes y datos en el proyecto de etapa de pruebas en Firebase console.
  4. Después de probar tu app en la etapa de pruebas, vuelve a cambiar firebase-config.js para usar la configuración de Firebase del proyecto de producción (el primer proyecto que creaste en este codelab).
  5. En la raíz del directorio web, ejecuta el siguiente comando para implementar la app en el proyecto de producción de Firebase.
    firebase deploy --only hosting --project=<PRODUCTION_PROJECT_ID>
    
  6. Abre tu app de producción en el navegador a través de la URL que se imprime en el resultado de firebase deploy. Intenta acceder, enviar mensajes y subir imágenes.

    Deberías ver imágenes y datos en tu proyecto de producción en Firebase console.
  7. Cuando termines de interactuar con las dos apps en este codelab, puedes dejar de que Firebase las entregue. Ejecuta el siguiente comando para cada uno de tus proyectos:
    firebase hosting:disable --project=<STAGING_PROJECT_ID>
    
    firebase hosting:disable --project=<PRODUCTION_PROJECT_ID>
    

13. ¡Felicitaciones!

Usaste Terraform para configurar una aplicación web de chat en tiempo real. Además, seguiste las prácticas recomendadas para entornos de desarrollo creando proyectos de Firebase independientes para la etapa de pruebas y la producción.

Temas abordados

  • Usa la CLI de Terraform para administrar recursos en la nube
  • Cómo usar Terraform para configurar productos de Firebase (Authentication, Firestore, Cloud Storage y reglas de seguridad)
  • Cómo ejecutar y probar una app web de forma local con Firebase Local Emulator Suite
  • Importa Firebase a una app web
  • Usa Terraform para replicar una configuración en varios entornos

Para obtener más información sobre Firebase y Terraform, visita nuestra documentación. Puedes encontrar una lista de todos los productos de Firebase compatibles con Terraform, muestras de configuraciones de Terraform para casos de uso comunes, y preguntas frecuentes y soluciones de problemas útiles.