ssh percent_expand token n not working
Troubleshooting SSH %n Token Expansion: A Comprehensive Guide
The ssh_config
file in OpenSSH provides powerful configuration options, including the use of percent_expand
tokens for dynamic path generation. Among these tokens, %n
is intended to represent the hostname as provided on the command line. However, users often encounter issues where the %n
token fails to expand correctly, leading to errors like “percent_expand: unknown key %n”. This article provides a detailed exploration of the problem, its causes, and effective solutions. We aim to help you configure your SSH client properly, enabling seamless key management for multiple repositories, particularly in scenarios involving GitHub deploy tokens.
Understanding the SSH Configuration and %n Token
The ssh_config
file (~/.ssh/config
for user-specific settings, /etc/ssh/ssh_config
for system-wide configurations) allows you to define settings for specific hosts or groups of hosts. This is particularly useful when managing multiple SSH connections with different configurations.
The percent_expand
tokens enable dynamic substitution of values within configuration options. In the context of IdentityFile
, the %n
token should represent the hostname specified in the SSH command. For example, if you run ssh github-MyPackage
, the %n
token in IdentityFile %d/.ssh/github/%n
should expand to github-MyPackage
.
Common Use Case: GitHub Deploy Tokens
GitHub allows using SSH tokens as deploy tokens, granting specific repositories access without requiring full user credentials. A common challenge is managing multiple deploy tokens for different repositories. One might attempt to use globbing and the %n
token to create a generic profile:
host github-*
Hostname github.com
User git
IdentityFile %d/.ssh/github/%n
IdentitiesOnly yes
The intention is that if you have a key pair named github-MyPackage
in the ~/.ssh/github/
directory, the configuration will automatically use that key when you run git clone github-MyPackage:/myorganization/MyPackage.git
or ssh github-MyPackage
.
Diagnosing the “percent_expand: unknown key %n” Error
The “percent_expand: unknown key %n” error indicates that the SSH client is unable to resolve the %n
token during configuration parsing. This can occur for several reasons:
1. SSH Client Version Compatibility
Older versions of OpenSSH may not fully support the %n
token or may have bugs in its implementation. It is critical to ensure that you are running a reasonably up-to-date version of OpenSSH.
Solution:
- Check your OpenSSH version: Run
ssh -V
in your terminal. - Upgrade OpenSSH: If your version is outdated, update it using your operating system’s package manager (e.g.,
apt update && apt upgrade openssh-client
on Debian/Ubuntu,yum update openssh-clients
on CentOS/RHEL,brew upgrade openssh
on macOS with Homebrew).
2. Configuration File Syntax Errors
Even a small syntax error in your ssh_config
file can prevent the entire file from being parsed correctly, leading to unexpected behavior.
Solution:
- Carefully review your
ssh_config
file: Look for typos, missing spaces, or incorrect indentation. Thessh_config
file is sensitive to formatting. - Use
ssh -v
for debugging: The-v
flag (verbose mode) provides detailed output during SSH connection attempts, including information about configuration file parsing. This can help identify the line where the error occurs. For even more detail, use-vv
or-vvv
.
3. Incorrect Hostname Matching
The host
directive in ssh_config
specifies which hosts the following configuration options apply to. If the hostname you’re using in the SSH command does not match the host
pattern, the configuration block will not be applied, and the %n
token will not be expanded.
Solution:
- Verify the
host
pattern: Ensure that thehost
pattern in yourssh_config
file matches the hostname you’re using. In the examplehost github-*
, the hostname must start withgithub-
. - Use wildcards appropriately: The
*
wildcard matches zero or more characters. If you want to match any hostname, usehost *
. If you want to match a specific set of hostnames, list them separated by commas (e.g.,host github-MyPackage, github-AnotherPackage
).
4. Contextual Limitations of %n
The %n
token’s behavior can vary depending on the context in which it’s used. While it generally represents the hostname provided on the command line, there might be specific situations where it is not correctly populated.
Solution:
- Test with a simple
ssh
command: Runssh -v github-MyPackage
to see how the%n
token is expanded in a basic SSH connection. This can help isolate whether the issue is specific togit clone
. - Experiment with alternative tokens: If
%n
consistently fails, consider whether other tokens might be suitable. For example, if you can derive the desired filename from another piece of information available in the environment.
5. Interaction with Git and SSH Wrappers
Git often uses SSH internally for authentication and data transfer. However, Git might introduce its own layer of configuration or environment variables that interfere with SSH’s percent_expand
mechanism.
Solution:
- Check Git’s
sshCommand
configuration: Git allows you to specify a custom SSH command using thesshCommand
configuration option (git config --global core.sshCommand
). If this is set, it might be overriding the standard SSH behavior. Ensure thatsshCommand
is either unset or correctly configured to pass the hostname to the underlying SSH client. - Examine environment variables: Environment variables like
GIT_SSH
orGIT_SSH_COMMAND
can also influence Git’s SSH behavior. Unset these variables to ensure that Git uses the default SSH client. - Use
ssh -Tvvv github-MyPackage
for Git-related debugging: The-T
option disables pseudo-terminal allocation, which can sometimes interfere with SSH connections used by Git. The verbose output (-vvv
) will help pinpoint the source of the problem.
Advanced Configuration and Workarounds
If the above solutions do not resolve the issue, consider the following advanced configuration options and workarounds:
1. Explicit Host Entries
Instead of relying on globbing and the %n
token, you can create explicit host entries for each repository. This is more verbose but can be more reliable.
host github-MyPackage
Hostname github.com
User git
IdentityFile %d/.ssh/github/github-MyPackage
IdentitiesOnly yes
host github-AnotherPackage
Hostname github.com
User git
IdentityFile %d/.ssh/github/github-AnotherPackage
IdentitiesOnly yes
2. Using a Script to Generate the IdentityFile Path
You can create a script that dynamically generates the IdentityFile
path based on the hostname and use the ProxyCommand
directive to execute the script.
- Create a script (e.g.,
~/bin/ssh-key-selector.sh
):
#!/bin/bash
HOST="$1"
KEY_PATH="$HOME/.ssh/github/$HOST"
if [ -f "$KEY_PATH" ]; then
echo "IdentityFile $KEY_PATH"
else
echo "IdentityFile $HOME/.ssh/id_rsa" # Default key if no match
fi
Make the script executable:
chmod +x ~/bin/ssh-key-selector.sh
Update your
ssh_config
file:
host github-*
Hostname github.com
User git
ProxyCommand ~/bin/ssh-key-selector.sh %n
IdentitiesOnly yes
IdentityFile /dev/null # Prevents ssh from trying other keys first
This setup uses ProxyCommand
to execute the ssh-key-selector.sh
script, passing the hostname (%n
) as an argument. The script then checks if a key file exists for that hostname and outputs the corresponding IdentityFile
directive. Setting IdentityFile /dev/null
prevents SSH from trying other keys before the key specified by the script.
3. Leveraging SSH Certificates
SSH certificates provide a more robust and scalable solution for managing SSH keys. Instead of distributing individual key pairs, you can create a certificate authority (CA) and sign user keys with the CA. The SSH client can then be configured to trust the CA, allowing it to authenticate any key signed by the CA.
This approach eliminates the need to manage individual IdentityFile
entries for each repository.
Specific Considerations for GitHub Deploy Tokens
When using GitHub deploy tokens, it’s essential to ensure that the key associated with the token has the correct permissions. The deploy token should be granted read-only or read-write access to the specific repository.
1. Key Permissions on GitHub
Verify that the public key associated with your deploy token is added to the correct repository with the necessary permissions. You can manage deploy tokens in the repository’s settings under “Deploy keys.”
2. Testing the Connection
Use the ssh -Tvvv github-MyPackage
command to test the SSH connection. This will provide detailed output about the authentication process, including whether the correct key is being used and whether the GitHub server is accepting the key.
3. Addressing Potential GitHub Rate Limiting
In rare cases, GitHub might impose rate limits on SSH connections. If you encounter intermittent connection issues, consider implementing retry logic or increasing the connection timeout in your SSH configuration.
Conclusion
Troubleshooting SSH %n
token expansion issues requires a systematic approach, starting with verifying SSH client version, syntax errors in ssh_config
, and hostname matching. Advanced techniques such as explicit host entries, scripting, and SSH certificates offer alternative solutions for complex key management scenarios. By carefully examining the configuration, understanding the limitations of %n
, and considering the specific context of Git and GitHub deploy tokens, you can resolve the “percent_expand: unknown key %n” error and achieve seamless SSH key management.