Merge "Add Apex based security scan code"
[functest.git] / testcases / security_scan / security_scan.py
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2016 Red Hat
4 # Luke Hinds (lhinds@redhat.com)
5 # This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # 0.1: This script installs OpenSCAP on the remote host, and scans the
12 # nominated node. Post scan a report is downloaded and if '--clean' is passed
13 # all trace of the scan is removed from the remote system.
14
15 import argparse
16 import connect
17 import datetime
18 import os
19
20 from ConfigParser import SafeConfigParser
21 from keystoneclient.auth.identity import v2
22 from keystoneclient import session
23 from novaclient import client
24
25 __version__ = 0.1
26 __author__ = 'Luke Hinds (lhinds@redhat.com)'
27 __url__ = 'https://wiki.opnfv.org/display/functest/Functest+Security'
28
29 # Global vars
30 INSTALLER_IP = os.getenv('INSTALLER_IP')
31 oscapbin = 'sudo /bin/oscap'
32
33 # Configure Nova Credentials
34 com = 'sudo hiera admin_password'
35 connect = connect.novaManager(com)
36 keypass = connect.keystonepass()
37 auth = v2.Password(auth_url='http://{0}:5000/v2.0'.format(INSTALLER_IP),
38                    username='admin',
39                    password=str(keypass).rstrip(),
40                    tenant_name='admin')
41 sess = session.Session(auth=auth)
42 nova = client.Client(2, session=sess)
43
44
45 # args
46 parser = argparse.ArgumentParser(description='OPNFV OpenSCAP Scanner')
47 parser.add_argument('--config', action='store', dest='cfgfile',
48                     help='Config file', required=True)
49 args = parser.parse_args()
50
51 # functest logger
52 logger = ft_logger.Logger("security_scan").getLogger()
53
54 # Config Parser
55 cfgparse = SafeConfigParser()
56 cfgparse.read(args.cfgfile)
57
58
59 def run_tests(host, nodetype):
60     port = cfgparse.get(nodetype, 'port')
61     user = cfgparse.get(nodetype, 'user')
62     user_key = cfgparse.get(nodetype, 'user_key')
63     logger.info("Host: {0} Selected Profile: {1}").format(host, nodetype)
64     logger.info("Creating temp file structure..")
65     createfiles(host, port, user, user_key)
66     logger.info("Installing OpenSCAP...")
67     install_pkg(host, port, user, user_key)
68     logger.info("Running scan...")
69     run_scanner(host, port, user, user_key, nodetype)
70     clean = cfgparse.get(nodetype, 'clean')
71     logger.info("Post installation tasks....")
72     post_tasks(host, port, user, user_key, nodetype)
73     if clean:
74         logger.info("Cleaning down environment....")
75         logger.info("Removing OpenSCAP....")
76         removepkg(host, port, user, user_key, nodetype)
77         logger.info("Deleting tmp file and reports (remote)...")
78         cleandir(host, port, user, user_key, nodetype)
79
80
81 def nova_iterate():
82     # Find compute nodes, active with network on ctlplane
83     for server in nova.servers.list():
84         if server.status == 'ACTIVE' and 'compute' in server.name:
85             networks = server.networks
86             nodetype = 'compute'
87             for host in networks['ctlplane']:
88                 run_tests(host, nodetype)
89         # Find controller nodes, active with network on ctlplane
90         elif server.status == 'ACTIVE' and 'controller' in server.name:
91             networks = server.networks
92             nodetype = 'controller'
93             for host in networks['ctlplane']:
94                 run_tests(host, nodetype)
95
96
97 def createfiles(host, port, user, user_key):
98     import connect
99     global tmpdir
100     localpath = os.getcwd() + '/scripts/createfiles.py'
101     remotepath = '/tmp/createfiles.py'
102     com = 'python /tmp/createfiles.py'
103     connect = connect.connectionManager(host, port, user, user_key,
104                                         localpath, remotepath, com)
105     tmpdir = connect.remotescript()
106
107
108 def install_pkg(host, port, user, user_key):
109     import connect
110     com = 'sudo yum -y install openscap-scanner scap-security-guide'
111     connect = connect.connectionManager(host, port, user, user_key, com)
112     connect.remotecmd()
113
114
115 def run_scanner(host, port, user, user_key, nodetype):
116     import connect
117     scantype = cfgparse.get(nodetype, 'scantype')
118     profile = cfgparse.get(nodetype, 'profile')
119     results = cfgparse.get(nodetype, 'results')
120     report = cfgparse.get(nodetype, 'report')
121     secpolicy = cfgparse.get(nodetype, 'secpolicy')
122     # Here is where we contruct the actual scan command
123     if scantype == 'xccdf':
124         cpe = cfgparse.get(nodetype, 'cpe')
125         com = '{0} xccdf eval --profile {1} --results {2}/{3}' \
126               ' --report {2}/{4} --cpe {5} {6}'.format(oscapbin,
127                                                        profile,
128                                                        tmpdir.rstrip(),
129                                                        results,
130                                                        report,
131                                                        cpe,
132                                                        secpolicy)
133         connect = connect.connectionManager(host, port, user, user_key, com)
134         connect.remotecmd()
135     elif scantype == 'oval':
136         com = '{0} oval eval --results {1}/{2} '
137         '--report {1}/{3} {4}'.format(oscapbin, tmpdir.rstrip(),
138                                       results, report, secpolicy)
139         connect = connect.connectionManager(host, port, user, user_key, com)
140         connect.remotecmd()
141     else:
142         com = '{0} oval-collect '.format(oscapbin)
143         connect = connect.connectionManager(host, port, user, user_key, com)
144         connect.remotecmd()
145
146
147 def post_tasks(host, port, user, user_key, nodetype):
148     import connect
149     # Create the download folder for functest dashboard and download reports
150     reports_dir = cfgparse.get(nodetype, 'reports_dir')
151     dl_folder = os.path.join(reports_dir, host + "_" +
152                              datetime.datetime.
153                              now().strftime('%Y-%m-%d_%H-%M-%S'))
154     os.makesdir(dl_folder, 0755)
155     report = cfgparse.get(nodetype, 'report')
156     results = cfgparse.get(nodetype, 'results')
157     reportfile = '{0}/{1}'.format(tmpdir.rstrip(), report)
158     connect = connect.connectionManager(host, port, user, user_key, dl_folder,
159                                         reportfile, report, results)
160     connect.download_reports()
161
162
163 def removepkg(host, port, user, user_key, nodetype):
164     import connect
165     com = 'sudo yum -y remove openscap-scanner scap-security-guide'
166     connect = connect.connectionManager(host, port, user, user_key, com)
167     connect.remotecmd()
168
169
170 def cleandir(host, port, user, user_key, nodetype):
171     import connect
172     com = 'sudo rm -r {0}'.format(tmpdir.rstrip())
173     connect = connect.connectionManager(host, port, user, user_key, com)
174     connect.remotecmd()
175
176
177 if __name__ == '__main__':
178     nova_iterate()