register_ssh_keys 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/python3
  2. #
  3. # Maximilian Wilhelm <max@rfc2324.org>
  4. # -- Sun 17 Feb 2019 09:51:48 PM CET
  5. #
  6. import argparse
  7. import netifaces
  8. import os
  9. import os.path
  10. import requests
  11. import sys
  12. key_types = [
  13. 'ssh_host_ecdsa_key',
  14. 'ssh_host_ecdsa_key.pub',
  15. 'ssh_host_ed25519_key',
  16. 'ssh_host_ed25519_key.pub',
  17. 'ssh_host_rsa_key',
  18. 'ssh_host_rsa_key.pub',
  19. ]
  20. def get_active_interface() -> str:
  21. try:
  22. # netifaces.gateway() will return a dict with multiple keys:
  23. # 'default' -> dict with default route information (AF -> (ip, iface))
  24. # netifaces.AF_INET -> list of IPv4 next-hop tuples (IP, iface, default yes/no)
  25. # netifaces.AF_INET6 -> list of IPv6 next-hop tuples (see above)
  26. def_gw = netifaces.gateways()['default']
  27. # The 'default' dict should contain an IPv6 default gw (we need IPv6 to reach NACL),
  28. # and if so we care about the interface name
  29. return def_gw[netifaces.AF_INET6][1]
  30. except KeyError:
  31. return None
  32. def get_interface_mac(ifname: str) -> str:
  33. iface_addrs = netifaces.ifaddresses(ifname)
  34. try:
  35. # We care about the MAC of the 1st entry in the AF_LINK addresses (from right to left)
  36. return iface_addrs[netifaces.AF_LINK][0]['addr']
  37. except KeyError:
  38. return None
  39. except IndexError:
  40. return None
  41. def upload_key(nacl_url: str, key_type: str, mac: str):
  42. print (f"Registering key '{key_type}'... ", end = '')
  43. try:
  44. with open (f"/etc/ssh/{key_type}", "r") as key_fh:
  45. data = {
  46. 'key_type' : key_type,
  47. 'key' : "".join (key_fh.readlines ()),
  48. }
  49. if mac is not None:
  50. data['mac'] = mac
  51. res = requests.post (f"{nacl_url}/node/register_ssh_key", data = data)
  52. if res.status_code == 200:
  53. print("already registered.")
  54. elif res.status_code == 201:
  55. print("done.")
  56. else:
  57. print(f"FAILED: {res.text}", file=sys.stderr)
  58. sys.exit(3)
  59. except Exception as e:
  60. print(f"FAILED: {str(e)}", file=sys.stderr)
  61. sys.exit(4)
  62. parser = argparse.ArgumentParser(description = 'NACL SSH key registration tool')
  63. parser.add_argument('--mac', '-m', help = 'Use MAC address from gateway interface rather than IP address to identify ourselves', action = 'store_true', default = False)
  64. parser.add_argument('--url', help = "URL to reach NACL service, e.g http://nacl:2342", default = os.environ.get('NACL_URL', 'http://nacl'))
  65. args = parser.parse_args()
  66. mac = None
  67. if args.mac:
  68. uplink_ifname = get_active_interface()
  69. if uplink_ifname is None:
  70. print("Failed to identify uplink interface!", file=sys.stderr)
  71. sys.exit(1)
  72. mac = get_interface_mac(uplink_ifname)
  73. if mac is None:
  74. print(f"Failed to get MAC address of uplink interface {uplink_ifname}!", file=sys.stderr)
  75. sys.exit(2)
  76. for key_type in key_types:
  77. upload_key(args.url, key_type, mac)