I wrote: [ ... ssh tunnels, port forwarding, vnc ... ] On Thu, Oct 07, 1999 at 07:19:36PM +1000, Darryl Harvey wrote: | And in English that means ??? | Any clearer explanation on how to achieve this ? Hmm, the penalties of trying to be succinct... Ok, here's the long description: I assume you know about VNC, but for the sake of clarity, here's how VNC works (since we need the networking details for the tunneling). Trust me - we _will_ get to the firewall and ssh. VNC consists of two programs - a server and a viewer. This separation lets you have a session of some kind running on the server, and to start up and shutdown the viewer whenever and wherever you like. So you can view at work, set up something long running and GUIfied, then go home and work from there too. VNC does this by having the server speak two protocols: the VNC protocol, which it speaks between the vncviewer and the vncserver (so that you can view any VNC server's session) and the native windowing protocol of whatever system the server's running the session on (for UNIX, this is X11). So, on UNIX the vncserver acts as a X server, just like XFree86 and suchlike, but it doesn't talk to a video card. So, you fire up vncserver like so: vncserver 5 # <== pick some number - 0 will be in use by # your "real" X display, so something else This results in the server (Xvnc) firing up and listening on two ports: 6005 (for normal X clients like xterm, using the DISPLAY name "host:5", where "host" is the machine your running on), and 5905 (for vncviewers to connect to to see what's going on). So, for the VNC session numbered "n" it lists on port 6000+n as the X server :n and on port 5900+n as the VNC server ":n". Digging through my old mail I find a diagram I drew for a friend, which I will adapt here. Here's a normal X session, such as you normally run: monitor | You <-> X server <---------X11 protocol--> client (eg xterm) | | desktop client machine machine (host B) (host A) Of course, hosts A and B needn't be separate machines. The client (xterm) is connected to port 6000 on host A, and speaks the X11 graphics protocol to draw text and whatnot. The X server speaks to the video card of host A. Here's a similar setup, using VNC as an intermediary: monitor | You <-> X server <---------X11 protocol--> vncviewer (a normal monitor X client from host C's | point of view) desktop | machine | (host C) | | +---------------VNC protocol----------+ | V X server <---------X11 protocol--> client (eg xterm) (Xvnc in this case) | | | desktop client machine machine (host B) (host A) Here we have you seated in front of host C, with the viewer open before you, showing the desktop on host A. Using the earlier example (VNC display #5) the vncviewer is: - connected to port 6000 on host C, to display the desktop on your local X display - connected to port 5905 (== 5900+5, because "n" is 5) on host A, to get the desktop contents from the vncserver The X clients on the desktop are: - connected to port 6005 (== 6000+5) on host A, to write to the X session called "hostA:5" The Xvnc on host A is not controlling a video card. Instead, it depicts the X session it's supporting to any vncviewer which connects. (There's a login challenge when you connect to a VNC viewer, so don't imagine this leaves you wide open to Joe Cracker). Your vncviewer transcribes that to the X server on host C, and _that_ X server scribbles on your monitor. So... The original problem was that host C and host A were on different sides of a firewall. To the outer world (yea, even to the inner world) a firewall looks much like an ordinary router - a transparent box for passing packets back and forth between two networks, save the the firewall only passes some packets, not all. And thus the crackers are kept out. The proposal was to open a hole in the firewall to pass VNC - in short, to instruct the firewall to pass packets to and from port 5905 (or whichever) on host A, and the outside world. While this would work, it's a bad idea for two reasons: - you want to minimise the holes in your firewall anyway, and opening a hole means that service is now available to the attack attempts of anyone in the outside world - most protocols carry their traffic in the clear (which is fine, since there are separate tools to tunnel cleartext through encrypted channels, like ssh); this means that if you _don't_ tunnel the traffic through ssh or suchlike then your session passes in the clear across the open net, available to anyone who wants to snoop. It is to be presumed that this is bad because your activity is confidential, otherwise you'd not want a firewall at all. So, rather than pass the VNC session in the clear, we will use ssh to get in through the firewall, and tunnel the VNC traffic (and everything else: email, news, telnet, whatever you like provided it's TCP/IP) across the ssh connection, safe from prying eyes. This has two main advantages: as stated, it conceals the traffic with strong encryption (ssh is a fine Finnish product, unencumbered by the reactionary oppression of the Wassenaur agreements as enforced by the "free" governments in the US and Oz and elsewhere). Secondly, the permission to make the ssh connection is governed by strong cryptographic authentication, so you have good confidence that the people you've let in aren't Joe Cracker but in fact particular individuals to whom you've granted this right, like yourself. (That confidence is, of course, subject to these people all practicing good security: good pass phrases, careful control of keys, etc). So, there are thus three tasks ahead: 1 set up ssh service on host A, and a client on host C with the right key 2 arrange the tunneling of the VNC traffic over ssh 3 permit ssh (port 22) traffic through your firewall, probably only aimed at select hosts like host A, which have ssh set up Part 1: Install ssh. ==================== Visit the ssh faq: http://www.uni-karlsruhe.de/~ig25/ssh-faq/ Well worth the read, and it also lists download sites. Fetch ssh (current up to 1.2.27 for ssh1) from ftp://ftp.cs.hut.fi/pub/ssh/ Build and install on host A and host C. You should lock down whatever machine will be reached from the outside with ssh (host A). I've appended an (edited) copy of the /etc/sshd_config for our ssh terminus (the box people can ssh to from outside) at the bottom of this message. Note in particular the following settings (described in the manual entry for sshd): AllowUsers cameron RSAAuthentication yes KerberosAuthentication no PasswordAuthentication no RhostsAuthentication no RhostsRSAAuthentication no TISAuthentication no PermitEmptyPasswords no KerberosOrLocalPasswd no KerberosTgtPassing no AllowTcpForwarding yes FascistLogging yes IgnoreRhosts yes IgnoreRootRhosts yes PermitRootLogin no In short: an explicit list of permitted users, RSA auth only, no root logins. Host A is exposed to the whole planet for the ssh service - make it well defended. Client setup: For the initial testing, we will use a host C which is _inside_ the firewall. Only after this is properly set up will we be opening holes in the firewall for this scheme. (If you've only got host A inside the firewall, pretend it's host C; nothing prevents you sshing to a host from itself). Ssh must be installed on host C. On host C, as yourself (not root!), run the command ssh-keygen This will generate a keypair and prompt you for a passphrase to protect the keys. Make you passphrase good - an entire sentence, at least somewhat obscure. The passphrase is the weakest point in the scheme in some ways, and deserves attention. Ssh-keygen will have made two files: ~/.ssh/identity ~/.ssh/identity.pub These are your private and public keys, respectively. The public key is the one you give to the people running the hosts you want to connect to; it is used by them to verify that you possess the private key, and thus that you are who you say you are. From that, you can deduce immediately that YOU MUST NEVER GIVE THE PRIVATE KEY TO ANYONE! Ok, you have the keys. The public key must be installed in your account on host A so that host A knows to let you log in. Copy the identity.pub file from host C to the file ~/.ssh/authorized_keys on host A. If there's already an authorized_keys file there (such as when you repeat this for a new remote host "D"), append the identity.pub file to the authorized_keys file. "authorized_keys" is simply a list of the public keys identifying the people whom we will permit to log in. Ok, on host C say: ssh -v hostA This should connect to the running sshd on host A, prompt you for your passphrase, then give you a login shell on host A. If your login on host A has a different name than on host C, you'll need to supply that: ssh -v -l hostAlogin hostA Things like the login name can later be automated in your .ssh/config file, and you can use the ssh-agent command to save typing your passphrase for every login. However, those are activities for later, and outside the scope of this message. Some RTFMing ahead! Once you can ssh from host C to host A, it's time to configure the port forwarding. Part 2: Tunneling VNC over the connection. ========================================== I'll presume you've got VNC running happily on host A already. For the sake of concrete examples I'll presume you're using display :5. One of ssh's facilities is port forwarding. This comes in two flavours: local and remote. A local forward causes your client ssh (on host C) to listen on a particular port; when something connects to that port, the server end (on host A) makes a corresponding connection to some specified host and port, and copies the traffic to and fro, via the ssh connection. A remote forward is just the reverse: the server on host A listens, and your client on host C makes connections. We will be using a local forward to do the VNC traffic, because we will be connecting the vncserver on host C to your client (on host C), and the sshd on host A will be connecting to the vncserver and copying the traffic. To do this, run this command on host C: ssh -v -L 5905:hostA:5905 hostA This says that the client on host C listens on port 5905 (the first one in the -L option) and that an connections it receives should be forward to "hostA:5905". With this ssh session active, host C now has a service listening on 5905, as though it were running a vncserver locally. Any connections to that are passed through to the real VNC server on host A, through the ssh session. So... With that up and running, you can run a vncviewer on host C, telling it to connect to "localhost:5". This will connect to the port serviced by your ssh command, and thus transparently through to the real service on host A. Obscure? Let me draw the new picture: monitor | You <-> X server <---------X11 protocol--> vncviewer (a normal monitor X client from host C's | point of view) desktop | machine ssh on host C <--VNC proto-+ (host C) | | ssh protocol | V +-VNC proto-- ssh on host A | | V X server <---------X11 protocol--> client (eg xterm) (Xvnc in this case) | | | desktop client machine machine (host B) (host A) The ssh-on-host-C is listening on port 5905. The ssh-on-host-A has made a connection to port 5905 on hostA in response to your vncviewer (on host C) connectioning to hostC:5905. Part 3: allow ssh through the firewall. ======================================= You can this arrange yourself, since you control your firewall. Once done, we will consider the firewall to be just another router, since it's no longer obstructing our ssh traffic. The upshort of this is that I don't need to draw it in the diagram! And you can then repeat your host C stuff on a machine outside the firewall and it should behave the same as it did inside the firewall. Is that any clearer? With schemes like this in place you can do all sorts of groovey variations, like also passing email and news and web traffic from host C to private services inside your firewall. We arrange this for our travelling staff. Sample /etc/sshd_config appended below. Read, understand (with the help of the FM), and adapt. Cheers, -- Cameron Simpson, DoD#743 cs@zip.com.au http://www.zip.com.au/~cs/ Careful and correct use of language is a powerful aid to straight thinking, for putting into words precisely what we mean necessitates getting our own minds quite clear on what we mean. - W.I.B. Beveridge # This is ssh server systemwide configuration file. # Access control # AllowGroups # AllowHosts # AllowSHosts # AllowUsers AllowUsers cameron # DenyGroups # DenyHosts # DenySHosts # DenyUsers # Authentication RSAAuthentication yes KerberosAuthentication no PasswordAuthentication no RhostsAuthentication no RhostsRSAAuthentication no TISAuthentication no # CAKeysSource /var/ssh/userkeys # GlobalKnownHostsFile /path/to/textfile # X11 X11DisplayOffset 10 X11Forwarding yes # Passwords PasswordExpireWarningDays 14 PermitEmptyPasswords no # Kerberos KerberosOrLocalPasswd no KerberosTgtPassing no # Misc non-defaults AccountExpireWarningDays 14 AllowTcpForwarding yes CheckMail no FascistLogging yes IdleTimeout 1d IgnoreRhosts yes IgnoreRootRhosts yes ListenAddress 0.0.0.0 PermitRootLogin no Port 22 PrintMotd no SilentDeny no Umask 0022 # Compiled-in defaults # ForcedEmptyPasswdChange # ForcedPasswdChange # HostKey # KeepAlive # KeyRegenerationInterval # LoginGraceTime # PidFile # QuietMode # RandomSeed # ServerKeyBits # StrictModes # SyslogFacility # XAuthLocation