apiVersion: influxdata.com/v2alpha1
kind: Label
metadata:
    name: endpoint-security-state
spec:
    name: Endpoint Security State
    color: '#7A65F2'
---
apiVersion: influxdata.com/v2alpha1
kind: Label
metadata:
    name: telegraf
spec:
    color: '#C9D0FF'
    name: Telegraf
---
apiVersion: influxdata.com/v2alpha1
kind: Label
metadata:
    name: outputs-influxdb-v2
spec:
    color: '#108174'
    name: outputs.influxdb_v2
---
apiVersion: influxdata.com/v2alpha1
kind: Label
metadata:
    name: security
spec:
    color: '#F95F53'
    name: security
---
apiVersion: influxdata.com/v2alpha1
kind: Label
metadata:
    name: solution
spec:
    color: '#FFD255'
    name: Solution
---
apiVersion: influxdata.com/v2alpha1
kind: Dashboard
metadata:
    name: endpoint-security-state
spec:
    associations:
      - kind: Label
        name: telegraf
      - kind: Label
        name: outputs-influxdb-v2
      - kind: Label
        name: security
      - kind: Label
        name: solution
    charts:
      - colors:
          - hex: '#ffffff'
            name: white
            type: text
        fieldOptions:
          - displayName: Endpoint
            fieldName: Endpoint
            visible: true
          - displayName: AuthenticationOn
            fieldName: AuthenticationOn
            visible: true
          - displayName: AuthenticationWorks
            fieldName: AuthenticationWorks
            visible: true
          - displayName: Available
            fieldName: Available
            visible: true
          - displayName: Certificate
            fieldName: Certificate
            visible: true
        height: 4
        kind: Table
        name: Endpoints State
        queries:
          - query: |-
                from(bucket: v.bucket)
                  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
                  |> filter(fn: (r) =>
                    ( r._measurement == "http_response" and r._field == "http_response_code" )
                    or (
                      r._measurement == "x509_cert"
                      and r._field == "expiry"
                      and exists r.san
                      and exists r.common_name
                    )
                  )
                  |> drop(columns: ["method","result","_field","common_name","issuer_common_name","organizational_unit","public_key_algorithm","san","serial_number","signature_algorithm","country","locality","province","organization","verification","server","source"])
                  |> map(fn: (r) => ({ r with authon: 0, authwork: 0, available: 0, expires: 0}))
                  |> group(columns: ["_start","_stop","_time","Endpoint"])
                  |> map(fn: (r) => ({
                    r with available: if ( r._measurement == "http_response" and exists r.status_code )
                      and ( ( r._value >= 400 and r._value < 500 ) or ( r._value == 200 ) )
                      then r.available + 1 else r.available + 0,
                    authon: if ( r._measurement == "http_response" and exists r.status_code )
                      and ( ( r._value >= 400 and r._value < 500 ) or ( r._value == 200 ) )
                      then r.authon + 1 else r.authon + 0,
                    authwork: if ( r._measurement == "http_response" and exists r.status_code )
                      and r._value == 200 then r.authwork + 1 else r.authwork + 0,
                    expires: if ( r._measurement == "x509_cert" ) then r._value / 86400 else 0
                  }))
                  |> group(columns: ["Endpoint"])
                  |> drop(columns: ["_time","_start","_stop","_measurement","status_code","_value"])
                  |> reduce(
                    identity: {aosum: 0, awsum: 0, avsum: 0, exsum: 0},
                    fn: (r, accumulator) => ({
                      aosum: r.authon + accumulator.aosum,
                      awsum: r.authwork + accumulator.awsum,
                      avsum: r.available + accumulator.avsum,
                      exsum: r.expires + accumulator.exsum
                    })
                  )
                  |> map(fn: (r) => ({ r with
                    AuthenticationOn: if r.aosum >= 1 then "โœ…" else "๐Ÿ”ด",
                    AuthenticationWorks: if r.awsum >= 1 then "โœ…" else "๐Ÿ”ด",
                    Available: if r.avsum >= 1 then "โœ…" else "๐Ÿ”ด",
                    Certificate: if r.exsum > 30 then "โœ…"
                      else if r.exsum > 2 then "๐ŸŸก"
                      else if r.exsum > 0 then "๐Ÿ”ด"
                      else "โ“"
                  }))
                  |> drop(columns: ["aosum","avsum","awsum","exsum"])
                  |> group()
        tableOptions:
            sortBy: Endpoint
            verticalTimeAxis: true
        timeFormat: YYYY/MM/DD HH:mm:ss
        width: 12
    name: Endpoint Security State
