OpenAPI config for a Graphql backend using GCP API Gateway? - api

I have an apollo/graphql server sitting behind a GCP API gateway. Google says it requires an OpenAPI spec to secure endpoints:
https://cloud.google.com/api-gateway/docs/get-started-cloud-run#creating_an_api_config
But how exactly would this look for securing a single graphql endpoint? Also, as a side question, is a new API Gateway needed to be created for each Cloud Run/App Engine service?
Thanks in advance.

Here's a repo that demonstrates what you want to achieve. It's a GCP API Gateway fronting a GraphQL API on Cloud Run, secured with Identity-Aware Proxy. Here's the API config from the link:
api-spec.yaml
swagger: '2.0'
info:
title: gcp-demo-api
description: Sample GraphQL API on API Gateway with a Cloud Run backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/:
post:
summary: GraphQL endpoint
operationId: gql
x-google-backend:
address: https://PROJECT_AND_RANDOM_STRING.a.run.app/graphql # App URL/endpoint
jwt_audience: LONG_RANDOM_STRING.apps.googleusercontent.com # IAP client ID
responses:
'200':
description: A successful response
schema:
type: object
To answer your side question, it is important to understand what an API Gateway does. An API Gateway is what stands between your user requests and your collection of backend services so all API requests goes through it.
Therefore, you don't need to create a new API gateway for each service. It is possible in API Gateway to serve multiple services such as Cloud Run, App Engine, Cloud Functions, etc. by specifying the backend address on each endpoint. Here's a link that further explains the concept.

Related

Authorize different API endpoints via oauth2

I currently secure my API (running on k8s) with an oauth2-proxy which then redirects requests to the API.
As the scope of content (on API-level) should vary based on subgroups, these groups should be authorized only for their entitled scope. The Access Token provides the required subgroups affiliations but I cannot bridge the gap between the proxy handling the authentication and the API doing the authorization. I also just want to use a single API and oauth2 infrastructure.
Is it possible to pass the Access Token to the downstream API? What are best practices for this pattern?
Can someone point me in the right direction?
Cheers
Yes, that's possible: See the --pass-access-token and --set-xauthrequest options in oauth2-proxy.
E.g., I use this in oauth2-proxy.cfg
# Get JWT in x-auth-request-access-token
pass_access_token = true
set_xauthrequest = true
combined with this in the nginx ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-response-headers: x-auth-request-access-token # This holds the JWT (without 'Bearer ')
nginx.ingress.kubernetes.io/auth-signin: http://dev.k8s.ese-ia/oauth2-proxy/start # external URL!
nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.ese-ia.svc.cluster.local/oauth2-proxy/auth # internal service URL – must be fqdn to be reachable from the ingress!
Note that the header name is not Authorization and that there is no Bearer prefix in the value. So the services using it might have to be changed. E.g, if you use Spring Boot, you will have to set a custom BearerTokenResolver.
(Bonus: If you use an AWS ELB with OIDC authentication instead of oauth2-proxy and an nginx ingress, the system is basically the same. Only the header name is different.)

How to Secure A Cloud Run gRPC Service

This article explains how to handle authentication from an end-user with Identity Platform.
The crux seems to be that the client should authenticate with Identity Platform to get a token. That's straightforward enough and I've been able to retrieve the token from the client side code. The server side should receive the token from the client in a request header. But the article doesn't seem to explain what to do after this point. We can get the user with the Identity Platform SDK, but what if the token is invalid? Should we just throw an exception so that the gRPC call errors out?
There is a Java sample and you can that is what it does here. In the sample it returns a Forbidden 403 HTTP status.
But, my assumption is that Cloud Run would have a more automatic level of integration than this. This requires the Cloud Run gateway to send a request to the gRPC service, and get the response. Theoretically, that would allow a malicious actor to continuously hit the gateway with spam tokens that could potentially cost money. If we simply return an error, how are we protected from malicious actors pounding our services? Does the gateway automatically block the IP address if the gRPC service returns too many errors? How does it know which errors should trigger this? A HTTP error of 403 could alert the gateway that the endpoint is getting attacked, but what about gRPC?
Part I.
So lets clarify some facts to realize why you need another layer.
Cloud Run is just the HTTP service. And as you mentioned, if you let the traffic hit it, you will pay all the traffic, that's why you need another layer before "that's designed" for a specific purpose. There are other layers that can be placed before like Cloud Armor, Load Balancer, Identity-Aware-Proxy. Those are standalone products, with their own docs/config, and their own pay per use model.
Part II.
Also look into API Gateway for gRPC, you can use the API management capabilities of API Gateway to add monitoring, hosting, tracing, authentication, and more to your gRPC services on Cloud Run.
In addition, once you specify special mapping rules, API Gateway translates RESTful JSON over HTTP into gRPC requests. This means that you can deploy a gRPC server managed by API Gateway and call its API using a gRPC or JSON/HTTP client, giving you much more flexibility and ease of integration with other systems.
You can create gRPC services for API Gateway in any gRPC-supported language.

Securing Cloud Function Using API Gateway

