Apache2 Proxy Reverse Custom Log Address IP : request via proxy or not

Tags: #<Tag:0x00007fc9e2952910> #<Tag:0x00007fc9e29527a8> #<Tag:0x00007fc9e2952640>

Apache2 Web Server

Salut à tous.

Je viens vers vous pour vous demander un truc que tout le monde doit connaître :

Comment configurer les logs du serveur web Apache pour récupérer 3 types de requêtes « reqenv »

J’ai un site web configuré comme cela :

# host www.zw3b.fr
www.zw3b.fr has address 158.69.126.137
www.zw3b.fr has IPv6 address 2607:5300:60:9389::1

J’ai installé Apache reverse pour faire pointer sur différentes machines en « back end » par exemple celle-ci :

# host ww1.zw3b.fr
ww1.zw3b.fr has IPv6 address 2607:5300:60:9389:15:1:a:10

J’aimerais avoir dans les logs Apache, l’adresse IP de la machine « cliente » et cela que la demande vienne du proxy ou directement sur l’hôte (ww1).

En demandant « www », j’arrive bien à récupérer l’IPv4 et l’IPv6 en traversant le proxy reverse, jusque là c’est normal comme configuration.

Par contre si je « tape » sur la machine « backend ww1 » je ne vois aucune adresse IP dans les logs.


Sur « ww1 » j’ai configuré les logs d’Apache de cette manière " /etc/apache2/apache2.conf " :

# Les logs par default d'une installe
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# default

J’ai ajouté le " X-Forwarded-For " de cette manière :

LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded

Dans mes Virtual-Hosts la configuration des CustomLog est la suivante :

# exemple de CustomLog par default:
#CustomLog ${APACHE_LOG_DIR}/access.log combined
# req sur l'IPv4 du HOST -> IPv4 (after proxy)
CustomLog ${APACHE_LOG_DIR}/access.log proxy env=forwarded
# req sur l'IPv6 du HOST -> IPv6 (after proxy)
CustomLog ${APACHE_LOG_DIR}/access.log proxy env=!forwarded
Résumé de la configuration la proxy :
<IfModule mod_proxy.c>
	# Show Proxy LoadBalancer status in mod_status
	ProxyStatus On

	ProxyPreserveHost On
	ProxyRequests Off

	ProxyVia On

#	SetEnv force-proxy-request-1.0 1
	SetEnv proxy-nokeepalive 1

	# On fait du proxy vers un autre serveur en https
	SSLProxyEngine On

	# Disable SSLProxyCheck
	SSLProxyVerify none
	SSLProxyCheckPeerCN off
	SSLProxyCheckPeerName off
	SSLProxyCheckPeerExpire off

</IfModule>

Et enfin, les logs en demandant l’Apache proxy reverse « load balancer » " www.zw3b (dot) fr " :

root@client:~ # curl -4 -I -L https://www.zw3b.fr
root@ww1:~ # tail -f /var/pro/web_logs/zw3b_fr/www/logs/access.log
109.210.56.240 - - [23/Oct/2024:01:59:46 +0200] "HEAD / HTTP/1.1" 200 - "-" "curl/7.88.1"
root@client:~ # curl -6 -I -L https://www.zw3b.fr
root@ww1:~ # tail -f /var/pro/web_logs/zw3b_fr/www/logs/access.log
2a01:cb1d:12:1c00:beef::cafe - - [23/Oct/2024:02:03:19 +0200] "HEAD / HTTP/1.1" 200 - "-" "curl/7.88.1"

Par contre si je demande " ww1.zw3b (dot) fr " :

root@client:~ # curl -6 -I -L https://ww1.zw3b.fr
root@ww1:~ # tail -f /var/pro/web_logs/zw3b_fr/www/logs/access.log
- - - [23/Oct/2024:02:06:24 +0200] "HEAD / HTTP/1.1" 200 - "-" "curl/7.88.1"

Est-ce que quelqu’un a une configuration de LogFormat / CustomLog d’Apache2 de ce type ?

J’ai du faire une boulette quelques part, je n’y arrive plus :face_with_raised_eyebrow:

Merci.

@+

Romain.

Liens Annexes Apache2 Web Server :

:wink:


Contrôle d’accès Backend Allow from / Require ip from « Reverse proxy »

Je souhaitais autorisé seulement l’adresse IPv4 et IPv6 de chez moi, à l’interface PhpMyAdmin.

Mais j’ai un deuxième soucis avec le « back-end » d’Apache du « Contrôle d’accès » - C’est que je n’arrive pas à attraper l’adresse IP du client qui passe par le « proxy reverse » ;

