ssh_keys.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. """
  2. SSH keys management utilities.
  3. """
  4. import subprocess
  5. from sqlalchemy import select
  6. from app.core.database import async_session_maker
  7. from app.models.device import Device
  8. async def sync_authorized_keys():
  9. """
  10. Sync all device SSH keys to /home/tunnel/.ssh/authorized_keys
  11. This should be called:
  12. - After device registration (to add new key)
  13. - After device deletion (to remove key)
  14. """
  15. try:
  16. async with async_session_maker() as session:
  17. result = await session.execute(select(Device))
  18. devices = result.scalars().all()
  19. keys = []
  20. # Security restrictions for tunnel keys:
  21. # - no-pty: no terminal allocation (prevents shell)
  22. # - no-X11-forwarding: no X11
  23. # - no-agent-forwarding: no SSH agent
  24. # - permitopen: only allow forwarding to localhost ports 22 and 80
  25. restrictions = (
  26. 'no-pty,'
  27. 'no-X11-forwarding,'
  28. 'no-agent-forwarding,'
  29. 'permitopen="localhost:22",'
  30. 'permitopen="localhost:80"'
  31. )
  32. for device in devices:
  33. if device.config and 'ssh_public_key' in device.config:
  34. ssh_key = device.config['ssh_public_key'].strip()
  35. if ssh_key:
  36. # Format: restrictions key comment
  37. keys.append(f"{restrictions} {ssh_key} # device:{device.mac_address}")
  38. authorized_keys_content = "\n".join(keys) + "\n" if keys else ""
  39. # Write using sudo
  40. subprocess.run(
  41. ["sudo", "tee", "/home/tunnel/.ssh/authorized_keys"],
  42. input=authorized_keys_content.encode(),
  43. stdout=subprocess.DEVNULL,
  44. check=True
  45. )
  46. subprocess.run(
  47. ["sudo", "chmod", "600", "/home/tunnel/.ssh/authorized_keys"],
  48. check=True
  49. )
  50. subprocess.run(
  51. ["sudo", "chown", "tunnel:tunnel", "/home/tunnel/.ssh/authorized_keys"],
  52. check=True
  53. )
  54. print(f"[SSH] Synced {len(keys)} keys to authorized_keys")
  55. except Exception as e:
  56. print(f"[SSH] Failed to sync authorized_keys: {e}")