├── host.json ├── media └── azuremonitor2syslog_overview.png ├── AzureMonitor2Syslog ├── function.json └── index.js ├── LICENSE └── README.md /host.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /media/azuremonitor2syslog_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miguelangelopereira/azuremonitor2syslog/HEAD/media/azuremonitor2syslog_overview.png -------------------------------------------------------------------------------- /AzureMonitor2Syslog/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "eventHubTrigger", 5 | "name": "myEventHubMessage", 6 | "connection": "logging01_RootManageSharedAccessKey_EVENTHUB", 7 | "eventHubName": "logs", 8 | "consumerGroup": "$Default", 9 | "direction": "in" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Miguel Pereira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Forward Azure Monitor Logs to Syslog (via Event Hub) 2 | 3 | [Azure Monitor](https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-azure-monitor) provides base-level infrastructure metrics and logs for most services in Microsoft Azure. Azure services that do not yet put their data into Azure Monitor will put it there in the future. 4 | 5 | Azure monitor allows you to [forward monitoring data to eventhub](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/stream-monitoring-data-event-hubs). 6 | 7 | A common scenario is to have a centralized SIEM based on syslog. The best option is for the SIEM to integrate directly with Azure monitor (Splunk, IBM QRadar, ArcSight...). If that is not available you can use an Azure Function accomplish this integration. 8 | 9 | **This project is a sample for testing purpuses** 10 | 11 | # Overview 12 | ![alt text](https://github.com/miguelangelopereira/azuremonitor2syslog/blob/master/media/azuremonitor2syslog_overview.png "azuremonitor2syslog") 13 | 14 | The Azure monitor will send metrics to Event Hub. The Event Hub messages will trigger this Javascript Azure Function that will convert the message to syslog format and send to the correct server. 15 | 16 | Note: To send the syslog messages to an internal server in a VNET, configure the Function App with [VNET integration](https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet). 17 | 18 | # Usage 19 | * Create Event Hub and setup [Azure monitoring forwarding](https://azure.microsoft.com/en-us/blog/azure-monitor-send-monitoring-data-to-an-event-hub/) 20 | * Create the Function App (v2). Make sure the runtime is Javascript. 21 | * Import code or setup git deployment 22 | * In function.json configuration, **cardinality** should be set to **many**. "cardinality": "many", 23 | * In the integrate section of the function, make sure Event Hub connection is pointing to the correct event hub 24 | * In the Function App Application Settings, create the following App Settings: 25 | * SYSLOG_HOSTNAME: The source hostname in the syslog message 26 | * SYSLOG_SERVER: The remote syslog server 27 | * SYSLOG_PORT: The port syslog service is running 28 | * SYSLOG_PROTOCOL: TCP or UDP (defaults to UDP if not configured) 29 | * SYSLOG_FACILITY: SYSLOG Facility to be used (defaults to 16 = Local0) 30 | * Make sure the syslog-client package is updated 31 | 32 | 33 | Note: Make sure the EventHub function app extension is installed. See: https://github.com/Azure/azure-functions-host/wiki/Updating-your-function-app-extensions 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /AzureMonitor2Syslog/index.js: -------------------------------------------------------------------------------- 1 | // Forward Azure Monitor Logs to Syslog (via Event Hub) 2 | // Developed as a sample for testing purpuses 3 | // https://github.com/miguelangelopereira/azuremonitor2syslog 4 | // miguelp@microsoft.com 5 | 6 | module.exports = function (context, myEventHubMessage) { 7 | context.log(`JavaScript eventhub trigger function called for message array ${myEventHubMessage}`); 8 | // initializing syslog 9 | try{ 10 | var syslog = require("syslog-client"); 11 | } catch (e) { 12 | throw e; 13 | } 14 | 15 | 16 | // getting environment variables 17 | var SYSLOG_SERVER = GetEnvironmentVariable("SYSLOG_SERVER"); 18 | var SYSLOG_PROTOCOL; 19 | if (GetEnvironmentVariable("SYSLOG_PROTOCOL")=="TCP") { 20 | SYSLOG_PROTOCOL = syslog.Transport.Tcp; 21 | } else { 22 | SYSLOG_PROTOCOL = syslog.Transport.Udp; 23 | } 24 | 25 | var SYSLOG_HOSTNAME; 26 | if (GetEnvironmentVariable("SYSLOG_HOSTNAME")==null) { 27 | SYSLOG_HOSTNAME = "azurefunction" 28 | } else { 29 | SYSLOG_HOSTNAME = GetEnvironmentVariable("SYSLOG_HOSTNAME"); 30 | } 31 | 32 | var SYSLOG_PORT = GetEnvironmentVariable("SYSLOG_PORT"); 33 | 34 | var SYSLOG_FACILITY; 35 | if (GetEnvironmentVariable("SYSLOG_FACILITY")==null) { 36 | SYSLOG_FACILITY = syslog.Facility.Local0; 37 | } else { 38 | SYSLOG_FACILITY = GetEnvironmentVariable("SYSLOG_FACILITY"); 39 | } 40 | 41 | // options for syslog connection 42 | var options = { 43 | syslogHostname: SYSLOG_HOSTNAME, 44 | transport: SYSLOG_PROTOCOL, 45 | port: SYSLOG_PORT, 46 | facility: SYSLOG_FACILITY 47 | }; 48 | 49 | // log connection variables 50 | context.log('SYSLOG Server: ', SYSLOG_SERVER); 51 | context.log('SYSLOG Port: ', SYSLOG_PORT); 52 | context.log('SYSLOG Protocol: ', SYSLOG_PROTOCOL); 53 | context.log('SYSLOG Hostname: ', SYSLOG_HOSTNAME); 54 | context.log('SYSLOG Facility: ', SYSLOG_FACILITY); 55 | 56 | if ((SYSLOG_SERVER == null) || (SYSLOG_PORT == null) || (SYSLOG_PROTOCOL == null) || (SYSLOG_HOSTNAME == null)) { 57 | throw "Please setup environment variables. " 58 | } 59 | 60 | // log received message from event hub 61 | context.log(`Event Hubs trigger function processed message: ${myEventHubMessage}`); 62 | context.log('EnqueuedTimeUtc =', context.bindingData.enqueuedTimeUtc); 63 | context.log('SequenceNumber =', context.bindingData.sequenceNumber); 64 | context.log('Offset =', context.bindingData.offset); 65 | 66 | // create syslog client 67 | var client = syslog.createClient(SYSLOG_SERVER, options); 68 | 69 | // cycle through eventhub messages and send syslog 70 | myEventHubMessage.forEach((message, index)=>{ 71 | if(typeof message === 'object'){ 72 | 73 | var msg = JSON.parse(JSON.stringify(message)); 74 | msg.records.forEach((m1, i) => { 75 | client.log(JSON.stringify(m1), options, function(error) { 76 | if (error) { 77 | context.log("error sending message"); 78 | context.log(error); 79 | } else { 80 | context.log("sent message successfully"); 81 | } 82 | }); 83 | }); 84 | 85 | } 86 | }); 87 | 88 | 89 | context.log("completed sending all messages"); 90 | 91 | context.done(); 92 | }; 93 | 94 | function GetEnvironmentVariable(name) 95 | { 96 | return process.env[name]; 97 | } 98 | --------------------------------------------------------------------------------