add_key.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #!/usr/bin/env python3
  2. """
  3. Simple script to add a key to the emergency access server
  4. Takes an existing key file, copies it to the configured directory, and adds it to config
  5. """
  6. import json
  7. import os
  8. import sys
  9. import shutil
  10. import secrets
  11. import hashlib
  12. import argparse
  13. from pathlib import Path
  14. def generate_password_hash(password: str) -> str:
  15. """Generate password hash using PBKDF2 with SHA-256"""
  16. salt = secrets.token_hex(16)
  17. password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
  18. return f"{salt}:{password_hash.hex()}"
  19. def generate_secure_password(length: int = 32) -> str:
  20. """Generate a secure password"""
  21. import string
  22. alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
  23. return ''.join(secrets.choice(alphabet) for _ in range(length))
  24. def load_config(config_path: str):
  25. """Load configuration file"""
  26. with open(config_path, 'r') as f:
  27. return json.load(f)
  28. def save_config(config, config_path: str):
  29. """Save configuration file"""
  30. with open(config_path, 'w') as f:
  31. json.dump(config, f, indent=2)
  32. def copy_key_file(source_path: str, dest_path: str):
  33. """Copy key file to destination with proper permissions"""
  34. # Create destination directory if needed
  35. dest_dir = os.path.dirname(dest_path)
  36. os.makedirs(dest_dir, exist_ok=True)
  37. # Copy file
  38. shutil.copy2(source_path, dest_path)
  39. # Set secure permissions
  40. os.chmod(dest_path, 0o600)
  41. # Try to set ownership to emergency-access user if running as root
  42. if os.geteuid() == 0: # Running as root
  43. try:
  44. import pwd, grp
  45. user = pwd.getpwnam('emergency-access')
  46. group = grp.getgrnam('emergency-access')
  47. os.chown(dest_path, user.pw_uid, group.gr_gid)
  48. print(f"✅ Copied key file with emergency-access ownership: {dest_path}")
  49. except (KeyError, OSError):
  50. print(f"✅ Copied key file: {dest_path}")
  51. print(f"⚠️ Run: sudo chown emergency-access:emergency-access {dest_path}")
  52. else:
  53. print(f"✅ Copied key file: {dest_path}")
  54. print(f"⚠️ Run: sudo chown emergency-access:emergency-access {dest_path}")
  55. def main():
  56. parser = argparse.ArgumentParser(description="Add a key to emergency access server")
  57. parser.add_argument('key_id', help='Key identifier (e.g., backup, master)')
  58. parser.add_argument('key_file', help='Path to existing key file')
  59. parser.add_argument('backends', help='Comma-separated notification backends')
  60. parser.add_argument('--config', default='config.json', help='Config file path')
  61. parser.add_argument('--dest-dir', default='/etc/emergency-access', help='Destination directory')
  62. parser.add_argument('--password', help='Password (generated if not provided)')
  63. parser.add_argument('--message', help='Custom notification message')
  64. args = parser.parse_args()
  65. # Check if source key file exists
  66. if not os.path.exists(args.key_file):
  67. print(f"❌ Key file not found: {args.key_file}")
  68. sys.exit(1)
  69. # Load config
  70. try:
  71. config = load_config(args.config)
  72. except FileNotFoundError:
  73. print(f"❌ Config file not found: {args.config}")
  74. sys.exit(1)
  75. # Check if key already exists
  76. if args.key_id in config.get('keys', {}):
  77. print(f"❌ Key '{args.key_id}' already exists")
  78. sys.exit(1)
  79. # Generate password if not provided
  80. if args.password:
  81. password = args.password
  82. else:
  83. password = generate_secure_password()
  84. print(f"🔑 Generated password: {password}")
  85. # Set up paths and config
  86. dest_file = os.path.join(args.dest_dir, f"{args.key_id}-key.txt")
  87. route = f"/emergency-key-{args.key_id}"
  88. username = f"emergency_{args.key_id}"
  89. password_hash = generate_password_hash(password)
  90. backends = [b.strip() for b in args.backends.split(',')]
  91. message = args.message or f"🚨 EMERGENCY: Key {args.key_id} accessed from server"
  92. # Copy key file
  93. copy_key_file(args.key_file, dest_file)
  94. # Add to config
  95. if 'keys' not in config:
  96. config['keys'] = {}
  97. config['keys'][args.key_id] = {
  98. 'route': route,
  99. 'file': dest_file,
  100. 'username': username,
  101. 'password_hash': password_hash,
  102. 'backends': backends,
  103. 'message': message
  104. }
  105. # Save config
  106. save_config(config, args.config)
  107. print(f"✅ Added key '{args.key_id}' to configuration")
  108. print(f" Route: {route}")
  109. print(f" Username: {username}")
  110. print(f" Password: {password}")
  111. print(f" Backends: {', '.join(backends)}")
  112. if __name__ == '__main__':
  113. main()