Kubernetes ingress controller for authenticating apps

Rahul Mahale

By Rahul Mahale

on August 14, 2018

Kubernetes Ingress has redefined the routing in this era of containerization and with all these freehand routing techniques the thought of "My router my rules" seems real.

We use nginx-ingress as a routing service for our applications. There is a lot more than routing we can do with ingress. One of the important features is setting up authentication using ingress for our application. As all the traffic goes from ingress to our service, it makes sense to setup authentication on ingress.

As mentioned in ingress repository there are different types of techniques available for authentication including:

  • Basic authentication
  • Client-certs authentication
  • External authentication
  • Oauth external authentication

In this blog, we will set up authentication for the sample application using basic ingress authentication technique.

Pre-requisites

First, let's create ingress resources from upstream example by running the following command.

1
2$ kubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
3namespace "ingress-nginx" created
4deployment "default-http-backend" created
5service "default-http-backend" created
6configmap "nginx-configuration" created
7configmap "tcp-services" created
8configmap "udp-services" created
9serviceaccount "nginx-ingress-serviceaccount" created
10clusterrole "nginx-ingress-clusterrole" created
11role "nginx-ingress-role" created
12rolebinding "nginx-ingress-role-nisa-binding" created
13clusterrolebinding "nginx-ingress-clusterrole-nisa-binding" created
14deployment "nginx-ingress-controller" created
15

Now that ingress controller resources are created we need a service to access the ingress.

Use following manifest to create service for ingress.

1apiVersion: v1
2kind: Service
3metadata:
4  annotations:
5    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
6  labels:
7    k8s-addon: ingress-nginx.addons.k8s.io
8  name: ingress-nginx
9  namespace: ingress-nginx
10spec:
11  externalTrafficPolicy: Cluster
12  ports:
13    - name: https
14      port: 443
15      protocol: TCP
16      targetPort: http
17    - name: http
18      port: 80
19      protocol: TCP
20      targetPort: http
21  selector:
22    app: ingress-nginx
23  type: LoadBalancer

Now, get the ELB endpoint and bind it with some domain name.

1
2$kubectl create -f ingress-service.yml
3service ingress-nginx created
4
5$ kubectl -n ingress-nginx get svc  ingress-nginx -o wide
6NAME            CLUSTER-IP      EXTERNAL-IP                                                               PORT(S)                      AGE       SELECTOR
7ingress-nginx   100.71.250.56   abcghccf8540698e8bff782799ca8h04-1234567890.us-east-2.elb.amazonaws.com   80:30032/TCP,443:30108/TCP   10s       app=ingress-nginx
8

Let's create a deployment and service for our sample application kibana. We need elasticsearch to run kibana.

Here is manifest for the sample application.

1---
2apiVersion: extensions/v1beta1
3kind: Deployment
4metadata:
5  labels:
6    app: kibana
7  name: kibana
8  namespace: ingress-nginx
9spec:
10  replicas: 1
11  template:
12    metadata:
13      labels:
14        app: kibana
15    spec:
16      containers:
17        - image: kibana:latest
18          name: kibana
19          ports:
20            - containerPort: 5601
21---
22apiVersion: v1
23kind: Service
24metadata:
25  annotations:
26  labels:
27    app: kibana
28  name: kibana
29  namespace: ingress-nginx
30
31spec:
32  ports:
33    - name: kibana
34      port: 5601
35      targetPort: 5601
36  selector:
37    app: kibana
38---
39apiVersion: extensions/v1beta1
40kind: Deployment
41metadata:
42  labels:
43    app: elasticsearch
44  name: elasticsearch
45  namespace: ingress-nginx
46spec:
47  replicas: 1
48  strategy:
49    type: RollingUpdate
50  template:
51    metadata:
52      labels:
53        app: elasticsearch
54    spec:
55      containers:
56        - image: elasticsearch:latest
57          name: elasticsearch
58          ports:
59            - containerPort: 5601
60---
61apiVersion: v1
62kind: Service
63metadata:
64  annotations:
65  labels:
66    app: elasticsearch
67  name: elasticsearch
68  namespace: ingress-nginx
69spec:
70  ports:
71    - name: elasticsearch
72      port: 9200
73      targetPort: 9200
74  selector:
75    app: elasticsearch

Create the sample application.

1
2kubectl apply -f kibana.yml
3deployment "kibana" created
4service "kibana" created
5deployment "elasticsearch" created
6service "elasticsearch" created
7

Now that we have created application and ingress resources, it's time to create an ingress and access the application.

Use the following manifest to create ingress.

1apiVersion: extensions/v1beta1
2kind: Ingress
3metadata:
4  annotations:
5  name: kibana-ingress
6  namespace: ingress-nginx
7spec:
8  rules:
9    - host: logstest.myapp-staging.com
10      http:
11        paths:
12          - path: /
13            backend:
14              serviceName: kibana
15              servicePort: 5601
1
2$kubectl -n ingress-nginx create -f ingress.yml
3ingress "kibana-ingress" created.
4

Now that our application is up, when we access the kibana dashboard using URL http://logstest.myapp-staging.com We directly have access to our Kibana dashboard and anyone with this URL can access logs as shown in the following image.

Kibana dashboard without authentication

Now, let's set up a basic authentication using htpasswd.

Follow below commands to generate the secret for credentials.

Let's create an auth file with username and password.

1
2$ htpasswd -c auth kibanaadmin
3New password: <kibanaadmin>
4New password:
5Re-type new password:
6Adding password for user kibanaadmin
7

Create k8s secret.

1
2$ kubectl -n ingress-nginx create secret generic basic-auth --from-file=auth
3secret "basic-auth" created
4

Verify the secret.

1
2kubectl get secret basic-auth -o yaml
3apiVersion: v1
4data:
5  auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
6kind: Secret
7metadata:
8  name: basic-auth
9  namespace: ingress-nginx
10type: Opaque
11

Use following annotations in our ingress manifest by updating the ingress manifest.

1kubectl -n ingress-nginx edit ingress kibana ingress

Paste the following annotations

1nginx.ingress.kubernetes.io/auth-type: basic
2nginx.ingress.kubernetes.io/auth-secret: basic-auth
3nginx.ingress.kubernetes.io/auth-realm: "Kibana Authentication Required - kibanaadmin"
4

Now that ingress is updated, hit the URL again and as shown in the image below we are asked for authentication.

Kibana dashboard without authentication

Stay up to date with our blogs. Sign up for our newsletter.

We write about Ruby on Rails, ReactJS, React Native, remote work,open source, engineering & design.