stop hardcoded FUNCTEST_REPO path everywhere
[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 datetime
16 import os
17 import sys
18 from ConfigParser import SafeConfigParser
19
20 import argparse
21 from functest.utils.functest_utils import FUNCTEST_REPO as FUNCTEST_REPO
22 from keystoneclient import session
23 from keystoneclient.auth.identity import v2
24 from novaclient import client
25
26 import connect
27
28 __version__ = 0.1
29 __author__ = 'Luke Hinds (lhinds@redhat.com)'
30 __url__ = 'https://wiki.opnfv.org/display/functest/Functest+Security'
31
32 # Global vars
33 INSTALLER_IP = os.getenv('INSTALLER_IP')
34 oscapbin = 'sudo /bin/oscap'
35 functest_dir = '%s/testcases/security_scan/' % FUNCTEST_REPO
36
37 # Apex Spefic var needed to query Undercloud
38 if os.getenv('OS_AUTH_URL') is None:
39     connect.logger.error(" Enviroment variable OS_AUTH_URL is not set")
40     sys.exit(0)
41 else:
42     OS_AUTH_URL = os.getenv('OS_AUTH_URL')
43
44 # args
45 parser = argparse.ArgumentParser(description='OPNFV OpenSCAP Scanner')
46 parser.add_argument('--config', action='store', dest='cfgfile',
47                     help='Config file', required=True)
48 args = parser.parse_args()
49
50 # Config Parser
51 cfgparse = SafeConfigParser()
52 cfgparse.read(args.cfgfile)
53
54 #  Grab Undercloud key
55 remotekey = cfgparse.get('undercloud', 'remotekey')
56 localkey = cfgparse.get('undercloud', 'localkey')
57 setup = connect.SetUp(remotekey, localkey)
58 setup.getockey()
59
60
61 # Configure Nova Credentials
62 com = 'sudo /usr/bin/hiera admin_password'
63 setup = connect.SetUp(com)
64 keypass = setup.keystonepass()
65 auth = v2.Password(auth_url=OS_AUTH_URL,
66                    username='admin',
67                    password=str(keypass).rstrip(),
68                    tenant_name='admin')
69 sess = session.Session(auth=auth)
70 nova = client.Client(2, session=sess)
71
72
73 def run_tests(host, nodetype):
74     user = cfgparse.get(nodetype, 'user')
75     port = cfgparse.get(nodetype, 'port')
76     connect.logger.info("Host: {0} Selected Profile: {1}".format(host,
77                                                                  nodetype))
78     connect.logger.info("Checking internet for package installation...")
79     if internet_check(host, nodetype):
80         connect.logger.info("Internet Connection OK.")
81         connect.logger.info("Creating temp file structure..")
82         createfiles(host, port, user, localkey)
83         connect.logger.info("Installing OpenSCAP...")
84         install_pkg(host, port, user, localkey)
85         connect.logger.info("Running scan...")
86         run_scanner(host, port, user, localkey, nodetype)
87         clean = cfgparse.get(nodetype, 'clean')
88         connect.logger.info("Post installation tasks....")
89         post_tasks(host, port, user, localkey, nodetype)
90         if clean:
91             connect.logger.info("Cleaning down environment....")
92             connect.logger.info("Removing OpenSCAP....")
93             removepkg(host, port, user, localkey, nodetype)
94             connect.logger.info("Deleting tmp file and reports (remote)...")
95             cleandir(host, port, user, localkey, nodetype)
96     else:
97         connect.logger.error("Internet timeout. Moving on to next node..")
98         pass
99
100
101 def nova_iterate():
102     # Find compute nodes, active with network on ctlplane
103     for server in nova.servers.list():
104         if server.status == 'ACTIVE' and 'compute' in server.name:
105             networks = server.networks
106             nodetype = 'compute'
107             for host in networks['ctlplane']:
108                 run_tests(host, nodetype)
109         # Find controller nodes, active with network on ctlplane
110         elif server.status == 'ACTIVE' and 'controller' in server.name:
111             networks = server.networks
112             nodetype = 'controller'
113             for host in networks['ctlplane']:
114                 run_tests(host, nodetype)
115
116
117 def internet_check(host, nodetype):
118     import connect
119     user = cfgparse.get(nodetype, 'user')
120     port = cfgparse.get(nodetype, 'port')
121     localpath = functest_dir + 'scripts/internet_check.py'
122     remotepath = '/tmp/internet_check.py'
123     com = 'python /tmp/internet_check.py'
124     testconnect = connect.ConnectionManager(host, port, user, localkey,
125                                             localpath, remotepath, com)
126     connectionresult = testconnect.remotescript()
127     if connectionresult.rstrip() == 'True':
128         return True
129     else:
130         return False
131
132
133 def createfiles(host, port, user, localkey):
134     import connect
135     global tmpdir
136     localpath = functest_dir + 'scripts/createfiles.py'
137     remotepath = '/tmp/createfiles.py'
138     com = 'python /tmp/createfiles.py'
139     connect = connect.ConnectionManager(host, port, user, localkey,
140                                         localpath, remotepath, com)
141     tmpdir = connect.remotescript()
142
143
144 def install_pkg(host, port, user, localkey):
145     import connect
146     com = 'sudo yum -y install openscap-scanner scap-security-guide'
147     connect = connect.ConnectionManager(host, port, user, localkey, com)
148     connect.remotecmd()
149
150
151 def run_scanner(host, port, user, localkey, nodetype):
152     import connect
153     scantype = cfgparse.get(nodetype, 'scantype')
154     profile = cfgparse.get(nodetype, 'profile')
155     results = cfgparse.get(nodetype, 'results')
156     report = cfgparse.get(nodetype, 'report')
157     secpolicy = cfgparse.get(nodetype, 'secpolicy')
158     # Here is where we contruct the actual scan command
159     if scantype == 'xccdf':
160         cpe = cfgparse.get(nodetype, 'cpe')
161         com = '{0} xccdf eval --profile {1} --results {2}/{3}' \
162               ' --report {2}/{4} --cpe {5} {6}'.format(oscapbin,
163                                                        profile,
164                                                        tmpdir.rstrip(),
165                                                        results,
166                                                        report,
167                                                        cpe,
168                                                        secpolicy)
169         connect = connect.ConnectionManager(host, port, user, localkey, com)
170         connect.remotecmd()
171     elif scantype == 'oval':
172         com = '{0} oval eval --results {1}/{2} '
173         '--report {1}/{3} {4}'.format(oscapbin, tmpdir.rstrip(),
174                                       results, report, secpolicy)
175         connect = connect.ConnectionManager(host, port, user, localkey, com)
176         connect.remotecmd()
177     else:
178         com = '{0} oval-collect '.format(oscapbin)
179         connect = connect.ConnectionManager(host, port, user, localkey, com)
180         connect.remotecmd()
181
182
183 def post_tasks(host, port, user, localkey, nodetype):
184     import connect
185     # Create the download folder for functest dashboard and download reports
186     reports_dir = cfgparse.get(nodetype, 'reports_dir')
187     dl_folder = os.path.join(reports_dir, host + "_" +
188                              datetime.datetime.
189                              now().strftime('%Y-%m-%d_%H-%M-%S'))
190     os.makedirs(dl_folder, 0755)
191     report = cfgparse.get(nodetype, 'report')
192     results = cfgparse.get(nodetype, 'results')
193     reportfile = '{0}/{1}'.format(tmpdir.rstrip(), report)
194     connect = connect.ConnectionManager(host, port, user, localkey, dl_folder,
195                                         reportfile, report, results)
196     connect.download_reports()
197
198
199 def removepkg(host, port, user, localkey, nodetype):
200     import connect
201     com = 'sudo yum -y remove openscap-scanner scap-security-guide'
202     connect = connect.ConnectionManager(host, port, user, localkey, com)
203     connect.remotecmd()
204
205
206 def cleandir(host, port, user, localkey, nodetype):
207     import connect
208     com = 'sudo rm -r {0}'.format(tmpdir.rstrip())
209     connect = connect.ConnectionManager(host, port, user, localkey, com)
210     connect.remotecmd()
211
212
213 if __name__ == '__main__':
214     nova_iterate()