Restrinja un host de Subversion a los usuarios de VPN con Apache 2.4
ServerName elige un host virtual; no limita quién se conecta. Exija el rango de VPN y un usuario real del repositorio, y luego demuestre ambas denegaciones.
Apuntar un host virtual de Subversion a una dirección de VPN cambia qué sitio responde a una petición, no quién tiene permiso para enviarla. La comprobación de acceso ocurre después, según las reglas de la sección que coincidió con la URL, y el nombre del host nunca entra en esa decisión. Si ServerName fue su único cambio, el repositorio es exactamente igual de accesible que ayer. Hay que responder dos preguntas separadas en la configuración: qué socket aceptó la conexión y qué identidad llevaba la petición.
Qué decide realmente ServerName
El alojamiento virtual basado en nombre compara la cabecera Host con las entradas ServerName y ServerAlias, elige un host y deja que ese host atienda la petición. La conexión en sí ya había sido aceptada por un socket Listen que pertenece al servidor, no al host. Por eso un nombre que parece privado no ofrece ninguna protección: cualquier cliente que alcance el socket puede enviar esa cabecera Host. El nombre es una clave de enrutamiento, y las claves de enrutamiento las elige quien llama.
Puede ver el mapeo sin adivinar. apachectl -S imprime cada host, su puerto y sus nombres, y marca cuál es el predeterminado para la dirección.
RequireAll es el contenedor que hace obligatorias ambas comprobaciones
Apache 2.4 envuelve las directivas Require de una sola sección en un RequireAny implícito, así que dos directivas desnudas significan que cualquiera de las dos basta. Añada el contenedor y el significado se invierte:
<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 necesita ambas condiciones: una dirección de origen dentro del rango del túnel y un usuario que el repositorio acepte. Eso es lo que debería significar solo-VPN para una URL de Subversion. La referencia de mod_authz_core documenta las reglas del contenedor. Mantenga el bloque dentro del Location existente del repositorio y deje en su sitio las directivas DAV que ya funcionan, porque este fragmento no sustituye ni AuthType ni el archivo de contraseñas ni la autorización a nivel de ruta.
La prueba de origen viene de mod_authz_host, así que confirme que está cargado antes de depurar cualquier otra cosa: apachectl -M | grep authz_host.
La dirección que Apache evalúa es la dirección del socket
Require ip compara con la dirección que Apache registró para la conexión, que no siempre es la dirección que el cliente cree tener.
Cuando la VPN enruta sus direcciones sin traducción, Apache ve la dirección del túnel y 10.8.0.0/24 coincide. Cuando una puerta de enlace traduce, Apache ve la puerta de enlace y la regla no coincide silenciosamente con nada; lo mismo ocurre detrás de un balanceador que termina TLS delante del host. Para ese caso existe mod_remoteip. RemoteIPHeader X-Forwarded-For junto con RemoteIPTrustedProxy para el balanceador sustituye la dirección registrada, y solo entonces el rango tiene con qué comparar.
Confiar en una cabecera de reenvío arbitraria es peor que no tener ninguna regla. Cualquier cliente puede enviar X-Forwarded-For con 10.8.0.9 y satisfacer una comprobación de rango que nunca estuvo anclada a un salto de confianza.
Superponga el oyente y la política del repositorio
La vinculación es un control aparte y a menudo el más simple. Listen 10.8.0.1:443 decide qué sockets existen, y una petición no puede elegir un host en un socket que nunca se abrió. El coste es el orden de arranque: si la interfaz del túnel está caída cuando Apache arranca, la vinculación falla y el servicio no levanta. Emparéjela con el orden de unidades, o vincule a una dirección que exista con independencia del túnel.
Los permisos de ruta se quedan en AuthzSVNAccessFile. Una cuenta válida para el sitio no es la misma concesión que el acceso de escritura a una ruta de proyecto, y la regla de red no lo cambia.
Vigile la fusión de secciones cuando el bloque está en un archivo incluido. Apache fusiona contenedores de autorización entre secciones anidadas y la sección coincidente más específica puede sustituir el requisito en lugar de añadirse a él, así que una regla en /svn puede no llegar a /svn/repo/trunk en cuanto una sección más estrecha define la suya.
Demuestre ambas denegaciones antes de darlo por hecho
Pruebe cuatro peticiones, no una. Dentro de la VPN con una cuenta válida debería obtener el listado del repositorio. Dentro de la VPN con una contraseña incorrecta debería obtener 401 en lugar de un listado. Desde fuera de la VPN con credenciales válidas debería obtener 403, y la misma petición pública contra un nombre de host alternativo debe fallar igual.
Un comando por caso es suficiente: curl -sI -u user:pass https://svn.example.com/svn/repo/, y luego lea la línea de estado. Repita también el caso que funciona con el cliente real, porque svn info ejercita los métodos DAV que usarán los commits y las actualizaciones.
Si cualquiera de los cuatro resultados no concuerda con la política que pretendía, la configuración no está terminada, y cambiar el nombre del host no lo cambiará.