Authentication using external service

Authentication using external service

Saaras Inc. May 13, 2022
Authentication using external service

Introduction

EnRoute Ingress API Gateway provides an extremely flexible mechanism to authenticate incoming requests. An external service can check authentication and authorization for requests entering the cluster. Every request before it reaches the destination service can be authenticated.

We explore Authentication support in EnRoute gateway. Using an example we walk through different aspects of external authentication including per-route disable.

What this article covers

We install EnRoute Gateway, expose a service externally and configure an external authentication service

Enroute external authentication

Install EnRoute with External Authentication support

External authentication support is provided in a separate EnRoute image. It can be installed using the following helm command after adding the helm repo and installing the enroute image with wasm tag. The image has support for both wasm and ext_authz envoy filters

helm repo add saaras https://getenroute.io
helm install enroute-demo saaras/enroute \
	--set serviceAccount.create=true \
	--create-namespace \
	--namespace enroutedemo \
	--set images.enrouteService.tag=wasm

Install example workload

kubectl create namespace httpbin
kubectl apply -f https://raw.githubusercontent.com/saarasio/enroute/master/helm-chart/httpbin-bin-service.yaml

Program EnRoute to make the service externally available

helm install httpbin-service-policy saaras/service-policy --set service.name=httpbin --set service.prefix=/post --set service.port=80 --namespace httpbin

Send request to External-IP of LoadBalancer service to verify it works as expected. The getting started guide has details on setting this up.

curl -X POST -H 'Content-Type: application/json' -d '{}' 212.2.241.255/post
{
  "args": {},
  "data": "{}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "2",
    "Content-Type": "application/json",
    "Host": "212.2.241.255",
    "User-Agent": "curl/7.68.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-External-Address": "192.168.1.5"
  },
  "json": {},
  "origin": "152.70.114.65,192.168.1.5",
  "url": "http://212.2.241.255/post"
}

Create a External Authentication filter

cat <<EOF | kubectl apply -f -
apiVersion: enroute.saaras.io/v1
kind: HttpFilter
metadata:
  name: extauthz-filter
  namespace: httpbin
spec:
  httpFilterConfig:
    config: |
        {
            "url" : "https://ext-authz-ns.ext-auth:8443",
            "auth_service" : "ext-auth",
            "auth_service_proto" : "http",
            "body_max_bytes" : 4096,
            "body_allow_partial" : true,
            "status_on_error" : 403,
            "failure_mode_allow" : true,
            "timeout" : 10,
            "path_prefix" : "",
            "pack_raw_bytes" : false,
            "allowed_request_headers": ["x-forwarded-for"],
            "allowed_authorization_headers" : ["x-org-auth-tenantid", "x-token"]
        }
  name: extauthz-filter
  type: http_filter_extauthz
EOF

This defines a destination service for external authorization in namespace ext-authz-ns to service ext-auth running on port 8443 over https

The detailed configuration options for the above service can be found in the External Authorization Filter reference.

Enable the External Authorization filter for service

kubectl edit -n httpbin gatewayhosts.enroute.saaras.io httpbin-80-gatewayhost
  5 apiVersion: enroute.saaras.io/v1
  6 kind: GatewayHost
  7 metadata:
  8   annotations:
 13   labels:
 14     app: httpbin
 16   name: httpbin-80-gatewayhost
 17   namespace: httpbin
 20 spec:
 21   routes:
 22   - conditions:
 23     - header:
 24         contains: auth-disabled-route
 25         name: X-auth-hint
 26     - prefix: /post
 27     disableExtauth: true
 28     filters:
 29     - name: httpbin-80-rl2
 30       type: route_filter_ratelimit
 31     services:
 32     - healthCheck:
 33         healthyThresholdCount: 3
 34         host: hc
 35         intervalSeconds: 5
 36         path: /
 37         timeoutSeconds: 3
 38         unhealthyThresholdCount: 3
 39       name: httpbin
 40       port: 80
 41   - conditions:
 42     - header:
 43         contains: auth-enabled-route
 44         name: X-auth-hint
 45     - prefix: /post
 46     filters:
 47     - name: httpbin-80-rl2
 48       type: route_filter_ratelimit
 49     services:
 50     - healthCheck:
 51         healthyThresholdCount: 3
 52         host: hc
 53         intervalSeconds: 5
 54         path: /
 55         timeoutSeconds: 3
 56         unhealthyThresholdCount: 3
 57       name: httpbin
 58       port: 80
 59   virtualhost:
 60     filters:
 61     - name: httpbin-80-luatestfilter
 62       type: http_filter_lua
 63     - name: extauthz-filter
 64       type: http_filter_extauthz
 65     fqdn: '*'

Note the lines 63-64 above that attaches the filter to GatewayHost

Note on line 27 external authorization is explicitly disabled (using disableExtauth: true directive) for a request with incoming header X-auth-hint: auth-disabled-route

Verify invocation of external authorization service

The external authentication service for this example when invoked sets three headers -

   "X-Org-Auth-Tenantid": "eC1hdXRoLWFjY291bnRJZAo=",
   "X-Token": "eC1hdXRoLXRva2VuCg==",

If the request was sent to the external authentication service, the above three headers would be set.

To send a request

curl -vv -X POST -H 'X-auth-hint: "auth-disabled-route"' -H 'Content-Type: application/json' -d '{"auth":"disabled"}' 212.2.241.255/post
{
  "args": {},
  "data": "{\auth\":\"disabled\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "26",
    "Content-Type": "application/json",
    "Host": "212.2.241.255",
    "User-Agent": "curl/7.68.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-External-Address": "192.168.1.6",
    "X-Stamp": "\"prod2\""
  },
  "json": {
    "auth": "disabled"
  },
  "origin": "152.70.114.65,192.168.1.6",
  "url": "http://212.2.241.255/post"
}

Now lets sent a request that will be authenticated by an external auth service

curl -vv -X POST -H 'X-auth-hint: "auth-enabled-route"' -H 'Content-Type: application/json' -d '{"auth":"enabled"}' 212.2.241.255/post
{
  "args": {},
  "data": "{\"auth\":\"enabled\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "26",
    "Content-Type": "application/json",
    "Ext-Authz-Example-Header": "ext-authz-example-header-value",
    "Host": "212.2.241.255",
    "User-Agent": "curl/7.68.0",
    "X-Org-Auth-Tenantid": "eC1hdXRoLWFjY291bnRJZAo=",
    "X-Token": "eC1hdXRoLXRva2VuCg==",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-External-Address": "192.168.1.6",
    "X-Stamp": "\"prod1\""
  },
  "json": {
    "auth": "enabled"
  },
  "origin": "152.70.114.65,192.168.1.6",
  "url": "http://212.2.241.255/post"
}

Conclusion

This howto quickly covers how to configure and enable an external authorization service for authenticating services at Ingress