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
-
Access to working kubernetes cluster.
-
Understanding of Kubernetes terms like pods, deployments, services, configmap, ingress and annotations
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.
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.