BotGuard Ingress Controller
This guide describes how to deploy a virtual machine instance with a minimal Kubernetes setup, web application, BotGuard ingress controller, and certificate manager.
As a result, you will get a botguard-protected website running in the Kubernetes environment.
About BotGuard Ingress Controller
The BotGuard Ingress Controller is a fork of the ingress-nginx, the popular ingress controller for Kubernetes. It fully compatible with ingress-nginx, but provides additional options. Moreover, both ingress-nginx and BotGuard Ingress Controller can be used in the same cluster simultaneously.
The differences from ingress-nginx are:
- ModSecurity is disabled due to the possible BotGuard incompatibility. The configuration options for ModSecurity are ignored when used.
- It uses patched version of the Nginx
- It uses patched latest version of the OpenSSL library
- It contains BotGuard module for Nginx
- There are additional configuration options to enable BotGuard protection
The additional configuration options are (per cluster):
controller:
config:
botguard-primary-server: "xxx.botguard.net"
botguard-secondary-server: "yyy.botguard.net"
botguard-skip: "regexp to skip urls"
botguard-primary-server
and botguard-secondary-server
are BotGuard servers assigned to your domain in the BotGuard dashboard. The optional botguard-skip
parameter is the regular expression applied to URL to ignore some patterns when matched. It is used to bypass static files analysis.
If those options are not set, the protection is disabled. To enable the protection per domain, the Ingress annotation is used:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-botguard: "true"
Virtual machine setup
Deploy a virtual machine in the DigitalOcean environment with the following specs:
- AlmaLinux 8
- 2 CPU
- 2 Gb RAM
- 60 Gb disk
- Additional reserved IPv4 address
Assign a reserved IPv4 address to the domain (botguard.example
for example) with DNS manager (record type A
).
As a result, the machine will be accessible by both of IPv4 addresses (primary and reserved):
Minikube setup
Minikube provides a minimal implementation of the Kubernetes environment. It supports different implementations ("drivers"). We will use podman (RedHat's Docker replacement).
Install required packages:
yum update
yum install podman podman-docker conntrack-tools
rpm -ihv https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm
Deploy Kubernetes single-node cluster:
To avoid extra typing, create an alias for kubectl in the shell config.
As a result, the kubectl get nodes
should display:
kubectl get all --all-namespaces
should display:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-5d78c9869d-hz5fc 1/1 Running 0 2m5s
kube-system pod/etcd-minikube 1/1 Running 0 2m16s
kube-system pod/kube-apiserver-minikube 1/1 Running 0 2m16s
kube-system pod/kube-controller-manager-minikube 1/1 Running 0 2m16s
kube-system pod/kube-proxy-mdq6w 1/1 Running 0 2m5s
kube-system pod/kube-scheduler-minikube 1/1 Running 0 2m16s
kube-system pod/storage-provisioner 1/1 Running 1 (94s ago) 2m14s
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m19s
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 2m17s
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-system daemonset.apps/kube-proxy 1 1 1 1 1 kubernetes.io/os=linux 2m17s
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 1/1 1 1 2m17s
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-5d78c9869d 1 1 1 2m5s
Web application
We will deploy a sample web application, that just shows the original request for demo purposes. It contains a Kubernetes deployment and a service:
echo "
apiVersion: apps/v1
kind: Deployment
metadata:
name: meow
spec:
replicas: 1
selector:
matchLabels:
app: meow
template:
metadata:
labels:
app: meow
spec:
containers:
- name: meow
image: gcr.io/kubernetes-e2e-test-images/echoserver:2.1
ports:
- containerPort: 8080
" | kubectl apply -f -
echo "
apiVersion: v1
kind: Service
metadata:
name: meow-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: meow
" | kubectl apply -f -
As a result of the application deployment, the kubectl get all
should display:
NAME READY STATUS RESTARTS AGE
pod/meow-75d6b9f5c8-kpw8d 1/1 Running 0 25s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40m
service/meow-svc ClusterIP 10.110.23.94 <none> 80/TCP 7s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/meow 1/1 1 1 25s
NAME DESIRED CURRENT READY AGE
replicaset.apps/meow-75d6b9f5c8 1 1 1 25s
BotGuard Ingress Controller
To install BotGuard Ingress Controller, first we need to install Helm package manager:
curl https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz | tar -zx
mv linux-amd64/helm /usr/local/bin/
rm -rf linux-amd64
Then add the Helm repositories:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add botguard https://repo.botguard.net/modules/ingress-nginx
helm repo add jetstack https://charts.jetstack.io
helm repo update
And finally install BotGuard Ingress Controller. Replace "xxx.botguard.net" and "yyy.botguard.net" with values provided by BotGuard dashboard
for the registered domain (botguard.example
).
helm install botguard botguard/ingress-nginx \
--set controller.config.botguard-primary-server=xxx.botguard.net \
--set controller.config.botguard-secondary-server=yyy.botguard.net \
--set controller.service.type=NodePort \
--set controller.service.nodePorts.http=32080 \
--set controller.service.nodePorts.https=32443 \
--set controller.service.externalTrafficPolicy=Local
To enable external access to the ingress controller, add the iptables rules. Replace 10.19.0.11
with the external private ip address ("anchor ip address") of the machine assigned by DigitalOcean:
iptables -t nat -I PREROUTING 1 -d 10.19.0.11 -p tcp -m tcp --dport 80 -j DNAT --to-destination `minikube ip`:32080
iptables -t nat -I PREROUTING 2 -d 10.19.0.11 -p tcp -m tcp --dport 443 -j DNAT --to-destination `minikube ip`:32443
At this point, navigating to the http://botguard.example
should display standard 404 Not Found
page.
Certificate Manager
Install cert-manager with the Helm:
And then apply the ACME certificate issuer to obtain a certificate from LetsEncrypt (replace email address with your one):
echo "
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: meow@botguard.example
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt
solvers:
- http01:
ingress:
ingressClassName: botguard
" | kubectl apply -f -
Protected Ingress
To issue the certificate and provide access to the web application, create Kubernetes ingress:
echo "
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/enable-botguard: "true"
name: meow-ingress
spec:
ingressClassName: botguard
tls:
- hosts:
- botguard.example
secretName: meow-tls
rules:
- host: botguard.example
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: meow-svc
port:
number: 80
" | kubectl apply -f -
In a couple of minutes, navigating to the http://botguard.example
and https://botguard.example
should display web application page.
Final tests
Check the BotGuard protection is worked as expected:
should display: