Configurar e gerenciar projetos e produtos do Firebase pelo Terraform

1. Introdução

Metas

É possível usar o Terraform para configurar e gerenciar um projeto do Firebase, incluindo a configuração programática da infraestrutura e dos produtos do Firebase.

Este codelab descreve primeiro como criar um arquivo de configuração do Terraform para criar um novo projeto do Firebase, seguido de como configurar os apps e produtos do Firebase que você quer usar nesse projeto. Também abordamos os conceitos básicos da linha de comando do Terraform, como conferir uma prévia das mudanças a serem feitas e implementá-las.

Se você quer aprender a configurar e gerenciar projetos e produtos do Firebase com o Terraform, este codelab é para você.

O que você vai aprender

  • Como criar um arquivo de configuração do Terraform (*.tf)
  • Como usar os comandos da CLI do Terraform para gerenciar sua infraestrutura
  • Como modificar a configuração para atualizar recursos e serviços
  • Como aplicar sua configuração em um app da Web real (chamado Friendly Chat)
  • Como definir configurações paralelas (e sincronizadas) em diferentes ambientes (produção, preparação etc.)

Pré-requisitos

Para ter sucesso neste codelab, você precisa ter conhecimento básico do Terraform e da terminologia dele, incluindo os seguintes pré-requisitos:

Este codelab fornece um app de exemplo real para que você possa testar e interagir com o que provisionou pelo Terraform. Para fazer isso, você precisa do seguinte:

  • O exemplo de código para um app da Web: faça o download dele na próxima etapa do codelab
  • O gerenciador de pacotes npm (que geralmente vem com o Node.js): instale essas ferramentas
  • A CLI do Firebase: instale essa CLI e faça login

2. Fazer o download do código inicial

Neste codelab, você pode testar o provisionamento pelo Terraform com um app da Web real. Recomendamos fazer isso para entender todas as etapas necessárias para usar os recursos provisionados pelo Terraform.

Clone o repositório do GitHub do codelab na linha de comando:

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

Se o git não estiver instalado, faça o download do repositório como um arquivo ZIP.

3. Criar uma configuração do Terraform

Configuração do Terraform

  1. Na base de código do app de exemplo transferido por download, navegue até a raiz do diretório web.
  2. Na raiz desse diretório, crie um arquivo de configuração do Terraform chamado main.tf com a seguinte configuração 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 um dos provedores google-beta tem um atributo chamado user_project_override, que determina como as operações do Terraform serão verificadas pela cota. Para provisionar a maioria dos recursos, use user_project_override = true, o que significa verificar a cota do seu próprio projeto do Firebase. No entanto, para configurar o novo projeto para que ele possa aceitar verificações de cota, primeiro você precisa usar user_project_override=false. A sintaxe alias do Terraform permite distinguir entre as duas configurações de provedor nas próximas etapas deste codelab.

Inicializar o Terraform no diretório

A criação de uma nova configuração pela primeira vez exige o download do provedor especificado na configuração.

Para fazer essa inicialização, execute o comando a seguir na raiz do mesmo diretório do arquivo de configuração main.tf:

terraform init

4. Criar um projeto do Firebase usando o Terraform

Para "criar um projeto do Firebase", é importante lembrar que cada projeto do Firebase é um projeto do Google Cloud, apenas com os serviços do Firebase ativados.

Adicionar blocos para o projeto e as APIs do Google Cloud

  1. Primeiro, provisione o projeto do Google Cloud.

    Adicione o seguinte bloco de recursos ao arquivo de configuração main.tf.

    Especifique o nome do projeto (como "Terraform FriendlyChat Codelab") e o ID do projeto (como "terraform-codelab-your-initials"). O valor name é usado apenas nas interfaces do Firebase e não é visível para os usuários finais. O valor project_id identifica seu projeto de forma exclusiva para o Google. Portanto, especifique um valor exclusivo. 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. Em seguida, ative as APIs necessárias: a API Usage e a API Firebase Management.

    Essa ativação de API geralmente é processada em segundo plano quando você usa o console do Firebase para criar um projeto do Firebase, mas o Terraform precisa ser instruído explicitamente para fazer essa ativação.

    Adicione o seguinte bloco de recursos ao arquivo de configuração main.tf (logo abaixo do bloco que cria o novo projeto do Cloud):

    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
    }
    
    Ao ativar a API Service Usage, seu novo projeto poderá aceitar verificações de cota. Portanto, para todo provisionamento de recursos e ativação de serviços subsequentes, use o provedor com user_project_override (não é necessário usar um alias).

