The option you're looking for is IdentityFile but it won't work by default: ssh-copy-id which is a shell script, expects to use its -i parameter both for the public key to copy, and for the private key to authenticate with, as a way to detect the creation of duplicate entries (note: without -f, the private key counterpart must be available in addition to the public key to be copied, to be able to authenticate). But -o IdentityFile overriding the -i parameter given to ssh inside ssh-copy-id makes ssh-copy-id believe the key was already authorized, since it could connect without password, and give this final result:
$ ssh-copy-id -o 'IdentityFile=.ssh/working-key' -i .ssh/new-key.pub user@ip
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: ".ssh/new-key.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
Enter passphrase for key '.ssh/working-key':
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
(if you think this is a mistake, you may want to use -f option)
Adding -f will make it work (note: and then doesn't require the availability of the private key) because there's no check to fail. Running the command twice will not be idempotent anymore: it will add again a new identical entry in remote's authorized_keys.
That this has not been seen as an issue is probably because it's working well when ssh-agent is in use: if working-key is loaded in the agent (but not new-key), then ssh-copy-id -i .ssh/new-key.pub user@ip will work as expected. Running it again will detect the duplicate.
In short:
- you should use
ssh-agent, and load working-key in it,
- else you can insert
-f -o IdentifyFile=~/.ssh/working-key but it won't detect duplicates,
- else here's a wrapper running
ssh-agent if needed.
Here's a wrapper that will just do this for you: in case it didn't find an already running ssh-agent, it will temporarily spawn one for the single operation. If one exists it will be used (and the added key will remain added, I intend this to stay simple). It will deal very simply with the additional option: the added option (-I) must be first if it exists and followed by its separate parameter, feel free to improve it (probably by using some case loop). I also took the extra step to not ask the passphrase for a key already loaded in an available agent (using this Q/A).
wrapper-ssh-copy-id.sh:
#!/bin/sh
if [ x"$1" = x-I ]; then
if [ $# -lt 2 ]; then
exit 1
fi
privkeyfile="$2"
shift 2
if [ -z "$SSH_AUTH_SOCK" ]; then
trap 'eval $(ssh-agent -k)' EXIT
eval $(ssh-agent)
fi
fingerprint=$(ssh-keygen -lf "$privkeyfile" | awk '{print $2}')
if [ -z "$fingerprint" ]; then
exit 1
fi
ssh-add -l | grep -F -q "$fingerprint" || ssh-add "$privkeyfile"
fi
ssh-copy-id "$@"