API key auth for Ambassador API key auth for Ambassador kubernetes kubernetes

API key auth for Ambassador


I suggest you do the following:

  1. Create an Authentication Application: for each protected endpoint, this app will be responsible for validating the Api Key.

  2. Configuring Ambassador to redirect requests to this service: you just need to annotate your authentication app service definition. Example:

    ---    apiVersion: v1    kind: Service    metadata:      name: auth-app      annotations:        getambassador.io/config: |          ---          apiVersion: ambassador/v1          kind:  AuthService          name:  authentication          auth_service: "auth-app:8080"          allowed_request_headers:          - "API-KEY"    spec:      type: ClusterIP      selector:        app: auth-app      ports:      - port: 8080        name: auth-app        targetPort: auth-app
  1. Configure an endpoint in auth-app corresponding to the endpoint of the app you want to authenticate. Suppose you have an app with a Mapping like this:
    apiVersion: ambassador/v1    kind:  Mapping    name:  myapp-mapping    prefix: /myapp/    service: myapp:8000

Then you need to have an endpoint "/myapp/" in auth-app. You will read your API-KEY header there. If the key is valid, return a HTTP 200 (OK). Ambassador will then send the original message to myapp. If auth-app returns any other thing besides a HTTP 200, Ambassador will return that response to the client.

  1. Bypass the authentication in needed apps. For example you might need a login app, responsible for providing an API Key to the clients. You can bypass authentication for these apps using bypass_auth: true in the mapping:
    apiVersion: ambassador/v1    kind:  Mapping    name:  login-mapping    prefix: /login/    service: login-app:8080    bypass_auth: true

Check this if you want to know more about authentication in Ambassador

EDIT: According to this answer it is a good practice if you use as header Authorization: Bearer {base64-API-KEY}. In Ambassador the Authorization header is allowed by default, so you don't need to pass it in the allowed_request_headers field.


I settled on this quick and dirty solution after not finding a simple approach (that would not involve spinning up an external authentication service).

You can use Header-based Routing and only allow incoming requests with a matching header:value.

---apiVersion: getambassador.io/v2kind: Mappingmetadata:  name: protected-mapping  namespace: defaultspec:  prefix: /protected-path/  rewrite: /  headers:    # Poorman's Bearer authentication    # Ambassador will return a 404 error unless the Authorization header value is set as below on the incoming requests.    Authorization: "Bearer <token>"  service: app:80

Testing

# Not authenticated => 404$ curl -sI -X GET https://ambassador/protected-path/HTTP/1.1 404 Not Founddate: Thu, 11 Mar 2021 18:30:27 GMTserver: envoycontent-length: 0# Authenticated => 200$ curl -sI -X GET -H 'Authorization: Bearer eEVCV1JtUzBSVUFvQmw4eVRVM25BenJa' https://ambassador/protected-path/HTTP/1.1 200 OKcontent-type: application/json; charset=utf-8vary: Origindate: Thu, 11 Mar 2021 18:23:20 GMTcontent-length: 15x-envoy-upstream-service-time: 3server: envoy

While you could technically use any header:value pair (e.g., x-my-auth-header: header-value) here, the Authorization: Bearer ... scheme seems to be the best option if you want to follow a standard.

Whether to base64-encode or not your token in this case is up to you.

Here's a lengthy explanation of how to read and understand the spec(s) in this regard: https://stackoverflow.com/a/56704746/4550880

It boils down to the following regex format for the token value:

[-a-zA-Z0-9._~+/]+=*