Introduction

Je pars du principe que vous utilisez Portainer, que vous savez vous servir d’un éditeur de texte et que vous connaissez vos machines.

Quelques notions

Loki est un système d’agrégation de logs horizontalement évolutif, hautement disponible et multi-tenant inspiré de Prometheus. Il est conçu pour être très rentable et facile à utiliser. Il n’indexe pas le contenu des journaux, mais plutôt un ensemble d’étiquettes pour chaque flux de journaux.Le projet Loki a été lancé à Grafana Labs en 2018, et annoncé à la KubeCon de Seattle. Loki est publié sous la licence AGPLv3.Grafana Labs est fier de diriger le développement du projet Loki, en construisant un support de première classe pour Loki dans Grafana, et en s’assurant que les clients de Grafana Labs reçoivent le support de Loki et les fonctionnalités dont ils ont besoin.

Site de Loki

Promtail est un agent qui envoie le contenu des journaux locaux vers une instance privée de Grafana Loki ou Grafana Cloud. Il est généralement déployé sur chaque machine qui a des applications à surveiller.Il permet principalement de :- Découvrir des cibles- Attache des étiquettes aux flux de journaux- Les pousse vers l’instance Loki.Actuellement, Promtail peut suivre les journaux provenant de deux sources : les fichiers journaux locaux et le journal systemd (sur les machines AMD64 uniquement).

Site de Promtail

Prérequis

Vous avez déjà installé un stack avec Grafana et Prometheus.

Fichiers requis

docker-compose.yml

[Fichier]

version: "3.0"

#
# updated: 2023-05-24
# stack:   loki
#

x-logging: &x-logging
  logging:
    driver: loki
    options:
      loki-url: "http://loki:3100/loki/api/v1/push"
      loki-retries: "5"
      loki-batch-size: "400"
        
x-common: &x-common
  <<: *x-logging
  restart: "no"
  stop_grace_period: 5s
  stdin_open: true
  tty: true
  privileged: false
  security_opt:
    - no-new-privileges=true
  cap_drop:
    - ALL
  cap_add:
    - KILL
  dns:
    - 1.1.1.1
    - 8.8.8.8
    - 1.0.0.1
    - 8.8.4.4
  ipc: "shareable"
  extra_hosts:
    - "template.home:192.168.0.0"
  environment:
    TZ: "Europe/Paris"
    PUID: 1000
    PGID: 1000
  user: 1000:1000
  labels:
    com.centurylinklabs.watchtower.enable: true
    logging: "promtail"
    com.stack.name: "common"
    com.stack.service.name: "common"
  devices:
    - /dev/kmsg:/dev/kmsg
  deploy:
    resources:
      limits:
        cpus: "0.50"
        memory: 256M
  ulimits:
    nproc: 65535
    nofile:
      soft: 20000
      hard: 40000
  tmpfs:
    - /tmp:rw,noexec,nosuid,size=64k
  sysctls:
    net.core.somaxconn: 1024
    net.ipv4.tcp_syncookies: 0
x-volume-timezone: &x-volume-timezone "/etc/timezone:/etc/timezone:ro"
x-volume-localtime: &x-volume-localtime "/etc/localtime:/etc/localtime:ro"
x-volume-docker-socket: &x-volume-docker-socket "/var/run/docker.sock:/var/run/docker.sock:rw"
x-volume-cgroups: &x-volume-cgroups "/proc/cgroups:/cgroup:rw"
x-volume-ssl: &x-volume-ssl "/opt/docker/ssl:/ssl:ro"

