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 primeiro descreve como criar um arquivo de configuração do Terraform para criar um novo projeto do Firebase e, em seguida, 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 visualizar as 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 comandos da CLI do Terraform para gerenciar sua infraestrutura
  • Como modificar sua 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, preparo etc.)

Pré-requisitos

Para concluir este codelab, você precisa ter proficiência básica com o Terraform e sua terminologia, incluindo os seguintes pré-requisitos:

Este codelab oferece um app de exemplo real para que você possa testar e interagir com o que provisiona usando o Terraform. Para isso, você precisa do seguinte:

  • O exemplo de código de um app da Web. Faça o download desse código 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 que provisiona com o Terraform usando um app da Web real. Recomendamos fazer isso para entender todas as etapas necessárias para usar recursos provisionados pelo Terraform.

Clone o repositório do GitHub (link em inglês) do codelab na linha de comando:

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

Se preferir, baixe o 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 baixado, 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 em relação à 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.

Inicialize o Terraform no diretório

Para criar uma configuração pela primeira vez, é necessário fazer o download do provedor especificado na configuração.

Para fazer essa inicialização, execute o seguinte comando na raiz do mesmo diretório que o 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 é, na verdade, um projeto do Google Cloud, só que 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 subjacente.

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

    É necessário especificar seu próprio nome de projeto (como "Terraform FriendlyChat Codelab") e ID do projeto (como "terraform-codelab-your-initials"). O valor name é usado apenas nas interfaces do Firebase e não fica visível para os usuários finais. No entanto, 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 subjacentes necessárias: a API Service Usage e a API Firebase Management.

    Essa ativação de API geralmente é processada nos bastidores quando você usa o console do Firebase para criar um projeto do Firebase, mas o Terraform precisa ser explicitamente instruído a fazer isso.

    No arquivo de configuração main.tf (logo abaixo do bloco que cria o novo projeto do Cloud), adicione o seguinte bloco 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
    }
    
    Ao ativar a API Service Usage, seu novo projeto poderá aceitar verificações de cota. Portanto, para todo o provisionamento de recursos e ativação de serviços subsequentes, use o provedor com user_project_override (não é necessário 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 nele.

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

Como mencionado acima, observe que esse bloco de recursos está usando 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 informa ao Terraform para aguardar a ativação das APIs subjacentes. Sem essa cláusula, o Terraform não sabe da 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 imprime um plano de ações que serão realizadas.

    Se tudo estiver conforme o esperado, aprove as ações inserindo 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ó precisar visualizar as mudanças sem aplicar, use o comando terraform plan.

Validar as mudanças

Depois que o Terraform terminar de ser executado, inspecione o estado de todos os recursos e serviços provisionados pelo Terraform executando o seguinte comando:

terraform show

Confira um exemplo de como o texto vai aparecer impresso. Seu estado vai conter valores específicos do 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, verifique se o projeto foi criado no Console do Firebase.

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

5. Registrar seu app do Firebase usando o 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 provisionar usando o Terraform. Como este é um app da Web, você precisa informar ao Terraform para registrar um app da Web do Firebase no projeto recém-criado.

Adicionar um bloco para registrar o app da Web

Para registrar o web app no projeto do Firebase, adicione o seguinte bloco de recursos ao arquivo main.tf.

Você precisa especificar seu próprio display_name para o app da Web. Esse nome é usado apenas nas interfaces do Firebase e não fica 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 seguinte comando na raiz do mesmo diretório que o arquivo main.tf (que deve ser web).
    terraform apply
    
    Esse comando não vai recriar um projeto do Google Cloud. O Terraform vai detectar que já existe um projeto com o ID especificado e vai comparar o estado atual do projeto com o que está no arquivo .tf, fazendo as mudanças necessárias.
  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 recém-provisionado, execute o seguinte comando:

terraform show

Você também pode verificar se o app foi registrado no projeto acessando o 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 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.
    • Usar essa opção significa que você não precisa associar seu novo projeto a uma conta do Cloud Billing.
  • Opção 2: configure o Firebase Authentication usando o Terraform com as APIs do Google Cloud Identity Platform (GCIP).
    • Usar essa opção significa que você precisa associar seu 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.

Veja 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, em 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 Provedores adicionais, selecione Google.
  4. Ative a opção Ativar.
  5. Defina o nome público do app como algo como FriendlyChat (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 via 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 projeto do Firebase e usar o plano Blaze, associe uma conta do Cloud Billing ao projeto.

Ativar o faturamento usando o Terraform

  1. Se você ainda não tiver uma conta do Cloud Billing, a primeira etapa é criar uma no Console do Google Cloud. Ao fazer isso, anote o ID da conta de faturamento. O ID da conta de faturamento pode ser encontrado na página "Faturamento", no ID da conta de faturamento associado ao seu projeto.Como ativar uma conta de faturamento usando o console do Google Cloud
  2. Para ativar o faturamento no seu projeto usando o 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 o login com o Google usando o Terraform

  1. Para provisionar o Firebase Authentication com o GCIP, adicione ao arquivo main.tf os 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 do 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 permissão 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 o seguinte e clique em Salvar e continuar.
      • Defina o Nome do app público como algo parecido com FriendlyChat. Não é necessário que ele seja globalmente exclusivo.
      • Escolha um e-mail de suporte ao usuário no menu suspenso.
      • Insira um e-mail nas 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 os padrões na página Testar usuários e clique em Salvar e continuar.
      • Revise o resumo e clique em Voltar ao painel.
      Configurar um cliente OAuth2 usando o console do Google Cloud
  4. Configure um cliente OAuth na página Credenciais fazendo o seguinte:
    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 Nome, 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 &quot;Credenciais&quot; do console do Google Cloud
  5. Para ativar o Login do Google usando o ID do cliente e a chave secreta do cliente OAuth, adicione o seguinte bloco ao arquivo 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
      ]
    }
    

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
    
    Executar terraform apply não vai recriar um projeto do Google Cloud. O Terraform vai detectar que já existe um projeto com o ID especificado e vai comparar o estado atual do projeto com o que está no arquivo .tf. Em seguida, ele fará as mudanças necessárias.
  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 depois 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 dele

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 de banco de dados, adicione ao arquivo main.tf 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 esteja em uma região próxima à maioria dos usuários e em comum com outros serviços do Firebase, como o Cloud Functions. Neste codelab, você pode usar 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 acessíveis ao 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 no arquivo local firestore.rules.
    • 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 dele.
  6. Verifique se o banco de dados foi provisionado e se as regras de segurança dele foram implantadas:
    1. No Console do Firebase, localize a seção Build no painel à esquerda.
    2. Vá até a seção Banco de dados do Firestore e clique na guia Regras.
    Como verificar regras do Cloud Firestore usando o console do Firebase

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