Adicionar um bloco para ativar os serviços do Firebase

A última coisa necessária para "criar um projeto do Firebase" é ativar os serviços do Firebase no projeto.

Continuando no arquivo de configuração main.tf, adicione o bloco de recursos a seguir.

Como mencionado acima, este bloco de recursos usa o provedor com user_project_override (não é necessário um 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,
  ]
}

No bloco de recursos acima, você pode notar a cláusula depends_on, que instrui o Terraform a aguardar a ativação das APIs. Sem essa cláusula, o Terraform não sabe sobre a dependência e pode encontrar erros ao provisionar recursos em paralelo.

Aplique a configuração

  1. Para provisionar os novos recursos e ativar as APIs especificadas no arquivo de configuração, execute o seguinte comando na raiz do mesmo diretório do arquivo main.tf (que deve ser web):
    terraform apply
    
  2. No terminal, o Terraform mostra um plano de ações que serão realizadas.

    Se tudo estiver conforme o esperado, aprove as ações digitando yes.

    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 # <----
    

Se você só precisa conferir as mudanças sem aplicá-las, use o comando terraform plan.

Validar as mudanças

Depois que o Terraform terminar a execução, será possível inspecionar o estado de todos os recursos e serviços provisionados e ativados pelo Terraform executando o seguinte comando:

terraform show

Confira um exemplo do que você vai encontrar impresso. O estado vai conter valores específicos do seu projeto.

# 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, é possível verificar se o projeto foi criado visualizando-o no Console do Firebase.

O projeto do Codelab do Terraform FriendlyChat selecionado no console do Firebase

5. Registrar seu app do Firebase pelo Terraform

Para usar o Firebase, é necessário registrar cada variante de plataforma do app no projeto do Firebase. Neste codelab, você vai usar um app real para testar e interagir com o que provisionou pelo Terraform. Como esse app é da Web, você precisa informar ao Terraform que um app da Web do Firebase foi registrado no projeto do Firebase recém-criado.

Adicionar um bloco para registrar o app da Web

Para registrar o app da Web no projeto do Firebase, anexe o arquivo main.tf ao bloco de recursos a seguir.

É necessário especificar seu próprio display_name para o app da Web. Esse nome é usado apenas nas interfaces do Firebase e não é visível para os usuários finais.

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"
}

Aplique a configuração

  1. Para provisionar o novo recurso, execute o comando a seguir na raiz do mesmo diretório do arquivo main.tf (que deve ser web).
    terraform apply
    
    Esse comando não recria um projeto do Google Cloud. O Terraform vai detectar que um projeto com o ID especificado já existe e comparar o estado atual do projeto com o que está no arquivo .tf e fazer as alterações encontradas.
  2. Analise o plano de ações impresso. Se tudo estiver certo, digite yes e pressione Enter para aprovar as ações.

Validar as mudanças

Para inspecionar o estado do recurso provisionado, execute o seguinte comando:

terraform show

Como alternativa, você pode verificar se o app foi registrado no projeto no console do Firebase. Acesse Configurações do projeto e role para baixo até a seção Seus apps.

6. Configurar o Firebase Authentication

A autenticação é uma parte importante de qualquer app. Para permitir que os usuários finais façam login no seu app da Web com as próprias Contas do Google, ative o Firebase Authentication e configure o método de login com o Google.

Neste codelab, oferecemos duas opções diferentes para configurar o Firebase Authentication:

  • Opção 1 (recomendada): configure o Firebase Authentication no console, que não exige o GCIP.
    • Ao usar essa opção, não é necessário associar o novo projeto a uma conta do Cloud Billing.
  • Opção 2: configurar a Autenticação do Firebase pelo Terraform usando as APIs do Google Cloud Identity Platform (GCIP).
    • Ao usar essa opção, você precisa associar o novo projeto a uma conta do Cloud Billing, já que o GCIP exige que o projeto esteja no plano de preços Blaze.

Opção 1: configurar a autenticação usando o console do Firebase

