Configurar e gerenciar projetos e produtos do Firebase pelo Terraform

1. Introdução

Metas

Você pode 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, 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 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 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 npm do gerenciador de pacotes (que normalmente 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 é provisionado pelo Terraform com um app da Web real. Recomendamos que você faça 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 a cota das operações do Terraform será verificada. 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 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, é preciso 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 seu 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, apenas com os serviços do Firebase ativados.

Adicione blocos ao projeto e às APIs do Google Cloud

  1. Primeiro, provisione o projeto do Google Cloud.

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

    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 fica visível para os usuários finais. No entanto, o valor project_id identifica exclusivamente seu projeto 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, você precisa ativar as APIs necessárias: Service Usage e Firebase Management.

    Essa ativação da API geralmente é realizada em segundo plano 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 provisionamento de recursos e ativação de serviços subsequentes, use o provedor com user_project_override (não é necessário usar um alias).

Adicione 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.

Ainda no arquivo de configuração main.tf, adicione o bloco de recursos abaixo.

Como mencionado acima, este bloco de recursos usa o provedor com user_project_override (não é necessário usar um alias).

main.tf (link em inglês)

...

# 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, é possível notar a cláusula depends_on, que diz ao Terraform para 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 que o arquivo main.tf, que precisa 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 visualizar as alterações 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

Veja um exemplo do que será exibido. 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, você pode verificar se o projeto foi criado acessando-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, é preciso registrar cada variante da plataforma do app no projeto do Firebase. Neste codelab, você vai usar um app real para testar e interagir com o que é provisionado pelo Terraform. Como esse é um app da Web, você precisa solicitar que o Terraform registre um app da Web no seu projeto 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 somente 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 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 já existe um projeto com o ID especificado, comparar o estado atual do projeto com o que está no arquivo .tf e fazer as mudanças encontradas.
  2. Analise o plano de ações impresso. Se tudo estiver como esperado, 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

Como alternativa, você pode verificar se o app foi registrado no seu 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 Contas do Google deles, ative o Firebase Authentication e configure o método de login com o Google.

Neste codelab, oferecemos duas opções diferentes para configurar a Autenticação do Firebase:

  • 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 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.

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, depois em Começar e na guia Método de login (ou clique aqui para acessar essa página).
  3. Clique em Adicionar novo provedor e, na seção Provedores adicionais, selecione Google.
  4. Acione o botã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. Você verá o Google 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. Faça upgrade do seu projeto do Firebase para usar o plano Blaze associando 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 com o Terraform, adicione um atributo billing_account ao recurso google_project atual 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"
      }
    }
    
    ...
    

Ative o Firebase Authentication e faça login com o Google usando o Terraform

  1. Para provisionar o Firebase Authentication com o GCIP, anexe o arquivo main.tf com 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 com o Google, você precisa ter um cliente OAuth. Acesse a página APIs e Serviços do console do Google Cloud para realizar 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, conclua as etapas a seguir e clique em Salvar e continuar.
      • Defina o nome do app público para algo como FriendlyChat. Ele não precisa ser globalmente exclusivo.
      • Escolha um E-mail para suporte do 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. Para isso, faça 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 Name, insira o nome do app, por exemplo, FriendlyChat (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 do cliente OAuth e a chave secreta do cliente, 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 a 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 novo projeto do Google Cloud. O Terraform vai detectar que um projeto com o ID especificado já existe e vai comparar o estado atual do projeto com o que está no arquivo .tf. Em seguida, ele vai fazer as mudanças encontradas.
  2. Revise o plano de ações impresso. Se tudo estiver como esperado, 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

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 onde você quer que o banco de dados resida.

    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. 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 acessíveis ao Firebase precisam ser protegidas pelas regras de segurança do Firebase.

    O exemplo de código 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 aos seguintes blocos de recursos para fazer o seguinte:
    • Crie um conjunto de regras de segurança do Firebase no arquivo firestore.rules local.
    • Libere o conjunto de regras da 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 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. Vá para 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 quiser ter 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 exemplo de código 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 aos seguintes blocos de recursos para fazer o seguinte:
    • Crie um conjunto de regras de segurança do Firebase a partir do 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 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 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ê verá a IU do app FriendlyChat, que (ainda) não está funcionando. O app ainda não está conectado ao Firebase, mas vai estar ao concluir as próximas etapas deste codelab.

Sempre que você fizer mudanças no app da Web (como nas etapas a seguir 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 exemplo de código deste codelab já é um app funcional com todas as dependências e funções necessárias para usar vários produtos do Firebase no app. Você pode consultar web/package.json e web/src/index.js se quiser ver o que já foi feito.

Mesmo que o exemplo de código esteja quase completo, você ainda precisa fazer algumas coisas para executar o app, incluindo: instalar o SDK do Firebase, iniciar seu 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

É necessário 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 recriará continuamente seu código-fonte.

Adicionar a configuração do Firebase ao app

Também é necessário adicionar a configuração do Firebase ao seu app para que os SDKs do Firebase saibam qual projeto você quer que eles usem.

Neste codelab, você tem duas opções diferentes para fazer a configuração do Firebase:

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

Opção 1: receber 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 o app da Web.
  3. Selecione Configuração no painel de 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 seu app da seguinte forma:

    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, é possível 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 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 seu app da seguinte forma:

    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 seu app com o seguinte código:

index.js

...

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

Testar seu 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, é possível até fazer upload deles.

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

O Terraform se destaca no gerenciamento de várias infraestruturas configuradas de forma semelhante, por exemplo, configurando 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 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: reutilizar 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 o máximo de flexibilidade em relação ao quanto o projeto replicado pode ser diferente do projeto de origem, como ter apps com diferentes nomes de exibição e lançamentos graduais.

  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, você precisa modificar cada um dos blocos de recursos replicados em main_staging.tf para que eles 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ê 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 "teste" o projeto do Firebase e todos os recursos associados, além de ativar os serviços dele.
  5. Verifique se tudo foi provisionado e ativado conforme o esperado no Console do Firebase, como antes.

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

Essa opção oferece mais reutilização de código se cada projeto não tiver diferenças significativas e você quiser propagar alterações em todos os projetos de uma só vez. Ele usa o meta-argumento for_each na linguagem do Terraform.

  1. Abra seu arquivo main.tf.
  2. Em cada bloco de recursos que você quer replicar, adicione um metaargumento 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ê pode encontrar 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, 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 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ê aplicou essa configuração que usa for_each, os endereços de recursos ficariam 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 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 de acordo com o estado atual.

      A saída deve mostrar que o Terraform excluiria o projeto que você criou 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 "teste" o projeto do Firebase e todos os recursos associados, além de ativar os serviços dele.
  5. Verifique se tudo foi provisionado e ativado conforme esperado no Console do Firebase.

12. Etapa bônus: implantar 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 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 seguinte comando 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 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 seu 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 exiba. Execute o seguinte comando para cada um dos 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. E 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 de 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
  • 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. Você encontra uma lista de todos os produtos do Firebase que oferecem suporte ao Terraform, exemplos de configurações do Terraform para casos de uso comuns, solução de problemas e perguntas frequentes.