{"id":19929149,"url":"https://github.com/nembery/saltstack-panorama-log-listener","last_synced_at":"2026-05-10T21:36:22.050Z","repository":{"id":134260437,"uuid":"261510810","full_name":"nembery/saltstack-panorama-log-listener","owner":"nembery","description":"Example configs to setup Saltstack to listen to and respond to log events in Panorama","archived":false,"fork":false,"pushed_at":"2020-05-05T19:26:40.000Z","size":14,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-12T01:13:41.790Z","etag":null,"topics":["palo","panorama","saltstack","skillets"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nembery.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-05T15:30:22.000Z","updated_at":"2021-09-07T01:39:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"4fe7b527-85a7-489b-ab9b-2c2dd30f72d6","html_url":"https://github.com/nembery/saltstack-panorama-log-listener","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nembery%2Fsaltstack-panorama-log-listener","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nembery%2Fsaltstack-panorama-log-listener/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nembery%2Fsaltstack-panorama-log-listener/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nembery%2Fsaltstack-panorama-log-listener/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nembery","download_url":"https://codeload.github.com/nembery/saltstack-panorama-log-listener/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241355279,"owners_count":19949340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["palo","panorama","saltstack","skillets"],"created_at":"2024-11-12T22:42:02.408Z","updated_at":"2026-05-10T21:36:16.997Z","avatar_url":"https://github.com/nembery.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Saltstack Event / Panorama Log Listener\n\nThis is a simple example of how to set up a log listener to execute arbitrary python code in response to various logs\nfrom Panorama.\n\n## Example Details\n\nThis example configured Panorama to send an event when a new device connects and is placed in the 'staging' device \ngroup.\n\nSaltstack is then configured to connect to that device, update it's dynamic content, then move it into a new device\ngroup. More actions and compliance checks could easily be added.\n\n\n\n## Extending this Example\n\n1. Set up HTTP log forwarding profile in PAN-OS, the URI to send the logs will be something \nlike /hook/vistoq/device-connected. Ensure you add a header of 'Content-Type': 'Application/json' and \nuse the following log format. The panorama-config directory contains a skillet to push the appropriate config.\n\n    ```json\n     {\n     \"device_name\": \"$device_name\",\n     \"serial\": \"$serial\",\n     \"description\": \"$opaque\"\n    } \n    ```\n      \n2. Configure a entry in the 'reactor.conf' such as:\n    ```bash\n        # the event URI /vistoq/device-connected will map to the vistoq_device_connected.sls file\n      - 'salt/netapi/hook/vistoq/device-connected':\n        - /srv/salt/reactor/vistoq_device_connected.sls\n    ```\n\n3. Create the reactor sls file in the salt/reactor directory to map the event structure to your python code\n\n    ```bash\n    # this sls file recieves two objects: data and tag\n    # the data object is a dict created from the JSON payload that is recieved on the webhook\n    # the whole point of this file is to map the recieved json payload to the function arguments\n    # required for our code\n    # this SLS file is jinja interpolated, so normal jinja syntax applies\n    # set a variable named H that contains the contents of the 'headers' attributes in the payload\n    {% set h = data.get('headers', {}) %}\n    # get the remote-address from the headers and set as r\n    {% set r = h.get('Remote-Addr', '') %}\n    # get the post attribute from the data\n    {% set p = data.get('post', {}) %}\n    # get the serial number from the posted payload\n    {% set s = p.get('serial', '') %}\n    # and get the description\n    {% set d = p.get('description', '') %}\n    \n    # top level is just an arbitrary name \n    content_update:\n      # to keep things simple, we are using a runner, which is a bit of python code found in \n      # salt/runner directory. This will execute the content_update function in the 'updates.py'\n      # The will send in the 4 keyword arguments listed below\n      runner.updates.content_update:\n       - panorama_ip: {{ r }}\n       - panorama_user: {{ panorama_user }}\n       - panorama_password: {{ panorama_password }}\n       - device_serial: \"{{ d.split(\":\")[1].split(\" \")[0] | string }}\" \n   ```\n \n 4. Create your python code in the salt/runner directory. In this case, the 'updates.py' file will\n contain something like the following:\n \n    ```python\n    # create a function that matches that listed in your reactor file above\n    def content_update(panorama_ip, panorama_user, panorama_password, device_serial)\n    ```\n   \n5. Use docker-compose to bring up the saltstack container and map in the config files as necessary ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnembery%2Fsaltstack-panorama-log-listener","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnembery%2Fsaltstack-panorama-log-listener","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnembery%2Fsaltstack-panorama-log-listener/lists"}