diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/kubearmor-grafana-loki/logs/README.md b/kubearmor-grafana-loki/logs/README.md new file mode 100644 index 0000000..2aae372 --- /dev/null +++ b/kubearmor-grafana-loki/logs/README.md @@ -0,0 +1,19 @@ +### About +This tutorial shows how to export kubearmor telemetry data to grafana using the kubearmor receiver and [loki exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/lokiexporter) + +### Steps +1. Follow [this tutorial](https://github.com/kubearmor/KubeArmor/blob/ce18fee4f87be7786dc1275aeb94ab7096c8b590/getting-started/deployment_guide.md#L20-L19) to set up Kubearmor +2. Follow this [tutorial](https://github.com/Chinwendu20/OTel-receiver/blob/otel/example/tutorial.md#create-a-custom-opentelemetry-collector-distribution) to create an opentelemetry custom collector. +3. This [tutorial](https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/) shows how to set up grafana and grafana loki. It also shows how to set up configuration for the collector. + Note: + - You would be using the kubearmor receiver for this tutorial. Ensure [this line](https://github.com/Chinwendu20/OTel-receiver/blob/e1b84530dd186b065275156fd80d5c8819295108/example/config.yml#L2-L4) and this [other line](https://github.com/Chinwendu20/OTel-receiver/blob/e1b84530dd186b065275156fd80d5c8819295108/example/config.yml#L13-L14) is in your configuration file. + - For kubearmor kubernetes deployment, you can make use of [this file](https://github.com/Chinwendu20/OTel-receiver/blob/otel/example/collector-k8-manifest.yml) for the collector configuration. Replace in this [line](https://github.com/Chinwendu20/OTel-receiver/blob/e1b84530dd186b065275156fd80d5c8819295108/example/collector-k8-manifest.yml#L16) [your](#loki-endpoint) loki endpoint. + - For Kubearmor bare metal deployment, you can make use of [this file](https://github.com/Chinwendu20/OTel-receiver/blob/otel/example/config.yml) for deployment. Add the loki exporter by adding [this line](https://github.com/Chinwendu20/OTel-receiver/blob/e1b84530dd186b065275156fd80d5c8819295108/example/collector-k8-manifest.yml#L15-L16) and [this line](https://github.com/Chinwendu20/OTel-receiver/blob/e1b84530dd186b065275156fd80d5c8819295108/example/collector-k8-manifest.yml#L25) to the file. Replace loki endpoint with [yours](#loki-endpoint) + + +> ###### Loki endpoint +> If you followed the grafana loki tutorial referenced above, you might have to, run a `docker inspect ` to get the endpoint. + + + +![image](https://user-images.githubusercontent.com/59079323/235289951-6842da6f-a020-4723-81f6-02bae0987d1c.png) diff --git a/kubearmor-grafana-loki/logs/grafana_dashboard.json b/kubearmor-grafana-loki/logs/grafana_dashboard.json new file mode 100644 index 0000000..64e8218 --- /dev/null +++ b/kubearmor-grafana-loki/logs/grafana_dashboard.json @@ -0,0 +1,624 @@ +{ + "__inputs": [ + { + "name": "DS_LOKI-1", + "label": "Loki-1", + "description": "", + "type": "datasource", + "pluginId": "loki", + "pluginName": "Loki" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.4.7" + }, + { + "type": "panel", + "id": "logs", + "name": "Logs", + "version": "" + }, + { + "type": "datasource", + "id": "loki", + "name": "Loki", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "Charts for kubearmor logs", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "{exporter=\"OTLP\"} | json | __error__=``", + "key": "Q-a15cd7ea-55ee-4867-9aec-3b462c5ffccc-0", + "queryType": "range", + "refId": "A" + } + ], + "title": "Logs", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "NameSpace" + } + ] + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "{exporter=\"OTLP\"}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Visual representation of log in a table", + "transformations": [ + { + "id": "extractFields", + "options": { + "format": "kvp", + "source": "Line" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Line": true, + "body": true, + "id": true, + "labels": true, + "tsNs": true + }, + "indexByName": {}, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 70 + }, + { + "color": "red", + "value": 85 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 10, + "maxPerRow": 2, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": false + }, + "pluginVersion": "9.4.7", + "repeat": "attribute", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "sum by(label) (count_over_time({exporter=\"OTLP\"} |= `` | json label=\"body.$attribute\" | __error__=`` [$__range]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Visual representation of log $attribute in a guage", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "{logLevel=\"\"}": "N/A", + "{logLevel=\"INFO\"}": "INFO", + "{logLevel=\"WARN\"}": "WARN" + } + } + } + ], + "type": "gauge" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 11, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true, + "values": [] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.7", + "repeat": "attribute", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "sum by(label) (count_over_time({exporter=\"OTLP\"} | json label=\"body.$attribute\" | __error__=`` [$__range]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Visual representation of log $attribute in a pie chart", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "{logLevel=\"\"}": "N/A", + "{logLevel=\"INFO\"}": "INFO", + "{logLevel=\"WARN\"}": "WARN" + } + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Amount" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 3, + "options": { + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "sum by(body_$attribute) (count_over_time({exporter=\"OTLP\"} |= `` | json | __error__=`` [$__range]))", + "queryType": "instant", + "refId": "A" + } + ], + "title": "Occurence of unique values in log $attribute", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "Value #A": "Amount" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 12, + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "9.4.7", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI-1}" + }, + "editorMode": "builder", + "expr": "sum by(logLevel) (count_over_time({exporter=\"OTLP\"} | json logLevel=\"body.$attribute\" | __error__=`` [$__range]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Visual representation of log $attribute in a bar guage", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "{logLevel=\"\"}": "N/A", + "{logLevel=\"INFO\"}": "INFO", + "{logLevel=\"WARN\"}": "WARN" + } + } + } + ], + "type": "bargauge" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Level", + "value": "Level" + }, + "hide": 0, + "label": "Log Attribute", + "name": "attribute", + "options": [ + { + "selected": true, + "text": "Level", + "value": "Level" + } + ], + "query": "Level", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": {}, + "hide": 0, + "name": "filter", + "options": [], + "query": "", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": {}, + "timezone": "Africa/Lagos", + "title": "KubeArmor", + "uid": "UohN2UU4k", + "version": 31, + "weekStart": "" +} \ No newline at end of file diff --git a/kubearmor-kafka-elk-stack/README.md b/kubearmor-kafka-elk-stack/README.md new file mode 100644 index 0000000..162eead --- /dev/null +++ b/kubearmor-kafka-elk-stack/README.md @@ -0,0 +1,39 @@ +# Integration with ELK + +KubeArmor provides a dashboard by integrating with Logstash + Elasticsearch + Kibana. + +For this, KubeArmor, KafkaClient, and Kafka should be deployed. +If you didn't set up KubeArmor's Kafka Client or the Kafka system, please follow the steps described in [KafkaClient](https://github.com/kubearmor/kubearmor-kafka-client). + +If those are ready, you can deploy ELK now. Note that the ELK stack will be deployed in the "kubearmor" namespace. + +``` +$ cd kubearmor-elk-stack +~/kubearmor-elk-stack$ kubectl apply -f elasticsearch.yaml +~/kubearmor-elk-stack$ kubectl apply -f kibana.yaml +~/kubearmor-elk-stack$ kubectl apply -f logstash.yaml +``` + +It takes a couple of minutes. Wait for the completed deployments of those services. + +# Kibana UI + +Using your browser, you can access the Kibana UI. + +``` +http://[the IP address of one of the cluster nodes]:30561 +``` + +If you just set up the ELK environment, wait until you see 'kubearmor-YYYYMMDD' in [Management] - [Index Management]. + +![Index Management](./res/kibana_index_management.png) + +After you see 'kubearmor' in the Index Management, go to [Management] - [Saved Objects] and import [kibana-export.json](https://github.com/kubearmor/kubearmor-elk-stack/blob/master/kibana-export.json). + +If you see the logs in [Discover], all works fine. + +![Discover](./res/kibana_discover.png) + +Now, feel free to make your own dashboard. + +![Dashboard](./res/kibana_dashboard.png) diff --git a/elasticsearch.yaml b/kubearmor-kafka-elk-stack/elasticsearch.yaml similarity index 100% rename from elasticsearch.yaml rename to kubearmor-kafka-elk-stack/elasticsearch.yaml diff --git a/kibana-export.json b/kubearmor-kafka-elk-stack/kibana-export.json similarity index 100% rename from kibana-export.json rename to kubearmor-kafka-elk-stack/kibana-export.json diff --git a/kibana.yaml b/kubearmor-kafka-elk-stack/kibana.yaml similarity index 100% rename from kibana.yaml rename to kubearmor-kafka-elk-stack/kibana.yaml diff --git a/logstash.yaml b/kubearmor-kafka-elk-stack/logstash.yaml similarity index 100% rename from logstash.yaml rename to kubearmor-kafka-elk-stack/logstash.yaml diff --git a/res/kibana_dashboard.png b/kubearmor-kafka-elk-stack/res/kibana_dashboard.png similarity index 100% rename from res/kibana_dashboard.png rename to kubearmor-kafka-elk-stack/res/kibana_dashboard.png diff --git a/res/kibana_discover.png b/kubearmor-kafka-elk-stack/res/kibana_discover.png similarity index 100% rename from res/kibana_discover.png rename to kubearmor-kafka-elk-stack/res/kibana_discover.png diff --git a/res/kibana_index_management.png b/kubearmor-kafka-elk-stack/res/kibana_index_management.png similarity index 100% rename from res/kibana_index_management.png rename to kubearmor-kafka-elk-stack/res/kibana_index_management.png