def ensure_postgresql_db(db_name='wapt',db_owner='wapt',db_password=''): """ create postgresql wapt db and user if it does not exists """ if type_redhat(): # we have to check what postgres we use between the upstream packages and the software collection ones pass elif type_debian(): run('systemctl start postgresql') run('systemctl enable postgresql') val = run(""" sudo -u postgres psql template1 -c " select usename from pg_catalog.pg_user where usename='wapt';" """, cwd='/opt/wapt') if 'wapt' in val: print ("user wapt already exists, skipping creating user ") else: print ("we suppose that the db does not exist either (or the installation has been screwed up") if not db_password: run(""" sudo -u postgres psql template1 -c "create user %s ; " """ % (db_owner), cwd='/opt/wapt/') else: run(""" sudo -u postgres psql template1 -c "create user %s with password '%s'; " """ % (db_owner,db_password), cwd='/opt/wapt/') val = '' #val = subprocess.check_output(""" sudo -u postgres psql template1 -c "select schema_name from information_schema.schemata where schema_name='wapt'; " """, shell= True) val = run(""" sudo -u postgres psql template1 -c " SELECT datname FROM pg_database WHERE datname='wapt'; " """, cwd='/opt/wapt/') if 'wapt' in val: print ("db already exists, skipping db creation") else: print ('creating db wapt') run(""" sudo -u postgres psql template1 -c "create database %s with owner=%s encoding='utf-8'; " """ % (db_name,db_owner), cwd='/opt/wapt/') # check if hstore (for json) is installed val = run(""" sudo -u postgres psql wapt -c "select * from pg_extension where extname='hstore';" """, cwd='/opt/wapt/') if 'hstore' in val: print ("hstore extension already loading into database, skipping create extension") else: run(""" sudo -u postgres psql wapt -c "CREATE EXTENSION hstore;" """, cwd='/opt/wapt/')
def setup_firewall(): """ Add permanent rules for firewalld """ if type_redhat(): output = run('firewall-cmd --list-ports') if '443/tcp' in output and '80/tcp' in output: print("[*] Firewall already configured, skipping firewalld configuration") elif subprocess.call(['firewall-cmd', '--state'], stdout=open(os.devnull, 'w')) == 0: run('firewall-cmd --permanent --add-port=443/tcp') run('firewall-cmd --permanent --add-port=80/tcp') run('firewall-cmd --reload') else: run('firewall-offline-cmd --add-port=443/tcp') run('firewall-offline-cmd --add-port=80/tcp')
def setup_firewall(): """ Add permanent rules for firewalld """ if type_redhat(): output = run('firewall-cmd --list-ports') if '443/tcp' in output and '80/tcp' in output: print("[*] Firewall already configured, skipping firewalld configuration") return if subprocess.call(['firewall-cmd', '--state'], stdout=open(os.devnull, 'w')) == 0: run('firewall-cmd --permanent --add-port=443/tcp') run('firewall-cmd --permanent --add-port=80/tcp') run('firewall-cmd --reload') else: run('firewall-offline-cmd --add-port=443/tcp') run('firewall-offline-cmd --add-port=80/tcp')
def main(): global wapt_folder, NGINX_GID parser = OptionParser(usage=usage, version=__version__) parser.add_option('-c', '--config', dest='configfile', default=waptserver.config.DEFAULT_CONFIG_FILE, help='Config file full path (default: %default)') parser.add_option( "-s", "--force-https", dest="force_https", default=False, action='store_true', help= "Use https only, http is 301 redirected to https (default: False). Requires a proper DNS name" ) parser.add_option( '-q', '--quiet', dest='quiet', default=False, action="store_true", help= 'Run quiet postconfiguration - default password and simple behavior') (options, args) = parser.parse_args() quiet = options.quiet if not quiet: if postconf.yesno("Do you want to launch post configuration tool ?" ) != postconf.DIALOG_OK: print("canceling wapt postconfiguration") sys.exit(1) else: print('WAPT silent post-configuration') # SELinux rules for CentOS/RedHat if type_redhat(): if re.match('^SELinux status:.*enabled', run('sestatus')): if not quiet: postconf.msgbox( 'SELinux detected, tweaking httpd permissions.') selinux_rules() postconf.msgbox( 'SELinux correctly configured for Nginx reverse proxy') else: print('[*] Redhat/Centos detected, tweaking SELinux rules') selinux_rules() print( '[*] Nginx - SELinux correctly configured for Nginx reverse proxy' ) # Load existing config file server_config = waptserver.config.load_config(options.configfile) if os.path.isfile(options.configfile): print('[*] Making a backup copy of the configuration file') datetime_now = datetime.datetime.now() shutil.copyfile( options.configfile, '%s.bck_%s' % (options.configfile, datetime_now.isoformat())) wapt_folder = server_config['wapt_folder'] # add secret key initialisation string (for session token) if not server_config['secret_key']: server_config['secret_key'] = ''.join( random.SystemRandom().choice(string.letters + string.digits) for _ in range(64)) # add user db and password in ini file if server_config['db_host'] in (None, '', 'localhost', '127.0.0.1', '::1'): ensure_postgresql_db(db_name=server_config['db_name'], db_owner=server_config['db_name'], db_password=server_config['db_password']) # Password setup/reset screen if not quiet: if not server_config['wapt_password'] or \ postconf.yesno("Do you want to reset admin password ?",yes_label='skip',no_label='reset') != postconf.DIALOG_OK: wapt_password_ok = False while not wapt_password_ok: wapt_password = '' wapt_password_check = '' while wapt_password == '': (code, wapt_password) = postconf.passwordbox( "Please enter the wapt server password (min. 10 characters): ", insecure=True, width=100) if code != postconf.DIALOG_OK: exit(0) while wapt_password_check == '': (code, wapt_password_check) = postconf.passwordbox( "Please enter the wapt server password again: ", insecure=True, width=100) if code != postconf.DIALOG_OK: exit(0) if wapt_password != wapt_password_check: postconf.msgbox('Password mismatch !') elif len(wapt_password) < 10: postconf.msgbox( 'Password must be at least 10 characters long !') else: wapt_password_ok = True password = pbkdf2_sha256.hash(wapt_password.encode('utf8')) server_config['wapt_password'] = password else: wapt_password = '' if not server_config['wapt_password']: print('[*] Generating random password for WAPT server') wapt_password = pwd.genword(entropy=56, charset="ascii_62") print('[*] WAPT admin password : %s' % wapt_password) password = pbkdf2_sha256.hash(wapt_password.encode('utf8')) server_config['wapt_password'] = password if not server_config['server_uuid']: server_config['server_uuid'] = str(uuid.uuid1()) # waptagent authentication method if not quiet: choices = [ ("1", "Allow unauthenticated registration, same behavior as WAPT 1.3", True), ("2", "Enable kerberos authentication required for machines registration", False), ("3", "Disable Kerberos but registration require strong authentication", False), ] code, t = postconf.radiolist("WaptAgent Authentication type?", choices=choices, width=120) if code == 'cancel': print("\n\npostconfiguration canceled\n\n") sys.exit(1) if t == "1": server_config['allow_unauthenticated_registration'] = True server_config['use_kerberos'] = False if t == "2": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = True if t == "3": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = False else: print( '[*] Set default registration method to : Allow anyone to register + Kerberos disabled' ) server_config['allow_unauthenticated_registration'] = True server_config['use_kerberos'] = False # Guess fqdn using socket fqdn = guess_fqdn() clients_signing_certificate = server_config.get( 'clients_signing_certificate') clients_signing_key = server_config.get('clients_signing_key') clients_signing_crl = server_config.get('clients_signing_crl') if not clients_signing_certificate or not clients_signing_key: clients_signing_certificate = os.path.join(wapt_root_dir, 'conf', 'ca-%s.crt' % fqdn) clients_signing_key = os.path.join(wapt_root_dir, 'conf', 'ca-%s.pem' % fqdn) server_config[ 'clients_signing_certificate'] = clients_signing_certificate server_config['clients_signing_key'] = clients_signing_key if clients_signing_certificate is not None and clients_signing_key is not None and not os.path.isfile( clients_signing_certificate): print('Create a certificate and key for clients certificate signing') key = SSLPrivateKey(clients_signing_key) if not os.path.isfile(clients_signing_key): print('Create SSL RSA Key %s' % clients_signing_key) key.create() key.save_as_pem() crt = key.build_sign_certificate(cn=fqdn, is_code_signing=False, is_ca=True) print('Create X509 cert %s' % clients_signing_certificate) crt.save_as_pem(clients_signing_certificate) if clients_signing_certificate is not None and clients_signing_key is not None and clients_signing_crl is not None and not os.path.isfile( clients_signing_crl): print('Create a CRL for clients certificate signing') key = SSLPrivateKey(clients_signing_key) crt = SSLCertificate(clients_signing_certificate) crl = SSLCRL(clients_signing_crl, cacert=crt, cakey=key) crl.revoke_cert() crl.save_as_pem() waptserver.config.write_config_file(cfgfile=options.configfile, server_config=server_config, non_default_values_only=True) print('[*] Protecting WAPT config file') run("/bin/chmod 640 %s" % options.configfile) run("/bin/chown wapt %s" % options.configfile) print('[*] Update WAPT repository') repo = WaptLocalRepo(wapt_folder) repo.update_packages_index(force_all=True) final_msg = [ '[*] Postconfiguration completed.', ] if not quiet: postconf.msgbox("Press ok to start waptserver and wapttasks daemons") enable_waptserver() start_waptserver() # In this new version Apache is replaced with Nginx? Proceed to disable Apache. After migration one can remove Apache install altogether stop_disable_httpd() # Nginx configuration if quiet: try: generate_dhparam() nginx_cleanup() make_httpd_config('/opt/wapt/waptserver', fqdn, options.force_https, server_config) enable_nginx() restart_nginx() setup_firewall() except subprocess.CalledProcessError as cpe: final_msg += [ 'Error while trying to configure Nginx!', 'errno = ' + str(cpe.returncode) + ', output: ' + cpe.output ] except Exception as e: import traceback final_msg += [ 'Error while trying to configure Nginx!', traceback.format_exc() ] else: reply = postconf.yesno("Do you want to configure nginx?") if reply == postconf.DIALOG_OK: try: msg = 'FQDN for the WAPT server (eg. wapt.acme.com)' (code, reply) = postconf.inputbox(text=msg, width=len(msg) + 4, init=fqdn) if code != postconf.DIALOG_OK: exit(1) else: fqdn = reply generate_dhparam() nginx_cleanup() if server_config['use_kerberos']: if type_debian(): if not check_if_deb_installed( 'libnginx-mod-http-auth-spnego'): print( '[*] Nginx - Missing dependency libnginx-mod-http-auth-spnego, please install first before configuring kerberos' ) sys.exit(1) make_httpd_config('/opt/wapt/waptserver', fqdn, options.force_https, server_config) final_msg.append('Please connect to https://' + fqdn + '/ to access the server.') postconf.msgbox( "The Nginx config is done. We need to restart Nginx?") run_verbose('systemctl enable nginx') run_verbose('systemctl restart nginx') setup_firewall() except subprocess.CalledProcessError as cpe: final_msg += [ 'Error while trying to configure Nginx!', 'errno = ' + str(cpe.returncode) + ', output: ' + cpe.output ] except Exception as e: import traceback final_msg += [ 'Error while trying to configure Nginx!', traceback.format_exc() ] # known certificates ssl_dir = server_config['known_certificates_folder'] if not os.path.isdir(ssl_dir): # move existing ssl dir in wapt repo to parent dir (default location) if os.path.isdir(os.path.join(server_config['wapt_folder'], 'ssl')): shutil.move(os.path.join(server_config['wapt_folder'], 'ssl'), ssl_dir) else: os.makedirs(ssl_dir) #Migrate file for new version waptwua wuafolder = server_config['waptwua_folder'] for (root, dirs, files) in list(os.walk(wuafolder, topdown=False)): if root == os.path.join(wuafolder, '.stfolder'): continue for f in files: oldpath = os.path.join(root, f) newpath = os.path.join(wuafolder, f) if os.path.isfile(newpath): continue print('Move %s --> %s' % (oldpath, newpath)) shutil.move(oldpath, newpath) for d in dirs: if d == '.stfolder': continue print('Delete folder %s' % os.path.join(root, d)) shutil.rmtree(os.path.join(root, d)) final_msg.append('Please connect to https://' + fqdn + '/ to access the server.') # Check if Mongodb > PostgreSQL migration is necessary if not quiet: if check_mongo2pgsql_upgrade_needed(options.configfile) and\ postconf.yesno("It is necessary to migrate current database backend from mongodb to postgres. Press yes to start migration",no_label='cancel') == postconf.DIALOG_OK: upgrade2postgres(options.configfile) else: if check_mongo2pgsql_upgrade_needed(options.configfile): upgrade2postgres(options.configfile) WAPT_UID = good_pwd.getpwnam('wapt').pw_uid # CHOWN of waptservertasks.sqlite it seems to be created before location_waptservertasks = os.path.join(wapt_root_dir, 'db', 'waptservertasks.sqlite') if os.path.isfile(location_waptservertasks): os.chown(location_waptservertasks, WAPT_UID, os.stat(location_waptservertasks).st_gid) # Create empty sync.json and rules.json file for all installations sync_json = os.path.join( os.path.abspath(os.path.join(wapt_folder, os.pardir)), u'sync.json') rules_json = os.path.join( os.path.abspath(os.path.join(wapt_folder, os.pardir)), u'rules.json') diff_rules_dir = wapt_folder + u'-diff-repos/' paths_to_modify = [ sync_json, rules_json, wapt_folder + '/', wuafolder + '/', diff_rules_dir, ssl_dir + '/' ] for apath in paths_to_modify: if os.path.isdir(apath): os.chown(apath, WAPT_UID, NGINX_GID) os.chmod(apath, 0o750) for root, dirs, files in os.walk(apath): for d in dirs: full_path = os.path.join(root, d) os.chown(full_path, WAPT_UID, NGINX_GID) os.chmod(full_path, 0o750) for f in files: full_path = os.path.join(root, f) os.chown(full_path, WAPT_UID, NGINX_GID) os.chmod(full_path, 0o640) else: if apath.endswith('/'): os.mkdir(apath) os.chmod(apath, 0o750) else: if not (os.path.isfile(apath)): with open(apath, 'w'): pass os.chmod(apath, 0o640) os.chown(apath, WAPT_UID, NGINX_GID) # Final message if not quiet: width = 4 + max(10, len(max(final_msg, key=len))) height = 2 + max(20, len(final_msg)) postconf.msgbox('\n'.join(final_msg), height=height, width=width) else: if wapt_password: final_msg.append('[*] WAPT admin password : %s\n' % wapt_password) for line in final_msg: print(line)
def make_httpd_config(waptserver_root_dir, fqdn, force_https, server_config): ssl_dir = os.path.join(waptserver_root_dir, 'ssl') scripts_dir = os.path.join(waptserver_root_dir, 'scripts') wapt_ssl_key_file = os.path.join(ssl_dir, 'key.pem') wapt_ssl_cert_file = os.path.join(ssl_dir, 'cert.pem') mkdir(ssl_dir) # write the apache configuration fragment jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(scripts_dir)) template = jinja_env.get_template('wapt.nginxconfig.template') krb5_realm = '.'.join(fqdn.split('.')[1:]).upper() template_vars = { 'waptserver_port': server_config['waptserver_port'], 'wapt_repository_path': os.path.dirname(server_config['wapt_folder']), 'windows': False, 'debian': type_debian(), 'redhat': type_redhat(), 'force_https': force_https, 'wapt_ssl_key_file': wapt_ssl_key_file, 'wapt_ssl_cert_file': wapt_ssl_cert_file, 'fqdn': fqdn, 'use_kerberos': server_config.get('use_kerberos', False), 'KRB5_REALM': krb5_realm, 'wapt_root_dir': wapt_root_dir, 'use_ssl_client_auth': server_config.get('use_ssl_client_auth', False), 'clients_signing_certificate': server_config.get('clients_signing_certificate'), 'known_certificates_folder': server_config.get('known_certificates_folder', None), 'clients_signing_crl': server_config.get('clients_signing_crl', None), 'htpasswd_path': server_config.get('htpasswd_path', None), } if quiet: print('[*] Nginx - creating wapt.conf virtualhost') config_string = template.render(template_vars) if type_debian(): dst_file = file('/etc/nginx/sites-available/wapt.conf', 'wt') if not os.path.exists('/etc/nginx/sites-enabled/wapt.conf'): print( subprocess.check_output( 'ln -s /etc/nginx/sites-available/wapt.conf /etc/nginx/sites-enabled/wapt.conf', shell=True)) if os.path.exists('/etc/nginx/sites-enabled/default'): os.unlink('/etc/nginx/sites-enabled/default') elif type_redhat(): dst_file = file('/etc/nginx/conf.d/wapt.conf', 'wt') dst_file.write(config_string) dst_file.close() # create keys for https:// access if not os.path.exists(wapt_ssl_key_file) or \ not os.path.exists(wapt_ssl_cert_file): if quiet: print('[*] Nginx - generate self-signed certs') old_apache_key = '/opt/wapt/waptserver/apache/ssl/key.pem' old_apache_cert = '/opt/wapt/waptserver/apache/ssl/cert.pem' if os.path.isfile(old_apache_cert) and os.path.isfile(old_apache_key): shutil.copyfile(old_apache_cert, wapt_ssl_cert_file) shutil.copyfile(old_apache_key, wapt_ssl_key_file) else: key = SSLPrivateKey(wapt_ssl_key_file) if not os.path.isfile(wapt_ssl_key_file): print('Create SSL RSA Key %s' % wapt_ssl_key_file) key.create() key.save_as_pem() if os.path.isfile(wapt_ssl_cert_file): crt = SSLCertificate(wapt_ssl_cert_file) if crt.cn != fqdn: shutil.move( wapt_ssl_cert_file, "%s-%s.old" % (wapt_ssl_cert_file, '{:%Y%m%d-%Hh%Mm%Ss}'.format( datetime.datetime.now()))) crt = key.build_sign_certificate(cn=fqdn, dnsname=fqdn, is_code_signing=False) print('Create X509 cert %s' % wapt_ssl_cert_file) crt.save_as_pem(wapt_ssl_cert_file) else: crt = key.build_sign_certificate(cn=fqdn, dnsname=fqdn, is_code_signing=False) print('Create X509 cert %s' % wapt_ssl_cert_file) crt.save_as_pem(wapt_ssl_cert_file) else: if quiet: print('[*] Nginx - self-signed certs already exists, skipping...')
return subprocess.check_output(*args, shell=True, **kwargs) def run_verbose(*args, **kwargs): output = subprocess.check_output(*args, shell=True, **kwargs) print(output) return output if type_debian(): MONGO_SVC = 'mongodb' APACHE_SVC = 'apache2' PGSQL_SVC = 'postgresql' wapt_folder = '/var/www/wapt' NGINX_GID = grp.getgrnam('www-data').gr_gid elif type_redhat(): MONGO_SVC = 'mongod' APACHE_SVC = 'httpd' PGSQL_SVC = 'postgresql-9.6' wapt_folder = '/var/www/html/wapt' NGINX_GID = grp.getgrnam('nginx').gr_gid else: print("distrib type unknown") sys.exit(1) quiet = False postconf = dialog.Dialog(dialog="dialog") def mkdir(path): if not os.path.isdir(path):
def make_httpd_config(waptserver_root_dir, fqdn, force_https, server_config): ssl_dir = os.path.join(waptserver_root_dir, 'ssl') scripts_dir = os.path.join(waptserver_root_dir, 'scripts') wapt_ssl_key_file = os.path.join(ssl_dir,'key.pem') wapt_ssl_cert_file = os.path.join(ssl_dir,'cert.pem') mkdir(ssl_dir) # write the apache configuration fragment jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(scripts_dir)) template = jinja_env.get_template('wapt.nginxconfig.template') krb5_realm = '.'.join(fqdn.split('.')[1:]).upper() template_vars = { 'waptserver_port': server_config['waptserver_port'], 'wapt_repository_path': os.path.dirname(server_config['wapt_folder']), 'windows': False, 'debian': type_debian(), 'redhat': type_redhat(), 'force_https': force_https, 'wapt_ssl_key_file': wapt_ssl_key_file, 'wapt_ssl_cert_file': wapt_ssl_cert_file, 'fqdn': fqdn, 'use_kerberos': server_config.get('use_kerberos',False), 'KRB5_REALM': krb5_realm, 'wapt_root_dir': wapt_root_dir, 'clients_signing_certificate' : server_config.get('clients_signing_certificate'), 'use_ssl_client_auth' : server_config.get('use_ssl_client_auth',False) } if quiet: print('[*] Nginx - creating wapt.conf virtualhost') config_string = template.render(template_vars) if type_debian(): dst_file = file('/etc/nginx/sites-available/wapt.conf', 'wt') if not os.path.exists('/etc/nginx/sites-enabled/wapt.conf'): print(subprocess.check_output('ln -s /etc/nginx/sites-available/wapt.conf /etc/nginx/sites-enabled/wapt.conf',shell=True)) if os.path.exists('/etc/nginx/sites-enabled/default'): os.unlink('/etc/nginx/sites-enabled/default') elif type_redhat(): dst_file = file('/etc/nginx/conf.d/wapt.conf', 'wt') dst_file.write(config_string) dst_file.close() # create keys for https:// access if not os.path.exists(wapt_ssl_key_file) or \ not os.path.exists(wapt_ssl_cert_file): if quiet: print('[*] Nginx - generate self-signed certs') old_apache_key = '/opt/wapt/waptserver/apache/ssl/key.pem' old_apache_cert = '/opt/wapt/waptserver/apache/ssl/cert.pem' if os.path.isfile(old_apache_cert) and os.path.isfile(old_apache_key): shutil.copyfile(old_apache_cert,wapt_ssl_cert_file) shutil.copyfile(old_apache_key,wapt_ssl_key_file) else: key = SSLPrivateKey(wapt_ssl_key_file) if not os.path.isfile(wapt_ssl_key_file): print('Create SSL RSA Key %s' % wapt_ssl_key_file) key.create() key.save_as_pem() if os.path.isfile(wapt_ssl_cert_file): crt = SSLCertificate(wapt_ssl_cert_file) if crt.cn != fqdn: os.rename(wapt_ssl_cert_file,"%s-%s.old" % (wapt_ssl_cert_file,'{:%Y%m%d-%Hh%Mm%Ss}'.format(datetime.datetime.now()))) crt = key.build_sign_certificate(cn=fqdn,dnsname=fqdn,is_code_signing=False) print('Create X509 cert %s' % wapt_ssl_cert_file) crt.save_as_pem(wapt_ssl_cert_file) else: crt = key.build_sign_certificate(cn=fqdn,dnsname=fqdn,is_code_signing=False) print('Create X509 cert %s' % wapt_ssl_cert_file) crt.save_as_pem(wapt_ssl_cert_file) else: if quiet: print('[*] Nginx - self-signed certs already exists, skipping...')
def main(): global wapt_folder,NGINX_GID parser = OptionParser(usage=usage, version=__version__) parser.add_option( '-c', '--config', dest='configfile', default=waptserver.config.DEFAULT_CONFIG_FILE, help='Config file full path (default: %default)') parser.add_option( "-s", "--force-https", dest="force_https", default=False, action='store_true', help="Use https only, http is 301 redirected to https (default: False). Requires a proper DNS name") parser.add_option( '-q', '--quiet', dest='quiet', default=False, action="store_true", help='Run quiet postconfiguration - default password and simple behavior') (options, args) = parser.parse_args() quiet = options.quiet if not quiet: if postconf.yesno("Do you want to launch post configuration tool ?") != postconf.DIALOG_OK: print "canceling wapt postconfiguration" sys.exit(1) else: print('WAPT silent post-configuration') # SELinux rules for CentOS/RedHat if type_redhat(): if re.match('^SELinux status:.*enabled', run('sestatus')): if not quiet: postconf.msgbox('SELinux detected, tweaking httpd permissions.') selinux_rules() postconf.msgbox('SELinux correctly configured for Nginx reverse proxy') else: print('[*] Redhat/Centos detected, tweaking SELinux rules') selinux_rules() print('[*] Nginx - SELinux correctly configured for Nginx reverse proxy') # Load existing config file server_config = waptserver.config.load_config(options.configfile) if os.path.isfile(options.configfile): print('[*] Making a backup copy of the configuration file') datetime_now = datetime.datetime.now() shutil.copyfile(options.configfile,'%s.bck_%s'% (options.configfile,datetime_now.isoformat()) ) wapt_folder = server_config['wapt_folder'] # add secret key initialisation string (for session token) if not server_config['secret_key']: server_config['secret_key'] = ''.join(random.SystemRandom().choice(string.letters + string.digits) for _ in range(64)) # add user db and password in ini file if server_config['db_host'] in (None,'','localhost','127.0.0.1','::1'): ensure_postgresql_db(db_name=server_config['db_name'],db_owner=server_config['db_name'],db_password=server_config['db_password']) # Password setup/reset screen if not quiet: if not server_config['wapt_password'] or \ postconf.yesno("Do you want to reset admin password ?",yes_label='skip',no_label='reset') != postconf.DIALOG_OK: wapt_password_ok = False while not wapt_password_ok: wapt_password = '' wapt_password_check = '' while wapt_password == '': (code,wapt_password) = postconf.passwordbox("Please enter the wapt server password (min. 10 characters): ", insecure=True,width=100) if code != postconf.DIALOG_OK: exit(0) while wapt_password_check == '': (code,wapt_password_check) = postconf.passwordbox("Please enter the wapt server password again: ", insecure=True,width=100) if code != postconf.DIALOG_OK: exit(0) if wapt_password != wapt_password_check: postconf.msgbox('Password mismatch !') elif len(wapt_password) < 10: postconf.msgbox('Password must be at least 10 characters long !') else: wapt_password_ok = True password = pbkdf2_sha256.hash(wapt_password.encode('utf8')) server_config['wapt_password'] = password else: wapt_password = '' if not server_config['wapt_password']: print('[*] Generating random password for WAPT server') wapt_password = pwd.genword(entropy=56, charset="ascii_62") print('[*] WAPT admin password : %s' % wapt_password) password = pbkdf2_sha256.hash(wapt_password.encode('utf8')) server_config['wapt_password'] = password if not server_config['server_uuid']: server_config['server_uuid'] = str(uuid.uuid1()) # waptagent authentication method if not quiet: choices = [ ("1","Allow unauthenticated registration, same behavior as WAPT 1.3", True), ("2","Enable kerberos authentication required for machines registration", False), ("3","Disable Kerberos but registration require strong authentication", False), ] code, t = postconf.radiolist("WaptAgent Authentication type?", choices=choices,width=120) if code=='cancel': print("\n\npostconfiguration canceled\n\n") sys.exit(1) if t=="1": server_config['allow_unauthenticated_registration'] = True server_config['use_kerberos'] = False if t=="2": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = True if t=="3": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = False else: print('[*] Set default registration method to : Allow anyone to register + Kerberos disabled') server_config['allow_unauthenticated_registration'] = True server_config['use_kerberos'] = False # Guess fqdn using socket fqdn = guess_fqdn() clients_signing_certificate = server_config.get('clients_signing_certificate') clients_signing_key = server_config.get('clients_signing_key') if not clients_signing_certificate or not clients_signing_key: clients_signing_certificate = os.path.join(wapt_root_dir,'conf','ca-%s.crt' % fqdn) clients_signing_key = os.path.join(wapt_root_dir,'conf','ca-%s.pem' % fqdn) server_config['clients_signing_certificate'] = clients_signing_certificate server_config['clients_signing_key'] = clients_signing_key if clients_signing_certificate is not None and clients_signing_key is not None and not os.path.isfile(clients_signing_certificate): print('Create a certificate and key for clients certificate signing') key = SSLPrivateKey(clients_signing_key) if not os.path.isfile(clients_signing_key): print('Create SSL RSA Key %s' % clients_signing_key) key.create() key.save_as_pem() crt = key.build_sign_certificate(cn=fqdn,is_code_signing=False,is_ca=True) print('Create X509 cert %s' % clients_signing_certificate) crt.save_as_pem(clients_signing_certificate) waptserver.config.write_config_file(cfgfile=options.configfile,server_config=server_config,non_default_values_only=True) print('[*] Protecting WAPT config file') run("/bin/chmod 640 %s" % options.configfile) run("/bin/chown wapt %s" % options.configfile) print('[*] Update WAPT repository') repo = WaptLocalRepo(wapt_folder) repo.update_packages_index(force_all=True) final_msg = ['[*] Postconfiguration completed.',] if not quiet: postconf.msgbox("Press ok to start waptserver and wapttasks daemons") enable_waptserver() start_waptserver() # In this new version Apache is replaced with Nginx? Proceed to disable Apache. After migration one can remove Apache install altogether stop_disable_httpd() # Nginx configuration if quiet: try: generate_dhparam() nginx_cleanup() make_httpd_config('/opt/wapt/waptserver', fqdn, options.force_https,server_config) enable_nginx() restart_nginx() setup_firewall() except subprocess.CalledProcessError as cpe: final_msg += [ 'Error while trying to configure Nginx!', 'errno = ' + str(cpe.returncode) + ', output: ' + cpe.output ] except Exception as e: import traceback final_msg += [ 'Error while trying to configure Nginx!', traceback.format_exc() ] else: reply = postconf.yesno("Do you want to configure nginx?") if reply == postconf.DIALOG_OK: try: msg = 'FQDN for the WAPT server (eg. wapt.acme.com)' (code, reply) = postconf.inputbox(text=msg, width=len(msg)+4, init=fqdn) if code != postconf.DIALOG_OK: exit(1) else: fqdn = reply generate_dhparam() nginx_cleanup() if server_config['use_kerberos']: if type_debian(): if not check_if_deb_installed('libnginx-mod-http-auth-spnego'): print('[*] Nginx - Missing dependency libnginx-mod-http-auth-spnego, please install first before configuring kerberos') sys.exit(1) make_httpd_config('/opt/wapt/waptserver', fqdn, options.force_https, server_config) final_msg.append('Please connect to https://' + fqdn + '/ to access the server.') postconf.msgbox("The Nginx config is done. We need to restart Nginx?") run_verbose('systemctl enable nginx') run_verbose('systemctl restart nginx') setup_firewall() except subprocess.CalledProcessError as cpe: final_msg += [ 'Error while trying to configure Nginx!', 'errno = ' + str(cpe.returncode) + ', output: ' + cpe.output ] except Exception as e: import traceback final_msg += [ 'Error while trying to configure Nginx!', traceback.format_exc() ] final_msg.append('Please connect to https://' + fqdn + '/ to access the server.') # Check if Mongodb > PostgreSQL migration is necessary if not quiet: if check_mongo2pgsql_upgrade_needed(options.configfile) and\ postconf.yesno("It is necessary to migrate current database backend from mongodb to postgres. Press yes to start migration",no_label='cancel') == postconf.DIALOG_OK: upgrade2postgres(options.configfile) else: if check_mongo2pgsql_upgrade_needed(options.configfile): upgrade2postgres(options.configfile) # Final message if not quiet: width = 4 + max(10, len(max(final_msg, key=len))) height = 2 + max(20, len(final_msg)) postconf.msgbox('\n'.join(final_msg), height=height, width=width) else: if wapt_password: final_msg.append('[*] WAPT admin password : %s\n' % wapt_password) for line in final_msg: print(line)
def run(*args, **kwargs): return subprocess.check_output(*args, shell=True, **kwargs) def run_verbose(*args, **kwargs): output = subprocess.check_output(*args, shell=True, **kwargs) print output return output if type_debian(): MONGO_SVC='mongodb' APACHE_SVC='apache2' PGSQL_SVC='postgresql' wapt_folder = '/var/www/wapt' NGINX_GID= grp.getgrnam('www-data').gr_gid elif type_redhat(): MONGO_SVC='mongod' APACHE_SVC='httpd' PGSQL_SVC='postgresql-9.6' wapt_folder = '/var/www/html/wapt' NGINX_GID= grp.getgrnam('nginx').gr_gid else: print "distrib type unknown" sys.exit(1) quiet = False postconf = dialog.Dialog(dialog="dialog") def mkdir(path): if not os.path.isdir(path): os.makedirs(path)
def make_httpd_config(wapt_folder, waptserver_root_dir, fqdn, use_kerberos,force_https, waptserver_port): if wapt_folder.endswith('\\') or wapt_folder.endswith('/'): wapt_folder = wapt_folder[:-1] ssl_dir = os.path.join(waptserver_root_dir, 'ssl') scripts_dir = os.path.join(waptserver_root_dir, 'scripts') wapt_ssl_key_file = os.path.join(ssl_dir,'key.pem') wapt_ssl_cert_file = os.path.join(ssl_dir,'cert.pem') mkdir(ssl_dir) # write the apache configuration fragment jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(scripts_dir)) template = jinja_env.get_template('wapt.nginxconfig.template') krb5_realm = '.'.join(fqdn.split('.')[1:]).upper() template_vars = { 'waptserver_port': waptserver_port, 'wapt_repository_path': os.path.dirname(wapt_folder), 'apache_root_folder': '/not/used', 'windows': False, 'debian': type_debian(), 'redhat': type_redhat(), 'force_https': force_https, 'wapt_ssl_key_file': wapt_ssl_key_file, 'wapt_ssl_cert_file': wapt_ssl_cert_file, 'fqdn': fqdn, 'use_kerberos': use_kerberos, 'KRB5_REALM': krb5_realm, 'wapt_root_dir': wapt_root_dir, } config_string = template.render(template_vars) if type_debian(): dst_file = file('/etc/nginx/sites-available/wapt.conf', 'wt') if not os.path.exists('/etc/nginx/sites-enabled/wapt.conf'): print(subprocess.check_output('ln -s /etc/nginx/sites-available/wapt.conf /etc/nginx/sites-enabled/wapt.conf',shell=True)) if os.path.exists('/etc/nginx/sites-enabled/default'): os.unlink('/etc/nginx/sites-enabled/default') elif type_redhat(): dst_file = file('/etc/nginx/conf.d/wapt.conf', 'wt') dst_file.write(config_string) dst_file.close() # create keys for https:// access if not os.path.exists(wapt_ssl_key_file) or \ not os.path.exists(wapt_ssl_cert_file): old_apache_key = '/opt/wapt/waptserver/apache/ssl/key.pem' old_apache_cert = '/opt/wapt/waptserver/apache/ssl/cert.pem' if os.path.isfile(old_apache_cert) and os.path.isfile(old_apache_key): shutil.copyfile(old_apache_cert,wapt_ssl_cert_file) shutil.copyfile(old_apache_key,wapt_ssl_key_file) else: void = subprocess.check_output([ 'openssl', 'req', '-new', # create a request '-x509', # no, actually, create a self-signed certificate! '-newkey', 'rsa:2048', # and the key that goes along, RSA, 2048 bits '-nodes', # don't put a passphrase on the key '-days', '3650', # the cert is valid for ten years '-out', wapt_ssl_cert_file, '-keyout', wapt_ssl_key_file, # fill in the minimum amount of information needed; to be revisited '-subj', '/C=FR/ST=Wapt/L=Wapt/O=Wapt/CN=' + fqdn + '/' ], stderr=subprocess.STDOUT)
def main(): global wapt_folder,NGINX_GID parser = OptionParser(usage=usage, version=__version__) parser.add_option( '-c', '--config', dest='configfile', default=waptserver.config.DEFAULT_CONFIG_FILE, help='Config file full path (default: %default)') parser.add_option( "-s", "--force-https", dest="force_https", default=False, action='store_true', help="Use https only, http is 301 redirected to https (default: False). Requires a proper DNS name") (options, args) = parser.parse_args() if postconf.yesno("Do you want to launch post configuration tool ?") != postconf.DIALOG_OK: print "canceling wapt postconfiguration" sys.exit(1) # TODO : check if it a new install or an upgrade (upgrade from mongodb to postgresql) if type_redhat(): if re.match('^SELinux status:.*enabled', run('sestatus')): postconf.msgbox('SELinux detected, tweaking httpd permissions.') run('setsebool -P httpd_can_network_connect 1') run('setsebool -P httpd_setrlimit on') for sepath in ('wapt','wapt-host'): run('semanage fcontext -a -t httpd_sys_content_t "/var/www/html/%s(/.*)?"' %sepath) run('restorecon -R -v /var/www/html/%s' %sepath) postconf.msgbox('SELinux correctly configured for Nginx reverse proxy') server_config = waptserver.config.load_config(options.configfile) if os.path.isfile(options.configfile): print('making a backup copy of the configuration file') datetime_now = datetime.datetime.now() shutil.copyfile(options.configfile,'%s.bck_%s'% (options.configfile,datetime_now.isoformat()) ) wapt_folder = server_config['wapt_folder'] # add secret key initialisation string (for session token) if not server_config['secret_key']: server_config['secret_key'] = ''.join(random.SystemRandom().choice(string.letters + string.digits) for _ in range(64)) # add user db and password in ini file if server_config['db_host'] in (None,'','localhost','127.0.0.1','::1'): ensure_postgresql_db(db_name=server_config['db_name'],db_owner=server_config['db_name'],db_password=server_config['db_password']) # Password setup/reset screen if not server_config['wapt_password'] or \ postconf.yesno("Do you want to reset admin password ?",yes_label='skip',no_label='reset') != postconf.DIALOG_OK: wapt_password_ok = False while not wapt_password_ok: wapt_password = '' wapt_password_check = '' while wapt_password == '': (code,wapt_password) = postconf.passwordbox("Please enter the wapt server password (min. 10 characters): ", insecure=True,width=100) if code != postconf.DIALOG_OK: exit(0) while wapt_password_check == '': (code,wapt_password_check) = postconf.passwordbox("Please enter the wapt server password again: ", insecure=True,width=100) if code != postconf.DIALOG_OK: exit(0) if wapt_password != wapt_password_check: postconf.msgbox('Password mismatch !') elif len(wapt_password) < 10: postconf.msgbox('Password must be at least 10 characters long !') else: wapt_password_ok = True password = pbkdf2_sha256.hash(wapt_password.encode('utf8')) server_config['wapt_password'] = password if not server_config['server_uuid']: server_config['server_uuid'] = str(uuid.uuid1()) # waptagent authentication method choices = [ ("1","Allow unauthenticated registration, same behavior as wapt 1.3", True), ("2","Enable kerberos authentication required for machines registration", False), ("3","Disable Kerberos but registration require strong authentication", False), ] code, t = postconf.radiolist("WaptAgent Authentication type?", choices=choices,width=120) if code=='cancel': print("\n\npostconfiguration canceled\n\n") sys.exit(1) if t=="1": server_config['allow_unauthenticated_registration'] = True server_config['use_kerberos'] = False if t=="2": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = True if t=="3": server_config['allow_unauthenticated_registration'] = False server_config['use_kerberos'] = False waptserver.config.write_config_file(cfgfile=options.configfile,server_config=server_config,non_default_values_only=True) run("/bin/chmod 640 %s" % options.configfile) run("/bin/chown wapt %s" % options.configfile) repo = WaptLocalRepo(wapt_folder) repo.update_packages_index(force_all=True) final_msg = ['Postconfiguration completed.',] postconf.msgbox("Press ok to start waptserver and wapttasks daemons") enable_waptserver() start_waptserver() # In this new version Apache is replaced with Nginx? Proceed to disable Apache. After migration one can remove Apache install altogether try: run_verbose('systemctl stop %s' % APACHE_SVC) except: pass try: run_verbose('systemctl disable %s' % APACHE_SVC) except: pass # nginx configuration dialog reply = postconf.yesno("Do you want to configure nginx?") if reply == postconf.DIALOG_OK: try: fqdn = socket.getfqdn() if not fqdn: fqdn = 'wapt' if '.' not in fqdn: fqdn += '.lan' msg = 'FQDN for the WAPT server (eg. wapt.acme.com)' (code, reply) = postconf.inputbox(text=msg, width=len(msg)+4, init=fqdn) if code != postconf.DIALOG_OK: exit(1) else: fqdn = reply dh_filename = '/etc/ssl/certs/dhparam.pem' if not os.path.exists(dh_filename): run_verbose('openssl dhparam -out %s 2048' % dh_filename) os.chown(dh_filename, 0, NGINX_GID) #pylint: disable=no-member os.chmod(dh_filename, 0o640) #pylint: disable=no-member # cleanup of nginx.conf file with open('/etc/nginx/nginx.conf','r') as read_conf: nginx_conf = nginxparser.load(read_conf) nginx_conf = nginx_set_worker_limit(nginx_conf) nginx_conf = nginx_clean_default_vhost(nginx_conf) with open("/etc/nginx/nginx.conf", "w") as nginx_conf_file: nginx_conf_file.write(nginxparser.dumps(nginx_conf)) if server_config['use_kerberos']: if type_debian(): if not check_if_deb_installed('libnginx-mod-http-auth-spnego'): print('missing dependency libnginx-mod-http-auth-spnego, please install first before configuring kerberos') sys.exit(1) make_httpd_config(wapt_folder, '/opt/wapt/waptserver', fqdn, server_config['use_kerberos'], options.force_https,server_config['waptserver_port']) final_msg.append('Please connect to https://' + fqdn + '/ to access the server.') postconf.msgbox("The Nginx config is done. We need to restart Nginx?") run_verbose('systemctl enable nginx') run_verbose('systemctl restart nginx') setup_firewall() except subprocess.CalledProcessError as cpe: final_msg += [ 'Error while trying to configure Nginx!', 'errno = ' + str(cpe.returncode) + ', output: ' + cpe.output ] except Exception as e: import traceback final_msg += [ 'Error while trying to configure Nginx!', traceback.format_exc() ] if check_mongo2pgsql_upgrade_needed(options.configfile) and\ postconf.yesno("It is necessary to migrate current database backend from mongodb to postgres. Press yes to start migration",no_label='cancel') == postconf.DIALOG_OK: upgrade2postgres(options.configfile) width = 4 + max(10, len(max(final_msg, key=len))) height = 2 + max(20, len(final_msg)) postconf.msgbox('\n'.join(final_msg), height=height, width=width)