script for Generating Keypair - private and public keys with passphrase

 In today's security-first environments, password-based authentication is gradually being phased out in favor of more robust methods like key-based authentication. Our team recently moved to this model as part of our compliance and security hardening efforts. With around 500 users, manually generating SSH or encryption key pairs for each person wasn’t practical, so we automated the process using a simple Python script — and it’s been a game changer.

Instead of asking users to generate their own keys (which leads to inconsistent key strengths, file formats, and often misconfiguration), we decided to centrally generate encrypted RSA key pairs. The script leverages OpenSSL via the command line to create a 2048-bit RSA private key for each user, encrypts it with a passphrase, and then extracts the corresponding public key. We also output a CSV file listing all the generated key paths for easy reference and tracking.

The idea is simple: take a list of usernames, loop through each one, and generate a secure, encrypted RSA key pair. The private key is protected with a passphrase, and the public key is extracted using OpenSSL. Everything gets saved in an output folder, and we generate a CSV with the paths for easy reference.

Before you run the script, make sure you’ve got OpenSSL installed. On Windows, Git Bash includes it, so we just pointed the script to that executable. If you're on Linux or macOS, you’re probably already good to go.

Here’s what the script looks like:

import os import subprocess import csv from getpass import getpass # Path to OpenSSL executable (adjust if needed) OPENSSL_PATH = r"C:\Program Files\Git\usr\bin\openssl.exe" # Input/output setup names_file = r"<path>/users.txt" # One username per line output_folder = r"<output path>" # Where the keys will go csv_output = os.path.join(output_folder, "keys_list.csv") os.makedirs(output_folder, exist_ok=True) # Either prompt for passphrase securely or hardcode it for automation # passphrase = getpass("Enter passphrase for private keys: ") passphrase = "<passphrase>" # Replace with a secure value # Write CSV headers with open(csv_output, mode='w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(["Name", "Private Key Path", "Public Key Path"]) # Read user names from input file with open(names_file, "r") as f: for line in f: name = line.strip() if not name: continue print(f"\n Generating keys for: {name}") private_key_path = os.path.join(output_folder, f"{name}_private.p8") public_key_path = os.path.join(output_folder, f"{name}_public.pub") # Step 1: Generate RSA private key cmd_private = [OPENSSL_PATH, "genrsa", "2048"] # Step 2: Encrypt the key using PKCS#8 with DES3 cmd_encrypt = [ OPENSSL_PATH, "pkcs8", "-topk8", "-v2", "des3", "-inform", "PEM", "-out", private_key_path, "-passout", f"pass:{passphrase}" ] try: # Pipe genrsa output into pkcs8 to encrypt it p1 = subprocess.Popen(cmd_private, stdout=subprocess.PIPE) p2 = subprocess.Popen(cmd_encrypt, stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() p2.communicate() p2.wait() except Exception as e: print(f" Failed to generate private key for {name}: {e}") continue # Generate the public key from the encrypted private key cmd_public = [ OPENSSL_PATH, "rsa", "-in", private_key_path, "-pubout", "-out", public_key_path, "-passin", f"pass:{passphrase}" ] try: subprocess.run(cmd_public, check=True) print(f" Keys done for {name}") except subprocess.CalledProcessError as e: print(f" Failed to generate public key for {name}: {e}") continue # Log everything to CSV writer.writerow([name, private_key_path, public_key_path]) print("\n All keys generated!") print(f"CSV saved at: {csv_output}")

You drop your usernames in a users.txt file, one per line. The script loops through them, spits out an encrypted .p8 private key and a .pub public key for each, and logs it all to a CSV. Super handy for onboarding or rotating keys across a large user base.

Couple of notes:

  • You can prompt for the passphrase using getpass() if you’re running it manually.

  • For automation (like in CI/CD), hardcoding the passphrase works, but make sure you’re storing it securely — don’t commit it to git or leave it lying around.

  • You’ll need to update the file paths before running. The placeholders are obvious.

This saved us hours of manual work and helped us enforce consistent key standards across the board. If you’ve got a big user base and need to move away from passwords, this little script might just make your life easier.

Comments