Architecture

July 16, 2020 · View on GitHub

English | Español

Architecture

high level architecture

Runtime

This reference web app uses a static Angular frontend hosted in Google Cloud Storage. The frontend makes authenticated API calls to Cloud Run services running in a GKE cluster. Cloud Firestore is used for persistence.

Networking

networking diagram

For every incoming request, traffic is directed to either the static GCS bucket or the GKE cluster ingress using a URL map.

By default, all requests are directed to the GCS bucket unless the request path begins with /api, in which case they are directed to the GKE cluster.

An HTTPS target proxy secures incoming traffic using SSL. An SSL certificate associated with the desired domain is either provided or generated automatically.

A forwarding rule provides the publicly-accessible IP address for incoming requests. The IP address of the forwarding rule is added to a managed DNS zone for the desired domain.

Authentication & Authorization

authentication diagram

Authentication is provided by Identity Platform, which issues a JSON Web Token (JWT) on the frontend that gets passed through on subsequent requests and gets validated by the Istio ingress.

Istio Authorization Policies enable access control to ensure certain operations are only accessible by certain users. Namely, there are policies to ensure:

  • Access is denied to users without a token
  • All roles are authorized to issue GET requests to the /api endpoint
  • Workers are authorized to create inventory transactions
  • Admins are authorized to all operations, including the creation and deletion of items, locations, etc.

Build & Infrastructure

build diagram

Build and setup is performed using Cloud Build.

Infrastructure is mostly orchestrated by Cloud Config Connector; the declarative infrastructure configuration can be found in infrastructure-tpl.yaml, backend-service-template.jq, and dns-tpl.yaml.

API Generation

Both the frontend Typescript client and backend Golang server are generated off of the OpenAPI spec. This way, changes to the API surface are automatically picked up by both the client and server on the next build.