ssh conditional configuration

Ho un server ssh in una rete privata.

Ho impostato il port forwarding sul router per accedere al server ssh da fuori.

Tutto funziona, ma devo usare una configurazione diversa per accedere al server ssh nel caso mi si stia connettendo dalla rete privata o dalla rete pubblica.

Non è un grosso problema per le connessioni ssh interattive, ma lo è per job rsync, configurazioni unison, script che usano ssh, git su ssh, ecc.

Fortunatamente, giocando con la configurazione ssh, sono riuscito ad ottenere un setup semplice per i miei programmi, spostando la complessità sul client ssh.

Tutto quello che serve sono 2 entry nel file .ssh/config e uno script bash che verifichi da dove mi sto collegando.

Una delle 2 entry nella configurazione ssh è usata quando mi collego dalla rete privata, l'altra quando mi collego dalla rete pubblica. Entrambe richiamano, attraverso Match exec, lo script bash con 3 parametri:

  • la zona dove la entry è valida (public per internet, private per la rete privata
  • l'hostname per il quale la configurazione è valida (<HOSTNAME> nella configurazione riportata sotto, da cambiare a seconda delle proprie esigenze)
  • l'hostname cui ci mi sto collegando, altrimenti la configurazione verrebbe usata anche quando mi collego ad altri host.

Le righe aggiunte a .ssh/config sono le seguenti:

    Match exec "~/callfrom public <HOSTNAME> %n"
        Hostname <YOUR PUBLIC IP/NAME>
        Port <THE PORT FORWARDED TO THE SSH SERVER>

    Match exec "~/callfrom private <HOSTANME> %n"
        Hostname <THE SSH SERVER PRIVATE IP/NAME>
        Port 22

Lo script bash per prima cosa controlla se sono sulla rete privata o su internet comparando l'indirizzo di broadcast in uso con quello della mia rete privata. Cambiarlo in base alle proprie confifurazioni.

Quindi verifica la zona da validare e l'hostname cui mi sto connettendo con quelli passati come 2° e 3° parametro, ritornando il valore corretto:

#!/bin/bash

from=$1
hostchecked=$2
rhost=$3

ip a s | grep "brd 10\.10\.10\.255\/8" # CHANGE WITH YOU PRIVATE NETOWRK BROADCAST ADDRESS
res=$?

case "$from" in
  private)
    if [ $res -eq 0 ] && [ "$rhost" == "$hostchecked" ] ; then
      exit 0
    else
      exit 1
    fi
    ;;
  public)
    if [ $res -ne 0 ] && [ "$rhost" == "$hostchecked" ] ; then
      exit 0
    else
      exit 1
    fi
    ;;
esac

Ora quando eseguo

ssh <HOSTNAME>

dalla mia rete privata, il 1° Match ritorna 1 (FALSE), mentre il 2° ritorna 0 (TRUE) (from=public, rhost=hostchecked, res!=0).

Per contro, quando mi collego da internet il 1° Match ritorna 0 (TRUE) mentre il 2° ritorna 1 (FALSE) (from=private,rhost=hostchecked, res==0).