If you're using keys for special-purpose accounts, be sure to limit what they can do. You can specify that only a certain command can be run, that port forwarding isn't permitted, etc.
Keys probably don't have to become unmanageable at scale - you can try use SSH certificate authentication.
Sign your keys with a CA, and encode the "principals" that the user has (so, be able to log into some machines as themself, some machines as some other user), and a validity period. Revocation wasn't there yet when last I looked at it (mid-last-year), but might be there now.
One benefit is that individual connections don't need to be brokered by an external authentication/authorisation service. However, it is a relatively new feature and there may be rough edges (such as making sure all your clients have a recent enough version of the tools to work with certificates - Lion was the first MacOS X version to have it, for example).
Another point to remember: If you use /bin/false and it's dynamically linked (which it probably is), then you MUST make sure that you have PermitUserEnvironment set to "no" -- otherwise people can LD_PRELOAD their way in.
JFTR PermitUserEnvironment is nowadays per default disabled. You should also make sure that AcceptEnv is sane (e.g. just accept LC_* and LANG)
But even if you use a static linked /bin/false you must make sure that you disable PermitUserEnvironment as sh(1) is executed if ~/.ssh/rc exists and sh is typically dynamically linked
It's disabled by default on most systems, but I wouldn't want to assume that Crazy Chimpanzee Linux doesn't do something stupid, or that no sysadmin flips that option on without understanding the consequences.
I ran into similar issues several years ago in setting up "sftp-only" ssh logins to a server. As I recall, the most robust solution involved disabling port forwarding and running the "sftp" ssh daemons in a nearly empty chroot environment.
At the time, I recall finding lots of misleading information on the Internet about restricting ssh, mostly task-oriented "howtos" that overlook the basic principles of operation in order to "get started quickly!"
In my experience, beyond "whitelisting" ssh access in the first place with AllowGroup and related, one should rely more on "deep" kernel-level restriction mechanisms (chroot, BSD jails, sandboxing, etc.) than "shallow" authorization controls ostensibly provided by ssh and/or the login subsystem.
I'm missing something. Why allow people to 'authenticate against [a machine] via ssh' at all if you don't want them to run any program there or use any ssh services on that machine?
(It seems one of the reasons you might want to allow someone an ssh account without a shell would be to give them a proxy with an internal IP address – a feature not a bug. Alternatively, it's possible every user casually ssh-enabled on these machines already had equivalent port-forwarding and shell capabilities on some other 'inside' machines, so this 'insecurity' is trivial.)
For example, you may be hosting a git repository on that machine and wish to allow ssh access, while limiting shell privileges for some developers (contractors vs full-time).
gitosis handles this with a single git account that has the public keys for the developers and the access rules set in the .conf. At that point, a developer doesn't need ssh to the git host. This is the infrastructure I believe kernel.org moved to after they were hacked.
I've seen applications (older, usually IT created, but sometimes "enterprise software") that use the passwd file for their own authentication. Remove the ability for a user to authenticate against the system and they no longer have access to the application.
It wouldn't surprise me if this server was involved with the school's student information system and did just that.
So it seems. I find the man-page slightly misleading in that regard. Other interesting way to escape /bin/false login shell from ssh man page:
~/.ssh/rc
Commands in this file are executed by ssh when the user logs in,
just before the user's shell (or command) is started. See the
sshd(8) manual page for more information.
If you copy shellcode to that file with scp (which I'd imagine would not try to invoke login shell), you'd get shell to the server.
I just tested it and i didn't get it to work. ~/.ssh/rc is not executed directly but given as an parameter to your shell (/bin/false) which will ignore the parameter.
To be more precise sh -c /bin/false -c '/bin/sh .ssh/rc' is executed where /bin/false is your shell as ssh uses popen(3) to run the command /bin/false -c '/bin/sh .ssh/rc'. I tested several shells which may be used as sh and none seems to read a user configurable file.
If you use a static linked shell and enabled PermitUserEnvironment an attacker can still use LD_* variables to circumvent restrictions as /bin/sh is typically dynamically linked.
I don't think it would work directly through scp. From what I can tell from skimming the source, it is really just a wrapper over ssh. Meaning: it forks an ssh, with the commands 'scp -t/-f' on the distant side, and does its magic to connect the pipes where they should go. 'scp -v' gives the exact command, but I don't think it works without previously having a shell.
But, if you have access to the filesystem through other means, you could use the .ssh/rc trick to bypass /bin/false, and get ssh access.
If you don't want people to log on a box in anyway, don't have the account. I don't see what's so strange or complex about that.
/bin/false has never been security. It's just good behavior for users that aren't supposed to get a shell. And that's that, they dont get a shell. They get everything else. Generally, those are daemons !
This DoS would require constant poking since sshd drops all looped connections once fds are exhausted... And can be fixed via small open fd limit put on sshd.
If you have a larger number, assign them to a group and AllowGroup.
Simple, fast, and effective.
If you can turn off password auth in favor of keys, do that, too.