WARNING: Creativity ahead, which is often bad for security (at least without thorough review).
This sounds like a case in which an SSH agent could be useful. An SSH agent provides a socket interface over which SSH clients can ask the agent to perform key operations for them, which enables the following common uses:
- You can have the long-running agent decrypts your private key once, instead of having each client decrypt the key separately.
- You can have your SSH client forward the agent connection, allowing you to use your key from the remote host without actually storing it there or otherwise revealing it.
This second case in particular sounds a lot like your use case, except instead of granting access on a different host, you want to grant access to multiple users on the same host.
It would look something like this:
sshkeeper@bastion$ eval "$(ssh-agent -a /path/to/socket)"
sshkeeper@bastion$ echo $SSH_AUTH_SOCK
/path/to/socket
sshkeeper@bastion$ ssh-add
Enter passphrase for /home/sshkeeper/.ssh/id_rsa:
sshkeeper@bastion$ chmod 660 /path/to/socket
sshkeeper@bastion$ chgrp ssh-users /path/to/socket
The key doesn't necessarily need a passphrase; I included one for illustration.
In any case, now anyone with read and write permissions to the socket can use the...
jander@bastion$ export SSH_AUTH_SOCK=/path/to/socket
jander@bastion$ ssh private_server
Error reading response length from authentication socket.
Permission denied (publickey).
Oops. It's a little trickier than that, because ssh-agent
is paranoid and double-checks the user ID of whoever connects to the socket. So we need a workaround. Let's try using socat
as a proxy:
sshkeeper@bastion$ eval "$(ssh-agent -a /home/sshkeeper/ssh_agent_socket)"
sshkeeper@bastion$ ssh-add
Enter passphrase for /home/sshkeeper/.ssh/id_rsa:
sshkeeper@bastion$ rm /path/to/socket
sshkeeper@bastion$ umask 117
sshkeeper@bastion$ socat UNIX-LISTEN:/path/to/socket,fork,group=ssh-users UNIX-CONNECT:/home/sshkeeper/ssh_agent_socket &
Now it's the sshkeeper-owned socat
process that's connecting to the agent, and not the jander-owned SSH client, so the agent has no complaint:
jander@bastion$ export SSH_AUTH_SOCK=/path/to/socket
jander@bastion$ ssh private_server
jander@private_server$ █
You'll want to be careful of the filesystem permissions for accessing the socket, as that's all that's left to protect it. Don't give anyone but sshkeeper
write access along the path to the socket. Beware also that some BSD-derived systems ignore the permissions on the socket file itself; test this thoroughly on your system.
Finally, beware that this is a nonstandard use of the SSH agent: in fact I had to work around a security feature to make it work. I believe that on a Linux system with proper filesystem permissions, it can be at least as safe as or safer than the sudo
solution... but you shouldn't take my word for that. Make sure you understand exactly what's going on here before using this.
UPDATE: I've taken a look at the openssh ssh-agent source code to see what you can do with an agent socket, and I can see a couple of opportunities for minor mischief. Namely, your users can ask the agent to add or remove keys.
So a person could tell the agent to drop the key, locking everyone else out of the servers until you (or a script) re-add the key.
A person could also add a key, giving everyone else access to additional servers. However, this person could also hand other people the key outright (without using the server), or use their own shared agent, so this point is relatively minor.