DEV Community

Roberto Guerra
Roberto Guerra

Posted on

GCP Notes: Configure API Gateway with Terraform

Originally posted in https://blog.openstep.net/posts/gcp-api-terraform/

GCP API Gateway gives you more control over access to your Cloud Functions triggered by HTTP. I will explain how to configure an API Gateway and why you might want to do that.

According to GCP's documentation: "With API Gateway, you can create, secure, and monitor APIs for Google Cloud serverless back ends, including Cloud Functions, Cloud Run, and App Engine. Built on Envoy, API Gateway gives you high performance, scalability, and the freedom to focus on building great apps. Consumption-based and tiered pricing means you can better manage cost."

If you have built serverless APIs in AWS, you have more than likely used AWS API Gateway to expose your lambdas as HTTP endpoints. AWS API Gateway allows you to throttle traffic, add authentication, modify headers, etc. GCP did not have an equivalent service until 2020, and as of this writing (September 2021), it is still in beta. GCP Cloud Functions provide you with an HTTP(s) endpoint by default if they have an HTTP trigger. You can also specify if the Cloud Function is publicly exposed. However, you can not secure the endpoint, nor throttle traffic, nor use a custom domain. API Gateway also provides metrics about the endpoints (latency, error rates, etc.). If you want to keep track of what applications use your APIs, you can create API keys for each application. API Gateway then allows you to view the traffic generated by each application, and you can throttle or disable APIs using the keys instead of having to modify code.

GCP API Gateway Components

The API Gateway is made up of 3 components:
The Config
The Gateway
The API

The Config is an OpenAPI v2 document that allows you to map the Cloud Function endpoint to an API endpoint:

swagger: '2.0'
info:
  title: poe-api
  description: API Gateway for POE
  version: 1.0.0
schemes:
  - https
produces:
  - application/json
paths:
  /api/echo:
    get:
      summary: Echo
      operationId: echo
      x-google-backend:
        address: https://project-id.cloudfunctions.net/HandlerEcho
      responses:
        200:
          description: Successful response
          schema:
            type: string
Enter fullscreen mode Exit fullscreen mode

This example deploys an API that forwards all requests to /api/echo to the Cloud Function HandlerEcho. It also only uses HTTPS, and all the endpoints return JSON.

Enabling CORS

You need to enable CORS if your APIs are accessed from a web application. Browsers restrict cross-origin HTTP requests initiate from scripts unless the response from other origins includes the correct CORS headers. I won't explain how to configure CORS on your server; that topic is out of scope, but I'll explain how to configure GCP API Gateway to work with CORS.

Configuring CORS can be annoying because you have to provide an additional path for every one of our endpoints. There is probably a better way of doing this, but I found that this works for me. You have to copy-paste the path you configured and change it to be an options request.

paths:
     /api/echo:
        get:
            summary: Echo
            operationId: echo
            x-google-backend:
                address: https://project-id.cloudfunctions.net/HandlerEcho
            responses:
                200:
                    description: Successful response
                    schema:
                        type: string
        options:
            summary: Echo
            operationId: echo
            x-google-backend:
                address: https://project-id.cloudfunctions.net/HandlerEcho
            responses:
        200:
            description: Successful response
            schema:
                type: string

Enter fullscreen mode Exit fullscreen mode

API Keys

GCP API Gateway allows you to secure & monitor your APIs in several ways. APIs can be throttled and disabled based on the API Key that they used. You can create an API key for a web application and another key for machine-to-machine access. If you notice that the latter makes more requests than expected, that API Key can be throttled or disabled without affecting the web application.

You need to configure API Keys in your config file and also using the GCP console. In your config file, add a top-level field:

security:
- api_key: []
securityDefinitions:
    api_key:
        type: apiKey
        name: apiKey
        in: query
Enter fullscreen mode Exit fullscreen mode

This snippet says that all endpoints expect a query parameter called apiKey. There are other types of security that API Gateway provides, but I won't cover them in this post.

The second step is to go to the GCP console, navigate to APIs & Services, then click on Enable APIs and Services. This will take you to a page where you should search for the API you created and enable it. Then return to the APIs & Services page and click on Credentials and Create Credentials. Then select API Key. GCP assigns an autogenerated name to the key, but you should change it and customize it. Click on the name of the generated key, and change the name to something that describes the service using the key. The string under API Key is what customers of your APIs should use. You can also further restrict access by type of application and HTTP referrers if the key will be used by a web application. Finally, click on Restrict Key and select your API from the drop-down.

Prevent access to the backend

You can force everyone to use your API only via the API Gateway by disabling unauthenticated access to your backend. The API Gateway will use a service account to access the backend. However, if your backends are inspecting the Authorization header for JWT tokens, then your endpoints will stop working. This happens because the API Gateway will inject its own JWT token on that header. You will need to use a different header to provide the JWT token that your application needs. Maybe something like X-Authorization, but whatever you use, be consistent and make sure to document it.

Deploying with Terraform

You will use the Terraform Google provider (https://registry.terraform.io/providers/hashicorp/google/latest/docs) for deployment. You need three resources to configure an API Gateway:

  • Config: google_api_gateway_api_config
  • API: google_api_gateway_api
  • Gateway: google_api_gateway_gateway

The Config holds the OpenAPI document that describes the endpoints that will be served.
The Gateway defines an external URL that API clients will use to access the API.

provider "google" {
  project = var.project_id
  region  = var.region
  zone    = var.zone
}

locals {
  api_config_id_prefix     = "api"
  api_id                   = "your-api-id"
  gateway_id               = "your-gateway-id"
  display_name             = "API Display Name"
}

resource "google_api_gateway_api" "api_gw" {
  provider     = google-beta
  api_id       = local.api_gateway_container_id
  project      = var.project_id
  display_name = local.display_name
}

resource "google_api_gateway_api_config" "api_cfg" {
  provider             = google-beta
  api                  = google_api_gateway_api.api_gw.api_id
  api_config_id_prefix = local.api_config_id_prefix
  project              = var.project_id
  display_name         = local.display_name

  openapi_documents {
    document {
      path     = "openapi.yaml"
      contents = filebase64("openapi.yml")
    }
  }
  lifecycle {
    create_before_destroy = true
  }
}

resource "google_api_gateway_gateway" "gw" {
  provider = google-beta
  region   = var.region
  project  = var.project_id


  api_config   = google_api_gateway_api_config.api_cfg.id

  gateway_id   = local.gateway_id
  display_name = local.display_name

  depends_on   = [google_api_gateway_api_config.api_cfg]
}

Enter fullscreen mode Exit fullscreen mode

You should be able to run terraform plan to verify the configuration, and terraform apply to deploy.

Conclusion

You can use GCP API Gateway to have more fine-grained control over your APIs. You saw how to do this using the OpenAPI specification and how to use API Keys to protect your endpoints. You can also leverage Terraform for declaring your API Gateway as code.

References

Top comments (0)