Building a Secure API Gateway with Go, Gin, and Cloudflare Zero Trust

Timothy OlalekeTimothy Olaleke
5 min read

Introduction

In today’s world of micro services, managing multiple APIs securely and efficiently is a key challenge. API Gateways have become an essential component of modern infrastructure, acting as a reverse proxy to accept all application programming interface (API) calls, aggregate the various services required to fulfill them, and return the appropriate result.

In this tutorial, we'll explore how to build a secure API Gateway using the Gin framework in Go, authenticate requests with Cloudflare Zero Trust, and deploy the service to Google Cloud Run for a scalable, server less solution.

Why Gin?

Gin is a web framework written in Go that features a Martini-like API with much better performance. It provides easy-to-use routing and a vast ecosystem of middle ware. It’s perfect for building highly performance, reliable micro services and APIs.

Prerequisites

Before we dive in, ensure you have the following tools installed:

  • Go 1.23 or later

  • Git

  • A Google Cloud Platform (GCP) account

  • Cloudflare account with Zero Trust enabled

Step 1: Setting Up Your Go Environment

1. Install Go

Start by installing Go on your machine. Download it from the official Go website and follow the installation instructions. After installation, verify it by running:

go version

2. Set Up Your Go Workspace

Set up your Go workspace by adding the following lines to your shell configuration file (.bashrc, .zshrc, etc.):

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

3. Install Git

If you don’t have Git installed, get it from Git’s official site.

Step 2: Creating a Simple API Gateway with Gin

1. Initialize Your Project

Create a new directory for your project and initialize a Go module:

mkdir my-api-gateway
cd my-api-gateway
go mod init my-api-gateway

2. Install Gin

Add Gin to your project:

go get -u github.com/gin-gonic/gin

3. Write Your First API Gateway

Create a main.go file and add the following code:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
    "github.com/joho/godotenv"
)

func main() {
    // Load environment variables from .env file if it exists
    err := godotenv.Load()
    if err != nil {
        log.Println("No .env file found, continuing without loading environment variables from file.")
    }

    // Set up Gin router with CORS
    router := gin.Default()
    router.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"*"},
        AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowHeaders:     []string{"Origin", "Authorization", "Content-Type"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
    }))

    // Example route
    router.GET("/health", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"status": "API Gateway is up and running"})
    })

    // Start the server
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    router.Run(":" + port)
}

This basic API Gateway simply returns a health check response to ensure the gateway is running.

Step 3: Integrating Cloudflare Zero Trust

Cloudflare Zero Trust adds a layer of security by authenticating requests using Service Tokens. Here’s how you can integrate it:

1. Create a Cloudflare Zero Trust Service Token

Log in to your Cloudflare account, navigate to Access > Service Tokens, and create a new Service Token. Copy the Client ID and Client Secret for later use.

2. Modify the Gateway to Use Cloudflare Service Tokens

Update your main.go to include Cloudflare authentication:

func main() {
    // ... (previous setup)

    requiredEnvVars := []string{"CF_ACCESS_CLIENT_ID", "CF_ACCESS_CLIENT_SECRET"}
    for _, envVar := range requiredEnvVars {
        if os.Getenv(envVar) == "" {
            log.Fatalf("Environment variable %s is not set", envVar)
        }
    }

    // Add a protected route
    router.GET("/protected", func(c *gin.Context) {
        token := fetchCloudflareToken(os.Getenv("CF_ACCESS_CLIENT_ID"), os.Getenv("CF_ACCESS_CLIENT_SECRET"))
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"message": "Access granted", "token": token})
    })

    // Start the server
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    router.Run(":" + port)
}

func fetchCloudflareToken(clientID, clientSecret string) string {
    req, _ := http.NewRequest("GET", "https://example.cloudflareaccess.com", nil)
    req.Header.Set("CF-Access-Client-Id", clientID)
    req.Header.Set("CF-Access-Client-Secret", clientSecret)
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil || resp.StatusCode != http.StatusOK {
        return ""
    }
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    return string(body)
}

This code adds a protected endpoint that checks for valid Cloudflare authentication.

Step 4: Deploying to Google Cloud Run

Google Cloud Run is a fully managed compute platform that automatically scales your stateless containers. Here’s how to deploy your API Gateway:

1. Set Up Google Cloud SDK

Install and configure the Google Cloud SDK on your machine.

2. Build and Push Your Docker Image

Create a Dockerfile for your Go application:

FROM golang:1.20 as builder

WORKDIR /app
COPY . .
RUN go build -o main .

FROM gcr.io/distroless/base-debian11
WORKDIR /
COPY --from=builder /app/main .

CMD ["./main"]

Then, build and push your Docker image to Google Container Registry (GCR):

gcloud auth configure-docker
docker build -t gcr.io/YOUR_PROJECT_ID/my-api-gateway .
docker push gcr.io/YOUR_PROJECT_ID/my-api-gateway

3. Deploy to Cloud Run

Finally, deploy your service to Cloud Run:

gcloud run deploy my-api-gateway \
  --image gcr.io/YOUR_PROJECT_ID/my-api-gateway \
  --platform managed \
  --region YOUR_REGION \
  --allow-unauthenticated

Best Practices for Cloud Run

  • Use Environment Variables: Securely manage secrets and configuration settings using environment variables in Cloud Run.

  • Enable Logging and Monitoring: Use Google Cloud's integrated logging and monitoring services to gain insights into your API Gateway’s performance.

  • Implement Caching: For performance, consider adding caching to reduce load times for frequently accessed resources.

Conclusion

In this guide, we built a secure API Gateway using Go and the Gin framework, integrated it with Cloudflare Zero Trust for authentication, and deployed it on Google Cloud Run. This setup offers a scalable, secure solution for managing access to your microservices.

Feel free to explore additional features, such as rate limiting, enhanced security configurations, or integrating with other Google Cloud services. By following these practices, you can build a robust, production-ready API Gateway that meets the demands of modern applications.


0
Subscribe to my newsletter

Read articles from Timothy Olaleke directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Timothy Olaleke
Timothy Olaleke

Tim is a software developer who builds awesome stuff, he has a wide experience in building customer-based solutions for digital needs using mind-blowing technologies. He is also a DevOps Enthusiast with a passion for automation and an open-source hobbyist, in his free time, he writes a lot of Google Cloud related tutorials and makes open contributions on GitHub. Tim is an active member of various developers communities, where he focuses on making impacts and sharing his experiences whilst learning.