]> gitweb.pimeys.fr Git - scripts-20-100.git/blob - ssh/generate_config.py
Génération automatique de .ssh/config
[scripts-20-100.git] / ssh / generate_config.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """Script de génération automatique de fichier ~/.ssh/config
5
6 TODO : mettre une option pour append le ssh des bornes
7 """
8
9 import sys
10 import re
11 sys.path.append('/usr/scripts/')
12
13 import lc_ldap.shortcuts
14 import lc_ldap.objets
15
16 #: Fichier à inclure au début
17 static_before_file = "./static_before"
18
19 #: Fichier à inclure à la fin
20 static_after_file = "./static_after"
21
22 #: regexp pour exclure certains "serveurs"
23 black_regex = re.compile('^((bigbrother|hugebrother|littlebrother|tinybrother|imprimante|vigile(--?\d[a-z])?|bat[abcghijmopk]-\d|minigiga|multiprise-v6|chu|pika|kvm|pulsar|nols2?).adm.crans.org|ftp.federez.net|ns1.crans.ens-cachan.fr)$')
24
25 #: Proxy pour contacter le VLAN adm
26 adm_proxy = u"sable.crans.org"
27
28 #: Login pour se connecter sur les serveurs Cr@ns
29 login_crans = u"legallic"
30
31 #: À afficher avant les serveurs Cr@ns
32 crans_header = u"""
33 # +-------------------+
34 # | Serveurs du Cr@ns |
35 # +-------------------+
36 # Accessible aux apprentis
37 # sauf zamok et ssh2, accessibles à tous les adhérents
38
39 """
40
41 #: À afficher avant les serveurs adm
42 crans_adm_header = u"""
43 # +-------------------------+
44 # | Serveurs Cr@ns adm-only |
45 # +-------------------------+
46 # Accessibles aux apprentis, mais ne sont que sur le VLAN adm
47 # d'où la ProxyCommand
48 # fy et fz ne sont accessibles qu'aux nounous
49
50 """
51
52 def blacklisted(key, aliases):
53 """Répond True si le serveur ne doit pas apparaître dans le fichier de conf."""
54 for a in aliases:
55 if black_regex.match(a):
56 return True
57 return False
58
59 def cache_servers(servs):
60 import json
61 json.dump(servs, open("plouf.json", "w"))
62
63 def load_servers():
64 import json
65 return json.load(open("plouf.json"))
66
67 def get_servers(help=None):
68 """Récupère la liste des serveurs dans la base LDAP."""
69 if help is None:
70 c = lc_ldap.shortcuts.lc_ldap_readonly(user=u"legallic")
71
72 l = c.allMachines()
73 l = [m for m in l if isinstance(m, lc_ldap.objets.machineCrans)]
74 else:
75 l = help
76
77 hosts = {}
78 for m in l:
79 host = m["host"][0].value
80 h = host.replace(".crans.org", "")
81 if hosts.has_key(h):
82 print (u"Doublon : clé %s had %r and wants %r" % (h, hosts[h], [host] + [a.value for a in m["hostAlias"]])).encode("utf-8")
83 else:
84 hosts[h] = [host] + [a.value for a in m["hostAlias"]]
85 return hosts
86
87 def output(key, aliases, use_adm_proxy=False):
88 """ Renvoie le block de conf pour un host.
89 Traite particulièrment : ssh2, les ilo, la ferme"""
90 # On teste si le serveur est dans la ferme
91 ferme = any([a.endswith(u".ferme.crans.org") for a in aliases])
92 shorts = list(set([a.replace(".crans.org", "") for a in aliases]))
93 if ferme:
94 shorts.append(a.split(".", 1)[0])
95 shorts.sort()
96 if key in shorts:
97 shorts.remove(key)
98 out = u"Host %s\n" % (u" ".join([key] + shorts + aliases))
99 if key=="ssh2":
100 out += u" # Un serveur ssh qui n'est qu'un nat vers 138.231.136.1:22\n"
101 out += u" # pour passer à travers les blocages de ports (443 = https)\n"
102 out += u" HostName 138.231.136.2\n"
103 out += u" Port 443\n"
104 out += u" User %s\n" % login_crans
105 out += u" ForwardAgent yes\n"
106 out += u"\n"
107 return out
108 hostname = u"%s.crans.org" % (key)
109 out += u" HostName %s\n" % (hostname)
110 out += u" User %s\n" % login_crans
111 if not key in ["apprentis", "batk-0"]:
112 out += u" ForwardAgent yes\n"
113 if use_adm_proxy:
114 out += u" ProxyCommand ssh %s -W %%h:%%p\n" % (adm_proxy)
115 if key.endswith("-ilo.adm"):
116 out += u" HostKeyAlgorithms ssh-rsa\n"
117 out += u"\n"
118 return out
119
120 def compute_ssh_config(servers):
121 """Affiche le ssh_config à partir de la liste de serveurs."""
122 # Un serveur "plouf.adm.crans.org" est adm-only si aucune clé "plouf", "plouf.ferme" n'existe
123 keys = servers.keys()
124 adm_only = {k : aliases for k, aliases in servers.items() if all([not k.replace(".adm", zone) in keys
125 for zone in [".ferme", ""]])}
126 # On veut pouvoir utiliser babar et pas seulement babar.adm
127 for k in adm_only.keys():
128 newk = k.replace(".adm", "")
129 if not newk in adm_only[k]:
130 adm_only[k] = [k.replace(".adm", "")] + adm_only[k]
131 for a in adm_only.keys():
132 del servers[a]
133 s = crans_header
134 keys = servers.keys()
135 keys.sort()
136 for h in keys:
137 s += output(h, servers[h])
138 s += crans_adm_header
139 keys = adm_only.keys()
140 keys.sort()
141 for h in keys:
142 s += output(h, adm_only[h], use_adm_proxy=True)
143 return s
144
145 if __name__ == '__main__':
146 try:
147 servers = load_servers()
148 except:
149 servers = get_servers()
150 cache_servers(servers)
151 servers = {h:aliases for h, aliases in servers.iteritems() if not blacklisted(h, aliases)}
152 out = compute_ssh_config(servers)
153 before = open(static_before_file).read().decode("utf-8")
154 after = open(static_after_file).read().decode("utf-8")
155 print (before + out + after).encode("utf-8")