1#!/usr/bin/python
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019 Fortinet, Inc.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18__metaclass__ = type
19
20ANSIBLE_METADATA = {'status': ['preview'],
21                    'supported_by': 'community',
22                    'metadata_version': '1.1'}
23
24DOCUMENTATION = '''
25---
26module: fortios_log_fortiguard_setting
27short_description: Configure logging to FortiCloud in Fortinet's FortiOS and FortiGate.
28description:
29    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
30      user to set and modify log_fortiguard feature and setting category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.5
33version_added: "2.8"
34author:
35    - Miguel Angel Munoz (@mamunozgonzalez)
36    - Nicolas Thomas (@thomnico)
37notes:
38    - Requires fortiosapi library developed by Fortinet
39    - Run as a local_action in your playbook
40requirements:
41    - fortiosapi>=0.9.8
42options:
43    host:
44        description:
45            - FortiOS or FortiGate IP address.
46        type: str
47        required: false
48    username:
49        description:
50            - FortiOS or FortiGate username.
51        type: str
52        required: false
53    password:
54        description:
55            - FortiOS or FortiGate password.
56        type: str
57        default: ""
58    vdom:
59        description:
60            - Virtual domain, among those defined previously. A vdom is a
61              virtual instance of the FortiGate that can be configured and
62              used as a different unit.
63        type: str
64        default: root
65    https:
66        description:
67            - Indicates if the requests towards FortiGate must use HTTPS protocol.
68        type: bool
69        default: true
70    ssl_verify:
71        description:
72            - Ensures FortiGate certificate must be verified by a proper CA.
73        type: bool
74        default: true
75        version_added: 2.9
76    log_fortiguard_setting:
77        description:
78            - Configure logging to FortiCloud.
79        default: null
80        type: dict
81        suboptions:
82            enc_algorithm:
83                description:
84                    - Enable and set the SSL security level for for sending encrypted logs to FortiCloud.
85                type: str
86                choices:
87                    - high-medium
88                    - high
89                    - low
90            source_ip:
91                description:
92                    - Source IP address used to connect FortiCloud.
93                type: str
94            ssl_min_proto_version:
95                description:
96                    - Minimum supported protocol version for SSL/TLS connections .
97                type: str
98                choices:
99                    - default
100                    - SSLv3
101                    - TLSv1
102                    - TLSv1-1
103                    - TLSv1-2
104            status:
105                description:
106                    - Enable/disable logging to FortiCloud.
107                type: str
108                choices:
109                    - enable
110                    - disable
111            upload_day:
112                description:
113                    - Day of week to roll logs.
114                type: str
115            upload_interval:
116                description:
117                    - Frequency of uploading log files to FortiCloud.
118                type: str
119                choices:
120                    - daily
121                    - weekly
122                    - monthly
123            upload_option:
124                description:
125                    - Configure how log messages are sent to FortiCloud.
126                type: str
127                choices:
128                    - store-and-upload
129                    - realtime
130                    - 1-minute
131                    - 5-minute
132            upload_time:
133                description:
134                    - "Time of day to roll logs (hh:mm)."
135                type: str
136'''
137
138EXAMPLES = '''
139- hosts: localhost
140  vars:
141   host: "192.168.122.40"
142   username: "admin"
143   password: ""
144   vdom: "root"
145   ssl_verify: "False"
146  tasks:
147  - name: Configure logging to FortiCloud.
148    fortios_log_fortiguard_setting:
149      host:  "{{ host }}"
150      username: "{{ username }}"
151      password: "{{ password }}"
152      vdom:  "{{ vdom }}"
153      https: "False"
154      log_fortiguard_setting:
155        enc_algorithm: "high-medium"
156        source_ip: "84.230.14.43"
157        ssl_min_proto_version: "default"
158        status: "enable"
159        upload_day: "<your_own_value>"
160        upload_interval: "daily"
161        upload_option: "store-and-upload"
162        upload_time: "<your_own_value>"
163'''
164
165RETURN = '''
166build:
167  description: Build number of the fortigate image
168  returned: always
169  type: str
170  sample: '1547'
171http_method:
172  description: Last method used to provision the content into FortiGate
173  returned: always
174  type: str
175  sample: 'PUT'
176http_status:
177  description: Last result given by FortiGate on last operation applied
178  returned: always
179  type: str
180  sample: "200"
181mkey:
182  description: Master key (id) used in the last call to FortiGate
183  returned: success
184  type: str
185  sample: "id"
186name:
187  description: Name of the table used to fulfill the request
188  returned: always
189  type: str
190  sample: "urlfilter"
191path:
192  description: Path of the table used to fulfill the request
193  returned: always
194  type: str
195  sample: "webfilter"
196revision:
197  description: Internal revision number
198  returned: always
199  type: str
200  sample: "17.0.2.10658"
201serial:
202  description: Serial number of the unit
203  returned: always
204  type: str
205  sample: "FGVMEVYYQT3AB5352"
206status:
207  description: Indication of the operation's result
208  returned: always
209  type: str
210  sample: "success"
211vdom:
212  description: Virtual domain used
213  returned: always
214  type: str
215  sample: "root"
216version:
217  description: Version of the FortiGate
218  returned: always
219  type: str
220  sample: "v5.6.3"
221
222'''
223
224from ansible.module_utils.basic import AnsibleModule
225from ansible.module_utils.connection import Connection
226from ansible.module_utils.network.fortios.fortios import FortiOSHandler
227from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
228
229
230def login(data, fos):
231    host = data['host']
232    username = data['username']
233    password = data['password']
234    ssl_verify = data['ssl_verify']
235
236    fos.debug('on')
237    if 'https' in data and not data['https']:
238        fos.https('off')
239    else:
240        fos.https('on')
241
242    fos.login(host, username, password, verify=ssl_verify)
243
244
245def filter_log_fortiguard_setting_data(json):
246    option_list = ['enc_algorithm', 'source_ip', 'ssl_min_proto_version',
247                   'status', 'upload_day', 'upload_interval',
248                   'upload_option', 'upload_time']
249    dictionary = {}
250
251    for attribute in option_list:
252        if attribute in json and json[attribute] is not None:
253            dictionary[attribute] = json[attribute]
254
255    return dictionary
256
257
258def underscore_to_hyphen(data):
259    if isinstance(data, list):
260        for elem in data:
261            elem = underscore_to_hyphen(elem)
262    elif isinstance(data, dict):
263        new_data = {}
264        for k, v in data.items():
265            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
266        data = new_data
267
268    return data
269
270
271def log_fortiguard_setting(data, fos):
272    vdom = data['vdom']
273    log_fortiguard_setting_data = data['log_fortiguard_setting']
274    filtered_data = underscore_to_hyphen(filter_log_fortiguard_setting_data(log_fortiguard_setting_data))
275
276    return fos.set('log.fortiguard',
277                   'setting',
278                   data=filtered_data,
279                   vdom=vdom)
280
281
282def is_successful_status(status):
283    return status['status'] == "success" or \
284        status['http_method'] == "DELETE" and status['http_status'] == 404
285
286
287def fortios_log_fortiguard(data, fos):
288
289    if data['log_fortiguard_setting']:
290        resp = log_fortiguard_setting(data, fos)
291
292    return not is_successful_status(resp), \
293        resp['status'] == "success", \
294        resp
295
296
297def main():
298    fields = {
299        "host": {"required": False, "type": "str"},
300        "username": {"required": False, "type": "str"},
301        "password": {"required": False, "type": "str", "default": "", "no_log": True},
302        "vdom": {"required": False, "type": "str", "default": "root"},
303        "https": {"required": False, "type": "bool", "default": True},
304        "ssl_verify": {"required": False, "type": "bool", "default": True},
305        "log_fortiguard_setting": {
306            "required": False, "type": "dict", "default": None,
307            "options": {
308                "enc_algorithm": {"required": False, "type": "str",
309                                  "choices": ["high-medium", "high", "low"]},
310                "source_ip": {"required": False, "type": "str"},
311                "ssl_min_proto_version": {"required": False, "type": "str",
312                                          "choices": ["default", "SSLv3", "TLSv1",
313                                                      "TLSv1-1", "TLSv1-2"]},
314                "status": {"required": False, "type": "str",
315                           "choices": ["enable", "disable"]},
316                "upload_day": {"required": False, "type": "str"},
317                "upload_interval": {"required": False, "type": "str",
318                                    "choices": ["daily", "weekly", "monthly"]},
319                "upload_option": {"required": False, "type": "str",
320                                  "choices": ["store-and-upload", "realtime", "1-minute",
321                                              "5-minute"]},
322                "upload_time": {"required": False, "type": "str"}
323
324            }
325        }
326    }
327
328    module = AnsibleModule(argument_spec=fields,
329                           supports_check_mode=False)
330
331    # legacy_mode refers to using fortiosapi instead of HTTPAPI
332    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
333                  'username' in module.params and module.params['username'] is not None and \
334                  'password' in module.params and module.params['password'] is not None
335
336    if not legacy_mode:
337        if module._socket_path:
338            connection = Connection(module._socket_path)
339            fos = FortiOSHandler(connection)
340
341            is_error, has_changed, result = fortios_log_fortiguard(module.params, fos)
342        else:
343            module.fail_json(**FAIL_SOCKET_MSG)
344    else:
345        try:
346            from fortiosapi import FortiOSAPI
347        except ImportError:
348            module.fail_json(msg="fortiosapi module is required")
349
350        fos = FortiOSAPI()
351
352        login(module.params, fos)
353        is_error, has_changed, result = fortios_log_fortiguard(module.params, fos)
354        fos.logout()
355
356    if not is_error:
357        module.exit_json(changed=has_changed, meta=result)
358    else:
359        module.fail_json(msg="Error in repo", meta=result)
360
361
362if __name__ == '__main__':
363    main()
364