Para o web app 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, adicione ao arquivo main.tf os seguintes blocos de recursos.

    O bucket padrão do Cloud Storage para seu projeto é provisionado pelo Google App Engine e precisa estar no mesmo local que o 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 com base no arquivo local.
    • Libere o conjunto de regras do 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 foi provisionado e se as regras de segurança foram 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 seu app da Web pela primeira vez. Você vai usar o emulador do Firebase Hosting para disponibilizar seu app localmente.

  1. Abra uma nova janela do terminal e, no diretório web, execute o seguinte comando da CLI do Firebase 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 ver a interface do usuário do app FriendlyChat, que (ainda) não está funcionando. O app ainda não está conectado ao Firebase, mas isso vai acontecer quando você concluir as próximas etapas deste codelab.

Sempre que você fizer mudanças no web app (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 do Firebase e da configuração do Firebase para seu 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. Consulte web/package.json e web/src/index.js se quiser ver o que já foi feito.

Embora o código de exemplo esteja quase completo, ainda é necessário fazer algumas coisas para executar o app, 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 seu 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 usar.

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

  • Opção 1: receba a configuração do Firebase no Console do Firebase.
  • Opção 2: obtenha a configuração do Firebase usando o Terraform.

Opção 1: extrair a configuração do Console do Firebase e adicioná-la à sua 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 seu web app.
  3. Selecione Config no painel de snippets 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, assim:

    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 usando o Terraform e adicioná-la à base de código

Como alternativa, é possível receber a configuração do Firebase via Terraform como um valor de saída na CLI.

  1. No arquivo main.tf, encontre o bloco de recursos google_firebase_web_app (o bloco que registrou um web app no seu 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 foram criados para modificar a infraestrutura de forma alguma, basta executar os seguintes comandos.
    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, assim:

    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, adicione o seguinte ao arquivo web/src/index.js do app:

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á veiculando 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, também poderá fazer upload deles.

11. Replicar sua configuração em vários ambientes

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

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

Para replicar uma configuração atual e criar esse projeto de staging, 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 em relação ao quanto o projeto replicado pode ser diferente do projeto de origem.
  • Opção 2: reutilize configurações com for_each.
    Essa opção oferece mais reutilização de código se cada projeto não for muito diferente e você quiser propagar as mudanças para todos os projetos de uma só vez.

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

Essa opção oferece a maior flexibilidade em relação ao quanto o projeto replicado pode diferir do projeto de origem, como ter apps com nomes de exibição diferentes e lançamentos graduais.

  1. Na raiz do diretório web, crie um 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 funcionem com seu projeto de preparo:
    • 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ê encontra 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 quiser usar essa configuração, faça o seguinte:
    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 os atributos name, project-id e (se você configurou a autenticação via Terraform) 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 seu novo projeto do Firebase "staging" e todos os recursos dele, além de 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 muito diferente e você quiser propagar as mudanças para todos os projetos de uma só 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, assim:

    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.
    
    Confira 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 quiser usar essa configuração, faça o seguinte:
    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 os atributos name, project-id e (se você configurou a autenticação via Terraform) 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ê aplicasse essa configuração que usa for_each, os endereços de recursos seriam semelhantes a este:
      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 que você criou na primeira parte deste codelab é conhecido pelo Terraform como:
      google_project.default
      google_firebase_project.default
      google_firebase_android_app.default
      
    2. Execute terraform plan para ver quais ações o Terraform realizaria 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 acontece 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 criado na primeira parte deste codelab.
  4. Execute terraform apply para provisionar seu novo projeto do Firebase "staging" e todos os recursos dele, além de ativar os serviços.
  5. Verifique se tudo foi provisionado e ativado conforme o esperado no Console do Firebase, como antes.

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

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

    Para lembrar como acessar e adicionar a configuração do Firebase 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 a seguir para implantar o app no projeto de teste do Firebase.
    firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
    
  3. Abra o app de teste no navegador usando o URL impresso na saída de firebase deploy. Tente fazer login, enviar mensagens e fazer upload de imagens.

    Quando você implanta um app em um projeto do Firebase, ele usa recursos reais do Firebase, não emulados. Ao interagir com o app de teste, você vai ver dados e imagens aparecerem no projeto de teste no console do Firebase.
  4. Depois de testar o app em staging, mude o firebase-config.js para usar a configuração do Firebase do projeto de produção (o primeiro projeto criado neste codelab).
  5. Na raiz do diretório web, execute o seguinte comando 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. Tente fazer login, enviar mensagens e fazer 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ê poderá impedir que o Firebase os veicule. 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 separados do Firebase para preparo e produção.

O que vimos

  • Como usar a CLI do Terraform para gerenciar recursos da nuvem
  • Usar o Terraform para configurar produtos do Firebase (Authentication, Firestore, Cloud Storage e regras de segurança)
  • Executar e testar um app da Web localmente usando o Pacote de emuladores locais do Firebase
  • Importar o Firebase para um app da Web
  • 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 do Terraform, exemplos de configurações do Terraform para casos de uso comuns e perguntas frequentes e dicas úteis para solução de problemas.