Para configurar o Firebase Authentication usando o console do Firebase, seu projeto não precisa estar no plano de preços Blaze.

Confira como configurar o Firebase Authentication e fazer login com o Google:

  1. No Console do Firebase, localize a seção Build no painel esquerdo.
  2. Clique em Autenticação, Começar e na guia Método de login (ou clique aqui para acessar diretamente).
  3. Clique em Adicionar novo provedor e, na seção Outros provedores, selecione Google.
  4. Ative a opção Ativar.
  5. Defina o nome público do app como algo como FriendlyChat. Ele não precisa ser globalmente exclusivo.
  6. Escolha um E-mail de suporte do projeto no menu suspenso e clique em Salvar.Como configurar o Firebase Auth no console do Firebase
  7. O Google vai aparecer como um provedor de login ativado.Página de autenticação do console do Firebase: Login do Google ativado

Opção 2: configurar a autenticação pelo Terraform usando as APIs do Google Cloud Identity Platform (GCIP)

Para configurar o Firebase Authentication pelo Terraform, é necessário usar as APIs do GCIP, o que significa que o projeto precisa estar no plano de preços Blaze. Para fazer upgrade do seu projeto do Firebase e usar o plano Blaze, basta associar uma conta do Cloud Billing a ele.

Ativar o faturamento pelo Terraform

  1. Se você ainda não tem uma conta do Cloud Billing, a primeira etapa é criar uma no Console do Google Cloud. Anote o ID da conta de faturamento. O ID da conta de faturamento pode ser encontrado na página de faturamento em ID da conta de faturamento associado ao seu projeto.Ativar uma conta de faturamento usando o console do Google Cloud
  2. Para ativar o faturamento no seu projeto pelo Terraform, adicione um atributo billing_account ao recurso google_project no arquivo 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"
      }
    }
    
    ...
    

Ativar o Firebase Authentication e fazer login com o Google pelo Terraform

  1. Para provisionar o Firebase Authentication com o GCIP, anexe o arquivo main.tf aos seguintes blocos 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 ativar o login com o Google, você precisa ter um cliente OAuth. Acesse a seção APIs e serviços do console do Google Cloud para fazer essa configuração.
  3. Como esta é a primeira vez que você cria um ID do cliente para este projeto, é necessário configurar a tela de consentimento do OAuth.
    1. Abra a página Tela de consentimento do OAuth e selecione o projeto que você acabou de criar.
    2. Defina o Tipo de usuário como Externo e clique em Criar.
    3. Na próxima tela, preencha as informações a seguir e clique em Salvar e continuar.
      • Defina o nome público do app para algo como FriendlyChat. Ele não precisa ser globalmente exclusivo.
      • Escolha um e-mail de suporte ao usuário no menu suspenso.
      • Insira um e-mail para as Informações de contato do desenvolvedor.
    4. Nas próximas telas, faça o seguinte:
      • Aceite os padrões na página Escopos e clique em Salvar e continuar.
      • Aceite as configurações padrão na página Testar usuários e clique em Salvar e continuar.
      • Leia o resumo e clique em Voltar ao painel.
      Como configurar um cliente OAuth2 usando o console do Google Cloud
  4. Configure um cliente OAuth na página Credenciais:
    1. Clique em Criar credenciais e selecione ID do cliente do Oauth.
    2. No menu suspenso Tipo de aplicativo, selecione Aplicativo da Web.
    3. No campo Name, insira o nome do app, por exemplo, FriendlyChat. Ele não precisa ser globalmente exclusivo.
    4. Permita que o URL do app use esse cliente OAuth definindo o seguinte:
      • Em Origens JavaScript autorizadas, clique em Adicionar URI e insira
        https://<PROJECT_ID>.firebaseapp.com, em que <PROJECT_ID> é o ID do projeto definido em main.tf.
      • Em URIs de redirecionamento autorizados, clique em Adicionar URI e insira
        https://<PROJECT_ID>.firebaseapp.com/__/auth/handler, em que <PROJECT_ID> é o ID do projeto definido em main.tf.
    5. Clique em Salvar.
    Como conseguir o ID e a chave secreta do cliente OAuth2 na página de credenciais do console do Google Cloud
  5. Para ativar o login com o Google usando o ID e a chave secreta do cliente OAuth, anexe o arquivo main.tf com o seguinte bloco:

    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
      ]
    }
    