---
apiVersion: influxdata.com/v2alpha1
kind: Variable
metadata:
    name: bucket
spec:
    name: bucket
    associations:
      - kind: Label
        name: endpoint-security-state
    language: flux
    query: |-
        buckets()
          |> filter(fn: (r) => r.name !~ /^_/)
          |> rename(columns: {name: "_value"})
          |> keep(columns: ["_value"])
    type: query
---
apiVersion: influxdata.com/v2alpha1
kind: Telegraf
metadata:
    name: endpoint-security-state-checks
spec:
    name: Endpoint Security State
    associations:
      - kind: Label
        name: endpoint-security-state
    config: |
        [agent]
        ## Default data collection interval for all inputs
        interval = "12h"
        ## Rounds collection interval to 'interval'
        ## ie, if interval="10s" then always collect on :00, :10, :20, etc.
        round_interval = false

        ## Telegraf will send metrics to outputs in batches of at most
        ## metric_batch_size metrics.
        ## This controls the size of writes that Telegraf sends to output plugins.
        metric_batch_size = 10

        ## For failed writes, telegraf will cache metric_buffer_limit metrics for each
        ## output, and will flush this buffer on a successful write. Oldest metrics
        ## are dropped first when this buffer fills.
        ## This buffer only fills when writes fail to output plugin(s).
        metric_buffer_limit = 100

        ## Collection jitter is used to jitter the collection by a random amount.
        ## Each plugin will sleep for a random time within jitter before collecting.
        ## This can be used to avoid many plugins querying things like sysfs at the
        ## same time, which can have a measurable effect on the system.
        collection_jitter = "0s"

        ## Default flushing interval for all outputs. Maximum flush_interval will be
        ## flush_interval + flush_jitter
        flush_interval = "10s"
        ## Jitter the flush interval by a random amount. This is primarily to avoid
        ## large write spikes for users running a large number of telegraf instances.
        ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s
        flush_jitter = "0s"

        ## By default or when set to "0s", precision will be set to the same
        ## timestamp order as the collection interval, with the maximum being 1s.
        ##   ie, when interval = "10s", precision will be "1s"
        ##       when interval = "250ms", precision will be "1ms"
        ## Precision will NOT be used for service inputs. It is up to each individual
        ## service input to set the timestamp at the appropriate precision.
        ## Valid time units are "ns", "us" (or "ยตs"), "ms", "s".
        precision = ""

        ## Logging configuration:
        ## Run telegraf with debug log messages.
        debug = false
        ## Run telegraf in quiet mode (error log messages only).
        quiet = false
        ## Specify the log file name. The empty string means to log to stderr.
        logfile = ""

        ## Override default hostname, if empty use os.Hostname()
        hostname = ""
        ## If set to true, do no set the "host" tag in the telegraf agent.
        omit_hostname = true
        [[outputs.influxdb_v2]]	
        ## The URLs of the InfluxDB cluster nodes.
        ##
        ## Multiple URLs can be specified for a single cluster, only ONE of the
        ## urls will be written to each interval.
        ## urls exp: http://127.0.0.1:9999
        urls = ["$INFLUX_HOST"]
        ## Token for authentication.
        token = "$INFLUX_TOKEN"
        ## Organization is the name of the organization you wish to write to; must exist.
        organization = "$INFLUX_ORG"
        ## Destination bucket to write into.
        bucket = "telegraf"

        ###############################################################################
        #                            INPUT PLUGINS                                    #
        ###############################################################################
        #
        # We must include the port for all of the URLs ( urls[] and sources[] ) below.
        # x509_cert requires this and we need the URLs ( endpoints ) to match for
        # display correlation
        #

        [[inputs.x509_cert]]
          sources = [
            "https://test.example.com:443/"
          ]

        [[inputs.http_response]]
          urls = [
            "https://test.example.com:443/"
          ]

        [[inputs.http_response]]
          urls = [
            "https://test.example.com:443/"
          ]
          username = "testuser"
          password = "testpassword"

        ###############################################################################
        #                        PROCESSOR PLUGINS                                    #
        ###############################################################################

        [[processors.regex]]
          [[processors.regex.tags]]
            key = "source"
            pattern = "^(.*)$"
            replacement = "${1}"
            result_key = "Endpoint"
          [[processors.regex.tags]]
            key = "server"
            pattern = "^(.*)$"
            replacement = "${1}"
            result_key = "Endpoint"