├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SUPPORT.md ├── images ├── azure_function_code.png ├── azure_function_trigger.png ├── create_azure_function.png ├── create_azure_function_function.png └── create_gcp_function.png ├── pcs_lambda_qradar.py ├── prisma_cloud_serverless_aws.py ├── prisma_cloud_serverless_azure.py ├── prisma_cloud_serverless_gcp.py ├── prisma_cloud_webhook_to_s3.py └── prisma_cloud_webhook_to_sqs.py /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | It's people like you that make security open source such a force in preventing 6 | successful cyber-attacks. Following these guidelines helps keep the project 7 | maintainable, easy to contribute to, and more secure. Thank you for taking the 8 | time to follow this guide. 9 | 10 | ## Where to start 11 | 12 | There are many ways to contribute. You can fix a bug, improve the documentation, 13 | submit bug reports and feature requests, or take a first shot at a feature you 14 | need for yourself. 15 | 16 | Pull requests are necessary for all contributions of code or documentation. 17 | 18 | ## New to open source? 19 | 20 | If you're **new to open source** and not sure what a pull request is, welcome!! 21 | We're glad to have you! All of us once had a contribution to make and didn't 22 | know where to start. 23 | 24 | Even if you don't write code for your job, don't worry, the skills you learn 25 | during your first contribution to open source can be applied in so many ways, 26 | you'll wonder what you ever did before you had this knowledge. It's worth 27 | learning. 28 | 29 | [Learn how to make a pull request](https://github.com/PaloAltoNetworks/.github/blob/master/Learn-GitHub.md#learn-how-to-make-a-pull-request) 30 | 31 | ## Fixing a typo, or a one or two line fix 32 | 33 | Many fixes require little effort or review, such as: 34 | 35 | > - Spelling / grammar, typos, white space and formatting changes 36 | > - Comment clean up 37 | > - Change logging messages or debugging output 38 | 39 | These small changes can be made directly in GitHub if you like. 40 | 41 | Click the pencil icon in GitHub above the file to edit the file directly in 42 | GitHub. This will automatically create a fork and pull request with the change. 43 | See: 44 | [Make a small change with a Pull Request](https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github/) 45 | 46 | ## Bug fixes and features 47 | 48 | For something that is bigger than a one or two line fix, go through the process 49 | of making a fork and pull request yourself: 50 | 51 | > 1. Create your own fork of the code 52 | > 2. Clone the fork locally 53 | > 3. Make the changes in your local clone 54 | > 4. Push the changes from local to your fork 55 | > 5. Create a pull request to pull the changes from your fork back into the 56 | > upstream repository 57 | 58 | Please use clear commit messages so we can understand what each commit does. 59 | We'll review every PR and might offer feedback or request changes before 60 | merging. 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2020, Palo Alto Networks Inc. 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prisma Cloud Function to Syslog 2 | 3 | Version: *1.1* 4 | Author: *Eddie Beuerlein, Marc Hobson, Sean Sullivan, Ismayl Msed* 5 | 6 | ### Use Cases 7 | - Can’t use AWS SQS integration because environment is Azure/GCP only 8 | - Need to support a SIEM or other data ingestion tool that we currently don’t have a built-in integration available (currently we support Splunk, Jira and ServiceNow) 9 | - Useful for anything that can ingest JSON data from a syslog message 10 | 11 | 12 | ### Requirements and Dependencies 13 | - Syslog-NG, Rsyslog or equivalent: needs to support TCP delivery due to the size of the alert payload 14 | - Serverless capability: 15 | - GCP Cloud Functions 16 | - AWS Lambda 17 | - Azure Functions 18 | - SIEM/or other data ingestion tool that supports JSON based data (this could be other formats if there is a way to convert to them such as CEF or LEEF) 19 | - Choose memory profile that meets your needs: 128MB is not very much 20 | 21 | 22 | ### Configuration 23 | #### AWS Lambda Setup 24 | - Create NEW Lambda Function 25 | - Paste Code 26 | - Save 27 | 28 | - Configure Amazon API Gateway 29 | - Create NEW API Gateway 30 | - Build “HTTP API” 31 | - Click “Add Integration” Button 32 | - Integration Type: “Lambda” 33 | - Integration Target: your choice 34 | - Select the above created Lambda Function from the text box 35 | - Give the API a name 36 | - Select “Review and Create” 37 | - Copy the “Invoke URL” to use to test with curl or other source. 38 | 39 | #### GCP Cloud Function Setup 40 | 41 | - Create Function 42 | - ![](./images/create_gcp_function.png) 43 | - Name function 44 | - Set Memory allocated to 128mb 45 | - Set trigger to HTTP for use with a webhook. 46 | 47 | - Use Inline Editor 48 | - Select “Python 3.7” 49 | - Paste code here 50 | - Configure function to Execute as “main”. Finish by clicking “Create”. 51 | 52 | - To attain the URL of the cloud function: 53 | - First click on the function 54 | - Select “Trigger” 55 | - Copy the URL for use with the Prisma Cloud webhook integration. 56 | 57 | #### Azure Function Setup 58 | 59 | - Create a Function App 60 | - Publish: Code 61 | - Runtime stack: Python 62 | - Version: 3.9 63 | ![](./images/create_azure_function.png) 64 | 65 | - Go to created Function App, and go to "Functions" 66 | - Create 67 | ![](./images/create_azure_function_function.png) 68 | - Develop in Portal 69 | - HTTP trigger 70 | - Authorization level: Function 71 | ![](./images/azure_function_trigger.png) 72 | - Code + Test 73 | - Paste code here (overwrite all) 74 | - **EDIT LINES 7 AND 8 to point to your syslog server** 75 | - Save 76 | ![](./images/azure_function_code.png) 77 | - Click _"Get function URL"_ and this is the Webhook URL to input into the Prisma Cloud integration for the payload to be sent. 78 | 79 | #### VM machine / Syslog Server Setup 80 | 81 | 1. Any Linux server will work for this setup, but the syslog server does need to support TCP in order to handle the large alert payload from Prisma. Rsyslog or SyslogNG work great in this scenario. Rsyslog will be used in the setup example. 82 | 83 | 2. Configuring rsyslog.conf file: 84 | Add to top of file (needed to handle large JSON alert payload): 85 | ``` 86 | $MaxMessageSize 64k 87 | #need TCP enabled due to payload sizes of JSON data 88 | $ModLoad imtcp 89 | $InputTCPServerRun 514 90 | #needs to match facility specified in python code 91 | local3.* /var/log/RedLock.log 92 | ``` 93 | 3. You may want to comment out the /etc/rsyslog.d/90-google.conf line as this can slow reception of the JSON messages or remove the file altogether. NOTE this only affects GCP provided virtual machines. https://logrhythm.com/blog/troubleshooting-delayed-syslog-messages/ 94 | 95 | #### Prisma integration setup 96 | 1. https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin/configure-external-integrations-on-prisma-cloud/integrate-prisma-cloud-with-webhooks 97 | 98 | 2. Insert Cloud Function trigger URL into the “Webhook URL” textbox 99 | 100 | ### Support 101 | See the [support policy](SUPPORT.md). 102 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Community Supported 2 | This template/solution is released under an as-is, best effort, support policy. These scripts should be seen as community supported and Palo Alto Networks will contribute our expertise as and when possible. We do not provide technical support or help in using or troubleshooting the components of the project through our normal support options such as Palo Alto Networks support teams, or ASC (Authorized Support Centers) partners and backline support options. The underlying product used (Prisma Cloud) by the scripts or templates are still supported, but the support is only for the product functionality and not for help in deploying or using the template or script itself. 3 | 4 | Unless explicitly tagged, all projects or work posted in our GitHub repository (at https://github.com/PaloAltoNetworks) or sites other than our official Downloads page on https://support.paloaltonetworks.com are provided under the best effort policy. 5 | -------------------------------------------------------------------------------- /images/azure_function_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/pcs-serverless-syslog/35aea3857fc55d8b076c2750c0d62abfdd91099e/images/azure_function_code.png -------------------------------------------------------------------------------- /images/azure_function_trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/pcs-serverless-syslog/35aea3857fc55d8b076c2750c0d62abfdd91099e/images/azure_function_trigger.png -------------------------------------------------------------------------------- /images/create_azure_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/pcs-serverless-syslog/35aea3857fc55d8b076c2750c0d62abfdd91099e/images/create_azure_function.png -------------------------------------------------------------------------------- /images/create_azure_function_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/pcs-serverless-syslog/35aea3857fc55d8b076c2750c0d62abfdd91099e/images/create_azure_function_function.png -------------------------------------------------------------------------------- /images/create_gcp_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/pcs-serverless-syslog/35aea3857fc55d8b076c2750c0d62abfdd91099e/images/create_gcp_function.png -------------------------------------------------------------------------------- /pcs_lambda_qradar.py: -------------------------------------------------------------------------------- 1 | """ 2 | An AWS Lambda function to forward Prisma Cloud webhook messages to syslog 3 | """ 4 | 5 | 6 | import json 7 | import logging 8 | import sys 9 | import logging.handlers 10 | import socket 11 | from botocore.vendored import requests 12 | 13 | SYSLOG_HOST = "123.456.789.012" 14 | SYSLOG_PORT = 514 15 | 16 | def lambda_handler(event, context): 17 | request_json = json.loads(event['body']) 18 | syslogger = logging.getLogger('MySysLogger') 19 | syslogger.setLevel(logging.INFO) 20 | handler = logging.handlers.SysLogHandler(address = (SYSLOG_HOST, SYSLOG_PORT),facility = logging.handlers.SysLogHandler.LOG_LOCAL3,socktype=socket.SOCK_STREAM) 21 | handler.setFormatter(logging.Formatter('%(message)s\n')) 22 | handler.append_nul = False 23 | syslogger.addHandler(handler) 24 | for alert in request_json: 25 | if 'resource' in alert: 26 | if 'data' in alert['resource']: 27 | del alert['resource']['data'] 28 | syslogger.info(json.dumps(alert)) 29 | return { 30 | 'statusCode': 200 31 | } 32 | -------------------------------------------------------------------------------- /prisma_cloud_serverless_aws.py: -------------------------------------------------------------------------------- 1 | """ 2 | An AWS Lambda function to forward Prisma Cloud webhook messages to syslog 3 | """ 4 | 5 | 6 | import json 7 | import logging 8 | import sys 9 | import logging.handlers 10 | import socket 11 | from botocore.vendored import requests 12 | 13 | SYSLOG_HOST = "123.456.789.012" 14 | SYSLOG_PORT = 514 15 | 16 | def lambda_handler(event, context): 17 | request_json = json.loads(event['body']) 18 | syslogger = logging.getLogger('MySysLogger') 19 | syslogger.setLevel(logging.INFO) 20 | handler = logging.handlers.SysLogHandler(address = (SYSLOG_HOST, SYSLOG_PORT),facility = logging.handlers.SysLogHandler.LOG_LOCAL3,socktype=socket.SOCK_STREAM) 21 | handler.setFormatter(logging.Formatter('%(message)s\n')) 22 | handler.append_nul = False 23 | syslogger.addHandler(handler) 24 | for alert in range(len(request_json)): 25 | syslogger.info(json.dumps(request_json[alert])) 26 | return { 27 | 'statusCode': 200 28 | } 29 | -------------------------------------------------------------------------------- /prisma_cloud_serverless_azure.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import azure.functions as func 3 | import logging.handlers 4 | import socket 5 | import json 6 | 7 | SYSLOG_HOST = "10.0.0.4" 8 | SYSLOG_PORT = 514 9 | 10 | 11 | def main(req: func.HttpRequest) -> func.HttpResponse: 12 | logging.info('Python HTTP trigger function processed a request.') 13 | request_json = req.get_json() 14 | syslogger = logging.getLogger('MySysLogger') 15 | syslogger.setLevel(logging.INFO) 16 | handler = logging.handlers.SysLogHandler(address = (SYSLOG_HOST, SYSLOG_PORT),facility = logging.handlers.SysLogHandler.LOG_LOCAL3,socktype=socket.SOCK_STREAM) 17 | handler.setFormatter(logging.Formatter('%(message)s\n')) 18 | handler.append_nul = False 19 | syslogger.addHandler(handler) 20 | for alert in range(len(request_json)): 21 | syslogger.info(json.dumps(request_json[alert])) 22 | return func.HttpResponse( 23 | "This HTTP triggered function executed successfully.", 24 | status_code=200 25 | ) 26 | -------------------------------------------------------------------------------- /prisma_cloud_serverless_gcp.py: -------------------------------------------------------------------------------- 1 | """ 2 | A GCP cloud function to forward Prisma Cloud webhook messages to syslog 3 | """ 4 | # 5 | # main() will be run when you invoke this action 6 | # 7 | 8 | import logging 9 | import sys 10 | import logging.handlers 11 | import socket 12 | import json 13 | import requests 14 | 15 | SYSLOG_HOST = "123.456.789.012" 16 | SYSLOG_PORT = 514 17 | 18 | def main(request): 19 | request_json = request.get_json(silent=True) 20 | syslogger = logging.getLogger('MySysLogger') 21 | syslogger.setLevel(logging.INFO) 22 | handler = logging.handlers.SysLogHandler(address = (SYSLOG_HOST, SYSLOG_PORT),facility = logging.handlers.SysLogHandler.LOG_LOCAL3,socktype=socket.SOCK_STREAM) 23 | handler.setFormatter(logging.Formatter('%(message)s\n')) 24 | handler.append_nul = False 25 | syslogger.addHandler(handler) 26 | for alert in range(len(request_json)): 27 | syslogger.info(json.dumps(request_json[alert])) 28 | -------------------------------------------------------------------------------- /prisma_cloud_webhook_to_s3.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import datetime 4 | 5 | DEST_TYPE = 'S3' 6 | S3_BUCKET_NAME = 'XXXXXXXXXX' 7 | 8 | 9 | def lambda_handler(event, context): 10 | request_json = json.loads(event['body']) 11 | 12 | if DEST_TYPE == "S3": 13 | s3 = boto3.resource("s3") 14 | 15 | for alert in range(len(request_json)): 16 | filename=str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.') + str('.json') 17 | s3.Bucket(S3_BUCKET_NAME).put_object(Key=filename, Body=json.dumps(request_json[alert])) 18 | return { 19 | 'statusCode': 200, 20 | } 21 | -------------------------------------------------------------------------------- /prisma_cloud_webhook_to_sqs.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | 4 | DEST_TYPE = 'SQS' 5 | SQS_QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/012345678912/my_queue_name' 6 | 7 | 8 | def lambda_handler(event, context): 9 | request_json = json.loads(event['body']) 10 | 11 | if DEST_TYPE == "SQS": 12 | sqs = boto3.resource('sqs') 13 | sqs_queue = sqs.Queue(SQS_QUEUE_URL) 14 | 15 | for alert in range(len(request_json)): 16 | response = sqs_queue.send_message(MessageBody=json.dumps(request_json[alert])) 17 | return { 18 | 'statusCode': 200, 19 | } 20 | --------------------------------------------------------------------------------