Aplique a configuração

  1. Para configurar a autenticação de acordo com sua configuração, execute os seguintes comandos na raiz do mesmo diretório do arquivo main.tf (que deve ser web):
    export TF_VAR_oauth_client_secret="<YOUR_OAUTH_CLIENT_SECRET>"
    
    terraform apply
    
    A execução de terraform apply não recria um projeto do Google Cloud. O Terraform vai detectar que um projeto com o ID especificado já existe e comparar o estado atual do projeto com o que está no arquivo .tf. Em seguida, ele vai fazer as mudanças encontradas.
  2. Analise o plano de ações impresso. Se tudo estiver certo, digite yes e pressione Enter para aprovar as ações.

Validar as mudanças

  1. No Console do Firebase, localize a seção Build no painel esquerdo.
  2. Clique em Autenticação e na guia Método de login (ou clique aqui para acessar diretamente).
  3. O Google vai aparecer como um provedor de login ativado.Página de autenticação do console do Firebase: Login do Google ativado

7. Configurar um banco de dados do Firestore e as regras de segurança

Para o app da Web deste codelab, você vai armazenar mensagens entre usuários finais em um banco de dados do Firestore.

  1. Para ativar as APIs necessárias e provisionar a instância do banco de dados, anexe o arquivo main.tf com os seguintes blocos 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. Mude <NAME_OF_DESIRED_REGION> para a região em que você quer que o banco de dados fique.

    Ao desenvolver um app de produção, é recomendável que ele fique em uma região próxima à maioria dos usuários e em comum com outros serviços do Firebase, como o Cloud Functions. Para este codelab, use us-east1 (Carolina do Sul) ou a região mais próxima de você (consulte Locais do Cloud Firestore).
  3. Todas as instâncias de banco de dados do Firestore que podem ser acessadas pelo Firebase precisam ser protegidas pelas regras de segurança do Firebase.

    O código de exemplo deste codelab fornece um conjunto de regras seguras do Firestore no arquivo firestore.rules, que pode ser encontrado na raiz do diretório web.
  4. Anexe o arquivo main.tf com os seguintes blocos de recursos para fazer o seguinte:
    • Crie um conjunto de regras de segurança do Firebase usando o arquivo firestore.rules local.
    • Libere o conjunto de regras para a instância do Firestore.
    Esses blocos de recursos equivalem a clicar no botão Publicar no console do Firebase ou executar 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. Execute terraform apply para provisionar o banco de dados do Firestore e implantar as regras de segurança.
  6. Verifique se o banco de dados está provisionado e se as regras de segurança dele estão implantadas:
    1. No Console do Firebase, localize a seção Build no painel esquerdo.
    2. Acesse a seção Banco de dados do Firestore e clique na guia Regras.
    Como verificar as regras do Cloud Firestore usando o console do Firebase

8. Configurar um bucket do Cloud Storage e as regras de segurança

