The pitfalls of using SSH-agent, or how to use an agent safely
rabexc.org
rabexc.org
The basic story is that ssh-agent really just exposes a primitive of "please sign this challenge," which is useful locally, but the protocol wasn't designed to be forwarded. If requests are coming from a semi-trusted intermediary host, the protocol doesn't tell the agent (a) "what remote server is being authenticated to [i.e., who generated the challenge?]", or (b) "what command is going to be executed?" It doesn't even really know (c) "what (semi-trusted) host forwarded the challenge and is asking to authenticate to the remote server?" (although this one you can approximate today by running lots of agents and giving each local ssh command a different agent to forward requests to).
Guardian Agent is a sort of hack that allows the agent to know (a), (b), and (c) before deciding whether to grant or deny the request, so the user can set up policies like, "I'd like to allow `semi-trusted host x` to use <SSH identity i> to run "git pull from <repository name y>" when talking to `git server z`, but that's it." The basic ssh-agent protocol just doesn't have enough info to be able to do something like that.
The problem with traditional Agent Forwarding is that an intermediary may be compromised. A compromised intermediary can still fool Guardian Agent with false values for (a), (b), and (c). The only way Guardian Agent is more secure than unmodified ssh is that it's relatively unknown. Obscurity, however, isn't a defensible security perimeter.
-c Indicates that added identities should be subject to confirmation be‐
fore being used for authentication. Confirmation is performed by
ssh-askpass(1). Successful confirmation is signaled by a zero exit
status from ssh-askpass(1), rather than text entered into the re‐
quester.
I'm a bit surprised that this is not mention in the article, as this seems very useful to make exploits more difficult. AddKeysToAgent confirmI need to look into the original post have wanted this for a while.
You can get the convenience of agent forwarding without the negatives by using openssh's ProxyJump (or, in old versions ProxyCommand). Either allows you to transparently forward your ssh connection via another host (or chain of hosts).
Host jumpbox-10.1.0.x
HostName jumpbox.example.com
Port ...
User ...
Host 10.1.0.*
ProxyJump jumpbox-10.1.0.x
Then you can just run any random command like ssh 10.1.0.4 and it will just transparently jump through the jumpbox without you needing to specify it!(Of course, if you have a local subnet that collides and you are also trying to SSH to local hosts then this won't be the right approach for you).
Host 10.1.0.*
ProxyJump jumpbox-10.1.0.x !host hosta,hostb.example.org,hostc,10.1.0.23 Host 10.1.0.* !hosta !hostb.example.org !hostc !10.1.0.23
ProxyJump jumpbox-10.1.0.x
Doing it at the Host level would also make it easier if there were other config you wanted to apply for the group of machines (like IdentifyFile or Port)e.g.,
Match !exec "test1 -h %h -p %p >/dev/null 2>&1 || test2 >/dev/null 2>&1" host 10.1.0.*,*@example.org !host 10.1.0.4,10.1.0.11,hostb@example.org
ProxyJump jumpbox-10.1.0.x
The tests can be, e.g., see if the destination host can be reached directly, and if yes, bypass the jumphost. Using %h and %p ssh will pass the destination hostname and port to the test command.https://github.com/maxgoedjen/secretive
Extra nice with the new Apple Magic Keyboard with Touch ID.
Modern SoCs do have secure enclaves, but how can one use it? I don't want a Yubikey dongle which i will forget at home when going to the office and vice versa. I'd be happy to get just the secure key storage without the fingerprint feature.
Second, you don't need a script to start the agent in your shell config, if you have systemd and logind. You can run one agent per session using systemd, with SSH_AUTH_SOCK set to a predictable path in /run/user/UID. Then you can include the predictable path as SSH_AUTH_SOCK in your .zshrc.
Second, if you're going to exclude every server on which anyone else has root, you're essentially excluding all hosting (except colocation), since essentially that means all computers you don't physically manage.
There are many scenarios where a physically local computer is only trustworthy for the moment, and where this could change at any time. Windows computers, for instance, aren't trustworthy in the long term. Work computers may have nefarious software on them. Computers which are shared with multiple people (think of a family) may have users who aren't as careful.
A shell on a trustworthy provider such as SDF may be safer as a place to store keys and from which to run ssh-agent, so this scenario shouldn't be discounted.
Of course, this means nothing if your access to your shell on a trustworthy server is compromised, but wholesale discounting this is not helping people.
Even a computer you manage yourself could have nefarious software on it, as most people don't usually manage their operating system and the operating system provider could serve up malicious software (intentionally or unintentionally), either originally or in an update. Same with the hardware of the machine, which could also compromise your keys or grant unauthorized people access.
I would not feel safe merely because I physically managed my own machines and knew something about security.
Really, a computer needs to be completely offline and with no ability to get online. Safest is not to use a computer at all.
This right here is what has been bugging me recently and the what is really selling me on the author's approach. Given that exposing a series of public keys to an SSH server acknowledges their connection, pervasive use of git hosting like Github/Gitlab, separating private and professional personas... How else do you keep maintain that consistently?
It's only mentioned in passing in the end but really, it's an underappreciated issue I haven't seen better solutions to.
0: http://manpages.ubuntu.com/manpages/bionic/man1/ssh-import-i...
https://wiki.archlinux.org/title/GnuPG#Using_a_PGP_key_for_S...
The simplest and best solution is don't use SSH. For Git remotes using HTTPS, use personal access tokens / API tokens. For each repository you check out, change the git remote URL to include the username, like git remote add origin https://username@github.com/user/repo.git. Then configure Git to use your system's credential keychain and store your token there with the hostname and username. Or use a .netrc file. The correct access token will be selected based on the hostname and username.
If you do use SSH, you can configure a Git repo to use some specific SSH arguments to specify the key file, like git config core.sshCommand "ssh -i ~/.ssh/id_ed25519_clientX". Or you can configure your SSH client to have a custom Host entry for a fake host that specifies the SSH key to use, and use that fake host for your Git ssh remote URL.
Running multiple agents is also a bit ugly, especially if you are trying to consolidate your keys with an agent integrated with your desktop environment, which I think is the most common use case.
FWIW my proposal for fixing it is https://github.com/openssh/openssh-portable/pull/233 but it isn't the most elegant solution either I guess. It doesn't seem to have picked up much interest so I don't think it's likely to ever be merged (at least in its current form) which is fine. Hopefully some tamed version of agent forwarding appears directly in openssh someday, either as a simple key filter or something more complicated like guardian-agent
Host *.foobar.com
IdentityAgent ~/.ssh-agent-for-foobar.ssh
Of course, you still need to run a separate agent for each security domain you wish to keep separate. IdentitiesOnly yes # Only use the identity specified by IdentityFile instead of any presented by an agent
ForwardAgent no # Don't forward to a remote server.
IdentityAgent none # Don't use an agent.
AddKeysToAgent no # Don't add any unlocked keys to an agent.
Host *.foobar.com
IdentityFile ~/.ssh/path/to/private/keyYes, and that's the rub.
It wouldn't be as bad if there was a way to make the ssh client manage the lifetime of the agent process itself (similar to ProxyCommand or something) And I definitely looked into building something like that.
Ultimately I thought that something built into the client was better overall for a couple reasons: * Filtering rules can be easily managed as .ssh/config settings * As I mentioned in the PR, I was able to reuse a lot of the existing code for the agent protocol that already is compiled into the client.
I also think the "filter" approach makes more sense than having truly separate ssh-agent binaries running. For one thing it's flexible to allow for multiple hops. Imagine if you are ssh'ing from A->B->C. On the first hop I want to give "B" access to keys "K1,K2" but then it wants to only give access to "K2" to C. With a protocol-filtering approach both hosts can prune back the amount of access being forwarded onwards.
FTFY.
In more detail: if your private keys ever leave your computer via the network, it's a good idea to consider your private keys compromised and to burn them and create new ones.
If you're in an organization which uses SSH CAs and Principals (see https://dmuth.medium.com/ssh-at-scale-cas-and-principals-b27... for details), you'll only need to create a single keypair, get it signed, and you're good to go again.
Why such a rigid rule? What if I backup the private keys online, after encrypting them, using software that’s known to be secure? I guess my question is also about how to manage things when the private key stored locally is lost.
Doesn't add 2FA so much as it prompts you for each agent use.
On the remote end, you can enable 2FA for logging into the server with libpam-google-authenticator.
However, it can still be useful to use different keys for different purposes; as the article explains, by default, ssh presents all your public keys to the remote server so it can identify you, which can be a privacy concern.
However, I thought people were using agent when they really needed the "one remote computer logs into another" feature - e.g. for direct file transfer. I have never used SSH agent in my life, though - when I need something like that, I just generate fresh SSH keys on the remote computer.
You can create a new key _on that machine_ and authorize _that key_ for the specific purpose you need.
Or you can also just clone the repo on your local machine and add the remote machine as a git repo remote. Then you proxy all commits between github and the remote machine.
If you don't want to proxy commits between three repos (github, your local, your remote) then you could install sshfs on your local machine and sshfs-mount your remote machine.
Regardless; if you're running git on the remote machine then the root user of that remote machine would have access to the key. Why let them have access to _your_ key when they're only administering a machine for that repository? Let them have access to a shared key.
if [ "$?" == 2 ]; then
why not $? -eq 2?why nested ifs?