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 -Vin 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-clienton Debian/Ubuntu,yum update openssh-clientson CentOS/RHEL,brew upgrade opensshon 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_configfile: Look for typos, missing spaces, or incorrect indentation. Thessh_configfile is sensitive to formatting. - Use
ssh -vfor debugging: The-vflag (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-vvor-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
hostpattern: Ensure that thehostpattern in yourssh_configfile 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
sshcommand: Runssh -v github-MyPackageto see how the%ntoken is expanded in a basic SSH connection. This can help isolate whether the issue is specific togit clone. - Experiment with alternative tokens: If
%nconsistently 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
sshCommandconfiguration: Git allows you to specify a custom SSH command using thesshCommandconfiguration option (git config --global core.sshCommand). If this is set, it might be overriding the standard SSH behavior. Ensure thatsshCommandis either unset or correctly configured to pass the hostname to the underlying SSH client. - Examine environment variables: Environment variables like
GIT_SSHorGIT_SSH_COMMANDcan also influence Git’s SSH behavior. Unset these variables to ensure that Git uses the default SSH client. - Use
ssh -Tvvv github-MyPackagefor Git-related debugging: The-Toption 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.shUpdate your
ssh_configfile:
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.