Para o app da Web deste codelab, você vai armazenar imagens compartilhadas entre usuários finais em um bucket do Cloud Storage.

  1. Para ativar as APIs necessárias e provisionar o bucket padrão do Cloud Storage, anexe o arquivo main.tf com os blocos de recursos a seguir.

    O bucket padrão do Cloud Storage para seu projeto é provisionado pelo Google App Engine e precisa ter o mesmo local que seu banco de dados do Firestore. Consulte Locais do App Engine para mais informações.

    Se você quiser vários buckets no projeto, provisione-os usando o recurso google_storage_bucket (não mostrado neste 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. Todos os buckets do Cloud Storage acessíveis ao Firebase precisam ser protegidos pelas regras de segurança do Firebase.

    O código de exemplo deste codelab fornece um conjunto de regras seguras do Firestore no arquivo storage.rules, que pode ser encontrado na raiz do diretório web.
  3. Anexe o arquivo main.tf com os seguintes blocos de recursos para fazer o seguinte:
    • Crie um conjunto de regras de segurança do Firebase usando o arquivo local.
    • Libere a regra para o bucket do Storage.
    Esses blocos de recursos equivalem a clicar no botão Publicar no console do Firebase ou executar 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. Execute terraform apply para provisionar o bucket padrão do Cloud Storage e implantar as regras de segurança dele.
  5. Verifique se o bucket está provisionado e se as regras de segurança dele estão implantadas:
    1. No Console do Firebase, localize a seção Build no painel esquerdo.
    2. Acesse a seção Armazenamento e clique na guia Regras.
    Como verificar as regras de segurança usando o Console do Firebase

9. Execute seu aplicativo localmente

Agora você já pode executar o app da Web pela primeira vez. Você vai usar o emulador do Firebase Hosting para disponibilizar o app localmente.

  1. Abra uma nova janela do terminal e, no diretório web, execute o comando CLI do Firebase a seguir para iniciar o emulador:
    firebase emulators:start --project=<PROJECT_ID>
    
  2. No navegador, abra o app da Web no URL local retornado pela CLI (geralmente http://localhost:5000).

Você vai notar a interface do app FriendlyChat, que (ainda) não está funcionando. O app ainda não está conectado ao Firebase, mas será depois de concluir as próximas etapas deste codelab.

Sempre que você fizer mudanças no app da Web (como nas próximas etapas deste codelab), atualize o navegador para atualizar o URL local com essas mudanças.

10. Instalar, configurar e inicializar o Firebase

Para que um app funcione com o Firebase, ele precisa do SDK e da configuração do Firebase para o projeto.

O código de exemplo deste codelab já é um app funcional com todas as dependências e funções necessárias para usar vários produtos do Firebase. Você pode conferir em web/package.json e web/src/index.js se quiser saber o que já foi feito.

Embora o código de exemplo esteja quase completo, ainda é necessário fazer algumas coisas para que o app funcione, incluindo: instalar o SDK do Firebase, iniciar o build, adicionar a configuração do Firebase ao app e, por fim, inicializar o Firebase.

Instalar o SDK do Firebase e iniciar o build do webpack

Você precisa executar alguns comandos para iniciar o build do app.

  1. Abra uma nova janela do terminal.
  2. Verifique se você está na raiz do diretório web.
  3. Execute npm install para fazer o download do SDK do Firebase.
  4. Execute npm update para atualizar as dependências.
  5. Execute npm run start para iniciar o Webpack.

No restante do codelab, o webpack vai recriar continuamente o código-fonte.

Adicionar a configuração do Firebase ao app

Você também precisa adicionar a configuração do Firebase ao seu app para que os SDKs do Firebase saibam qual projeto do Firebase você quer usar.

Para este codelab, você tem duas opções diferentes para acessar a configuração do Firebase:

  • Opção 1: extraia a configuração do Firebase do console do Firebase.
  • Opção 2: extrair a configuração do Firebase pelo Terraform.

Opção 1: extrair a configuração do console do Firebase e adicioná-la à base de código

  1. No Console do Firebase, acesse as Configurações do projeto.
  2. Role a tela para baixo até o card Seus apps e selecione o app da Web.
  3. Selecione Configuração no painel do snippet do SDK do Firebase e copie o snippet de configuração.
  4. Cole a configuração no arquivo web/src/firebase-config.js do app, como esta:

    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>",
    };
    
    ...
    

Opção 2: extrair a configuração pelo Terraform e adicioná-la à base de código

Como alternativa, você pode receber a configuração do Firebase pelo Terraform como um valor de saída na CLI.

  1. No arquivo main.tf, encontre o bloco de recursos google_firebase_web_app, que registrou um app da Web com o projeto.
  2. Imediatamente após esse bloco, adicione os seguintes blocos:

    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. Como o bloco data e o bloco output não têm a finalidade de modificar a infraestrutura de nenhuma forma, você só precisa executar os comandos a seguir.
    1. Para carregar a configuração do Firebase do seu app da Web no estado do Terraform do seu diretório, execute este comando:
      terraform refresh
      
    2. Para imprimir os valores de configuração do Firebase, execute este comando:
      terraform output –json
      
      Confira a seguir um exemplo de saída de uma configuração. A saída impressa vai conter os valores do projeto e do 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. Copie os valores do mapa value.
  5. Cole esses valores (sua configuração) no arquivo web/src/firebase-config.js do app, como este:

    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",
    };
    
    ...
    

Inicializar o Firebase no seu app

