Apontar um host virtual Subversion para um endereço de VPN muda qual site responde a um pedido, não quem tem permissão para o enviar. A verificação de acesso ocorre mais tarde, segundo as regras da secção que correspondeu ao URL, e o nome do host nunca entra nessa decisão. Se ServerName foi a sua única alteração, o repositório está exatamente tão acessível como ontem. Duas questões separadas têm de ser respondidas na configuração: que socket aceitou a ligação e que identidade o pedido transportava.

O que ServerName decide realmente

O alojamento virtual baseado em nome compara o cabeçalho Host com as entradas ServerName e ServerAlias, escolhe um host e deixa-o tratar do pedido. A ligação em si foi aceite anteriormente por um socket Listen que pertence ao servidor, não ao host. Por isso um nome com aparência privada não oferece qualquer proteção: qualquer cliente que alcance o socket pode enviar esse cabeçalho Host. O nome é uma chave de encaminhamento, e as chaves de encaminhamento são escolhidas por quem chama.

Pode ver o mapeamento sem adivinhar. apachectl -S imprime cada host, a sua porta e os seus nomes, e assinala qual é o predefinido para o endereço.

RequireAll é o contentor que torna ambas as verificações obrigatórias

O Apache 2.4 envolve as diretivas Require de uma só secção num RequireAny implícito, pelo que duas diretivas nuas significam que qualquer uma basta. Acrescente o contentor e o significado inverte-se:

<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 ambas as condições: um endereço de origem dentro do intervalo do túnel e um utilizador que o repositório aceite. É isso que VPN-único deve significar para um URL Subversion. A referência do mod_authz_core documenta as regras do contentor. Mantenha o bloco dentro do Location existente do repositório e deixe no lugar as diretivas DAV que já funcionam, porque este fragmento não substitui nem o AuthType nem o ficheiro de palavras-passe nem a autorização ao nível do caminho.

O teste de origem vem do mod_authz_host, por isso confirme que está carregado antes de depurar qualquer outra coisa: apachectl -M | grep authz_host.

O endereço que o Apache avalia é o endereço do socket

Require ip compara com o endereço que o Apache registou para a ligação, e nem sempre é o endereço que o cliente pensa ter.

Quando a VPN encaminha os seus endereços sem tradução, o Apache vê o endereço do túnel e 10.8.0.0/24 corresponde. Quando uma porta de ligação traduz, o Apache vê a porta de ligação e a regra silenciosamente não corresponde a nada; o mesmo acontece atrás de um balanceador que termina TLS à frente do host. Para esse caso existe o mod_remoteip. RemoteIPHeader X-Forwarded-For em conjunto com RemoteIPTrustedProxy para o balanceador substitui o endereço registado, e só então o intervalo tem com que comparar.

Confiar num cabeçalho de reencaminhamento arbitrário é pior do que não ter regra nenhuma. Qualquer cliente pode enviar X-Forwarded-For contendo 10.8.0.9 e satisfazer uma verificação de intervalo que nunca foi ancorada a um salto de confiança.

Sobreponha o ouvinte e a política do repositório

A ligação a um endereço é um controlo separado e muitas vezes o mais simples. Listen 10.8.0.1:443 decide que sockets existem, e um pedido não pode escolher um host num socket que nunca foi aberto. O custo é a ordem de arranque: se a interface do túnel estiver em baixo quando o Apache arranca, a ligação falha e o serviço não sobe. Combine-a com a ordem das unidades, ou ligue a um endereço que exista independentemente do túnel.

As permissões de caminho ficam no AuthzSVNAccessFile. Uma conta válida para o site não é a mesma concessão que o acesso de escrita a um caminho de projeto, e a regra de rede não altera isso.

Atenção à fusão de secções quando o bloco está num ficheiro incluído. O Apache funde contentores de autorização através de secções aninhadas e a secção correspondente mais específica pode substituir o requisito em vez de o acrescentar, pelo que uma regra em /svn pode não chegar a /svn/repo/trunk assim que uma secção mais estreita defina a sua.

Comprove as duas recusas antes de o considerar terminado

Teste quatro pedidos, não um. Dentro da VPN com uma conta válida deve obter a listagem do repositório. Dentro da VPN com uma palavra-passe errada deve obter 401 em vez de uma listagem. De fora da VPN com credenciais válidas deve obter 403, e o mesmo pedido público a um nome de host alternativo tem de falhar da mesma forma.

Um comando por caso é suficiente: curl -sI -u user:pass https://svn.example.com/svn/repo/, e depois leia a linha de estado. Repita também o caso que funciona com o cliente real, porque svn info exercita os métodos DAV que os commits e as atualizações vão usar.

Se qualquer dos quatro resultados discordar da política pretendida, a configuração não está terminada, e mudar o nome do host não altera isso.

Artigos relacionados