Commit ef936b2a authored by Alain Takoudjou's avatar Alain Takoudjou

re6st recipe: Add script to revoke certificate when instance is destroyed

parent f45fa313
...@@ -96,7 +96,7 @@ class Recipe(GenericBaseRecipe): ...@@ -96,7 +96,7 @@ class Recipe(GenericBaseRecipe):
if not reference in token_dict: if not reference in token_dict:
# we generate new token # we generate new token
number = reference.split('-')[1] number = reference.split('-')[1]
new_token = number + ''.join(random.sample(string.ascii_lowercase, 15)) new_token = number + ''.join(random.sample(string.ascii_lowercase, 20))
token_dict[reference] = new_token token_dict[reference] = new_token
to_add_dict[reference] = new_token to_add_dict[reference] = new_token
...@@ -127,6 +127,17 @@ class Recipe(GenericBaseRecipe): ...@@ -127,6 +127,17 @@ class Recipe(GenericBaseRecipe):
return content return content
return '' return ''
def genHash(self, length):
hash_path = os.path.join(self.options['conf-dir'], '%s-hash' % length)
if not os.path.exists(hash_path):
pool = string.letters + string.digits
hash_string = ''.join(random.choice(pool) for i in xrange(length))
self.writeFile(hash_path, hash_string)
else:
hash_string = self.readFile(hash_path)
return hash_string
def install(self): def install(self):
path_list = [] path_list = []
token_save_path = os.path.join(self.options['conf-dir'], 'token.json') token_save_path = os.path.join(self.options['conf-dir'], 'token.json')
...@@ -156,7 +167,7 @@ class Recipe(GenericBaseRecipe): ...@@ -156,7 +167,7 @@ class Recipe(GenericBaseRecipe):
path = os.path.join(token_list_path, '%s.remove' % reference) path = os.path.join(token_list_path, '%s.remove' % reference)
if not os.path.exists(path): if not os.path.exists(path):
self.createFile(path, rm_token_dict[reference]) self.createFile(path, rm_token_dict[reference])
# remove request add file if exists # remove request add token if exists
add_path = os.path.join(token_list_path, '%s.add' % reference) add_path = os.path.join(token_list_path, '%s.add' % reference)
if os.path.exists(add_path): if os.path.exists(add_path):
os.unlink(add_path) os.unlink(add_path)
...@@ -191,6 +202,12 @@ class Recipe(GenericBaseRecipe): ...@@ -191,6 +202,12 @@ class Recipe(GenericBaseRecipe):
) )
path_list.append(request_check) path_list.append(request_check)
revoke_check = self.createPythonScript(
self.options['revoke-service-wrapper'].strip(),
'%s.re6stnet.requestRevoqueCertificate' % __name__, service_dict
)
path_list.append(revoke_check)
# Send connection parameters of slave instances # Send connection parameters of slave instances
if token_dict: if token_dict:
self.slap.initializeConnection(self.server_url, self.key_file, self.slap.initializeConnection(self.server_url, self.key_file,
...@@ -211,7 +228,7 @@ class Recipe(GenericBaseRecipe): ...@@ -211,7 +228,7 @@ class Recipe(GenericBaseRecipe):
computer_partition.setConnectionDict( computer_partition.setConnectionDict(
{'token':token, '1_info':msg}, {'token':token, '1_info':msg},
slave_reference) slave_reference)
except: except Exception:
self.logger.fatal("Error while sending slave %s informations: %s", self.logger.fatal("Error while sending slave %s informations: %s",
slave_reference, traceback.format_exc()) slave_reference, traceback.format_exc())
......
...@@ -5,8 +5,10 @@ import os ...@@ -5,8 +5,10 @@ import os
import time import time
import sqlite3 import sqlite3
import slapos import slapos
import traceback
from re6st import registry from re6st import registry, x509
from OpenSSL import crypto
log = logging.getLogger('SLAPOS-RE6STNET') log = logging.getLogger('SLAPOS-RE6STNET')
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
...@@ -50,6 +52,7 @@ def bang(args): ...@@ -50,6 +52,7 @@ def bang(args):
partition.bang(message='Published parameters changed!') partition.bang(message='Published parameters changed!')
log.info("Bang with message 'parameters changed'...") log.info("Bang with message 'parameters changed'...")
def requestAddToken(args, can_bang=True): def requestAddToken(args, can_bang=True):
time.sleep(3) time.sleep(3)
...@@ -69,12 +72,13 @@ def requestAddToken(args, can_bang=True): ...@@ -69,12 +72,13 @@ def requestAddToken(args, can_bang=True):
token = readFile(request_file) token = readFile(request_file)
if token : if token :
reference = reference_key.split('.')[0] reference = reference_key.split('.')[0]
# email is unique as reference is also unique
email = '%s@slapos' % reference.lower() email = '%s@slapos' % reference.lower()
try: try:
result = client.requestAddToken(token, email) result = client.requestAddToken(token, email)
except Exception, e: except Exception:
log.debug('Request add token fail for %s... \n %s' % (request_file, log.debug('Request add token fail for %s... \n %s' % (request_file,
str(e))) traceback.format_exc()))
continue continue
if result and result == token: if result and result == token:
# update information # update information
...@@ -97,7 +101,7 @@ def requestRemoveToken(args): ...@@ -97,7 +101,7 @@ def requestRemoveToken(args):
if not path_list: if not path_list:
log.info("No token to delete. Exiting...") log.info("No token to delete. Exiting...")
return return
client = registry.RegistryClient(args['registry_url']) client = registry.RegistryClient(args['registry_url'])
for reference_key in path_list: for reference_key in path_list:
request_file = os.path.join(base_token_path, reference_key) request_file = os.path.join(base_token_path, reference_key)
...@@ -106,23 +110,58 @@ def requestRemoveToken(args): ...@@ -106,23 +110,58 @@ def requestRemoveToken(args):
reference = reference_key.split('.')[0] reference = reference_key.split('.')[0]
try: try:
result = client.requestDeleteToken(token) result = client.requestDeleteToken(token)
except Exception, e: except Exception:
log.debug('Request delete token fail for %s... \n %s' % (request_file, log.debug('Request delete token fail for %s... \n %s' % (request_file,
str(e))) traceback.format_exc()))
continue continue
else:
# certificate is invalidated, it will be revoked
writeFile(os.path.join(base_token_path, '%s.revoke' % reference), '')
if result == 'True': if result == 'True':
# update information # update information
log.info("Token deleted for slave instance %s. Clean up file status..." % log.info("Token deleted for slave instance %s. Clean up file status..." %
reference) reference)
if result in ['True', 'False']:
os.unlink(request_file) os.unlink(request_file)
status_file = os.path.join(base_token_path, '%s.status' % reference) status_file = os.path.join(base_token_path, '%s.status' % reference)
if os.path.exists(status_file): if os.path.exists(status_file):
os.unlink(status_file) os.unlink(status_file)
else:
log.debug('Request delete token fail for %s...' % request_file)
else: else:
log.debug('Bad token. Request add token fail for %s...' % request_file) log.debug('Bad token. Request add token fail for %s...' % request_file)
def requestRevoqueCertificate(args):
base_token_path = args['token_base_path']
db = getDb(args['db'])
path_list = [x for x in os.listdir(base_token_path) if x.endswith('.revoke')]
client = registry.RegistryClient(args['registry_url'])
for reference_key in path_list:
reference = reference_key.split('.')[0]
# XXX - email is always unique
email = '%s@slapos' % reference.lower()
cert_string = ''
try:
cert_string, = db.execute("SELECT cert FROM cert WHERE email = ?",
(email,)).next()
except StopIteration:
# Certificate was not generated yet !!!
pass
try:
if cert_string:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_string)
cn = x509.subnetFromCert(cert)
result = client.revoke(str(cn))
time.sleep(2)
except Exception:
log.debug('Request revoke certificate fail for %s... \n %s' % (reference,
traceback.format_exc()))
continue
else:
os.unlink(os.path.join(base_token_path, reference_key))
log.info("Certificate revoked for slave instance %s." % reference)
def checkService(args, can_bang=True): def checkService(args, can_bang=True):
base_token_path = args['token_base_path'] base_token_path = args['token_base_path']
token_dict = loadJsonFile(args['token_json']) token_dict = loadJsonFile(args['token_json'])
...@@ -164,7 +203,7 @@ def checkService(args, can_bang=True): ...@@ -164,7 +203,7 @@ def checkService(args, can_bang=True):
time.sleep(1) time.sleep(1)
writeFile(status_file, 'TOKEN_USED') writeFile(status_file, 'TOKEN_USED')
log.info("Token status of %s updated to 'used'." % slave_reference) log.info("Token status of %s updated to 'used'." % slave_reference)
except IOError, e: except IOError:
# XXX- this file should always exists # XXX- this file should always exists
log.debug('Error when writing in file %s. Clould not update status of %s...' % log.debug('Error when writing in file %s. Clould not update status of %s...' %
(status_file, slave_reference)) (status_file, slave_reference))
...@@ -181,3 +220,4 @@ def manage(args): ...@@ -181,3 +220,4 @@ def manage(args):
# check status of all token # check status of all token
checkService(args) checkService(args)
...@@ -36,6 +36,7 @@ class Re6stnetTest(unittest.TestCase): ...@@ -36,6 +36,7 @@ class Re6stnetTest(unittest.TestCase):
'manager-wrapper': os.path.join(self.base_dir, 'manager_wrapper'), 'manager-wrapper': os.path.join(self.base_dir, 'manager_wrapper'),
'drop-service-wrapper': os.path.join(self.base_dir, 'drop_wrapper'), 'drop-service-wrapper': os.path.join(self.base_dir, 'drop_wrapper'),
'check-service-wrapper': os.path.join(self.base_dir, 'check_wrapper'), 'check-service-wrapper': os.path.join(self.base_dir, 'check_wrapper'),
'revoke-service-wrapper': os.path.join(self.base_dir, 'revoke_wrapper'),
'slave-instance-list': '{}' 'slave-instance-list': '{}'
} }
...@@ -96,7 +97,7 @@ class Re6stnetTest(unittest.TestCase): ...@@ -96,7 +97,7 @@ class Re6stnetTest(unittest.TestCase):
with open(path, 'r') as f: with open(path, 'r') as f:
content = f.read() content = f.read()
self.assertIn("@%s" % config_file, content) self.assertIn("@%s" % config_file, content)
def test_generateCertificates(self): def test_generateCertificates(self):
self.options['ipv6-prefix'] = '2001:db8:24::/48' self.options['ipv6-prefix'] = '2001:db8:24::/48'
...@@ -175,6 +176,7 @@ class Re6stnetTest(unittest.TestCase): ...@@ -175,6 +176,7 @@ class Re6stnetTest(unittest.TestCase):
self.checkWrapper(os.path.join(self.base_dir, 'manager_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'manager_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'drop_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'drop_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'check_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'check_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'revoke_wrapper'))
self.checkRegistryWrapper() self.checkRegistryWrapper()
# Remove one element # Remove one element
...@@ -218,5 +220,6 @@ class Re6stnetTest(unittest.TestCase): ...@@ -218,5 +220,6 @@ class Re6stnetTest(unittest.TestCase):
self.checkWrapper(os.path.join(self.base_dir, 'manager_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'manager_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'drop_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'drop_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'check_wrapper')) self.checkWrapper(os.path.join(self.base_dir, 'check_wrapper'))
self.checkWrapper(os.path.join(self.base_dir, 'revoke_wrapper'))
self.checkRegistryWrapper() self.checkRegistryWrapper()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment