Restreindre un hôte Subversion aux utilisateurs VPN avec Apache 2.4
ServerName choisit un hôte virtuel ; il ne limite pas qui se connecte. Exigez la plage VPN et un véritable utilisateur du dépôt, puis prouvez les deux refus.
Pointer un hôte virtuel Subversion vers une adresse VPN change quel site répond à une requête, pas qui est autorisé à en envoyer une. Le contrôle d’accès a lieu plus tard, selon les règles de la section qui correspondait à l’URL, et un nom d’hôte n’entre jamais dans cette décision. Si ServerName était votre seul changement, le dépôt est exactement aussi accessible qu’hier. Deux questions distinctes doivent trouver réponse dans la configuration : quel socket a accepté la connexion et quelle identité portait la requête.
Ce que ServerName décide réellement
L’hébergement virtuel basé sur le nom compare l’en-tête Host aux entrées ServerName et ServerAlias, choisit un hôte et le laisse traiter la requête. La connexion elle-même avait été acceptée plus tôt par un socket Listen qui appartient au serveur, pas à l’hôte. C’est pourquoi un nom d’apparence privée n’offre aucune protection : tout client qui atteint le socket peut envoyer cet en-tête Host. Le nom est une clé de routage, et les clés de routage sont choisies par l’appelant.
Vous pouvez voir le mappage sans deviner. apachectl -S affiche chaque hôte, son port et ses noms, et marque lequel est celui par défaut pour l’adresse.
RequireAll est le conteneur qui rend les deux contrôles obligatoires
Apache 2.4 enveloppe les directives Require d’une même section dans un RequireAny implicite, donc deux directives nues signifient que l’une ou l’autre suffit. Ajoutez le conteneur et le sens s’inverse :
<Location /svn/repo>
AuthType Basic
AuthName "Subversion"
AuthBasicProvider file
AuthUserFile /etc/apache2/svn.htpasswd
<RequireAll>
Require ip 10.8.0.0/24
Require valid-user
</RequireAll>
</Location>RequireAll exige les deux conditions : une adresse source dans la plage du tunnel et un utilisateur que le dépôt accepte. C’est ce que devrait signifier VPN uniquement pour une URL Subversion. La référence mod_authz_core documente les règles du conteneur. Gardez le bloc à l’intérieur du Location existant du dépôt et laissez en place les directives DAV qui fonctionnent déjà, car ce fragment ne remplace ni AuthType, ni le fichier de mots de passe, ni l’autorisation au niveau du chemin.
Le test de source vient de mod_authz_host, alors confirmez qu’il est chargé avant de déboguer quoi que ce soit d’autre : apachectl -M | grep authz_host.
L’adresse qu’Apache évalue est l’adresse du socket
Require ip compare à l’adresse qu’Apache a enregistrée pour la connexion, et ce n’est pas toujours celle que le client croit avoir.
Quand le VPN route ses adresses sans traduction, Apache voit l’adresse du tunnel et 10.8.0.0/24 correspond. Quand une passerelle traduit, Apache voit la passerelle et la règle ne correspond silencieusement à rien ; la même chose se produit derrière un répartiteur de charge qui termine TLS devant l’hôte. mod_remoteip existe pour ce cas. RemoteIPHeader X-Forwarded-For avec RemoteIPTrustedProxy pour le répartiteur remplace l’adresse enregistrée, et c’est seulement alors que la plage a quelque chose à comparer.
Faire confiance à un en-tête de transfert arbitraire est pire que de n’avoir aucune règle. Tout client peut envoyer X-Forwarded-For contenant 10.8.0.9 et satisfaire un contrôle de plage qui n’a jamais été ancré à un saut de confiance.
Superposez l’écouteur et la politique du dépôt
La liaison est un contrôle distinct et souvent le plus simple. Listen 10.8.0.1:443 décide quels sockets existent, et une requête ne peut pas choisir un hôte sur un socket qui n’a jamais été ouvert. Le prix est l’ordre de démarrage : si l’interface du tunnel est arrêtée au démarrage d’Apache, la liaison échoue et le service ne monte pas. Associez-la à l’ordre des unités, ou liez-vous à une adresse qui existe indépendamment du tunnel.
Les permissions de chemin restent dans AuthzSVNAccessFile. Un compte valide pour le site n’est pas la même autorisation que l’accès en écriture à un chemin de projet, et la règle réseau n’y change rien.
Surveillez la fusion des sections lorsque le bloc se trouve dans un fichier inclus. Apache fusionne les conteneurs d’autorisation à travers les sections imbriquées et la section correspondante la plus spécifique peut remplacer l’exigence au lieu de s’y ajouter, si bien qu’une règle sur /svn peut ne pas atteindre /svn/repo/trunk dès qu’une section plus étroite définit la sienne.
Prouvez les deux refus avant de déclarer terminé
Testez quatre requêtes, pas une. À l’intérieur du VPN avec un compte valide, vous devriez obtenir la liste du dépôt. À l’intérieur du VPN avec un mot de passe erroné, vous devriez obtenir 401 plutôt qu’une liste. Depuis l’extérieur du VPN avec des identifiants valides, vous devriez obtenir 403, et la même requête publique vers un autre nom d’hôte doit échouer de la même manière.
Une commande par cas suffit : curl -sI -u user:pass https://svn.example.com/svn/repo/, puis lisez la ligne de statut. Répétez aussi le cas fonctionnel avec le vrai client, car svn info exerce les méthodes DAV que les commits et les mises à jour utiliseront.
Si l’un des quatre résultats contredit la politique visée, la configuration n’est pas terminée, et renommer l’hôte n’y changera rien.