3 # Bootstraps the PLC database with a default administrator account and
4 # a default site. Also generates the MA/SA API certificate.
6 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2006 The Trustees of Princeton University
9 # $Id: api-config,v 1.12 2006/05/30 15:06:20 mlhuang Exp $
12 from plc_config import PLCConfiguration
16 import CertOps, Certificate
22 cfg = PLCConfiguration()
24 variables = cfg.variables()
26 # Load variables into dictionaries
27 for category_id, (category, variablelist) in variables.iteritems():
28 globals()[category_id] = dict(zip(variablelist.keys(),
29 [variable['value'] for variable in variablelist.values()]))
31 # Get the issuer e-mail address of the root CA certificate
32 root_ca_email = commands.getoutput("openssl x509 -in %s -noout -email" % \
33 plc['root_ca_ssl_crt'])
35 # Verify API certificate
36 if os.path.exists(plc_ma_sa['api_crt']):
37 print "Verifying API certificate '%s'" % plc_ma_sa['api_crt']
39 cert_xml = file(plc_ma_sa['api_crt']).read().strip()
40 # Verify root CA signature
41 CertOps.authenticate_cert(cert_xml,
43 file(plc['root_ca_ssl_key_pub']).read().strip()})
44 # Check if MA/SA e-mail address has changed
45 dom = xml.dom.minidom.parseString(cert_xml)
46 for issuer in dom.getElementsByTagName('issuer'):
47 if issuer.getAttribute('email') != plc_mail['support_address']:
48 raise Exception, "E-mail address '%s' in certificate '%s' does not match support address '%s'" % \
49 (issuer.getAttribute('email'), plc_ma_sa['api_crt'], plc_mail['support_address'])
51 # Delete invalid API certificate
53 os.unlink(plc_ma_sa['api_crt'])
55 # Generate API certificate
56 if not os.path.exists(plc_ma_sa['api_crt']):
57 print "Generating new API certificate"
59 cert = Certificate.Certificate('ticket-cert-0')
60 ma_sa_ssl_key_pub = file(plc_ma_sa['ssl_key_pub']).read().strip()
61 cert.add_subject_pubkey(pubkey = ma_sa_ssl_key_pub, email = plc_mail['support_address'])
62 root_ca_subject = commands.getoutput("openssl x509 -in %s -noout -subject" % \
63 plc['root_ca_ssl_crt'])
64 m = re.search('/CN=([^/]*).*', root_ca_subject)
66 root_ca_cn = plc['name'] + " Root CA"
68 root_ca_cn = m.group(1)
69 cert.set_issuer(email = root_ca_email, cn = root_ca_cn)
70 cert_xml = cert.sign(plc['root_ca_ssl_key'])
71 ma_sa_api_crt = file(plc_ma_sa['api_crt'], "w")
72 ma_sa_api_crt.write(cert_xml)
75 print "Warning: Could not generate API certificate: ", e
77 # For backward compatibility, until we can convert all code to use
78 # the now standardized variable names.
80 # API expects root SSH public key to be at /etc/planetlab/node_root_key
81 if not os.path.exists("/etc/planetlab/node_root_key"):
82 os.symlink(plc['root_ssh_key_pub'], "/etc/planetlab/node_root_key")
84 # Old variable names littered throughout the API
85 old_variables = {'PL_API_SERVER': plc_api['host'],
86 'PL_API_PATH': plc_api['path'],
87 'PL_API_PORT': plc_api['port'],
88 'PL_API_CAPABILITY_AUTH_METHOD': "capability",
89 'PL_API_CAPABILITY_PASS': plc_api['maintenance_password'],
90 'PL_API_CAPABILITY_USERNAME': plc_api['maintenance_user'],
91 'PLANETLAB_SUPPORT_EMAIL': plc_mail['support_address'],
92 'BOOT_MESSAGES_EMAIL': plc_mail['boot_address'],
93 'WWW_BASE': plc_www['host'],
94 'BOOT_BASE': plc_boot['host'],
96 'MA_SA_NAMESPACE': plc_ma_sa['namespace'],
97 'SESSION_LENGTH_HOURS': "24",
98 'ROOT_CA_EMAIL': root_ca_email,
99 'ROOT_CA_PUB_KEY': plc['root_ca_ssl_key_pub'],
100 'API_CERT_PATH': plc_ma_sa['api_crt'],
101 'MA_SA_PRIVATE_KEY': plc_ma_sa['ssl_key'],
102 'PL_API_TICKET_KEY_FILE': plc_ma_sa['ssl_key']}
104 # The format of an "allowed maintenance source" specification is
106 # ip:max_role_id:organization_id:password
108 # It is unlikely that we will let federated sites use the
109 # maintenance account to access each others' APIs, so we always
110 # set organization_id to -1.
111 old_variables['PL_API_CAPABILITY_SOURCES'] = " ".join(
112 ["%s:-1:-1:%s" % (ip, plc_api['maintenance_password']) \
113 for ip in plc_api['maintenance_sources'].split()])
115 old_config = open("/etc/planetlab/plc_api", "w")
116 for name, value in old_variables.iteritems():
117 old_config.write("%s='%s'\n" % (name, value))
121 if __name__ == '__main__':