Routes

Cet article vise à expliquer comment personnaliser la configuration du routeur Openshift de manière à l’adapater à certains besoins métiers.

Public visé : administrateurs et utilisateurs d’Openshift.

Par Jacques Roussel, Consultant Cloud @Objectif Libre

Personnalisation du routeur Openshift

Lorsqu’on utilise Openshift, on crée rapidement de nombreuses routes. Ces routes permettent d’exposer à l’extérieur du cluster, des applications web. Derrière toutes ces routes se cachent un ou plusieurs pods haproxy dont la configuration est complètement managée. Sachant cela, il est assez frustrant par exemple de ne pas pouvoir simplement interdire l’accès à certains pattern pour des routes données.

Prenons l’exemple d’un blog wordpress qui tournerait sur Openshift : on pourrait souhaiter bloquer l’accès à « wp-admin » sur la route publique.

C’est ce type de configuration que nous allons apprendre à faire aujourd’hui. Bien que cela semble fastidieux au premier abord, il n’en est rien et vous verrez à quel point cela peut-être puissant pour généraliser des pratiques entre des projets différents.

Préparation de l’environnement

Tout d’abord, installons un environnement de test Openshift. Pour cela, nous utiliserons minishift.

$ sudo curl -L https://github.com/dhiltgen/docker-machine-kvm/releases/download/v0.7.0/docker-machine-driver-kvm -o /usr/local/bin/docker-machine-driver-kvm
$ sudo chmod +x /usr/local/bin/docker-machine-driver-kvm
$ sudo apt install libvirt-bin qemu-kvm
$ sudo usermod -a -G libvirtd $(whoami)
$ newgrp libvirtd
$ cd /tmp
$ wget https://github.com/minishift/minishift/releases/download/v1.13.1/minishift-1.13.1-linux-amd64.tgz
$ tar -xf minishift-1.13.1-linux-amd64.tgz
$ sudo mv minishift-1.13.1-linux-amd64/minishift /usr/local/bin/minishift
$ minishift version
$ minishift start --memory 4GB
$ eval $(minishift oc-env)

Création du projet de test dans Openshift

On crée un projet dans lequel on déploie des pods httpd, un service et une route.

$ oc login -u system:admin https://$(minishift ip):8443 # On se logue en admin pour ne pas avoir de problème de droits
$ oc new-project blog-article
$ oc run --image=registry.access.redhat.com/rhscl/httpd-24-rhel7 --replicas=2 httpd
$ cat <<EOF | oc create -f -
apiVersion: v1
kind: Service
metadata:
 name: httpd
spec:
 ports:
   - name: 8080-tcp
     port: 8080
     protocol: TCP
     targetPort: 8080
 selector:
   run: httpd
EOF
$ oc expose service httpd
$ curl -I httpd-blog-article.$(minishift ip).nip.io/admin
HTTP/1.1 404 Not Found
Date: Wed, 11 Apr 2018 12:38:42 GMT
Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
Content-Type: text/html; charset=iso-8859-1
Set-Cookie: a3fe51630340065f682306a4f6d5c314=a50715fc19b88e07724c5dc4309782aa; path=/; HttpOnly

Notez que le déploiement des images peut prendre une ou deux minutes.

Récupération et personnalisation du template du routeur

L’objectif que l’on se fixe est d’empêcher l’accès aux urls de type /admin sur certaines routes grâce à une annotation spécifique. Pour cela, nous devons récupérer le template actuel du routeur puis le personnaliser et enfin configurer le routeur pour qu’il utilise notre nouveau template :

Récupération du template

oc -n default rsh $(oc -n default get po -l router=router --template="{{ (index .items 0).metadata.name }}") cat haproxy-config.template > haproxy-config.template

Personnalisation

Ensuite, on édite le fichier haproxy-config.template pour modifier son comportement. Pour cela, on ajoute à la ligne 332, en dessous de mode http :

  {{- if (ne (index $cfg.Annotations "haproxy.router.openshift.io/forbidden_regexp") "") }}
  acl forbidden_regexp path_reg {{ index $cfg.Annotations "haproxy.router.openshift.io/forbidden_regexp" }}
  http-request deny if forbidden_regexp
  {{- end}}

Explications :
Si l’annotation « haproxy.router.openshift.io/forbidden_regexp » n’est pas vide, alors on insère dans la configuration haproxy les deux lignes suivantes :

« acl forbidden_regexp path_reg {{ index $cfg.Annotations « haproxy.router.openshift.io/forbidden_regexp » }} » -> ici on insère la regexp récupérée via l’annotation qui définie la variable forbidden_regexp si le path de la requête entrante match la regexp.
http-request deny if forbidden_regexp -> Cette instruction dit à haproxy de rejeter la requête si la variable forbidden_regexp est présente.

Mise en place du nouveau template

Il ne reste plus qu’à mettre à jour la configuration du routeur openshift pour qu’il utilise ce nouveau template :

$ oc create configmap customrouter --from-file=haproxy-config.template -n default
$ oc set env dc/router TEMPLATE_FILE=/var/lib/haproxy/conf/custom/haproxy-config.template -n default
$ oc volume dc/router --add --overwrite --name=config-volume --mount-path=/var/lib/haproxy/conf/custom --source='{"configMap": { "name": "customrouter"}}' -n default

C’est terminé, nous pouvons dès maintenant utiliser notre nouvelle fonctionnalité.

Utilisation de notre nouvelle annotation

$ cat <<EOF |oc create -f -
apiVersion: v1
kind: Route
metadata:
 annotations:
   openshift.io/host.generated: "true"
   haproxy.router.openshift.io/forbidden_regexp: "^/admin$"
 name: httpd2
spec:
 host: httpd2-blog-article.$(minishift ip).nip.io
 port:
   targetPort: 8080-tcp
 to:
   kind: Service
   name: httpd
EOF
$ curl -I httpd-blog-article.$(minishift ip).nip.io/admin
HTTP/1.1 404 Not Found
Date: Wed, 11 Apr 2018 12:38:42 GMT
Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
Content-Type: text/html; charset=iso-8859-1
Set-Cookie: a3fe51630340065f682306a4f6d5c314=a50715fc19b88e07724c5dc4309782aa; path=/; HttpOnly
$ curl -I httpd2-blog-article.$(minishift ip).nip.io/admin
HTTP/1.0 403 Forbidden
Cache-Control: no-cache
Connection: close
Content-Type: text/html

Conclusion

Comme nous venons de le voir, il est très simple de modifier le routeur intégré d’Openshift pour lui ajouter certains comportements.

Attention toutefois à ne pas en abuser : le routeur doit rester suffisamment générique. Aussi, on sera attentif à ne modifier son comportement qu’avec des fonctionnalités génériques utilisables par n’importe quel type de projet. En effet, il ne faut pas le modifier pour des projets spécifiques car sa maintenance deviendrait compliquée.