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_threat_weight 27short_description: Configure threat weight settings 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 feature and threat_weight 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_threat_weight: 77 description: 78 - Configure threat weight settings. 79 default: null 80 type: dict 81 suboptions: 82 application: 83 description: 84 - Application-control threat weight settings. 85 type: list 86 suboptions: 87 category: 88 description: 89 - Application category. 90 type: int 91 id: 92 description: 93 - Entry ID. 94 required: true 95 type: int 96 level: 97 description: 98 - Threat weight score for Application events. 99 type: str 100 choices: 101 - disable 102 - low 103 - medium 104 - high 105 - critical 106 blocked_connection: 107 description: 108 - Threat weight score for blocked connections. 109 type: str 110 choices: 111 - disable 112 - low 113 - medium 114 - high 115 - critical 116 failed_connection: 117 description: 118 - Threat weight score for failed connections. 119 type: str 120 choices: 121 - disable 122 - low 123 - medium 124 - high 125 - critical 126 geolocation: 127 description: 128 - Geolocation-based threat weight settings. 129 type: list 130 suboptions: 131 country: 132 description: 133 - Country code. 134 type: str 135 id: 136 description: 137 - Entry ID. 138 required: true 139 type: int 140 level: 141 description: 142 - Threat weight score for Geolocation-based events. 143 type: str 144 choices: 145 - disable 146 - low 147 - medium 148 - high 149 - critical 150 ips: 151 description: 152 - IPS threat weight settings. 153 type: dict 154 suboptions: 155 critical_severity: 156 description: 157 - Threat weight score for IPS critical severity events. 158 type: str 159 choices: 160 - disable 161 - low 162 - medium 163 - high 164 - critical 165 high_severity: 166 description: 167 - Threat weight score for IPS high severity events. 168 type: str 169 choices: 170 - disable 171 - low 172 - medium 173 - high 174 - critical 175 info_severity: 176 description: 177 - Threat weight score for IPS info severity events. 178 type: str 179 choices: 180 - disable 181 - low 182 - medium 183 - high 184 - critical 185 low_severity: 186 description: 187 - Threat weight score for IPS low severity events. 188 type: str 189 choices: 190 - disable 191 - low 192 - medium 193 - high 194 - critical 195 medium_severity: 196 description: 197 - Threat weight score for IPS medium severity events. 198 type: str 199 choices: 200 - disable 201 - low 202 - medium 203 - high 204 - critical 205 level: 206 description: 207 - Score mapping for threat weight levels. 208 type: dict 209 suboptions: 210 critical: 211 description: 212 - Critical level score value (1 - 100). 213 type: int 214 high: 215 description: 216 - High level score value (1 - 100). 217 type: int 218 low: 219 description: 220 - Low level score value (1 - 100). 221 type: int 222 medium: 223 description: 224 - Medium level score value (1 - 100). 225 type: int 226 malware: 227 description: 228 - Anti-virus malware threat weight settings. 229 type: dict 230 suboptions: 231 botnet_connection: 232 description: 233 - Threat weight score for detected botnet connections. 234 type: str 235 choices: 236 - disable 237 - low 238 - medium 239 - high 240 - critical 241 command_blocked: 242 description: 243 - Threat weight score for blocked command detected. 244 type: str 245 choices: 246 - disable 247 - low 248 - medium 249 - high 250 - critical 251 content_disarm: 252 description: 253 - Threat weight score for virus (content disarm) detected. 254 type: str 255 choices: 256 - disable 257 - low 258 - medium 259 - high 260 - critical 261 mimefragmented: 262 description: 263 - Threat weight score for mimefragmented detected. 264 type: str 265 choices: 266 - disable 267 - low 268 - medium 269 - high 270 - critical 271 oversized: 272 description: 273 - Threat weight score for oversized file detected. 274 type: str 275 choices: 276 - disable 277 - low 278 - medium 279 - high 280 - critical 281 switch_proto: 282 description: 283 - Threat weight score for switch proto detected. 284 type: str 285 choices: 286 - disable 287 - low 288 - medium 289 - high 290 - critical 291 virus_blocked: 292 description: 293 - Threat weight score for virus (blocked) detected. 294 type: str 295 choices: 296 - disable 297 - low 298 - medium 299 - high 300 - critical 301 virus_file_type_executable: 302 description: 303 - Threat weight score for virus (filetype executable) detected. 304 type: str 305 choices: 306 - disable 307 - low 308 - medium 309 - high 310 - critical 311 virus_infected: 312 description: 313 - Threat weight score for virus (infected) detected. 314 type: str 315 choices: 316 - disable 317 - low 318 - medium 319 - high 320 - critical 321 virus_outbreak_prevention: 322 description: 323 - Threat weight score for virus (outbreak prevention) event. 324 type: str 325 choices: 326 - disable 327 - low 328 - medium 329 - high 330 - critical 331 virus_scan_error: 332 description: 333 - Threat weight score for virus (scan error) detected. 334 type: str 335 choices: 336 - disable 337 - low 338 - medium 339 - high 340 - critical 341 status: 342 description: 343 - Enable/disable the threat weight feature. 344 type: str 345 choices: 346 - enable 347 - disable 348 url_block_detected: 349 description: 350 - Threat weight score for URL blocking. 351 type: str 352 choices: 353 - disable 354 - low 355 - medium 356 - high 357 - critical 358 web: 359 description: 360 - Web filtering threat weight settings. 361 type: list 362 suboptions: 363 category: 364 description: 365 - Threat weight score for web category filtering matches. 366 type: int 367 id: 368 description: 369 - Entry ID. 370 required: true 371 type: int 372 level: 373 description: 374 - Threat weight score for web category filtering matches. 375 type: str 376 choices: 377 - disable 378 - low 379 - medium 380 - high 381 - critical 382''' 383 384EXAMPLES = ''' 385- hosts: localhost 386 vars: 387 host: "192.168.122.40" 388 username: "admin" 389 password: "" 390 vdom: "root" 391 ssl_verify: "False" 392 tasks: 393 - name: Configure threat weight settings. 394 fortios_log_threat_weight: 395 host: "{{ host }}" 396 username: "{{ username }}" 397 password: "{{ password }}" 398 vdom: "{{ vdom }}" 399 https: "False" 400 log_threat_weight: 401 application: 402 - 403 category: "4" 404 id: "5" 405 level: "disable" 406 blocked_connection: "disable" 407 failed_connection: "disable" 408 geolocation: 409 - 410 country: "<your_own_value>" 411 id: "11" 412 level: "disable" 413 ips: 414 critical_severity: "disable" 415 high_severity: "disable" 416 info_severity: "disable" 417 low_severity: "disable" 418 medium_severity: "disable" 419 level: 420 critical: "20" 421 high: "21" 422 low: "22" 423 medium: "23" 424 malware: 425 botnet_connection: "disable" 426 command_blocked: "disable" 427 content_disarm: "disable" 428 mimefragmented: "disable" 429 oversized: "disable" 430 switch_proto: "disable" 431 virus_blocked: "disable" 432 virus_file_type_executable: "disable" 433 virus_infected: "disable" 434 virus_outbreak_prevention: "disable" 435 virus_scan_error: "disable" 436 status: "enable" 437 url_block_detected: "disable" 438 web: 439 - 440 category: "39" 441 id: "40" 442 level: "disable" 443''' 444 445RETURN = ''' 446build: 447 description: Build number of the fortigate image 448 returned: always 449 type: str 450 sample: '1547' 451http_method: 452 description: Last method used to provision the content into FortiGate 453 returned: always 454 type: str 455 sample: 'PUT' 456http_status: 457 description: Last result given by FortiGate on last operation applied 458 returned: always 459 type: str 460 sample: "200" 461mkey: 462 description: Master key (id) used in the last call to FortiGate 463 returned: success 464 type: str 465 sample: "id" 466name: 467 description: Name of the table used to fulfill the request 468 returned: always 469 type: str 470 sample: "urlfilter" 471path: 472 description: Path of the table used to fulfill the request 473 returned: always 474 type: str 475 sample: "webfilter" 476revision: 477 description: Internal revision number 478 returned: always 479 type: str 480 sample: "17.0.2.10658" 481serial: 482 description: Serial number of the unit 483 returned: always 484 type: str 485 sample: "FGVMEVYYQT3AB5352" 486status: 487 description: Indication of the operation's result 488 returned: always 489 type: str 490 sample: "success" 491vdom: 492 description: Virtual domain used 493 returned: always 494 type: str 495 sample: "root" 496version: 497 description: Version of the FortiGate 498 returned: always 499 type: str 500 sample: "v5.6.3" 501 502''' 503 504from ansible.module_utils.basic import AnsibleModule 505from ansible.module_utils.connection import Connection 506from ansible.module_utils.network.fortios.fortios import FortiOSHandler 507from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG 508 509 510def login(data, fos): 511 host = data['host'] 512 username = data['username'] 513 password = data['password'] 514 ssl_verify = data['ssl_verify'] 515 516 fos.debug('on') 517 if 'https' in data and not data['https']: 518 fos.https('off') 519 else: 520 fos.https('on') 521 522 fos.login(host, username, password, verify=ssl_verify) 523 524 525def filter_log_threat_weight_data(json): 526 option_list = ['application', 'blocked_connection', 'failed_connection', 527 'geolocation', 'ips', 'level', 528 'malware', 'status', 'url_block_detected', 529 'web'] 530 dictionary = {} 531 532 for attribute in option_list: 533 if attribute in json and json[attribute] is not None: 534 dictionary[attribute] = json[attribute] 535 536 return dictionary 537 538 539def underscore_to_hyphen(data): 540 if isinstance(data, list): 541 for elem in data: 542 elem = underscore_to_hyphen(elem) 543 elif isinstance(data, dict): 544 new_data = {} 545 for k, v in data.items(): 546 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 547 data = new_data 548 549 return data 550 551 552def log_threat_weight(data, fos): 553 vdom = data['vdom'] 554 log_threat_weight_data = data['log_threat_weight'] 555 filtered_data = underscore_to_hyphen(filter_log_threat_weight_data(log_threat_weight_data)) 556 557 return fos.set('log', 558 'threat-weight', 559 data=filtered_data, 560 vdom=vdom) 561 562 563def is_successful_status(status): 564 return status['status'] == "success" or \ 565 status['http_method'] == "DELETE" and status['http_status'] == 404 566 567 568def fortios_log(data, fos): 569 570 if data['log_threat_weight']: 571 resp = log_threat_weight(data, fos) 572 573 return not is_successful_status(resp), \ 574 resp['status'] == "success", \ 575 resp 576 577 578def main(): 579 fields = { 580 "host": {"required": False, "type": "str"}, 581 "username": {"required": False, "type": "str"}, 582 "password": {"required": False, "type": "str", "default": "", "no_log": True}, 583 "vdom": {"required": False, "type": "str", "default": "root"}, 584 "https": {"required": False, "type": "bool", "default": True}, 585 "ssl_verify": {"required": False, "type": "bool", "default": True}, 586 "log_threat_weight": { 587 "required": False, "type": "dict", "default": None, 588 "options": { 589 "application": {"required": False, "type": "list", 590 "options": { 591 "category": {"required": False, "type": "int"}, 592 "id": {"required": True, "type": "int"}, 593 "level": {"required": False, "type": "str", 594 "choices": ["disable", "low", "medium", 595 "high", "critical"]} 596 }}, 597 "blocked_connection": {"required": False, "type": "str", 598 "choices": ["disable", "low", "medium", 599 "high", "critical"]}, 600 "failed_connection": {"required": False, "type": "str", 601 "choices": ["disable", "low", "medium", 602 "high", "critical"]}, 603 "geolocation": {"required": False, "type": "list", 604 "options": { 605 "country": {"required": False, "type": "str"}, 606 "id": {"required": True, "type": "int"}, 607 "level": {"required": False, "type": "str", 608 "choices": ["disable", "low", "medium", 609 "high", "critical"]} 610 }}, 611 "ips": {"required": False, "type": "dict", 612 "options": { 613 "critical_severity": {"required": False, "type": "str", 614 "choices": ["disable", "low", "medium", 615 "high", "critical"]}, 616 "high_severity": {"required": False, "type": "str", 617 "choices": ["disable", "low", "medium", 618 "high", "critical"]}, 619 "info_severity": {"required": False, "type": "str", 620 "choices": ["disable", "low", "medium", 621 "high", "critical"]}, 622 "low_severity": {"required": False, "type": "str", 623 "choices": ["disable", "low", "medium", 624 "high", "critical"]}, 625 "medium_severity": {"required": False, "type": "str", 626 "choices": ["disable", "low", "medium", 627 "high", "critical"]} 628 }}, 629 "level": {"required": False, "type": "dict", 630 "options": { 631 "critical": {"required": False, "type": "int"}, 632 "high": {"required": False, "type": "int"}, 633 "low": {"required": False, "type": "int"}, 634 "medium": {"required": False, "type": "int"} 635 }}, 636 "malware": {"required": False, "type": "dict", 637 "options": { 638 "botnet_connection": {"required": False, "type": "str", 639 "choices": ["disable", "low", "medium", 640 "high", "critical"]}, 641 "command_blocked": {"required": False, "type": "str", 642 "choices": ["disable", "low", "medium", 643 "high", "critical"]}, 644 "content_disarm": {"required": False, "type": "str", 645 "choices": ["disable", "low", "medium", 646 "high", "critical"]}, 647 "mimefragmented": {"required": False, "type": "str", 648 "choices": ["disable", "low", "medium", 649 "high", "critical"]}, 650 "oversized": {"required": False, "type": "str", 651 "choices": ["disable", "low", "medium", 652 "high", "critical"]}, 653 "switch_proto": {"required": False, "type": "str", 654 "choices": ["disable", "low", "medium", 655 "high", "critical"]}, 656 "virus_blocked": {"required": False, "type": "str", 657 "choices": ["disable", "low", "medium", 658 "high", "critical"]}, 659 "virus_file_type_executable": {"required": False, "type": "str", 660 "choices": ["disable", "low", "medium", 661 "high", "critical"]}, 662 "virus_infected": {"required": False, "type": "str", 663 "choices": ["disable", "low", "medium", 664 "high", "critical"]}, 665 "virus_outbreak_prevention": {"required": False, "type": "str", 666 "choices": ["disable", "low", "medium", 667 "high", "critical"]}, 668 "virus_scan_error": {"required": False, "type": "str", 669 "choices": ["disable", "low", "medium", 670 "high", "critical"]} 671 }}, 672 "status": {"required": False, "type": "str", 673 "choices": ["enable", "disable"]}, 674 "url_block_detected": {"required": False, "type": "str", 675 "choices": ["disable", "low", "medium", 676 "high", "critical"]}, 677 "web": {"required": False, "type": "list", 678 "options": { 679 "category": {"required": False, "type": "int"}, 680 "id": {"required": True, "type": "int"}, 681 "level": {"required": False, "type": "str", 682 "choices": ["disable", "low", "medium", 683 "high", "critical"]} 684 }} 685 686 } 687 } 688 } 689 690 module = AnsibleModule(argument_spec=fields, 691 supports_check_mode=False) 692 693 # legacy_mode refers to using fortiosapi instead of HTTPAPI 694 legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 695 'username' in module.params and module.params['username'] is not None and \ 696 'password' in module.params and module.params['password'] is not None 697 698 if not legacy_mode: 699 if module._socket_path: 700 connection = Connection(module._socket_path) 701 fos = FortiOSHandler(connection) 702 703 is_error, has_changed, result = fortios_log(module.params, fos) 704 else: 705 module.fail_json(**FAIL_SOCKET_MSG) 706 else: 707 try: 708 from fortiosapi import FortiOSAPI 709 except ImportError: 710 module.fail_json(msg="fortiosapi module is required") 711 712 fos = FortiOSAPI() 713 714 login(module.params, fos) 715 is_error, has_changed, result = fortios_log(module.params, fos) 716 fos.logout() 717 718 if not is_error: 719 module.exit_json(changed=has_changed, meta=result) 720 else: 721 module.fail_json(msg="Error in repo", meta=result) 722 723 724if __name__ == '__main__': 725 main() 726