services:
  loki:
    <<: *x-common
    logging:
      driver: json-file
      options:
        max-size: 32m
        max-file: "7"
        compress: "true"
    stop_grace_period: 60s
    cap_add:
      - DAC_OVERRIDE
    container_name: loki
    hostname: loki
    image: grafana/loki:latest
    restart: always
    ports:
      - "3100:3100"
    expose:
      - "3100"
    command: -config.file=/etc/loki/loki.yml
    labels:
      com.stack.name: "loki"
      com.stack.service.name: "loki"
    deploy:
      resources:
        limits:
          cpus: "4.0"
          memory: 1G
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=512M
    volumes:
      - *x-volume-timezone
      - *x-volume-localtime
      - *x-volume-docker-socket
      - *x-volume-cgroups
      - /opt/docker/loki/conf:/etc/loki
      - /opt/docker/loki/datas/loki:/datas
  promtail:
    <<: *x-common
    user: 0:0
    cap_add:
      - DAC_OVERRIDE
    container_name: promtail
    hostname: promtail
    image: grafana/promtail:latest
    restart: always
    depends_on:
      - loki
    ports:
      - "1514:1514"
    expose:
      - "1514"
    command: -config.file=/etc/promtail/promtail.yml
    labels:
      com.stack.name: "loki"
      com.stack.service.name: "promtail"
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=512M
    volumes:
      - *x-volume-timezone
      - *x-volume-localtime
      - *x-volume-docker-socket
      - *x-volume-cgroups
      - /var/log:/var/log:ro
      - /opt/docker/loki/conf:/etc/promtail
      - /opt/docker/loki/datas/promtail:/datas

loki.yml

[Fichier]

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  path_prefix: /datas
  storage:
    filesystem:
      chunks_directory: /datas/chunks
      rules_directory: /datas/rules
  replication_factor: 1
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: inmemory

schema_config:
  configs:
    - from: 2023-05-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb:
    directory: /datas/index
  filesystem:
    directory: /datas/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h
  split_queries_by_interval: 24h

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  chunk_tables_provisioning:
    inactive_read_throughput: 0
    inactive_write_throughput: 0
    provisioned_read_throughput: 0
    provisioned_write_throughput: 0
  index_tables_provisioning:
    inactive_read_throughput: 0
    inactive_write_throughput: 0
    provisioned_read_throughput: 0
    provisioned_write_throughput: 0
  retention_deletes_enabled: false
  retention_period: 0s

querier:
  max_concurrent: 100
  
frontend:
  max_outstanding_per_tenant: 10000
  scheduler_worker_concurrency: 20

query_scheduler:
  max_outstanding_requests_per_tenant: 10000
  
ruler:
  alertmanager_url: http://alerts:9093

promtail.yml

[Fichier]

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /datas/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:

  # local machine logs
  - job_name: local
    static_configs:
      - targets:
          - localhost
        labels:
          host: "template"
          job: "varlogs"
          __path__: /var/log/*log

  # docker logs
  - job_name: docker
    pipeline_stages:
      - docker: {}
    static_configs:
      - labels:
          host: "template"
          job: "docker"
          __path__: /var/lib/docker/containers/*/*-json.log

  # syslog target
  - job_name: syslog
    syslog:
      listen_address: 0.0.0.0:1514
      idle_timeout: 60s
      label_structured_data: yes
      labels:
        host: "template"
        job: "syslog"
    relabel_configs:
      - source_labels: ["__syslog_message_hostname"]
        target_label: "host"

  # log containers with label: logging=promtail
  - job_name: scrape
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
        filters:
          - name: label
            values: ["logging=promtail"]
    relabel_configs:
      - source_labels: ["__meta_docker_container_log_stream"]
        target_label: "stream"
      - source_labels: ["__meta_docker_container_name"]
        regex: "/(.*)"
        target_label: "container"
      - source_labels: ["__meta_docker_container_id"]
        regex: "(.*)"
        target_label: "id"
      - source_labels: ["__meta_docker_container_label_logging_jobname"]
        target_label: "job"

parser.json

[Fichier]

