forked from seveas/python-hpilo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hpilo_ca
executable file
·253 lines (224 loc) · 9.67 KB
/
hpilo_ca
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#!/usr/bin/python
try:
import ConfigParser
except ImportError:
import configparser as ConfigParser
import hpilo
import optparse
import os
import subprocess
import sys
import time
def main():
usage = """%prog [options] init
%prog [options] sign hostname [hostname ...]"""
p = optparse.OptionParser(usage=usage)
p.add_option("-l", "--login", dest="login", default=None,
help="Username to access the iLO")
p.add_option("-p", "--password", dest="password", default=None,
help="Password to access the iLO")
p.add_option("-c", "--config", dest="config", default="~/.ilo.conf",
help="File containing authentication and config details", metavar="FILE")
p.add_option("-t", "--timeout", dest="timeout", type="int", default=60,
help="Timeout for iLO connections")
p.add_option("-P", "--protocol", dest="protocol", choices=("http","raw"), default=None,
help="Use the specified protocol instead of autodetecting")
p.add_option("-d", "--debug", dest="debug", action="count", default=0,
help="Output debug information, repeat to see all XML data")
p.add_option("-o", "--port", dest="port", type="int", default=443,
help="SSL port to connect to")
p.add_option("-s", "--openssl", dest="openssl_bin", default="/usr/bin/openssl",
help="Path to the openssl binary")
p.add_option("-u", "--upgrade", dest="upgrade", action="store_true", default=False,
help="Upgrade iLO firmware that is too old automatically")
opts, args = p.parse_args()
if not args or args[0] not in ('init','sign'):
p.print_help()
p.exit(1)
if not os.path.exists(os.path.expanduser(opts.config)):
p.error("COnfiguration file does not exist")
config = ConfigParser.ConfigParser()
config.read(os.path.expanduser(opts.config))
if not config.has_option('ca', 'path'):
p.error("No CA path specified in the config")
ca_path = os.path.expanduser(config.get('ca', 'path'))
os.environ['CA_PATH'] = ca_path
openssl_cnf = os.path.join(ca_path, 'openssl.cnf')
openssl = OpenSSL(opts.openssl_bin, openssl_cnf)
if args[0] == 'init':
if len(args) > 2:
p.error("Too many arguments")
if not os.path.exists(ca_path):
os.makedirs(ca_path)
if not os.path.exists(openssl_cnf):
open(openssl_cnf, 'w').write(default_openssl_cnf)
for dir in ('ca', 'certs', 'crl', 'archive'):
if not os.path.exists(os.path.join(ca_path, dir)):
os.mkdir(os.path.join(ca_path, dir))
if not os.path.exists(os.path.join(ca_path, 'archive', 'index')):
open(os.path.join(ca_path, 'archive', 'index'),'w').close()
if not os.path.exists(os.path.join(ca_path, 'archive', 'serial')):
fd = open(os.path.join(ca_path, 'archive', 'serial'),'w')
fd.write("00\n")
fd.close()
if not os.path.exists(os.path.join(ca_path, 'ca', 'hpilo_ca.key')):
openssl('genrsa', '-out', os.path.join(ca_path, 'ca', 'hpilo_ca.key'), '2048')
if not os.path.exists(os.path.join(ca_path, 'ca', 'hpilo_ca.crt')):
openssl('req', '-new', '-x509', '-days', '7300', # 20 years should be enough for everyone :-)
'-key', os.path.join(ca_path, 'ca', 'hpilo_ca.key'),
'-out', os.path.join(ca_path, 'ca', 'hpilo_ca.crt'))
sys.exit(0)
# Do we have login information
login = None
password = None
if config.has_option('ilo', 'login'):
login = config.get('ilo', 'login')
if config.has_option('ilo', 'password'):
password = config.get('ilo', 'password')
if opts.login:
login = opts.login
if opts.password:
password = opts.password
if not login or not password:
p.error("No login details provided")
for hostname in args[1:]:
csr_path = os.path.join(ca_path, 'certs', hostname + '.csr')
crt_path = os.path.join(ca_path, 'certs', hostname + '.crt')
if os.path.exists(crt_path):
print("Certificate already signed, skipping")
continue
ilo = hpilo.Ilo(hostname, login, password, opts.timeout, opts.port)
ilo.debug = opts.debug
if opts.protocol == 'http':
ilo.protocol = hpilo.ILO_HTTP
elif opts.protocol == 'raw':
ilo.protocol = hpilo.ILO_RAW
print("(1/5) Checking certificate config of %s" % hostname)
fw_version = ilo.get_fw_version()
if fw_version['management_processor'] == 'iLO2':
version = fw_version['firmware_version']
i_version = [int(x) for x in version.split('.')]
if i_version < [2,6]:
print("iLO2 firmware version %s is too old" % version)
if not opts.upgrade:
print("Please upgrade firmware to 2.06 or newer")
continue
if not config.has_option('firmware', 'ilo2'):
print("Cannot upgrade firmware, no firmware specified in the config")
continue
print("Upgrading iLO firmware")
ilo.update_rib_firmware(config.get('firmware', 'ilo2'), print_progress)
print("Waiting a minute to let firmware upgrade settle...")
time.sleep(60)
cn = ilo.get_cert_subject_info()['csr_subject_common_name']
if '.' not in cn:
ilo.cert_fqdn(use_fqdn=True)
cn = ilo.get_cert_subject_info()['csr_subject_common_name']
if cn != hostname:
print("Hostname (%s) and CN (%s) do not match, fixing" % (hostname, cn))
ilo.mod_network_settings(dns_name=hostname[:hostname.find('.')])
print("Waiting a minute to let the iLO reset itself")
time.sleep(60)
elif fw_version['management_processor'] == 'iLO3':
cn = ilo.get_network_settings()['dns_name']
if cn != hostname[:hostname.find('.')]:
print("Hostname (%s) and CN (%s) do not match, fixing" % (hostname, cn))
ilo.mod_network_settings(dns_name=hostname[:hostname.find('.')])
print("Waiting a minute to let the iLO reset itself")
time.sleep(60)
else:
print("hpilo_ca cannot manage certificates for %s, only iLO2 and iLO3 are supported" % (fw_version['management_processor'], hostname))
continue
print("(2/5) Retrieving certificate signing request")
csr = ilo.certificate_signing_request()
fd = open(csr_path, 'w')
fd.write(csr)
fd.close()
print("(3/5) Signing certificate")
openssl('ca', '-batch', '-in', csr_path, '-out', crt_path)
print("(4/5) Uploading certificate")
fd = open(crt_path)
cert = fd.read()
fd.close()
cert = cert[cert.find('-----BEGIN'):]
ilo.import_certificate(cert)
print("(5/5) Resetting iLO")
ilo.reset_rib()
class OpenSSL(object):
def __init__(self, openssl_bin, openssl_cnf):
self.openssl_bin = openssl_bin
self.openssl_cnf = openssl_cnf
def __call__(self, *args):
args = list(args)
if args[0] in ('req', 'ca'):
args = args[:1] + ['-config', self.openssl_cnf] + args[1:]
return subprocess.call([self.openssl_bin] + args)
default_openssl_cnf = """default_ca = hpilo_ca
[hpilo_ca]
dir = $ENV::CA_PATH
certs = $dir/certs
crl_dir = $dir/crl
private_key = $dir/ca/hpilo_ca.key
certificate = $dir/ca/hpilo_ca.crt
database = $dir/archive/index
new_certs_dir = $dir/archive
serial = $dir/archive/serial
crlnumber = $dir/crl/crlnumber
crl = $dir/crl/crl.pem
RANDFILE = $dir/.rand
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = 1825 # 5 years
default_crl_days = 30
default_md = sha1
preserve = no
policy = req_policy
[req_policy]
countryName = supplied
stateOrProvinceName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
dir = $ENV::CA_PATH
default_bits = 2048
default_md = sha1
default_keyfile = $dir/ca/hpilo_ca.key
distinguished_name = req_distinguished_name
x509_extensions = ca_cert # The extentions to add to the self signed cert
string_mask = MASK:0x2002
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = NL
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Flevoland
localityName = Locality Name (eg, city)
localityName_default = Lelystad
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Kaarsemaker.net
commonName = Common Name (eg, your name or your server's hostname)
commonName_max = 64
commonName_default = hpilo_ca
[usr_cert]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
nsComment = "Certificate generated by iLO CA"
[ca_cert]
basicConstraints = CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
nsComment = "Certificate generated by iLO CA"
"""
def print_progress(text):
if text.startswith('\r'):
sys.stdout.write(text)
sys.stdout.flush()
else:
print(text)
if __name__ == '__main__':
main()