Sunday, November 28, 2021

Google Cloud API Gateway - M2M client, GCF server

Summary

I'll be showing some of the detailed configuration necessary to deploy API Gateway with a Cloud Functions back-end and authentication for a non-human (machine) client.  I'll be focusing on the front and back-end authentication configuration.  I'll also be showing the client side in Node.js which is very thinly documented by Google.


Architecture




Authentication

Back-end:  Cloud Functions

The back-end GCF is deployed requiring authentication.  The API Gateway is configured to operate under a Service Account that has the Cloud Function Invoker role.

Front-end:  Machine Client

Configuration here is significantly more complicated than the back-end.  Configuration areas:
  • A Service Account needs to be created and a SA key downloaded.  That key is then used to sign a JWT for authentication to the API Gateway.
  • Security definitions must be added to OpenAPI spec (Swagger 2.0) that specify that SA as an allowed user.
  • The Machine Client itself must generate a JWT to the API Gateway specs and sign that JWT with the SA key.

Code

OpenAPI Security Definition

securityDefinitions:
  machine-service:
    authorizationUrl: ""
    flow: "implicit"
    type: "oauth2"
    x-google-issuer: "machine-service@kvpstore.iam.gserviceaccount.com"
    x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/machine-service@kvpstore.iam.gserviceaccount.com"
security:
  - machine-service: []

Machine Client-side 


'use strict';
const fetch = require('node-fetch');
const jwt = require('jsonwebtoken');
 
const sakey = require('./sakey.json');  //json file downloaded from Google IAM
const EMAIL = sakey.client_email;
const AUDIENCE = 'your audience';// this value corresponds to the "Managed service" name of the API Gateway
const ALGORITHM = 'RS256';
const GWY_URL = 'your URL';
const KEY = sakey.private_key

function exampleAPICall(email, audience, key, algorithm) {
    const payload = {
        iat: Date.now(),
        exp: Date.now() + 3600,
        iss: email,
        aud: audience,
        sub: email,
        email: email
    }

    const token = jwt.sign(payload, key, {algorithm: algorithm});
    
    const response = await fetch(`${gwyurl}/guid`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    });
    return await response.json();
}

Copyright ©1993-2024 Joey E Whelan, All rights reserved.