{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "datasource",
          "uid": "grafana"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "description": "",
  "editable": true,
  "fiscalYearStartMonth": 0,
  "gnetId": 13198,
  "graphTooltip": 0,
  "id": 18,
  "links": [
    {
      "asDropdown": true,
      "icon": "external link",
      "includeVars": false,
      "keepTime": false,
      "tags": [
        "Zogg"
        ],
      "targetBlank": false,
      "title": "Dashboards",
      "tooltip": "",
      "type": "dashboards",
      "url": ""
    }
  ],
  "liveNow": false,
  "panels": [
    {
      "datasource": {
        "type": "loki",
        "uid": "$datasource"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisCenteredZero": false,
            "axisColorMode": "text",
            "axisLabel": "",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "normal"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "id": 4,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "showLegend": true
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "uid": "$datasource"
          },
          "editorMode": "code",
          \"expr\": \"count\_over\_time\({host=~\"\$host\", container\_name=~\"\$job\"} |~ \"\$search\"\[1m])\",
          "legendFormat": "",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "Metric Rate",
      "type": "timeseries"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "gridPos": {
        "h": 14,
        "w": 24,
        "x": 0,
        "y": 8
      },
      "id": 2,
      "options": {
        "dedupStrategy": "none",
        "enableLogDetails": true,
        "prettifyLogMessage": false,
        "showCommonLabels": false,
        "showLabels": false,
        "showTime": true,
        "sortOrder": "Descending",
        "wrapLogMessage": true
      },
      "pluginVersion": "7.1.3",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", container\_name=~\"\$job\"} |~ \"\$search\"\",
          "legendFormat": "",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "Loki Search",
      "type": "logs"
    }
  ],
  "refresh": "5m",
  "schemaVersion": 38,
  "style": "dark",
  "tags": [
    "Zogg",
    "Loki"
  ],
  "templating": {
    "list": [
      {
        "current": {
          "selected": false,
          "text": "Loki",
          "value": "Loki"
        },
        "hide": 0,
        "includeAll": false,
        "label": "Datasource",
        "multi": false,
        "name": "datasource",
        "options": [],
        "query": "loki",
        "queryValue": "",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "type": "datasource"
      },
      {
        "current": {
          "selected": false,
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "loki",
          "uid": "${datasource}"
        },
        "definition": "",
        "hide": 0,
        "includeAll": true,
        "label": "Host",
        "multi": false,
        "name": "host",
        "options": [],
        "query": {
          "label": "host",
          "refId": "LokiVariableQueryEditor-VariableQuery",
          "stream": "",
          "type": 1
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      },
      {
        "allValue": "",
        "current": {
          "selected": false,
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "loki",
          "uid": "$datasource"
        },
        "definition": "label_values(container_name)",
        "hide": 0,
        "includeAll": true,
        "label": "Job",
        "multi": false,
        "name": "job",
        "options": [],
        "query": {
          "label": "container_name",
          "refId": "LokiVariableQueryEditor-VariableQuery",
          "stream": "{host=\"$host\"}",
          "type": 1
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "tagValuesQuery": "",
        "tagsQuery": "",
        "type": "query",
        "useTags": false
      },
      {
        "current": {
          "selected": false,
          "text": "",
          "value": ""
        },
        "hide": 0,
        "label": "Search",
        "name": "search",
        "options": [
          {
            "selected": true,
            "text": "",
            "value": ""
          }
        ],
        "query": "",
        "skipUrlSync": false,
        "type": "textbox"
      }
    ]
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ]
  },
  "timezone": "",
  "title": "Parser",
  "uid": "ZOGG0012",
  "version": 11,
  "weekStart": ""
}

logs.json

[Fichier]

{
  "annotations": {
    "list": [
      {
        "$$hashKey": "object:75",
        "builtIn": 1,
        "datasource": {
          "type": "datasource",
          "uid": "grafana"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "description": "Log Viewer Dashboard for Loki",
  "editable": true,
  "fiscalYearStartMonth": 0,
  "gnetId": 13639,
  "graphTooltip": 0,
  "id": 14,
  "links": [
    {
      "asDropdown": true,
      "icon": "external link",
      "includeVars": false,
      "keepTime": false,
      "tags": [
        "Zogg"
      ],
      "targetBlank": false,
      "title": "Dashboards",
      "tooltip": "",
      "type": "dashboards",
      "url": ""
    }
  ],
  "liveNow": false,
  "panels": [
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisCenteredZero": false,
            "axisColorMode": "text",
            "axisLabel": "",
            "axisPlacement": "hidden",
            "barAlignment": 0,
            "drawStyle": "bars",
            "fillOpacity": 100,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "links": [],
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "id": 6,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom",
          "showLegend": false
        },
        "tooltip": {
          "mode": "multi",
          "sort": "none"
        }
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "expr": "sum(count_over_time({job=\"$app\"} |= \"$search\" [$__interval]))",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "type": "timeseries"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "gridPos": {
        "h": 25,
        "w": 24,
        "x": 0,
        "y": 3
      },
      "id": 2,
      "maxDataPoints": "",
      "options": {
        "dedupStrategy": "none",
        "enableLogDetails": true,
        "prettifyLogMessage": false,
        "showCommonLabels": false,
        "showLabels": false,
        "showTime": true,
        "sortOrder": "Descending",
        "wrapLogMessage": false
      },
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{job=\"\$app\"} |= \"\$search\" | logfmt\",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "transparent": true,
      "type": "logs"
    }
  ],
  "refresh": "5m",
  "schemaVersion": 38,
  "style": "dark",
  "tags": [
    "Zogg",
    "Loki"
  ],
  "templating": {
    "list": [
      {
        "current": {
          "selected": true,
          "text": [
            "All"
          ],
          "value": [
            "$__all"
          ]
        },
        "datasource": {
          "type": "loki",
          "uid": "P8E80F9AEF21F6940"
        },
        "definition": "",
        "hide": 0,
        "includeAll": true,
        "label": "Host",
        "multi": true,
        "name": "host",
        "options": [],
        "query": {
          "label": "host",
          "refId": "LokiVariableQueryEditor-VariableQuery",
          "stream": "",
          "type": 1
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      },
      {
        "current": {
          "selected": false,
          "text": "varlogs",
          "value": "varlogs"
        },
        "datasource": {
          "type": "loki",
          "uid": "P8E80F9AEF21F6940"
        },
        "definition": "label_values(job)",
        "hide": 0,
        "includeAll": false,
        "label": "Job",
        "multi": false,
        "name": "app",
        "options": [],
        "query": "label_values(job)",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "tagValuesQuery": "",
        "tagsQuery": "",
        "type": "query",
        "useTags": false
      },
      {
        "current": {
          "selected": false,
          "text": "",
          "value": ""
        },
        "hide": 0,
        "label": "Search",
        "name": "search",
        "options": [
          {
            "selected": true,
            "text": "",
            "value": ""
          }
        ],
        "query": "",
        "skipUrlSync": false,
        "type": "textbox"
      }
    ]
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {
    "hidden": false,
    "refresh_intervals": [
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ]
  },
  "timezone": "",
  "title": "Logs",
  "uid": "ZOGG0011",
  "version": 14,
  "weekStart": ""
}

ssh.json

[Fichier]

{
  "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": "",
  "editable": true,
  "fiscalYearStartMonth": 0,
  "gnetId": 17514,
  "graphTooltip": 0,
  "id": 24,
  "links": [
    {
      "asDropdown": true,
      "icon": "external link",
      "includeVars": false,
      "keepTime": false,
      "tags": [
        "Zogg"
      ],
      "targetBlank": false,
      "title": "Dashboards",
      "tooltip": "",
      "type": "dashboards",
      "url": ""
    }
  ],
  "liveNow": false,
  "panels": [
    {
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "id": 5,
      "panels": [],
      "title": "SSH - Total Stats",
      "type": "row"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "index": 0,
                  "text": "0"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "purple",
                "value": null
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 0,
        "y": 1
      },
      "id": 2,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "center",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by(instance) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |=\": session opened for\" | __error__=\"\" [$__interval]))",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "Total Opened Connection",
      "type": "stat"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "index": 0,
                  "text": "0"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "purple",
                "value": null
              },
              {
                "color": "red",
                "value": 1
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 3,
        "x": 6,
        "y": 1
      },
      "id": 3,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "center",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by(instance) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Failed|: Invalid|: Connection closed by authenticating user\" | __error__=\"\" [$__interval]))",
          "hide": false,
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "Total Failed Connection",
      "transformations": [
        {
          "id": "merge",
          "options": {}
        }
      ],
      "type": "stat"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "index": 0,
                  "text": "0"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "purple",
                "value": null
              },
              {
                "color": "red",
                "value": 1
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 3,
        "x": 9,
        "y": 1
      },
      "id": 21,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "count"
          ],
          "fields": "/^IP$/",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count by (ip) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Invalid|: Connection closed by authenticating user|: Failed\" |~\".* from .*\" | pattern `<_> from <ip> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A",
          "resolution": 1
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count by (ip) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Invalid|: Connection closed by authenticating user|: Failed\" !~\".* from .*\" | pattern `<_> user <_> <ip> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "Total Failed - Unique IP",
      "transformations": [
        {
          "id": "labelsToFields",
          "options": {
            "mode": "rows",
            "valueLabel": "ip"
          }
        },
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "178.40.119.51": false,
              "194.154.240.221": false,
              "label": true
            },
            "indexByName": {},
            "renameByName": {
              "value": "IP"
            }
          }
        }
      ],
      "type": "stat"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "index": 0,
                  "text": "0"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "orange",
                "value": null
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 3,
        "x": 12,
        "y": 1
      },
      "id": 6,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" | __error__=\"\" [$__interval])",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "SSH Log Lines",
      "type": "stat"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "index": 0,
                  "text": "0"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "orange",
                "value": null
              }
            ]
          },
          "unit": "decbytes"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 4,
        "w": 3,
        "x": 15,
        "y": 1
      },
      "id": 7,
      "options": {
        "colorMode": "background",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "bytes_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" | __error__=\"\" [$__interval])",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "SSH Log in bytes",
      "type": "stat"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "mappings": []
        },
        "overrides": []
      },
      "gridPos": {
        "h": 9,
        "w": 6,
        "x": 0,
        "y": 5
      },
      "id": 15,
      "options": {
        "displayLabels": [],
        "legend": {
          "displayMode": "table",
          "placement": "right",
          "showLegend": true,
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "multi",
          "sort": "none"
        }
      },
      "pluginVersion": "9.2.5",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by (username) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |=\": session opened for\" | pattern `<_> session opened for user <username>(` | username !~\".* by \" | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by (username) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |=\": session opened for\" | pattern `<_> session opened for user <username> <_>` | username !~\".*(uid=.*)\" | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "Session Opened by User",
      "transformations": [],
      "type": "piechart"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "mappings": []
        },
        "overrides": []
      },
      "gridPos": {
        "h": 9,
        "w": 6,
        "x": 6,
        "y": 5
      },
      "id": 16,
      "options": {
        "displayLabels": [],
        "legend": {
          "displayMode": "table",
          "placement": "right",
          "showLegend": true,
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "multi",
          "sort": "none"
        }
      },
      "pluginVersion": "9.2.5",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by (username) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Invalid|: Connection closed by authenticating user|: Failed .* user\" | pattern `<_> user <username> <_> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "sum by (username) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |=\": Failed\" !~\"invalid user\" | pattern `<_> for <username> from <_> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "Failed Attempt by User",
      "transformations": [
        {
          "id": "joinByLabels",
          "options": {
            "value": "username"
          }
        }
      ],
      "type": "piechart"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "gridPos": {
        "h": 16,
        "w": 12,
        "x": 12,
        "y": 5
      },
      "id": 9,
      "options": {
        "dedupStrategy": "signature",
        "enableLogDetails": true,
        "prettifyLogMessage": false,
        "showCommonLabels": false,
        "showLabels": false,
        "showTime": false,
        "sortOrder": "Descending",
        "wrapLogMessage": false
      },
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" \",
          "queryType": "range",
          "refId": "A"
        }
      ],
      "title": "SSH Recent Log",
      "type": "logs"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 7,
        "w": 6,
        "x": 0,
        "y": 14
      },
      "id": 22,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "frameIndex": 0,
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count by (ip) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |=\": Accepted\" | pattern `<_> Accepted <_> for <_> from <ip> port <_>` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A",
          "resolution": 1
        }
      ],
      "title": "Session Opened by Unique IP",
      "transformations": [
        {
          "id": "labelsToFields",
          "options": {
            "mode": "rows"
          }
        },
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "label": true
            },
            "indexByName": {},
            "renameByName": {
              "value": "IP"
            }
          }
        }
      ],
      "type": "table"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 7,
        "w": 6,
        "x": 6,
        "y": 14
      },
      "id": 19,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "frameIndex": 0,
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count by (ip) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Invalid|: Connection closed by authenticating user|: Failed\" |~\".* from .*\" | pattern `<_> from <ip> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "A",
          "resolution": 1
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          "expr": "count by (ip) (count_over_time({host=~\"$host\", $filename=~\"$source\"} |=\"sshd[\" |~\": Invalid|: Connection closed by authenticating user|: Failed\" !~\".* from .*\" | pattern `<_> user <_> <ip> port` | __error__=\"\" [$__interval]))",
          "hide": false,
          "legendFormat": "",
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "Failed by Unique IP",
      "transformations": [
        {
          "id": "labelsToFields",
          "options": {
            "mode": "rows"
          }
        },
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "label": true
            },
            "indexByName": {},
            "renameByName": {
              "value": "IP"
            }
          }
        }
      ],
      "type": "table"
    },
    {
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 21
      },
      "id": 11,
      "panels": [],
      "title": "Detailed Stats",
      "type": "row"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 10,
        "w": 12,
        "x": 0,
        "y": 22
      },
      "id": 20,
      "maxDataPoints": 1,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": Accepted\" | pattern `<_> Accepted <_> for <username> from <ip> port <_>` | \_\_error\_\_=\"\"\",
          "hide": false,
          "legendFormat": " ",
          "queryType": "range",
          "refId": "A",
          "resolution": 1
        }
      ],
      "title": "Session Opened by User and IP",
      "transformations": [
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "extractFields",
          "options": {
            "format": "auto",
            "replace": false,
            "source": "labels"
          }
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "Line": true,
              "Time": false,
              "env": true,
              "filename": true,
              "id": true,
              "job": true,
              "label": true,
              "labels": true,
              "tsNs": true
            },
            "indexByName": {},
            "renameByName": {
              "label": "",
              "value": ""
            }
          }
        },
        {
          "id": "sortBy",
          "options": {
            "fields": {},
            "sort": [
              {
                "desc": true,
                "field": "Time"
              }
            ]
          }
        }
      ],
      "type": "table"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 10,
        "w": 12,
        "x": 12,
        "y": 22
      },
      "id": 23,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |~\": Invalid|: Failed .\* user\" | pattern `<_> user <username> from <ip> <_> port` | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": Failed\" !~\"invalid user\" | pattern `<_> for <username> from <ip> port` | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "B"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": Connection closed by authenticating user\" | pattern `<_> user <username> <ip> port` | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "C"
        }
      ],
      "title": "SSH Failure by User and IP",
      "transformations": [
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "extractFields",
          "options": {
            "format": "auto",
            "replace": false,
            "source": "labels"
          }
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "Line": true,
              "env": true,
              "filename": true,
              "id": true,
              "job": true,
              "labels": true,
              "tsNs": true
            },
            "indexByName": {},
            "renameByName": {
              "Time": "",
              "env": "",
              "instance": "",
              "job": "",
              "tsNs": ""
            }
          }
        },
        {
          "id": "sortBy",
          "options": {
            "fields": {},
            "sort": [
              {
                "desc": true,
                "field": "Time"
              }
            ]
          }
        }
      ],
      "type": "table"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 10,
        "w": 12,
        "x": 0,
        "y": 32
      },
      "id": 13,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": session opened for\" | pattern `<_> session opened for user <username>(` | username !~\".\* by \" | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": session opened for\" | pattern `<_> session opened for user <username> <_>` | username !~\".\*\(uid=.\*)\" | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "SSH Session Opened by User",
      "transformations": [
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "extractFields",
          "options": {
            "format": "auto",
            "replace": false,
            "source": "labels"
          }
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "Line": true,
              "env": true,
              "filename": true,
              "id": true,
              "job": true,
              "labels": true,
              "tsNs": true
            },
            "indexByName": {},
            "renameByName": {
              "Time": "",
              "env": "",
              "instance": "",
              "job": "",
              "tsNs": ""
            }
          }
        },
        {
          "id": "sortBy",
          "options": {
            "fields": {},
            "sort": [
              {
                "desc": true,
                "field": "Time"
              }
            ]
          }
        }
      ],
      "type": "table"
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "P8E80F9AEF21F6940"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            },
            "filterable": true,
            "inspect": false
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 10,
        "w": 12,
        "x": 12,
        "y": 32
      },
      "id": 14,
      "options": {
        "cellHeight": "sm",
        "footer": {
          "countRows": false,
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "showHeader": true
      },
      "pluginVersion": "9.5.2",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |~\": Invalid|: Connection closed by authenticating user|: Failed .\* user\" | pattern `<_> user <username> <_> port` | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "loki",
            "uid": "P8E80F9AEF21F6940"
          },
          "editorMode": "code",
          \"expr\": \"{host=~\"\$host\", \$filename=~\"\$source\"} |=\"sshd\[\" |=\": Failed\" !~\"invalid user\" | pattern `<_> for <username> from <_> port` | \_\_error\_\_=\"\"\",
          "hide": false,
          "queryType": "range",
          "refId": "B"
        }
      ],
      "title": "SSH Failure by User",
      "transformations": [
        {
          "id": "merge",
          "options": {}
        },
        {
          "id": "extractFields",
          "options": {
            "format": "auto",
            "replace": false,
            "source": "labels"
          }
        },
        {
          "id": "organize",
          "options": {
            "excludeByName": {
              "Line": true,
              "env": true,
              "filename": true,
              "id": true,
              "job": true,
              "labels": true,
              "tsNs": true
            },
            "indexByName": {},
            "renameByName": {
              "Time": "",
              "env": "",
              "instance": "",
              "job": "",
              "tsNs": ""
            }
          }
        },
        {
          "id": "sortBy",
          "options": {
            "fields": {},
            "sort": [
              {
                "desc": true,
                "field": "Time"
              }
            ]
          }
        }
      ],
      "type": "table"
    }
  ],
  "refresh": "5m",
  "revision": 2,
  "schemaVersion": 38,
  "style": "dark",
  "tags": [
    "Zogg",
    "Loki"
  ],
  "templating": {
    "list": [
      {
        "current": {
          "selected": false,
          "text": "Loki",
          "value": "Loki"
        },
        "hide": 0,
        "includeAll": false,
        "label": "Datasource",
        "multi": false,
        "name": "datasource",
        "options": [],
        "query": "loki",
        "queryValue": "",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "type": "datasource"
      },
      {
        "current": {
          "selected": true,
          "text": "services",
          "value": "services"
        },
        "datasource": {
          "type": "loki",
          "uid": "${datasource}"
        },
        "definition": "label_names()",
        "hide": 0,
        "includeAll": false,
        "label": "Host",
        "multi": false,
        "name": "host",
        "options": [],
        "query": {
          "label": "host",
          "refId": "LokiVariableQueryEditor-VariableQuery",
          "stream": "",
          "type": 1
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "type": "query"
      },
      {
        "current": {
          "selected": false,
          "text": "filename",
          "value": "filename"
        },
        "hide": 0,
        "includeAll": false,
        "label": "Filename",
        "multi": false,
        "name": "filename",
        "options": [
          {
            "selected": true,
            "text": "filename",
            "value": "filename"
          }
        ],
        "query": "filename",
        "queryValue": "",
        "skipUrlSync": false,
        "type": "custom"
      },
      {
        "current": {
          "selected": false,
          "text": "/var/log/auth.log",
          "value": "/var/log/auth.log"
        },
        "description": "",
        "hide": 0,
        "includeAll": false,
        "label": "Source",
        "multi": false,
        "name": "source",
        "options": [
          {
            "selected": true,
            "text": "/var/log/auth.log",
            "value": "/var/log/auth.log"
          }
        ],
        "query": "/var/log/auth.log",
        "queryValue": "",
        "skipUrlSync": false,
        "type": "custom"
      }
    ]
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "SSH",
  "uid": "ZOGG0013",
  "version": 8,
  "weekStart": ""
}

Mise en place

Je partirai du principe que vous utilisez Portainer pour gérer vos stack Docker.

Il vous faudra créer les répertoires suivants (ou adapter au besoin) :

  • /opt/docker/loki/conf/
  • /opt/docker/loki/datas/loki/
  • /opt/docker/loki/datas/promtail/

Et une fois ceci fait, vous copiez les fichiers présentés ci-dessus dans les chemins tels qu’indiqué dans le docker-compose.yml.

Ces informations doivent refléter votre propre besoin.

Lorsque c’est fait, vous créez une nouvelle stack sous Portainer et copier/coller le contenu du fichier docker-compose.yml dans l’éditeur et vous lancez sa création.

Précisions

Il s’agit ici d’une configuration complète incluant Loki et Promtail.

Sur vos autres machines, il vous suffit de jouer le stack suivant sous Portainer :

loki-light.yml

[Fichier]

version: "3.0"

#
# updated: 2023-05-24
# stack:   loki (light only for other VMs)
#


x-logging: &x-logging
  logging:
    driver: loki
    options:
      loki-url: "http://loki:3100/loki/api/v1/push"
      loki-retries: "5"
      loki-batch-size: "400"
        
x-common: &x-common
  <<: *x-logging
  restart: "no"
  stop_grace_period: 5s
  stdin_open: true
  tty: true
  privileged: false
  security_opt:
    - no-new-privileges=true
  cap_drop:
    - ALL
  cap_add:
    - KILL
  dns:
    - 1.1.1.1
    - 8.8.8.8
    - 1.0.0.1
    - 8.8.4.4
  ipc: "shareable"
  extra_hosts:
    - "template.home:192.168.0.0"
  environment:
    TZ: "Europe/Paris"
    PUID: 1000
    PGID: 1000
  user: 1000:1000
  labels:
    com.centurylinklabs.watchtower.enable: true
    logging: "promtail"
    com.stack.name: "common"
    com.stack.service.name: "common"
  devices:
    - /dev/kmsg:/dev/kmsg
  deploy:
    resources:
      limits:
        cpus: "0.50"
        memory: 256M
  ulimits:
    nproc: 65535
    nofile:
      soft: 20000
      hard: 40000
  tmpfs:
    - /tmp:rw,noexec,nosuid,size=64k
  sysctls:
    net.core.somaxconn: 1024
    net.ipv4.tcp_syncookies: 0
x-volume-timezone: &x-volume-timezone "/etc/timezone:/etc/timezone:ro"
x-volume-localtime: &x-volume-localtime "/etc/localtime:/etc/localtime:ro"
x-volume-docker-socket: &x-volume-docker-socket "/var/run/docker.sock:/var/run/docker.sock:rw"
x-volume-cgroups: &x-volume-cgroups "/proc/cgroups:/cgroup:rw"
x-volume-ssl: &x-volume-ssl "/opt/docker/ssl:/ssl:ro"

services:
  promtail:
    <<: *x-common
    user: 0:0
    cap_add:
      - DAC_OVERRIDE
    container_name: promtail
    hostname: promtail
    image: grafana/promtail:latest
    restart: always
    ports:
      - "1514:1514"
    expose:
      - "1514"
    command: -config.file=/etc/promtail/promtail.yml
    labels:
      com.stack.name: "loki"
      com.stack.service.name: "promtail"
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=512M
    volumes:
      - *x-volume-timezone
      - *x-volume-localtime
      - *x-volume-docker-socket
      - *x-volume-cgroups
      - /var/log:/var/log:ro
      - /opt/docker/loki/conf:/etc/promtail
      - /opt/docker/loki/datas/promtail:/datas

Exploitation

Loki en soit n’est qu’un backend permettant de récupérer et stocker les logs tel que configurés.

Vous pouvez utiliser les dashboards que j’ai mis dans la section fichiers requis comme base pour consulter vos logs depuis Grafana :

  • parser.json
  • logs.json
  • ssh.json

Dashboards

Voici quelques captures des dashboards que j’utilise au quotidien :

Conclusion

Vous avez maintenant les bases pour centraliser vos différents logs, les visualiser et les manipuler.

Il est donc possible, sur la base de règles d’alertes, d’utiliser Alertmanager ou Grafana directement pour vous envoyer automatiquement des alertes :)