杰瑞科技汇

Python如何用ssh-keygen生成密钥对?

Of course! Generating SSH keys in Python is a common task, especially for automating server setups, cloud deployments, or CI/CD pipelines. The best and most secure way to do this is by using Python's built-in paramiko library, which is a pure Python implementation of the SSHv2 protocol.

Python如何用ssh-keygen生成密钥对?-图1
(图片来源网络,侵删)

Here’s a complete guide, from the basics to a full, reusable function.

The Best Approach: Using the paramiko Library

paramiko is the de-facto standard for SSH in Python. It's robust, well-maintained, and avoids the security risks of calling external command-line tools like ssh-keygen via subprocess.

Step 1: Install paramiko

If you don't have it installed, open your terminal or command prompt and run:

pip install paramiko

Step 2: Generate the SSH Key Pair

The core of the process is using paramiko.RSAKey.generate(bits=2048). You can then save the public and private keys to files.

Python如何用ssh-keygen生成密钥对?-图2
(图片来源网络,侵删)

Here is a simple, complete script to generate a key pair:

import paramiko
import os
def generate_ssh_key_pair(key_type='rsa', key_size=2048, comment="python-keygen"):
    """
    Generates a new SSH key pair and saves them to files.
    Args:
        key_type (str): The type of key to generate ('rsa', 'dsa', 'ecdsa', 'ed25519').
                        'rsa' is the most common and widely supported.
        key_size (int): The size of the key in bits. 2048 is a good minimum for RSA.
        comment (str): A comment to add to the public key.
    Returns:
        tuple: A tuple containing the paths to the private and public key files.
               (private_key_path, public_key_path)
    """
    # Generate the key object
    if key_type.lower() == 'rsa':
        key = paramiko.RSAKey.generate(bits=key_size)
    elif key_type.lower() == 'dsa':
        key = paramiko.DSSKey.generate(bits=key_size)
    elif key_type.lower() == 'ecdsa':
        # For ECDSA, key_size is the key size in bits (e.g., 256, 384, 521)
        key = paramiko.ECDSAKey.generate(bits=key_size)
    elif key_type.lower() == 'ed25519':
        # Ed25519 uses a fixed key size
        key = paramiko.Ed25519Key.generate()
    else:
        raise ValueError(f"Unsupported key type: {key_type}")
    # Define filenames
    private_key_path = f"id_{key_type}"
    public_key_path = f"{private_key_path}.pub"
    # --- Save the Private Key ---
    # The private key is saved in the OpenSSH format
    # The password argument can be used to encrypt the private key with a passphrase
    key.write_private_key_file(private_key_path, password=None)
    print(f"[*] Private key saved to: {os.path.abspath(private_key_path)}")
    # --- Save the Public Key ---
    # The public key is just the key's base64 representation plus the comment
    public_key_line = f"{key.get_name()} {key.get_base64()} {comment}"
    with open(public_key_path, 'w') as f:
        f.write(public_key_line + '\n')
    print(f"[*] Public key saved to: {os.path.abspath(public_key_path)}")
    return private_key_path, public_key_path