Por fim, para inicializar o Firebase, anexe o arquivo web/src/index.js do app com o seguinte:

index.js

...

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

Testar o app

Agora que tudo está configurado para o Firebase, você pode testar seu app da Web funcional.

  1. Atualize o navegador que está exibindo seu app.
  2. Agora você pode fazer login com o Google e começar a postar mensagens no chat. Se você tiver arquivos de imagem, pode fazer o upload deles.

11. Replique a configuração em vários ambientes

O Terraform é excelente para gerenciar várias infraestruturas configuradas de maneira semelhante (por exemplo, configurar um projeto do Firebase de teste semelhante a um projeto de produção).

Neste codelab, você vai criar um segundo projeto do Firebase para ser um ambiente de preparo.

Para replicar uma configuração atual e criar esse projeto de preparação, você tem duas opções:

  • Opção 1: faça uma cópia da configuração do Terraform.
    Essa opção oferece a maior flexibilidade para a diferença entre o projeto replicado e o projeto de origem.
  • Opção 2: reutilize as configurações com for_each.
    Essa opção oferece mais reutilização de código se cada projeto não for diferente de forma significativa e você quiser propagar as mudanças para todos os projetos de uma vez.

Opção 1: fazer uma cópia da configuração do Terraform

Essa opção oferece a maior flexibilidade para a diferença entre o projeto replicado e o projeto de origem, como ter apps com nomes de exibição e lançamentos em etapas diferentes.

  1. Na raiz do diretório web, crie um novo arquivo de configuração do Terraform chamado main_staging.tf.
  2. Copie todos os blocos de recursos do arquivo main.tf (exceto os blocos terraform e provider) e cole-os no arquivo main_staging.tf.
  3. Em seguida, modifique cada um dos blocos de recursos replicados em main_staging.tf para que eles funcionem com seu projeto de preparação:
    • Rótulos de recursos:use um novo nome para evitar conflitos. Por exemplo, renomeie resource "google_project" "default" como resource "google_project" "staging".
    • Referências de recursos:atualize cada uma delas. Por exemplo, atualize google_firebase_project.default.project para google_firebase_project.staging.project.
    Você pode encontrar a configuração completa de um arquivo main_staging.tf no repositório do GitHub deste codelab:

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

    Se você quiser usar essa configuração, siga estas etapas:
    1. Copie a configuração de main_staging-copypaste.tf e cole no arquivo main_staging.tf.
    2. No arquivo main_staging.tf, faça o seguinte:
      • No bloco de recursos google_project, atualize o atributo name, o atributo project-id e (se você configurar a autenticação pelo Terraform) o atributo billing_account com seus próprios valores.
      • No bloco de recursos google_firebase_web_app, atualize o atributo display_name com seu próprio valor.
      • Nos blocos de recursos google_firestore_database e google_app_engine_application, atualize os atributos location_id com seu próprio 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. Execute terraform apply para provisionar o novo projeto de "ambiente de testes" do Firebase e todos os recursos e ativar os serviços.
  5. Verifique se tudo foi provisionado e ativado conforme o esperado no Console do Firebase, como antes.

Opção 2: reutilizar configurações com for_each

