SSH hacks – a little sanity for remote workers
smallstep.com
smallstep.com
Host x
Hostname full.host.name.com (or 1.2.3.4)
User <myuser>
IdentitiesOnly yes
IdentityFile ~/.ssh/id_x_ed25519
I give hosts short names so you can `ssh x`to do automatic login, I generate identities for some machines
ssh-keygen -t ed25519 -f ~/.ssh/id_x_ed25519
use ssh-copy-id to copy the identity to the target machine so it lets you in: ssh-copy-id -i ~/.ssh/id_x_ed25519.pub x
or if your machine doesn't have ssh-copy-id (older macs); cat ~/.ssh/id_x_ed25519.pub | ssh x "cat >> .ssh/authorized_keys"
IdentitiesOnly means it will only send that one identity for that one machine (otherwise it will try all of them, like a janitor trying to open a locker with a big keychain of identical keys)If you always want to use a password to log into a machine, but want to be able to log in in other windows to the same machine without a password:
Host x
...
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
this will multiplex all activity to that host through one tcp connectionyou can also use Host * at the beginning of your config to do this for all hosts
to tunnel vnc over ssh to a remote mac(I do this with mac)
Host foo
...
LocalFoward 5900 localhost:5900
ssh foo
then locally vnc to localhost:127.0.0.1edit: a typo
alias ssh-MasterConnection-check="ssh -O check " alias ssh-MasterConnection-exit="ssh -O exit "
+ then you use them as 'ssh-MasterConnection-check host' etc.
It seems to me like the session persistence tmux gives would be worthwhile if you have a lot of simultaneous sessions going.
scp remote:~/err[tab] .[enter]
Also, bastion connections get multiplexed as well so connecting to multiple different hosts behind the bastion goes faster.
ssh x
then in other windows, I do things like this: scp file x:
ssh x command
rsync from/ x:to/
emacs /ssh:x:filename (this is tramp mode)
edit: one more thing ssh x -o BatchMode=yes command
if you have an automatic script to run on a remote machine, adding BatchMode=yes will make it error out instead of stopping and asking for a passwordHaving multiple windows vs tabs on my desktop seems so much easier.
From what I gather, tmux is useful if you are basically running a persistent remote workspace via terminal on a server and treat your desktop like a thin-client, is that correct?
If the bad guys get a copy of my public key off one remote server, they can't use it to access any other remote server. They would need the private key, which is on my laptop.
And if the bad guys get my laptop, then they get all my keys; having separate private keys for separate servers doesn't help if they're all sitting next to each other on one device.
I do set a password on my private key, though.
See also: https://github.com/FiloSottile/whoami.filippo.io
Using a private key per system or set of systems means that such an attacker would only gain access to what that key grants them access to.
My "github" key only grants access to my github repos, not to my bitbucket repos or to my DigitalOcean servers, or my Scaleway servers.
I have an SSH key for each "thing", and each key is kept in a different keyring via https://github.com/ccontavalli/ssh-ident, _precisely_ to avoid that problem.
As an example, an attacker gaining root on my Oracle Cloud free server will not be able to clone all my Github repos with it: I only use that key to connect to that server, and while I may have the github key unlocked at the same time - that's on a different keyring which the server has no visibility of.
I have, since 2010, practiced "jumps" only - that is, if I need to connect to a non-routeable host through a routeable one ("bastion host" or "jump host"), then the intermediate host is only used as a transport, by way of -L/-R forwarding of the final destination's ssh port, or by netcat, or (since a couple of years ago) SSH's internal ProxyJump or ProxyCommand; compared to agent forwarding, this is less efficient CPU-wise and traffic-wise, but not by much; and it is as safe as connecting to the final destination directly, unlike agent forwarding.
Never seen this use case or anything similar myself. Do you have other examples? I want to broaden my horizons
It's when you want to use some other tool that tunnels over SSH -- scp, git, sftp, rsync, etc. -- that you run into trouble.
Consider a remote development instance. So I'm an engineer, and instead of developing on my local I do development on an EC2 instance in AWS (there are a variety of reasons this may be preferential or even required). If I'm pushing & pulling code from GitHub to/from this development instance I'm gonna need to either have a private key on that development instance or have agent forwarding back to my local.
Now suppose I want to copy a large database snapshot between two instances on EC2. There are obvious benefits to being able to transfer directly between these two instances, on the same private network, versus bringing the data to your local (where you might not even have sufficient disk space) and pushing it back up.
Not sure what other use cases exist, but these two alone I think justify the existence of agent forwarding.
SSH agent forwarding does have subtle security issues. But so does putting a private key on a remote server. If you're the only one who has access to the remote server, neither option is problematic. If someone else has root, and you don't trust that person, then both are problematic (and which is worse is debatable).
That said, I don't have to do that often; If I did, I'd probably look for a simpler way (or ignore my paranoia and use ssh agent forwarding...)
1. I still have a need to "for s in $list_of_servers; ssh -A $s '..'; done"
How many times do I have to push the button? Is there a setting that allows that "push to allow" for a short while? Great, if so:
2) when I ssh into a system and touch the button to allow it, and the push allowed the use of they key for a short while, am I not in the same problem as before - as the system may be compromised and may be performing other operations I'm unawares of?
A solution for this would be to have multiple hardware keys for things I manage: one for $work, one for $personal, another for $github, etc. etc. but then managing them and - especially!! - their SSH agent which may be in memory but relies on the hardware being present, with all issues _that_ entails.... becomes a frigging mess.
So I'm torn... between the simplicity of a hardware key with push-to-allow... and actually being able to _use_ it _securely_.
Yes there is. In a newer firmware.
> 2) when I ssh into a system and touch the button to allow it, and the push allowed the use of they key for a short while, am I not in the same problem as before - as the system may be compromised and may be performing other operations I'm unawares of?
Yes but the window of opportunity for the attacker is smaller. Also: it's your setup that requires multiple key operations within short time interval, for some people touching every time is sufficient and most secure.
https://github.com/ccontavalli/ssh-ident is what I use to manage those agents - one agent per key.
> Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 2048 bits. Generally, 2048 bits is considered sufficient. DSA keys must be exactly 1024 bits as specified by FIPS 186-2. For ECDSA keys, the -b flag determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will fail. Ed25519 keys have a fixed length and the -b flag will be ignored.
ssh-copy-id -i ~/.ssh/id_x_ed25519.pub x
Thanks for mentioning this - I've been SSH'ing for a long time and never run across it. $ ssh -J user1@host1 user_final@host_final
or $ ssh -J user1@host1,user2@host2 user_final@host_final
Not many people know it, you don't need to launch a SSH within a SSH session - SSH has built-in support of using one SSH server as a proxy to another SSH server. Useful for <del>hacking servers</del> accessing servers behind a firewall, or using your own server as a proxy to bypass a bottleneck in the network.Just do: ssh -D9090 user@remote
Then, in Firefox, set it to use a SOCK5 proxy of localhost:9090 and "Proxy DNS when using SOCKS v5".
Now, when you use Firefox it is as if you are using Firefox on the machine you are SSH'd into(including DNS resolution!). This is really handy for things like accessing otherwise unreachable resources or other internal resources externally. I use it for accessing iDRAC/IPMI/ESXi (you can also tell Java to use the proxy so VMRC works as well). It is also handy to be able to put all your web traffic as originating from a remote VPS with no advanced setup required.
Don't forget to check the "Proxy DNS when using SOCKS v5" option in Firefox.
You habe to create a local "proxy.pac" file with the following contents:
function FindProxyForURL(URL,host) { host = host.toLowerCase(); if (shExpMatch(host,"*.my-company.com")) { return "SOCKS5 127.0.0.1:9090"; } return "DIRECT"; }
Then set "file:///path/to/proxy.pac" as auto-config URL in the Firefox-proxy-settings. Don't forget to enable DNS-Requests over SOCKS5.
For services, which you can't proxy with SOCKS5, you can use LocalForward in your ssh_config: Match host your-workstation !exec "nc -vz xmpp.my-company.com 5222 &>/dev/null || { echo 'xmpp.my-company.com not reachable, using LocalForward' 1>&2 && exit 1 ; }" LocalForward 127.0xcafe1:5222 xmpp.my-company.com:5222
Then add the following line to your /etc/hosts: 127.12.175.225 xmpp.my-company.com
My closest coffee shop would allow people to access Wi-Fi only if you gave them full access to your Facebook account. DNS was the only port open to the outside world.
What the???
Terms of service had wording that made mining all data in your Facebook account sound like the intent.
large responses == some DNSSEC, some IPv6
The office is also a large university. Therefore, I have access to many additional library and other subscription services.
It’s great as a lot of the office struggled to get a work setup in place. I’m happily the only one who didn’t need Gotomypc. It also helped me save time durning this transition by not having to answer my less technical coworkers questions about getting Gotomypc set up.
In my case, I usually do "ssh target -t tmux -2 att" to attach to my tmux session, then when I detach it will close the SSH connection (and all of my tunnels).
A lot of software uses ssh to do various things. You can pull a lot of neat tricks with SSH config coming in through a bastion on a non-standard port to a host machine into a shell executed in a docker container with the right .ssh/config, aliased to "machine", and the you can use anything that can run on SSH to "machine" with all that fancy configuration. Check your favorite editor; good odds it can edit files through that mess, or give you a remote directory explorer, or whatever.
(Yes you don't intend it at the start, but the realities of your later evaluations of where to invest effort security-wise will leave the internal network to rot since you won't think of the scenarios of how it would be compromised)
Host <host>
...
RequestTTY yes
RemoteCommand tty
The problem is that this will mess up your one-off command invocations of ssh, git ssh connections, etc: $ ssh <host> ls
Cannot execute command-line and remote command.
However, we can use `Match` blocks to get around that! There are a thousand ways to skin this cat, but one way is to use an environment variable, here `t` for "tmux". Put this at the end of your config: Match exec "test ${t:-0} = 1"
RequestTTY yes
RemoteCommand tmux has-session && tmux attach-session || tmux
and the following Just Work, reattaching tmux sessions as necessary: $ t=1 ssh <host>
$ ssh <host> ls Host *-via-dc1
ProxyCommand ssh you@jump-01.example.com nc $(echo %h | sed 's/-via-dc1$//') %p
I wrote about it ages ago here https://jloh.co/posts/dynamic-ssh-jump-hosts/I'd maybe even reverse it, having:
Host my-jump-host
Hostname my-jump-host.mydomain.example
User myuser
Host my-jump-host-*
User myuser
ProxyCommand ssh my-jump-host nc $(echo %h | sed 's/^my-jump-host-//') %p
This way, autocomplete in bash would work. Typing "ssh m<tab>", assuming m* doesn't match anything else, would suggest "ssh my-jump-host" (which I often ssh directly to anyway). Then just add "-myotherhost" so the whole sequence becomes "ssh m<tab><bs>-myotherhost". Not a huge saving but I'm lazy and like autocomplete in the shell.``` Host xyz HostName 1.2.3.4 ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600 ```
Then if you SSH to the same host multiple times it will re-use the connection and it persists for 10 minutes after you disconnect.
If you are using a ProxyJump like the above post this can speed up the initial ProxyJump connection.. or you can just use it with normal SSH (which is what I do) and when i want to open multiple tabs to the same machine its significantly faster.
Why is it faster to establish the connection? Does it re-use the authentication from the existing ControlMaster too, so you skip the handshake? Seems like it could be dangerous if you're not careful. I guess that's why you can configure it to use `ssh-askpass` for conformation (which, btw, is missing on macOS these days).
The other neat-looking directive that I've never tried is `ProxyUseFdpass`, which tells OpenSSH to expect a file descriptor back from your `ProxyCommand` instead of using stdin/stdout. I'm not sure why it exists, but it feels like it could be a performance optimization. Particularly for `scp`. But I've never actually run into a performance problem using `ProxyCommand` so shrug?
e.g.
$ ping -c 2 foo
PING foo (a.b.c.d) 56(84) bytes of data.
64 bytes from foo (a.b.c.d): icmp_seq=1 ttl=55 time=3.56 ms
64 bytes from foo (a.b.c.d): icmp_seq=2 ttl=55 time=3.62 ms
--- foo ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 3.564/3.594/3.624/0.030 ms
$ time ssh root@foo "echo foo"
foo
real 0m0.650s
user 0m0.062s
sys 0m0.006s
Now if I add the following to .ssh/config: Host foo
controlmaster auto
controlpath ~/.ssh/ssh-%r@%h:%p
You can see how much faster it gets if I already have a connection to that server open: $ time ssh root@foo "echo foo"
foo
real 0m0.032s
user 0m0.003s
sys 0m0.004sI do this for my email, for example, where the actual programs for dealing with my email sits on a server, but on each host I have shell scripts with the same name as the original program, except all they do is SSH to the server and run the actual program there. When navigating a GUI that runs these shell wrappers, you get a lot of opening and closing of SSH sessions very quickly.
It's not just for performance - it "reuses authentication" by not needing it. The authentication is an encapsulation, within which multiple channels get used. Usually, it's just the main "shell" channel; but occasionally it's also forwarding (-L / -R / -D), sftp; what ControlMaster does is let you open more "shell" channels when you run the "ssh" command again, instead of establishing a whole new connection.
> The other neat-looking directive that I've never tried is `ProxyUseFdpass`,
It's so you can use whatever weird communication hardware/protocol you like (serial? non-tcp satellite modem?), and all you have to do to get all of ssh's wonderful features over it, is make provide a file descriptor that works well enough (serial port; pipe you create; etc.)
Host host_final
ProxyJump user1@host1
will do the same thing as `-J user1@host`, but will allow you to just type: ssh user_final@host_final
If you're using an older SSH you can do this with a `ProxyCommand` (requires netcat on the jump box, but that's pretty standard): Host host_final
ProxyCommand ssh user1@host1 nc %h %p
There are a bunch of variations on this technique, but these are the most common configs. Super easy transparent bastioning.You can get really fancy with this stuff, particularly with `ProxyCommand`. We use it to trigger auto-login for our "Single sign-on for SSH" product at smallstep. When you have a `ProxyCommand` configured, instead of opening its own socket, OpenSSH just execs your proxy command and expects stdin & stdout to end up connected to a socket to the remote server. It doesn't care how that happens or what else happens before you get there. So we (ab)use this as a hook to check if you have a valid SSH certificate in your `ssh-agent` and, if you don't, trigger a single sign-on flow. It's nifty.
If you've never read the man pages for `ssh_config` and `sshd_config`, I highly recommend it. It's not that long and there's a lot of good stuff in there.
Even without ProxyJump, you can do something similar with ProxyCommand without netcat:
Host final
HostName host.example.com
ProxyCommand ssh -W %h:%p user@jumpbox.example.com
(Granted, this is still more recent, but I think ProxyJump was introduced later than this.)apt install miredo (on most debian based systems)
Yeah, it's hopeless, and it goes as if [0] they explicitly decided not to support it, incredibly frustrating!
> The faster people move to gitlab the better.
A lot projects will always host their master repository on GitHub for better or worse...
[0] Not meant to be an accusation, I don't have any evidence.
So yea, GitHub definitely knows about AAAA records and has intentionally decided not to have one. The question is: why? They must have a reason. Maybe even a good one. I'm curious.
Sounds like most of the internet would be inaccessible to them as well?
[0] https://old.reddit.com/r/ipv6/comments/ec8i7y/github_still_d...
$ ssh -T user@host <command>
Even if you're plumb out of file descriptors for example, you can run... $ ssh -T user@host lsof
...or whatever, and get your command output dumped to the screen, even if you don't get the niceties of a terminal. CanonicalizeHostname yes
CanonicalDomains example.org
That ensures that you never have the same host listed twice under the bare hostname and the fully-qualified version, avoiding the need to change keys twice when you rotate them.This setting allows you to automatically accept keys for new hosts but still report conflicts for existing hosts:
StrictHostKeyChecking accept-new
I highly recommend using the control-master feature to keep a persistent connection open to servers you access a lot. This makes new connections and tools like Git, scp, sftp, rsync, etc. much faster: Host *.amazonaws.com github.com *.github.com gitlab.com *.gitlab.com *.googleusercontent.com
ControlMaster auto
ControlPath ~/.ssh/control/%C.socket
ControlPersist 600
On MacOS, you can use an x509 certificate on a device like a Yubikey as the SSH key so you can authenticate everywhere with the private key never leaving the token and, should you set it up that way, requiring a tap to use.This will enable the provider:
PKCS11Provider=/usr/lib/ssh-keychain.dylib
This will get the public key: ssh-keygen -D /usr/lib/ssh-keychain.dylib
(see https://piv.idmanagement.gov/engineering/ssh/ for other platforms)Here is an example of some of mine (double spaced to read clearly on HN):
Host *
Ciphers aes128-ctr
Compression yes
ServerAliveInterval 120
ForwardX11 yes
Host example HostName example.url.com
User my_name
ForwardX11Trusted yes
I keep global settings behind the glob, and more specific settings for all the hosts I use.No need to use aliases in your .bashrc or wherever. With this setup, typing 'ssh example' is equivalent to 'ssh -XCY -c aes128-ctr my_name@example.url.com' which definitely saves some keystrokes.
If you want, it is very easy to do view-only tmux sessions with no third-party tools required. That is, you start your tmux specifying a socket (tmux -S ...), and then have a dedicated ssh user which references it (tmux -S ... attach -r, where -r is for read-only) as sshd's ForceCommand (a 10-liner https://gist.github.com/madars/e6b957ea508be1dcd9044fd2c7096...)
Include config.d/*
Include hosts.d/*
config.d is basically one 'Host *' file, but hosts.d lets me keep the random host/device settings for work and personal use separated.- mirror: to attach to server in read-only mode.
- pair: attach to server in pair mode, allowing the client to control the terminal as well.
- rogue: attach to server in rogue mode, which allows both editing with the host and switching to windows independently from the host.
I personally use rogue to share tmux sessions between my own devices without affecting whatever I'm doing on the other devices.
Wee, no VPN to deal with. No lack of a VPN for remote access to deal with.
If you have to spend time wrestling the VPN while you're on the clock, that's their own time being wasted.
Using this to circumvent policy is exactly the kind of move which would lead to those other uses being banned and making life worse for all of your coworkers.
That's right, and that's how it is with my current employer.
If you need outbound SSH to work with Git, that probaly means you're working on a side project, not work. Fetching public code needed for work from a hosting site can be done over https.
Managing servers in the cloud, ditto. If managing servers in the cloud isn't part of your job description, why would your workplace enable that?
But I agree that it's not a good idea to poke holes in your corporate firewall (which is really what this is doing).
Hacking your home domain would give someone a powerful jumping off point for hacking other things on your corporate network.
Only challenge is that getting corkscrew compiled on Windows is a massive pain.
No one seems to have packaged up binaries for it either.
Is that good enough support?
We tried.
MinGW refers to headers from BSD sockets, which doesn't exist on windows.
He still works there in a Government Agency riddled with staff who are perfectly adapt at doing enough to stay hired and doing little enough to describe their job as a paid hobby.
This was long enough ago that I didn't know quite how to proceed (time before rsync, scp...? Nah...) so he asked if he could do it and I let him have the keyboard.
He tar'd (with z) the dir, piped the output of tar to ssh, with a remote command to cat it out there through tar again, all in one CLI line. Blew my mind at the time. UNIX philo FTW.
tar cf - /mnt/data2 | ssh user@10.0.0.10 "cat > /mnt/data1/file1/file_data2.tar"
... and if the directory is large, you can 'split' it into multiple files: tar cfp - /mnt/data1 | ssh user@10.0.0.10 "split - -b 1024m /mnt/data1/file1/file_data2.tar"
This is really no longer relevant because, of course, we all just use rsync ... but in the modern world, my favorite example of the unix philosophy is: mysqldump -u mysql db | ssh user@rsync.net "dd of=db_dump"tar -czvf - <sourcedir> | ssh <user>@<remotehost> tar -xzf - -C <remotedir>
This is _much_ faster if you're sending over a directory with a lot of small files, especially if the link has even a modest amount of latency. The 'z' parameter can be omitted if the source files are not compressible (media files or already compressed).
If the files are highly compressible but very large you might consider this instead:
tar -cvf - <sourcedir> | pbzip2 -c | ssh <user>@<remotehost> tar -xf - -C <remotedir>
rsync -av --progress indir/ x:outdir/* "-D" for ssh tunneling.
* "-L" for forwarding all traffic on a specific port.
* sshfs - mount small directories over ssh on your local machine (works with big ones but way too slow, for big ones I go rsync).
* "-R" for reverse forwarding on a specific address.
That is, you can connect from the remote host to your local network. I used to do this to make my system at home accessible on my workstation in the office :) if you don't specify the address to forward to you will get a SOCKS proxy on the port specified that tunnels connections to your local network.
It is also possible to forward non local ports but ports on machines accessible to the side that is forwarding too.
It's a poor man's one way VPN: It inherits encryption/integrity/authentication (and some authorization) from ssh; It works incredibly well; For most practical network purposes it puts you on the computer you are sshuttlling to; And all it needs on that computer is the ability to ssh into it and some version of python - no special privileges or prior installations.
The bad: It only does TCP (and does some UDP magic to make DNS work, but not UDP in general). It's only one way (no one on the destination network can "call you back", as you don't have an IP on that network). The only config is which network addresses get routed across the sshuttle (no policy / rules / firewall / anything else). You appear to come from the computer you shuttled to (so, unlike a real VPN, for better or worse - no policy along the way can tell you are coming from outside)
Still looking for a way to make sftp/scp work fast.
Making it fast while still using it, not sure. But I can share an alternative, since a friend had the same issue and this was a literally ten times faster for a lot of small files (in the order of 30 minutes instead of 5 hours):
cd path/to/target/location
ssh user@target 'tar c /tmp/example' | tar x
Quick guide to tar, since it's super simple: c for compress
x for extract
f for file (since we send it to stdout / read from stdin, I don't use the f option)
v for verbosity (not sure if that works on the remote side)
z for zlib compression (ssh can do compression already, so also unused here)
t for testing (reading) an archive without extracting it ("tar tv <your.tar" will show you the contents, it's almost like real TV!)
That's all I've ever needed.So what this will do is run "tar create <directory>" on the remote system and, tar being a classic tool, it'll just output that binary archive data to stdout since you didn't specify a file ("tar cf your.tar <directory>"). On the receiving side, you pipe it to another tar command that reads from stdin (since, again, no file was specified) and extracts the files from the incoming data stream.
At the moment I use intellij which has a "sync with remote" function; I can run the things local and push them to the remote testing environment whenever I feel like it.
(my predecessor would use git a lot, ugh)
rsync -av lcldir/ x:remotedir/
rsync -av x:remotedir/ lcldir/
I've gotten pretty strict about trailing slashes otherwise I end up creating directories within directories depending on whether things exist or not[1] https://smallstep.com/blog/use-ssh-certificates/
Perhaps better is to set a different escape char for layers you care about.
ssh> ?
Commands:
-L[bind_address:]port:host:hostport Request local forward
-R[bind_address:]port:host:hostport Request remote forward
-D[bind_address:]port Request dynamic forward
-KL[bind_address:]port Cancel local forward
-KR[bind_address:]port Cancel remote forward
-KD[bind_address:]port Cancel dynamic forward
Time to read some source, I suppose.ssh-copy-id to never enter passwords again
~/.ssh/config add servers to never write hostnames etc again
and repo on gitlab with bash script that installs all of this and sets up own config of zsh and tmux for me on any new ubuntu server machine.
what else to dream about? curious
With the script named "go", Here's what that allows in practice:
go foo.bar - Connects to host foo.bar
go foo.bar - Second connection to host foo.bar that uses same session, so keystrokes show in both, even if they originate from separate locations, like home and work.
go foo.bar 2 - Additional param is added to session name, so you get a new connection to foo.bar.
go -list - Lists all connection sessions, and only connection sessions, because there's a special prefix to distinguish them from normal tmux sessions that might exist on the VM.
go -restore - Spawn a new terminal for all open connections. Useful for getting all terminals back after the network drops, or you reboot, or you're on your home computer instead of work, etc.
Currently this is implemented in a batch script on windows with some ugly hacks to make it work well with what PuTTY's command line options support (commands for the remote host need to be in a file you specify...), and it's pretty ugly, but I'll share if if anyone is interested. It would be much easier in bash with openssh (it's even possible OpenSSH supports enough features to do this in the ssh config).
ET looks great for a lot of things, but not necessarily this environment, which is a few hundred systems administered by multiple people, with extremely high stability and security requirements. Honestly, all the extra stuff ET and MOSH does is to give you that extra 1-2% of features to make it seamless, but at the expense of separate protocols and new software, so you don't have to expend new hardware (or in this case, virtualized hardware.
Connectivity problems almost always come from the last mile, whether that's you moving to make the last mile somewhere else or your wifi or home connection having a problem. A VM at Digital Ocean, or in my case the highly redundant and available VMware cluster at work, is much less likely to have any sort of problems, as are the servers that are generally being connected to (and it those ARE having problems, you can't rely on sessions to them being kept anyway).
For 99% of the cases, you can get by easily by just SSHing to a highly available VM, starting a tmux session for the desired connection, and within that session SSHing to the desired system. Jumping through other systems with SSH is so common that OpenSSH has features built in to support it, even transparently (where your config can just make it automatic for a class of systems). In fact, I bet there's a way to get the OpenSSH Proxying SSH server to keep the session open to reconnect to from the client if it's only the client side that had a problem, so it doesn't even require the little script I have. It's actually on my todo list to figure out the windows included OpenSSH agent stuff and see how well the new Windows Terminal works as an SSH terminal, but I haven't gotten around to it (or just use the WSL stuff, but I haven't seen much need for it yet, I'm happy to do most my dev work in vim on a dev server).
while true ; do
# TODO: make this do desktop notifications instead of osd_cat
echo "TUNNEL CONNECTING" | osd_cat --pos=middle --align=center --lines=1 \
--font="-unregistered-latin modern sans-bold-r-*-*-140-*-*-*-*-*-*-*" \
--color=green1 --outline=2 --outlinecolour=white --delay=1
ssh -2 -4 -a -k -n -x -y -N -T -D 127.0.0.1:1234 user@example.com
sleep 3
done
Separate from these little personal tunnels, there's some additional SSH timeout options (sorry I don't have handy at the moment) that I've found frequently helpful in my uses of SSH at work, plus an external timeout wrapper that can kill the ssh process, for long-running scripts dealing with a non-OpenSSH server, but they've almost never been necessary in practice for these personal tunnels.[1] The ssh package for vscode is great
https://code.visualstudio.com/docs/remote/ssh
[2] Also check out rsub which allows you to open a file in your terminal locally
IIRC it's written in Python, so it runs in most places: https://xpra.org/
It's not something I know a lot about. Is this where VNC steps in?
Really? Probably half of all web servers on the Internet (using HTTP/1.1) use it.
> The proper solution is surely to use a modern lossy video-compression algorithm.
The X11 protocol doesn't send bitmaps so I'm not certain that a "lossy video-compression algorithm" is gonna have the effect you think it will.
For context: passwords rotate every 90 days, there are different passwords for client facing and "internal" servers, (and different passwords for linux machines vs Windows machines).
All connections to client facing servers (which is my job) must go via:
1) a VPN
2) a "local" jumphost (both ssh/rdp), only accessible via VPN
3) a "remote" jumphost (also, both ssh/rdp), only accessible via the "local" jumphost".
Additionally; The majority of my servers are Windows based.
So, what do you do when everything goes wrong? well, you VPN with your "normal" password, and your 2FA RSA token. Then you rdp (or SSH) to the local jumphost with the same password as the vpn, then you rdp (or, ssh) to the remote jumphost with a different password, then you finally RDP into the machine that is interesting.
So, being the lazy git that I am, I wrote a program that scrapes my passwords from 1password, and ssh's into those jumphosts creating a tunnel all the way through. Then I call freerdp on localhost.
For this to work I had to do a bunch of ugly things like:
1) figure out the dimensions of my display and scale everything, because freerdp doesn't do this automatically.
2) call python from bash because getting a unique random socket requires binding to "port 0" which is not something I think is possible inside of bash.
3) do the same on each hop.
4) determine which password is needed based on the "domain" of the machine
5) detect if the machine is actually accessible or not (IE; are you on the VPN? is the machine actually "local"?)
Anyway, I should share the code, we can all revel in its ugliness.
Then to extend this a notch or two install Zerotier on all your hosts. Now you have virtual LAN between all your machines even outside of your home. It is P2P and does hole punching and whatever you need to work. You can connect to your computer via tethering from a puny little laptop while sitting on a bench outside your house. If you are a home admin for your family you can add those computers to your virtual LAN. Or your friends can also join. Then you can easily share photos or whatever straight with Samba or even an intranet of sorts.
And: I don't know if it's the placebo effect, but it seems to me that connections over ZeroTier are noticeably more responsive. Like slightly but noticeably.
I did not hear about Live Share, but was planning on using Visual Studio Code Remote Development. For my current work ssh -CX is often enough for me. I also intend to use Xpra, as I found X2Go a bit more rough around the edges.
It could be interesting to measure the effect. Probably they did some testing already, but probably as you said - placebo ;)
I commonly do ssh remote ‘(cd foo; git pull; make && run)’
Of course with tramp I don’t have to do this as much as I used to.
Is another great tool for getting off SSH.
Similarly if you're in AWS and not using Session Manager, you're missing out on a huge value add: https://docs.aws.amazon.com/systems-manager/latest/userguide...
Smallstep has a product[1] that's a lot like gravitational teleport. That's how we got deep enough into SSH to write this post. Teleport isn't bad. The two biggest differentiators are probably:
- Smallstep SSH is hosted (with HSM-backed private keys)
- Smallstep SSH does user & group syncing from your identity provider (i.e., you don't need to adduser / deluser folks anymore) so you don't need to do any user or key management on servers at all
We're also doing everything using standard OpenSSH, whereas teleport replaces your SSH client & server (or at least it used to, skimming their docs it looks like that might be changing). Authentication is via OAuth OIDC (single sign-on), user & group sync is via SCIM, plus PAM & NSS on the host side. So it's all pretty standard stuff.
Finally, Smallstep SSH is built on our open source toolchain, step[2] and step-ca[3]. Actually, if you want something completely free that does all of this you can just use those tools and do something like gravitational yourself. We have a blog post[4] explaining how.
This product is only a couple weeks old, so feedback is very welcome!
[1] https://smallstep.com/sso-ssh/
[2] https://github.com/smallstep/cli
It's sort of like a browser session where you "login" and then you can browse until your cookie expires. Here you "login" and you can SSH until your certificate expires. So you have strong authentication, but you're only asked to do it periodically.
It's packaged for most Linux distributions and offers a seam-less "share your terminal" experience over the web. Has an optional read-only mode. Users can access the terminal via https and ssh. Great for low-bandwidth videoconferencing.
If you are out there and you DO NOT want to lose your session due to a network error screen is for you! Even better, you can have your coworkers join your screen or reattach to it and watch you use ssh.
sshuttle:
> Transparent proxy server that works as a poor man's VPN. Forwards over ssh. Doesn't require admin. Works with Linux and MacOS. Supports DNS tunneling.
> Forward all traffic:
> sshuttle -r username@sshserver 0.0.0.0/0
byobu:
> Byobu is an enhancement for the GNU Screen terminal multiplexer or tmux [...] that can be used to provide on-screen notification or status, and tabbed multi-window management. It is intended to improve terminal sessions when users connect to remote servers.
https://stallman.org/articles/on-hacking.html
However if someone said "hacking ssh" without the context of hacker news, I can see why the general computer person would probably think of the newer definition, which implies cracking or seeking security vulnerabilities.
Depending on use case, though, this can be a bit sketch. At smallstep we like SSH certificates, which make life similarly easy on everyone with a bunch of other benefits. You can find a couple relevant posts on our blog if you’re interested.
Incidentally, GitHub now supports SSH certificates (for enterprise edition, at least).
Sure you could have a secure system that only you use, but the people behind ssh cannot make that assumption. Removing the risk entirely is better than trusting the users.
I'm sure there's a shell trick you could use to pass a password on the prompt anyway. For all other use cases, copy SSH keys securely.
I'm fine typing (or pasting) my password in an interactive prompt when I'm interactively using it; that's not the problem. What I would like a --password option for is when I'm not interactively using it, like from a script. It'll still show up in the process list (ssh could overwrite it but there are some µs where it's there) but my laptop is single-user so that's no big deal.
> I'm sure there's a shell trick you could use to pass a password on the prompt anyway.
There is software that does it, but it's a real pain to find a short command that does it. Simply echo password | ssh user@host does not work, the openssh authors disabled that on purpose.
Ssh keys are, of course, the solution whenever possible, but that's not always possible. I'll be the first to admit that the legitimate uses for --password are rare, but they're definitely there and having to install extra software to make that crap work is just a real pain. I'd rather be able to shoot myself in the foot with unix tools.
https://binblog.info/2008/10/20/openssh-going-flexible-with-...
Forced commands are implemented on both sides of the session, as the previously linked reference ... doesn't entirely make clear. Locally you need to create, and generally configure, a specific key with the remote user@host Remotely, you associate that key with a specific command, in an authorized_keys file.
I think sshpass might be a workaround, but sometimes you can just dig a little deeper into your situation and find if you can add authorized keys somehow.
I recall using a router with ssh access, but it didn't run true ssh with a .ssh/authorized_keys, but there turned out to be a way to add keys to the config for automated access.
----------------------
ssh_config_best_practices.md
CanonicalizeHostname yes
##############
### GitHub ###
##############
Host github.com
User jdoe
IdentityFile ~/.ssh/id_rsa_github
##################
### My Company ###
##################
Host myproject-dev-*
ProxyJump bastion-dev
Host myproject-prod-*
ProxyJump bastion-prod
Host bastion-dev
HostName bastion.myproject-dev.mycompany.com
ProxyJump bounce.myproject-dev.mycompany.com
Host bastion-prod
HostName bastion.myproject-prod.mycompany.com
ProxyJump bounce.myproject-prod.mycompany.com
Host *.mycompany.com myproject-dev-* myproject-prod-*
User john_doe
IdentityFile ~/.ssh/id_rsa_mycompany
##############
### Common ###
##############
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h
ControlPersist 2h
# On OS X, UseKeyChain specifies that we should store passphrases in the Keychain.
IgnoreUnknown UseKeychain
UseKeychain yes
AddKeysToAgent yes
- "CanonicalizeHostname" ensures the config is re-parsed after hostname canonicalization. This means that when you SSH into "bastion-dev", SSH re-parses the config using the full hostname "bastion.myproject-dev.mycompany.com", which then correctly matches the entry "Host * .mycompany.com".- "ProxyJump" was added in OpenSSH 7.2 (2016) and is simpler and more powerful than "ProxyCommand".
- "bastion-xxx" hosts are the only ones whose hostname can be resolved from the bounce gateways. To connect to other hosts, the trick we use in this config is to do two ProxyJumps: your machine --> bounce --> bastion --> target host.
- "ControlMaster" lets you do SSH multiplexing, which in our case is particularly useful when channeling multiple connections through a bastion host. It also persists SSH connections for a while after we disconnect, which speeds up future connections, and avoids typing the password all the time.
- When you ssh into a host, you must enter your LDAP password twice: first for the bastion, then for the target host. If you then ssh into a second host, you must enter your LDAP password only once, since ControlMaster reuses the SSH connection previously established to the bastion. Also, if you close those SSH shells, the connections will persist for two hours (see ControlPersist), so you won't need to type your password for those two hosts if you try to SSH into them again in the next two hours.
- Using this ssh_config, there is no need to add an Host entry for each host. It is not even needed to specify the IP addresses, since they will be resolved using the DNS on the bastion host.
- With this configuration, you can easily copy a file using scp between your local machine and the target host, without needing to first copy it to the bastion, then ssh to the bastion, then copy it to the target host, then remove it from the bastion...
PS: an ssh_config is parsed from top to bottom, so specific comes first, generic comes last. That's why "Host *" must be at the bottom.
- Customise ~/.ssh/config to suite your needs (be careful with storm - manage ssh like a boss, it helps when scripting or searching hosts but has a outstanding bug converting keywords to lowercase [1])
- Use ed25519 key over RSA
- OpenSSH 8.1 added support for FIDO/U2F (use your YubiKey or equivalent)
- Put `IPQoS lowdelay throughput` in your ~/.ssh/config if you run a rolling release (e.g. Arch, Gentoo) or your openssh rolls via homebrew on macOS. latest openssh client with older version of sshd may produce weird disconnection issues (server reset connection, client side is able to connect but terminal hangs in 5~10s). Spend quite some time digging only to find that it was caused by default change for IPQoS (to IPQoS af21 cs1) introduced in OpenSSH 7.8p1 [3]
- leverage ssh-copy-id
- ssh -vvv | ssh -G (troubleshooting from client side)
- /usr/sbin/sshd -p 2222 -f /path/to/sshd_config -D -ddd (troubleshooting sshd server side)
- Be careful with `UsePAM no`, make sur
- use AllowUsers / DenyUsers vs DenyGroups vs AllowGroups , mind the order
- know how to use ssh-add / ssh-keygen / ssh-agent / ssh-keyscan
- audit SSH config (ssh-audit / lynis), version control ssh_config / sshd_config properly if possible
- openssh + tmux ;-)
Personal favourite tips/tricks:
- ssh -D (used to use this dynamic port forwarding, open a local Socks5 proxy to punch hole in firewall, encrypt traffic, it worked for a while against the infamous GFW, only a little while though)
- ssh -L | -R TCP forwarding
- ssh -X | -Y X11 forwarding (run X11 apps remotely and display it on X Server locally)
- More personal SSH tricks put together over the years, surprise to find that my person OpenSSH notes are 150+ pages in Google Docs, sorry can't put all in a comment... [2]
- RTFM works, OpenSSH is worth the time ;-)
[1]: https://github.com/emre/storm/issues/157
[2]: https://sites.google.com/site/imterry/computer/tools/ssh
[3]: ssh(1)/sshd(8): the default IPQoS used by ssh/sshd has changed. https://www.openssh.com/releasenotes.html
1. Install iTerm.
2. ssh -t remote.workstation 'tmux -CC new-session -A -D -s main'
It does:
vim scp://server//path
Run :h netrw
inside vim to learn all about editing remote files.It mounts sftp.