Wandering Thoughts archives


What ssh-agent does with multiple keys loaded

Ssh-agent is probably normally used to handle a single identity key, but it can hold more than one if you want. One of the things that the ssh-agent and ssh manpages are a bit silent on is what happens if you have multiple SSH keys loaded into a single ssh-agent. Since I've been dealing with this as the result of transitioning from one set of SSH keys to another, I'm going to write down what I've learned so far.

(The simple version of why I decided to roll over my SSH keys is that I decided to transition from keys that had once been used without encryption to keys that were created encrypted.)

Before I started loading multiple keys into ssh-agent, what I expected to happen is that the choice of which ssh-agent key to use would be controlled by the key that ssh itself would normally use. If you had, for example, 'IdentityFile .../key1-rsa', then I expected ssh to ask ssh-agent to do operations only with that key. This is not what happens. Instead what happens by default is that ssh tries all keys loaded into ssh-agent, one after another, in the order that they were loaded into ssh-agent.

You can partly override this behavior with the IdentitiesOnly configuration directive, which will restrict the keys that ssh tries to only the identities listed either as IdentityFile directives or supplied on the command line with -i. However this is an incomplete override because it doesn't prioritize the -i identity the way a normal (agentless) ssh will; ssh will first ask ssh-agent for any IdentityFile keys it has and only then fall back to a non-agent key given with -i. This implies that if you have a script and you want it to always use a particular restricted identity even if more general ones are available (as I do in one case) you need to clear $SSH_AUTH_SOCK in the script.

(This can apply any time you have a remote system that accepts multiple identities from you but applies different access permissions or access restrictions to them. Remember that IdentityFile directives add together and -i stacks with with them too, so even if you have a specific identity configured for something, a general 'Host *' identity or the like will also be tried.)

There are a couple of interesting uses I can see for this multiple key behavior. One of them is making a transition between old and new SSH keys easier. First off, you can load both your new and your old key into ssh-agent; you'll then use your new key on systems that have been updated to accept only it but have a transparent fallback to systems that only have your old key. More cleverly you can use this to uncover systems that haven't been updated to your new key by loading only your new key into ssh-agent but leaving your old encrypted key configured as your IdentityFile. If you try to ssh to somewhere but get prompted to unlock your old key, you've found a host that either prefers your old key to your new key or doesn't have your new key at all.

Another use is encrypting secondary keys (for example your Github key) but still loading them into ssh-agent for passwordless use. Since ssh with ssh-agent will try multiple keys, pushing to Github and other such uses will eventually try the right keys. You can force this to happen earlier by setting IdentitiesOnly in .ssh/config for the particular hosts involved; this will definitely be necessary if you have a lot of SSH keys, because SSH servers only accept so many key attempts (cf).

(Some of this information comes from this stackoverflow answer.)

(Talking of the interaction of ssh and ssh-agent, it's a pity that as far as I know ssh can't be told 'load keys into ssh-agent when you unlock them'. This would make it very convenient to incrementally load keys into ssh-agent as you turn out to need them while not having them sitting around unlocked in a session if you didn't.)

sysadmin/SshAgentAndMultipleKeys written at 23:18:31; Add Comment

Why Java is a compiled language and Python is not

A commentator on Charles Marsh's article Why are there so many Pythons asked an interesting question:

[...] If both Java and Python produces Bytecodes which in-turn is run by VM's why Java is called as Compiled language and Python is called Interpreted language? [...]

One comment's answer was 'marketing', which in a sense is correct; one reason we call Java a compiled language is that that's what Sun called it from the start. Another comment noted that Java has an explicit compilation phase that is separate from having the JVM execute your Java program by interpreting the bytecodes. All of this points us towards what I feel is the real answer:

In Java, bytecode is a first class object. In Python it's an internal implementation detail.

You've always been able to find specific documentation on the JVM and its bytecodes; as far as I know they were released along side the first definitions of Java the language. JVM bytecode has never been marked 'for internal use only' and in fact it's explicitly been a stable, public representation of Java programs. For example you don't download the source code for Java applets into your browser, you download the JVM bytecode (and in general JVM bytecode is the common delivery method of Java code even on servers). And the JVM guarantees that this will work regardless of what sort of machine you have (and in theory guarantees to make it work securely even in the face of maliciously generated bytecode).

This public visibility, this treatment of bytecode as a real part of the language environment with its own documentation and guarantees and specifications, makes JVM bytecode a first class object in the overall Java ecosystem. In turn this makes it accurate to say that Java programs are (usually) compiled to JVM bytecode and then executed by an interpreter of that bytecode. This is especially so when the language's implementation makes these two explicitly separate steps with a whole collection of artifacts that are this compiled bytecode.

In Python there is nothing like this; CPython's use of bytecode is just an internal detail of the interpreter implementation. CPython bytecode is not part of Python semantics, it is not really documented, and you are not really supposed to generate your own. There's no guarantee of any cross-version compatibility, as CPython bytecode is expected to be consumed by the same interpreter that generated it. And so on. CPython bytecode is an interesting curiosity, not a first class part of (C)Python.

(It's technically accurate to say that CPython compiles Python source to bytecodes and then interprets these bytecodes. But this is a narrow technicality, not how people really see CPython working, and can be said about any number of languages that we normally think of as interpreted.)

programming/WhyJavaIsCompiled written at 03:17:52; Add Comment

Page tools: See As Normal.
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.