When attempting to establish an SSH connection to a remote server, you might encounter the error message: Bad owner or permissions on ~/.ssh/config
. This issue typically arises because the SSH client enforces strict security rules for its configuration files to prevent unauthorized access or modification.
This article will explore the reasons behind this error and offer a comprehensive set of solutions to rectify it, ensuring that your SSH connections can be established securely and without interruption.
Understanding the SSH Configuration File Security
The SSH (Secure Shell) client relies on configuration files, primarily ~/.ssh/config
, to manage connection parameters, host-specific settings, and private keys. Due to the sensitive nature of this information, SSH mandates that these files, especially the config
file and private keys, must have restrictive permissions.
The core principle is that only the file owner should have read and write access to the ~/.ssh/config
file. Suppose the permissions are too open (e.g., allowing other users or groups to write to the file). In that case, SSH considers it a security risk and refuses to use the configuration, leading to the “Bad owner or permissions” error. This strictness prevents malicious actors or accidental changes from compromising your SSH setup.
Solutions to Fix “Bad owner or permissions on ~/.ssh/config”
Here are several methods to resolve this SSH configuration error, ranging from permission adjustments to file ownership corrections.
1. Adjusting File Permissions (Most Common Fix)
The most frequent cause of this error is incorrect file permissions on the ~/.ssh/config
file. It should be readable and writable only by the owner.
To set the correct permissions (rw-------
or 600
), execute the following command:
In some cases, read-only permission (400
) for the owner might also suffice if you do not intend to edit the file directly frequently, though 600
is generally recommended for a configuration file you might need to modify.
2. Verifying and Correcting File Ownership
Another common issue is that the ~/.ssh/config
file might not be owned by the current user. SSH requires that the user attempting the connection is the owner of their SSH configuration file.
To check the current owner and permissions, use:
admin@technofossy.com:~$ ls -la ~/.ssh/config
-rw——- 1 your_user your_group 31 Mar 29 11:04 /home/your_user/.ssh/config
Replace your_user
and your_group
with your actual username and group. If the owner is incorrect (e.g., root
), change it back to your user. You can use $USER
to automatically use the current logged-in username.
To ensure both user and group ownership are correct, especially if you want to be explicit or if group settings are a concern:
If multiple files within the ~/.ssh
directory have incorrect ownership, you can apply the change recursively to the entire directory (use with caution):
Note: You might need sudo
if the files are currently owned by another user, like root
.
Read: How to Fix SSH ‘Permission denied (publickey)’; Authentication Failures
3. Recommended Permissions for the Entire ~/.ssh
Directory
It’s good practice to ensure all files and the directory itself within ~/.ssh
have appropriate permissions. Here’s a general guideline:
- For /.ssh: use the sode snippet :
user@host:~$ cat validate_directory_algorithm.txt # Algorithm: validate_directory_path # Purpose: Validates the security of parent directories of a given path, # iterating upwards towards root or a specified home directory. # Inputs: # path_to_check: The initial path whose ancestors are to be validated. # home_directory_path: The path to the user's home directory (boundary). # user_id: The UID of the current user for ownership checks. # check_home_boundary_flag: Boolean, if true, stop at home_directory_path. # error_message_string_ref: A reference to store error messages. # Returns: # 0 on success (all checked directories are secure). # -1 on failure (an insecure directory was found or an error occurred). FUNCTION validate_directory_path(path_to_check, home_directory_path, user_id, check_home_boundary_flag, OUT error_message_string_ref): current_path = path_to_check LOOP FOREVER: # 1. Get parent directory path of the current_path parent_path = get_parent_directory(current_path) IF parent_path IS NULL OR FAILED_TO_GET_PARENT: error_message_string_ref = "Failed to get parent directory for: " + current_path RETURN -1 # 2. Update current_path to this parent for the current iteration's checks current_path = parent_path # 3. Check if directory exists and get its properties TRY: file_properties = get_file_info(current_path) EXCEPT (DOES_NOT_EXIST_ERROR OR PERMISSION_ERROR_TO_STAT): error_message_string_ref = "Cannot access directory: " + current_path RETURN -1 # 4. Validate ownership and permissions is_system_owned = platform_is_system_owned_uid(file_properties.uid) is_user_owned = (file_properties.uid == user_id) # Secure permissions = No Group Write AND No Other Write (e.g., mode & 0o022 == 0) has_secure_permissions = ( (file_properties.mode & GROUP_WRITE_BIT) == 0 AND (file_properties.mode & OTHER_WRITE_BIT) == 0 ) IF NOT (is_system_owned OR is_user_owned): error_message_string_ref = "Directory " + current_path + " has invalid ownership (UID: " + file_properties.uid + ")" RETURN -1 IF NOT has_secure_permissions: error_message_string_ref = "Directory " + current_path + " has insecure permissions (Mode: " + OCTAL(file_properties.mode) + ")" RETURN -1 # 5. Stop if we've reached the home directory boundary (if applicable) IF check_home_boundary_flag IS TRUE AND current_path == home_directory_path: BREAK LOOP # 6. Stop if we've reached filesystem root or "." (current directory marker) IF current_path == "/" OR current_path == ".": BREAK LOOP END LOOP RETURN 0 # Success END FUNCTION # --- Helper/Placeholder Function Explanations --- # get_parent_directory(path): Corresponds to POSIX `dirname()`. # get_file_info(path): Corresponds to POSIX `stat()`. Returns object with .uid, .mode. # platform_is_system_owned_uid(uid): Checks if UID is root (0) or other system UIDs. # GROUP_WRITE_BIT, OTHER_WRITE_BIT: Constants for permission checking (e.g., 0o020, 0o002). # OCTAL(value): Converts number to octal string. # error_message_string_ref: Output parameter for error messages.
- For /config : use readconf.c
- For /authorized_keys : use the code below :
user@host:~$ cat secure_authorized_keys_algorithm.txt # Algorithm: secure_ssh_authorized_keys # Purpose: Secures the SSH authorized_keys file by removing ACLs # and setting appropriate file permissions (644). # Inputs: # user_home_directory_path: The absolute path to the user's home directory. # Returns: # 0 on success (file secured or does not exist). # 1 on failure (e.g., unable to set permissions). FUNCTION secure_ssh_authorized_keys(user_home_directory_path): keys_file_path = user_home_directory_path + "/.ssh/authorized_keys" # Check if the authorized_keys file exists and is a regular file IF file_exists(keys_file_path) AND is_regular_file(keys_file_path) THEN # Attempt to remove any existing ACLs; ignore errors (mimics '|| true') TRY: remove_all_acls(keys_file_path) CATCH ANY_ERROR_DURING_ACL_REMOVAL: PASS # Continue regardless of ACL removal outcome # Apply secure permissions (owner: read/write, group: read, other: read - typically 644) permissions_to_set = "rw-r--r--" # Symbolic or octal (e.g., 0o644) IF set_file_permissions(keys_file_path, permissions_to_set) IS SUCCESSFUL THEN RETURN 0 # Success ELSE display_warning_message("Unable to set proper permissions on " + keys_file_path) display_warning_message("Manual intervention required. Ensure the file owner has read access") display_warning_message("and that group/other users cannot modify the file.") print_newline() RETURN 1 # Failure END IF ELSE # File does not exist or is not a regular file. # Considered a success for this function's purpose as no action is needed on the file. RETURN 0 # Success END IF END FUNCTION # --- Helper/Placeholder Function Explanations --- # file_exists(path): Checks if a file or directory exists at the given path. # is_regular_file(path): Checks if the path points to a regular file. # remove_all_acls(path): Attempts to remove all Access Control Lists from the file. # set_file_permissions(path, mode): Sets the file's permissions (e.g., to "rw-r--r--" or 644). # display_warning_message(message): Outputs a warning message to the user. # print_newline(): Outputs a newline character.
You can set these systematically:
admin@technofossy.com:~$ chmod 0600 ~/.ssh/config
admin@technofossy.com:~$ chmod 0600 ~/.ssh/id_rsa # And other private keys
admin@technofossy.com:~$ chmod 0644 ~/.ssh/id_rsa.pub # And other public keys
admin@technofossy.com:~$ chmod 0600 ~/.ssh/authorized_keys
admin@technofossy.com:~$ chmod 0644 ~/.ssh/known_hosts
4. Solution for Windows Subsystem for Linux (WSL) Users
If you are using WSL and your ~/.ssh
directory (or your entire home directory) is symlinked or mounted from your Windows filesystem, chmod
commands might not have the intended effect by default. This is because WSL needs to be configured to handle Linux metadata correctly for files on Windows drives.
Read: How to Access Serial Ports (COM & ttyS) in Windows Subsystem for Linux (WSL1 & WSL2)
To enable metadata handling, you need to edit or create the /etc/wsl.conf
file in your WSL distribution and add the following lines (this requires WSL build 17093 or later):
Add this content to the file:
options = “metadata”
After saving the file, you must restart WSL. You can do this by closing all WSL terminals and then reopening one, or by running wsl --shutdown
in PowerShell/CMD and then restarting your WSL distribution.
Once WSL restarts with metadata enabled, chmod
commands applied to files on mounted Windows drives should work as expected, allowing you to set the correct permissions for your ~/.ssh/config
file.
5. When to Consider Removing or Recreating the Config File
In some situations, the ~/.ssh/config
file might be empty, corrupted, or contain auto-generated content from tools (like SourceTree or Vagrant) that is no longer needed or is causing conflicts.
If you suspect this, and the file doesn’t contain critical configurations you need, you can try renaming or deleting it:
Rename (backup):
Delete (if you are sure it’s not needed or empty):
For users encountering this with Vagrant on Windows, sometimes deleting the config
file located at C:\Users\[YourUser]\.ssh\config
(or its equivalent path used by Vagrant) can resolve the “Bad owner or permissions” error when running vagrant ssh
. For example:
After removing the problematic config file, try your SSH or vagrant ssh
command again. If a config file is necessary, you can recreate it manually with the correct permissions.
6. Addressing Global IdentityFile Issues
Occasionally, a global IdentityFile
setting within your ~/.ssh/config
might cause issues if the specified key is not appropriate for all connections or has permission problems itself. If you have a line like IdentityFile ~/.ssh/id_rsa
at the top level of your config (not within a specific Host
block), SSH will try to use this key for all connections. If this key is not suitable or has its own permission issues, it can indirectly contribute to connection problems. Review your ~/.ssh/config
for such global settings and ensure they are intended or move them into specific Host
blocks if necessary.
Verification
After applying any of the solutions above, attempt your SSH connection again:
If the “Bad owner or permissions” error is gone, the issue has been resolved. You should now be prompted for a password or connect via your SSH key if configured.
Conclusion
The “Bad owner or permissions on ~/.ssh/config” error is a common safeguard in SSH, ensuring your configuration remains secure. By understanding the necessity for strict permissions and applying the appropriate chmod
and chown
commands, or addressing WSL-specific configurations, you can quickly resolve this issue and restore your SSH connectivity.