My goal is to prevent users from accessing my cloud function endpoints by using an API key and API gateway. I have successfully deployed the API gateway; however, the original endpoint of each cloud function still exists and is accessible to the public. I want to have the cloud function endpoints private, while having the api gateway endpoints public, but I am not sure how to achieve this. Any suggestions would be great.
You can't hide your Cloud Functions endpoint. In any configuration it will be publicly viewable.
However, you can restrict who has access. In your case, deploy your Cloud Functions in secured mode (set the param --no-allow-unauthenticated or remove allUsers from the permissions section)
Then, deploy your API Gateway with a custom (backend) service account. Grant this service account the permission to invoke Cloud Functions (role: cloudfunctions.invoker).
When you have achieve this, only the API Gateway identity will be allowed to access to your Cloud Functions. The users will be able to see and to request the Cloud Functions URL, but they will get a 403 or a 401 error.
EDIT 1
After tests, and with Cloud Functions (I haven't have this case with Cloud Run), the Cloud Functions generated target audience is wrong with you use addition path in your backend. Here the conf that I have
/function:
get:
summary: Greet a user
operationId: function
x-google-backend:
address: https://us-central1-gdglyon-cloudrun.cloudfunctions.net/gdg-go
responses:
'200':
description: A successful response
schema:
type: string
/function-path:
get:
summary: Greet a user
operationId: function-path
x-google-backend:
address: https://us-central1-gdglyon-cloudrun.cloudfunctions.net/gdg-go/path
jwt_audience: https://us-central1-gdglyon-cloudrun.cloudfunctions.net/gdg-go
responses:
'200':
description: A successful response
schema:
type: string
The /function uses the root path of the Cloud Functions, no problem to invoke it directly.
The /function-path add /path to the root path of the Cloud Functions. I guess that API Gateway use this same full URL (with the /path at the end) which is a wrong audience for the function.
You can override that with the jwt_audience parameter.

Consul vs API Gateway

I would like to ask about the functionalities of Consul and API Gateway. Is Consul can replace API Gateway as a service referrer ?
Or how to use both of them in term of microservices architecture ?
Thank You
Consul is multi datacenter service discovery (+health checking) and distributed K/V store.
API Gateway is a service that handles all the tasks involved in accepting and processing API calls, including traffic management, authorization and access control, monitoring, and API version management.
so they're quite different..
depends on what you're trying to achieve and your current API Gateway use case, you may be able to use Consul + Consul aware load balancers, such as https://github.com/fabiolb/fabio and https://traefik.io/.
At a high-level, an API gateway would become the single point of entry to your micro services. It would allow you to give a consistent user experience to your clients - irrespective of the backend services.
They act as an abstraction - when you hit a /product/{productId} endpoint, you shouldn't need to know about the internal microservices e.g. /reviews, /recommendations etc - the gateway can do this for you and return a single response.
API gateways will be configured to receive a request on a listen path e.g.
curl http://gateway.com/myservice/mypath -H 'Authorization: secret_auth_token'
Internally, the gateway will receive the request and will see that myservice points to a specific api definition.
And based on that auth-token, will be able to establish whether the user is allowed access, what rate limit / quotas and also what upstream targets & paths they are allowed access. A few typical features:
Authentication & Authorisation
Rate Limits
Body Transforms (Filters / Map Reduce / Json -> XML, XML -> Json)
Header Injection
Json Schema Validation
Method Transforms
Mock Responses
API Versioning Strategy
Send requests to multiple targets
the list goes on.
So the gateway will then proxy the request to myservice.com/mypath for example and return the response to the client.
Now let's assume you want your upstream to be highly available - e.g. you may have myservice1.com and myservice2.com.
The gateway can be configured to load balance requests between these services. And you could use features of the gateway for testing the health of the upstreams, but there are also dedicated tools for this. One such tool is Consul.
API gateways should be able to integrate with service discovery tools. So let's assume myservice1.com goes down for maintenance, the gateway will know never to send traffic there and to only send to service2.com till service1 comes back up.
Screenshot below is example of tyk.io api gateway integration support for Consul.

Security considerations for API Gateway clustering?

Clients that communicate against a single point of entry via an API Gateway over HTTPS against a RESTful API
API Gateway: API Keys for tracking and analytics, oAuth for API platform authentication
User Micro service provides user authentication and authorization, generates JWT that is signed and encrypted (JWS,JWE)
Other micro services determine permissions based on claims inside JWT
Micro services communicate internally via PUB/SUB using JWT in the message and other info. Each micro service could be scaled out with multiple instances (cluster with a load balancer).
Question: Can I cluster the the API Gateway and have the load balancer in front of it. What do I need to consider with respect to managing authentication? ie: sharing of API Keys across the API Gateway cluster?
Extra notes, I'm planning on terminating SSL at the gateway and the use of bcrypt for passwords in the db.
Any feedback would be great, thank you.
Can I cluster the the API Gateway and have the load balancer in front
of it.
Yes, you can. Most of the good Api Gateway solutions will provide the ability to do clustering. e.g. https://getkong.org/docs/0.9.x/clustering/ or you can use cloud based Api Gateway: Azure API Management or AWS API Gateway
What do I need to consider with respect to managing authentication?
These specifics depends on your selection of API Gateway solution.