# --- Example Usage ---
if __name__ == "__main__":
    try:
        # Generate a standard 2048-bit RSA key pair
        private_key, public_key = generate_ssh_key_pair(key_type='rsa', key_size=2048)
        # Print the public key to the console
        print("\n--- Public Key ---")
        with open(public_key, 'r') as f:
            print(f.read())
    except ValueError as e:
        print(f"Error: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

How to Run the Script

  1. Save the code above as a Python file (e.g., create_keys.py).
  2. Run it from your terminal: python create_keys.py

You will see output similar to this:

[*] Private key saved to: /path/to/your/project/rsa
[*] Public key saved to: /path/to/your/project/rsa.pub
--- Public Key ---
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... (long string of characters) python-keygen

This will create two files in your current directory:

  • id_rsa: Your private key. Treat this like a password! Keep it secure and never share it.
  • id_rsa.pub: Your public key. This is the one you can share and place on servers.

Advanced: Adding a Passphrase to the Private Key

For better security, you should encrypt your private key with a passphrase. You can do this easily by providing the password argument to write_private_key_file.

Python如何用ssh-keygen生成密钥对?-图3
(图片来源网络,侵删)

Here's how you would modify the example usage:

# Inside the generate_ssh_key_pair function, when saving the private key:
# key.write_private_key_file(private_key_path, password="your-super-secret-passphrase")
# --- Example Usage with Passphrase ---
if __name__ == "__main__":
    try:
        # Ask for a passphrase (ideally, use a more secure method for input in a real app)
        passphrase = input("Enter a passphrase for your new private key (leave blank for no passphrase): ")
        if not passphrase:
            passphrase = None # No passphrase
        private_key, public_key = generate_ssh_key_pair(key_type='rsa', key_size=2048)
        # Modify the key saving part to include the passphrase
        key.write_private_key_file(private_key_path, password=passphrase)
        print(f"[*] Private key saved to: {os.path.abspath(private_key_path)} (with passphrase)")
        # ... (rest of the script is the same)
    except ValueError as e:
        print(f"Error: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

Now, when you try to use this private key with SSH or another tool, it will prompt you for the passphrase.


Alternative (Not Recommended): Using subprocess to Call ssh-keygen

You can use Python's subprocess module to call the system's ssh-keygen command. This is generally not recommended because:

  1. Portability: It assumes ssh-keygen is installed on the system, which isn't always true (e.g., in some minimal Docker containers).
  2. Security: You have to be very careful with how you handle arguments and file paths to avoid command injection vulnerabilities.
  3. Error Handling: It's harder to get detailed error information compared to a native library.

However, if you absolutely must, here's how it would look:

import subprocess
import os
def generate_key_with_subprocess():
    """Generates an SSH key pair by calling the ssh-keygen command."""
    key_type = 'rsa'
    key_size = 2048
    private_key_path = f"id_{key_type}"
    public_key_path = f"{private_key_path}.pub"
    comment = "python-keygen-subprocess"
    passphrase = None # Or a passphrase
    # The -f flag specifies the output file name for the private key.
    # The public key will be automatically created with a .pub extension.
    command = [
        'ssh-keygen',
        '-t', key_type,
        '-b', str(key_size),
        '-C', comment,
        '-f', private_key_path,
        '-N', passphrase if passphrase else '' # -N for new passphrase, empty string for none
    ]
    try:
        print(f"[*] Running command: {' '.join(command)}")
        # subprocess.run is the modern, safer way to call external commands
        result = subprocess.run(command, check=True, capture_output=True, text=True)
        # ssh-keygen prints to stderr on success, so we check that
        if result.stderr:
            print("[*] ssh-keygen output:")
            print(result.stderr)
        print(f"[*] Successfully generated keys using ssh-keygen.")
        print(f"[*] Private key: {os.path.abspath(private_key_path)}")
        print(f"[*] Public key: {os.path.abspath(public_key_path)}")
    except FileNotFoundError:
        print("Error: 'ssh-keygen' command not found. Is OpenSSH installed and in your PATH?")
    except subprocess.CalledProcessError as e:
        print(f"Error: ssh-keygen failed with return code {e.returncode}")
        print(f"Stderr: {e.stderr}")
# --- Example Usage ---
if __name__ == "__main__":
    generate_key_with_subprocess()

Summary: Which Method to Choose?

Feature paramiko (Recommended) subprocess (Not Recommended)
Portability High. Pure Python, works anywhere Python runs. Low. Requires ssh-keygen to be installed on the system.
Security High. No risk of command injection. Medium/Low. Risk of vulnerabilities if arguments are not sanitized.
Dependencies Requires pip install paramiko. None, relies on system tools.
Control Full. Can manipulate key objects directly in Python. Limited. Can only interact via command-line arguments and output.
Error Handling Excellent. Full Python exception handling. Basic. Relies on exit codes and parsing text output.

For any serious application, automation, or library, always use paramiko. It's the correct, secure, and professional way to handle SSH operations in Python.

分享:
扫描分享到社交APP
上一篇
下一篇