Essa opção oferece mais reutilização de código se cada projeto não for diferente de forma significativa e você quiser propagar as mudanças para todos os projetos de uma vez. Ele usa o meta-argumento for_each na linguagem Terraform.

  1. Abra seu arquivo main.tf.
  2. Em cada bloco de recursos que você quer replicar, adicione um meta-argumento for_each, como este:

    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.
    
    Você encontra a configuração completa de um arquivo main.tf que usa o metaargumento for_each no repositório do GitHub deste codelab:

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

    Se você quiser usar essa configuração, siga estas etapas:
    1. Copie a configuração de main-foreach.tf e cole no arquivo main.tf.
    2. No arquivo main.tf, faça o seguinte:
      • No bloco de recursos google_project, atualize o atributo name, o atributo project-id e (se você configurar a autenticação pelo Terraform) o atributo billing_account com seus próprios valores.
      • No bloco de recursos google_firebase_web_app, atualize o atributo display_name com seu próprio valor.
      • Nos blocos de recursos google_firestore_database e google_app_engine_application, atualize os atributos location_id com seu próprio valor.
  3. Em vez de aplicar essa configuração imediatamente, é importante entender e corrigir algumas coisas sobre como o Terraform interpreta essa configuração em comparação com a infraestrutura atual.
    1. No momento, se você aplicar essa configuração que usa for_each, os endereços de recursos vão ficar assim:
      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"]
      
      No entanto, o projeto criado na primeira parte deste codelab é conhecido pelo Terraform da seguinte forma:
      google_project.default
      google_firebase_project.default
      google_firebase_android_app.default
      
    2. Execute terraform plan para conferir quais ações o Terraform realizaria com base no estado atual.

      A saída vai mostrar que o Terraform excluiria o projeto criado na primeira parte deste codelab e criaria dois novos projetos. Isso ocorre porque o Terraform não sabe que o projeto no endereço google_project.default foi movido para o novo endereço google_project.default["prod"].
    3. Para corrigir isso, execute o comando terraform state mv:
      terraform state mv "google_project.default" "google_project.default[\"prod\"]"
      
    4. Da mesma forma, para corrigir todos os outros blocos de recursos, execute terraform state mv para google_firebase_project, google_firebase_web_app e todos os outros blocos de recursos no arquivo main.tf.
    5. Agora, se você executar terraform plan novamente, não vai aparecer que o Terraform excluiria o projeto que você criou na primeira parte deste codelab.
  4. Execute terraform apply para provisionar o novo projeto de "ambiente de testes" do Firebase e todos os recursos e ativar os serviços.
  5. Verifique se tudo foi provisionado e ativado conforme o esperado no Console do Firebase, como antes.

12. Etapa extra: implantar os apps de teste e de produção

  1. Na base de código do app, mude o firebase-config.js para usar a configuração do Firebase do seu projeto de preparação.

    Para lembrar como acessar a configuração do Firebase e adicioná-la ao app, consulte a etapa anterior deste codelab, "Adicionar a configuração do Firebase ao app".
  2. Na raiz do diretório web, execute o comando abaixo para implantar o app no projeto de teste do Firebase.
    firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
    
  3. Abra o app de pré-produção no navegador pelo URL impresso na saída de firebase deploy. Tente fazer login, enviar mensagens e fazer upload de imagens.

    Ao implantar um app em um projeto do Firebase, ele usa recursos reais do Firebase, não recursos emulados. Ao interagir com o app de pré-produção, os dados e as imagens vão aparecer no projeto de pré-produção no Console do Firebase.
  4. Depois de testar o app no ambiente de pré-produção, mude o firebase-config.js para usar a configuração do Firebase do projeto de produção (o primeiro projeto que você criou neste codelab).
  5. Na raiz do diretório web, execute o comando abaixo para implantar o app no projeto de produção do Firebase.
    firebase deploy --only hosting --project=<PRODUCTION_PROJECT_ID>
    
  6. Abra o app de produção no navegador usando o URL impresso na saída de firebase deploy. Faça login, envie mensagens e faça upload de imagens.

    Os dados e as imagens vão aparecer no projeto de produção no console do Firebase.
  7. Quando terminar de interagir com os dois apps deste codelab, você pode impedir que o Firebase os exiba. Execute o seguinte comando para cada um dos seus projetos:
    firebase hosting:disable --project=<STAGING_PROJECT_ID>
    
    firebase hosting:disable --project=<PRODUCTION_PROJECT_ID>
    

13. Parabéns!

Você usou o Terraform para configurar um aplicativo da Web de chat em tempo real. Você seguiu as práticas recomendadas para ambientes de desenvolvimento criando projetos do Firebase separados para ambiente de testes e produção.

O que vimos

  • Como usar a CLI do Terraform para gerenciar recursos da nuvem
  • Como usar o Terraform para configurar produtos do Firebase (Authentication, Firestore, Cloud Storage e regras de segurança)
  • Como executar e testar um app da Web localmente usando o Pacote de emuladores locais do Firebase
  • Como importar o Firebase para um app da Web
  • Como usar o Terraform para replicar uma configuração em vários ambientes

Para mais informações sobre o Firebase e o Terraform, acesse nossa documentação. Confira uma lista de todos os produtos do Firebase com suporte ao Terraform, exemplos de configurações do Terraform para casos de uso comuns, além de solução de problemas e perguntas frequentes.