| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- #!/usr/bin/env python3
- """
- Simple script to add a key to the emergency access server
- Takes an existing key file, copies it to the configured directory, and adds it to config
- """
- import json
- import os
- import sys
- import shutil
- import secrets
- import hashlib
- import argparse
- from pathlib import Path
- def generate_password_hash(password: str, iterations: int = 100000) -> str:
- """Generate password hash using PBKDF2 with SHA-256 in canonical format"""
- salt = secrets.token_hex(16)
- derived = hashlib.pbkdf2_hmac(
- "sha256", password.encode(), salt.encode(), iterations
- )
- # Return canonical format including algorithm and iteration count
- return f"pbkdf2_sha256${iterations}${salt}${derived.hex()}"
- def generate_secure_password(length: int = 32) -> str:
- """Generate a secure password"""
- import string
- alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
- return "".join(secrets.choice(alphabet) for _ in range(length))
- def load_config(config_path: str):
- """Load configuration file"""
- with open(config_path, "r") as f:
- return json.load(f)
- def save_config(config, config_path: str):
- """Save configuration file"""
- with open(config_path, "w") as f:
- json.dump(config, f, indent=2)
- def copy_key_file(source_path: str, dest_path: str):
- """Copy key file to destination with proper permissions"""
- # Create destination directory if needed
- dest_dir = os.path.dirname(dest_path)
- os.makedirs(dest_dir, exist_ok=True)
- # Copy file
- shutil.copy2(source_path, dest_path)
- # Set secure permissions
- os.chmod(dest_path, 0o600)
- # Try to set ownership to emergency-access user if running as root
- if os.geteuid() == 0: # Running as root
- try:
- import pwd, grp
- user = pwd.getpwnam("emergency-access")
- group = grp.getgrnam("emergency-access")
- os.chown(dest_path, user.pw_uid, group.gr_gid)
- print(f"✅ Copied key file with emergency-access ownership: {dest_path}")
- except (KeyError, OSError):
- print(f"✅ Copied key file: {dest_path}")
- print(f"⚠️ Run: sudo chown emergency-access:emergency-access {dest_path}")
- else:
- print(f"✅ Copied key file: {dest_path}")
- print(f"⚠️ Run: sudo chown emergency-access:emergency-access {dest_path}")
- def main():
- parser = argparse.ArgumentParser(description="Add a key to emergency access server")
- parser.add_argument("key_id", help="Key identifier (e.g., backup, master)")
- parser.add_argument("key_file", help="Path to existing key file")
- parser.add_argument("backends", help="Comma-separated notification backends")
- parser.add_argument("--config", default="config.json", help="Config file path")
- parser.add_argument(
- "--dest-dir", default="/etc/emergency-access", help="Destination directory"
- )
- parser.add_argument("--password", help="Password (generated if not provided)")
- parser.add_argument("--message", help="Custom notification message")
- args = parser.parse_args()
- # Check if source key file exists
- if not os.path.exists(args.key_file):
- print(f"❌ Key file not found: {args.key_file}")
- sys.exit(1)
- # Load config
- try:
- config = load_config(args.config)
- except FileNotFoundError:
- print(f"❌ Config file not found: {args.config}")
- sys.exit(1)
- # Check if key already exists
- if args.key_id in config.get("keys", {}):
- print(f"❌ Key '{args.key_id}' already exists")
- sys.exit(1)
- # Generate password if not provided
- if args.password:
- password = args.password
- else:
- password = generate_secure_password()
- print(f"🔑 Generated password: {password}")
- # Set up paths and config
- dest_file = os.path.join(args.dest_dir, f"{args.key_id}-key.txt")
- route = f"/emergency-key-{args.key_id}"
- username = f"emergency_{args.key_id}"
- password_hash = generate_password_hash(password)
- backends = [b.strip() for b in args.backends.split(",")]
- message = args.message or f"🚨 EMERGENCY: Key {args.key_id} accessed from server"
- # Copy key file
- copy_key_file(args.key_file, dest_file)
- # Add to config
- if "keys" not in config:
- config["keys"] = {}
- config["keys"][args.key_id] = {
- "route": route,
- "file": dest_file,
- "username": username,
- "password_hash": password_hash,
- "backends": backends,
- "message": message,
- }
- # Save config
- save_config(config, args.config)
- print(f"✅ Added key '{args.key_id}' to configuration")
- print(f" Route: {route}")
- print(f" Username: {username}")
- print(f" Password: {password}")
- print(f" Backends: {', '.join(backends)}")
- if __name__ == "__main__":
- main()
|