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