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