Contrôle d'accès Backend Allow from / Require ip

Dans le " .htaccess " (ou dans la config d’un « Virtual-Host » que ce soit avec " allow from " ou que ce soit avec " require ip " il croit que mon IP est celle du « proxy reverse ».

J’ai trouvé cette solution ; celle d’autoriser le " frontal " (l’apache « proxy reverse ») - C’est à dire que tout le monde peut rentrer (en quelque sorte) ; Et donc, j’ai fermé sur le « frontal ».

Sur le serveur « ww1 » (backend) :

<Directory /usr/share/phpmyadmin/>
	Options MultiViews FollowSymLinks
	AllowOverride All AuthConfig

	# ---------------
	# Old config
	Order deny,allow
	Deny from all
	# Address normal
#	Allow from 109.210.56.240
#	Allow from 2a01:cb1d:0012:1c00:beef::cafe
#	Allow from 172.16.0.142
#	Allow from fc01::172:16:0:142

	# Address proxy
	Allow from 10.101.0.254
	Allow from 2607:5300:60:9389:15:1:0:f

	# ---------------
	# Recent config

	Require all denied

	# Address normal
#	Require ip 109.210.56.240
#	Require ip 2a01:cb1d:0012:1c00:beef::cafe
#	Require ip 172.16.0.142
#	Require ip fc01::172:16:0:142

	# Address proxy
	Require ip 10.101.0.254
	Require ip 2607:5300:60:9389:15:1:0:f

#	Require %{HTTP:X-Forwarded-For} == "2a01:cb1d:0012:1c00:beef::cafe"

</Directory>

Sur le serveur Apache « reverse proxy » (frontal) :

<Proxy *>	
	Order deny,allow
	Deny from all
	Allow from 109.210.56.240
	Allow from 2a01:cb1d:12:1c00:beef::cafe
	Allow from fc01::172:16:0:142
</Proxy>

Mais, j’aimerai bien avoir une configuration « fermer » sur la machine elle-même, qu’Apache reconnaisse les IP clientes en utilisant " Allow from " et/ou " Require ip " .


Exemple de configuration d’un Load Balancer Apache Proxy Reverse :

  • 2 serveurs cible en facteur 1 de charge par activité (une requête sur un, une sur l’autre).
  • 1 serveur en Spar : Le serveur cible sert de remplaçant à chaud. Lorsqu’un serveur cible avec un lbset donné est inutilisable (maintenance, arrêt, en erreur, etc…), un serveur de remplacement à chaud libre de même lbset sera utilisé à sa place. Les remplaçants à chaud permettent de s’assurer qu’un nombre déterminé de serveurs cibles sera toujours disponible pour un répartiteur de charge.
  • 1 serveur en Stby : Le serveur est en mode hot-standby et ne sera donc utilisé que si aucun autre serveur ou serveur de remplacement n’est disponible dans le jeu de serveurs du répartiteur de charge.

Screenshot 2024-10-23 at 10-50-54 Balancer Manager - IPv10.net - Init Err + Spar Err + Stby Ok

Screenshot 2024-10-23 at 10-51-40 Balancer Manager - IPv10.net - Init Ok + Spar Ok + Stby Ok

:heart: Apache !

Tu essaies d’ajouter à une ligne de log un entête spécifique envoyé par le reverse proxy amont / upstream, tel que X-Forwarded-For .

Il vaut mieux configurer Apache pour qu’il récupère l’adresse IP du client d’après l’entête X-Forwarded-For .
Ainsi, tu n’auras pas besoin de modifier la configuration des logs et cela marchera aussi tel quel pour du PHP, par exemple.

Je te laisse le soin de chercher sur Google, d’autres que moi ont fait de bons articles à ce sujet.


AnonymousCoward

Bonjour, @AnonymousCoward.

En-têtes de requête du mandataire inverse - mod_proxy - Apache HTTP Server Version 2.4

Lorsqu’il est configuré en mode mandataire inverse (en utilisant par exemple la directive ProxyPass ), mod_proxy_http ajoute plusieurs en-têtes de requête afin de transmettre des informations au serveur demandé. Ces en-têtes sont les suivants :

X-Forwarded-For : L’adresse IP du client.
X-Forwarded-Host : L’hôte d’origine demandé par le client dans l’en-tête de requête HTTP Host .
X-Forwarded-Server : Le nom d’hôte du serveur mandataire.

Pourtant ce n’est pas vrai, je ne vois aucune de ces entêtes, sur les serveurs « cible ».

Faut-t’il que j’ajoute ces Headers moi-même dans mes « virtual-host » du Proxy Load-Balancer avec des la « Directive Headers ».

Cette directive permet de remplacer, fusionner, ou supprimer des en-têtes de réponse HTTP. L’en-tête est modifié juste après que le gestionnaire de contenu et les filtres en sortie ne s’exécutent, ce qui permet la modification des en-têtes sortants.

Et, ou faut-il que sur chacun de mes serveurs cible, j’ajoute des « Directive RequestHeader »

Cette directive permet de remplacer, fusionner, modifier ou supprimer des en-têtes de requête HTTP. L’en-tête est modifié juste avant que le gestionnaire de contenu ne s’exécute, ce qui permet la modification des en-têtes entrants.

Puis, si j’ai bien compris sur les « serveurs cible » il faut activer le module « remoteip » pour le « Traitement des adresses distantes »

Ce module permet de traiter le client qui a initié la requête en tant que client original du point de vue de httpd à des fins d’autorisation et de connexion, même si ce client se trouve derrière un répartiteur de charge, un serveur frontal, ou un serveur mandataire.

Le module remplace l’adresse IP du client pour la connexion par l’adresse IP indiquée dans l’en-tête de requête configuré via la directive RemoteIPHeader .

Par exemple, pour SQUID (serveur mandataire, proxy transparent) il faudrait configurer dans le fichier /etc/apache2/conf-enabled/remoteip.conf (sur un autre serveur « mandataire » (au cas où il y aurait une suite de serveur mandataire) :

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy proxy1 

Par contre pour un proxy Load balancer, ce serait plutôt configurer dans le fichier /etc/apache2/conf-enabled/remoteip.conf sur les « serveurs cible » :

RemoteIPHeader X-Client-IP
RemoteIPTrustedProxy proxy1  proxy2  

Soit j’ai rien compris, ce qui m’étonne.
Soit c’est bien comme çà qu’il faut configurer ces types de serveur proxy.

En tant que développeur je connais la directive PHP « X-Forwarded-For » pour récupérer l’adresse IP de l’internaute mais sinon, « X-Client-IP » je ne suis pas tombé souvent dessus (de mémoire). Mais peut-être que l’on doit faire comme cela :wink: si j’ai bien compris la documentation officielle d’Apache.


En sachant, qu’il faut ensuite créer plusieurs vhosts pour le même « site web » comme indiquer par la « Directive RemoteIPProxyProtocol » :

Cette directive permet d’activer ou de désactiver la prise en compte et la gestion de l’en-tête de connexion du protocole PROXY. Si elle est définie à On , la demande du client doit envoyer l’en-tête approprié pour chaque nouvelle connexion, sinon cette dernière sera fermée à moins qu’il ne fasse partie de la liste, définie via la directive…

Mais, je n’aurais toujours pas « ma » 3ème « façon » de me connecter à mon serveur de « backend ».

Par contre j’aurais plus de chance que le module « Authentification et autorisation » fonctionne. Là je suis d’accord, parce que pour l’instant ; c’est, ce que j’expliquais « en 2ème problème », sur les « backend » j’ai l’adresse des « proxy reverse » vu par le module d’accès « Require ip » et « Allow from ».

Çà m’a l’air compliqué tout çà :smiley: Ce n’est pas logique, je ne vais pas foutre l’adresse du « client » dans un « header ».

Note de Moi-même : Tous le monde fait comme çà et même dans Windows :wink: IIS / Apache : Ajouter l’en-tête X-Forwarded-For dans les logs

Et, bien, vous, vous êtes Apache c’est çà ? Je plaisante. Bonne journée. Bon courage.
Je cherche et réfléchis à mettre tout çà en place. Merci.

@+

J’ajoute quand même qu’en fait théoriquement, personne n’accède aux serveurs de « backend » sur leurs adresses « wwX » directement (puisqu’en plus dans les configurations des « backend » ou des .htaccess je/on rewrite l’URL vers le « www ») ; mais bon. Ne serais-ce que pour le module d’accès, çà me semble important de lancer ce sujet ; ou pire question « sécurité », je veut voir l’IP du « mec » qui serait arriver à attraper le serveur du « backend » directement !! ET comme je le dis mettre mes contrôles d’accès directement sur les serveurs de « backend ».

J’ajoute un commentaire séparé exprès :

$ curl -4 -I -L https://www.ipv10.net
HTTP/1.1 200 OK
Date: Thu, 24 Oct 2024 06:50:05 GMT
Server: Apache
Strict-Transport-Security: max-age=31536000; includeSubDomains;
Pragma: no-cache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
X-ZW-Head: IPv10 D=2338 t=1729752605788980
X-ZW-BackNode: lb1.ipv10.net
X-ZW-LB-IPv4: 158.69.126.137
X-ZW-LB-IPv6: 2607:5300:60:9389:15:1:a:10
X-ZW-LB-Name: lb1
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: deny
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=UTF-8
Set-Cookie: PHPSESSID=ti5foilfl8ugdss5vk8vup23mc; path=/
X-Forwarded-For: (null)
X-Forwarded-Server: wan.ipv10.net
Set-Cookie: ROUTEID=.lb1.ipv10.net; path=/

Ajout d’Header dans la configuration sur / d’un serveur de « backend » :

X-ZW-Head: IPv10 D=2338 t=1729752605788980
X-ZW-BackNode: lb1.ipv10.net
X-ZW-LB-IPv4: 158.69.126.137
X-ZW-LB-IPv6: 2607:5300:60:9389:15:1:a:10
X-ZW-LB-Name: lb1

J’essaie de créer les Headers à envoyer depuis le « Load Balancer » :

X-Forwarded-Server: (null)
X-Forwarded-For: (null)
X-Forwarded-Host: (null)
Header set "X-Forwarded-Server" "wan.ipv10.net"
Header set "X-Forwarded-For" %{REMOTE_ADDR}s
Header set "X-Forwarded-Host" %{HTTP_HOST}s

! Comment-faire pour récupérer le nom de la machine, le FQDN aussi tant qu’à faire, depuis Apache ou l’adresse IP de la machine ? Quelqu’un sait !?

Pour ce type de variable « perso » par exemple :

X-perso-BackNode: (null)
X-perso-LB-IPv4: (null)
X-perso-LB-IPv6: (null)
X-perso-LB-Name: (null)

J’arrive à envoyer certaines de ces variables… mais pas toutes.

#Header set "X-IP" %A
#J'aimerai bien celle-ci moi ;)
Header set "X-date" %t
Header set "X-time-req" %D

Pour vérifier votre configuration :

$ apachectl configtest

[…]

Bonjour,
Pourquoi ne pas utiliser HAProxy où tous ces aspects sont plus facilement couverts?

Bonjour, c’est parce que, je ne connais pas HA Proxy (j’ai trouvé que la gestion des certificats SSL était confuse (quand j’ai essayé) si tu avais plusieurs sites web).

Tu as la doc: https://docs.haproxy.org/
un tuto assez simple: https://www.it-connect.fr/mise-en-place-dun-serveur-haproxy/
Pour la partie concernant les x-forwarded-for etc… : Forwarding Client IP Addresses from HAProxy to Apache2 Web Server | Linuxbeast

Bonjour,

Sur une machine d’IP 192.168.1.158, j’ai mis en place un apache2 « frontend » en ajoutant deux lignes au fichier /etc/apache2/sites-enabled/000-default.conf :

<VirtualHost *:80>

        ProxyPass "/"  "http://192.168.1.2:2080/"
        ProxyPassReverse "/"  "http://192.168.1.2:2080/"

        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating

Ensuite, sur la machine d’adresse IP 192.168.1.2, j’ai lancé un micro serveur web et obtenu ce résultat :

$ { echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c </var/www/html/index.nginx-debian.html)\r\n\r\n"; cat /var/www/html/index.nginx-debian.html; } | nc -l 2080
GET / HTTP/1.1
Host: 192.168.1.2:2080
User-Agent: Mozilla/5.0 (...) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 192.168.1.32
X-Forwarded-Host: 192.168.1.158
X-Forwarded-Server: 127.0.1.1
Connection: Keep-Alive

L’entête X-Forwarded-For est donc bien présent, contenant l’IP de l’ordi client. Cela marche donc correctement.

Ceci dit, oui, utiliser haproxy comme reverse-proxy serait plus approprié. C’est ce pourquoi le logiciel a été conçu.

De même, il ne faut pas perdre de vue le protocole utilisé entre le serveur reverse proxy dit « frontend » et le serveur web final dit « backend ».
Apache en frontend utilise du HTTP mais on pourrait avoir un haproxy utilisant le Proxy Protocol .
Or, HTTP ou Proxy Protocol, ce sont deux choses différentes. Sans paramétrage spécifique, Apache ne cause pas le Proxy Protocol.


AnonymousCoward

2 J'aime

Ok super. merci @AnonymousCoward !

Chez moi je ne reçois pas d’headers sur les « backend » après avoir ajouter ce genre de configuration.

Merci d’avoir essayé et d’avoir confirmé la documentation d’apache.