diff --git a/examples/chart/event-handler/templates/configmap.yaml b/examples/chart/event-handler/templates/configmap.yaml index f2602c579eeaa..e0d5e213c82d5 100644 --- a/examples/chart/event-handler/templates/configmap.yaml +++ b/examples/chart/event-handler/templates/configmap.yaml @@ -15,11 +15,34 @@ data: types = "{{ join "," .Values.eventHandler.types }}" {{- end }} {{- if .Values.eventHandler.skipEventTypes }} - skip-event-types = "{{ join "," .Values.eventHandler.skipEventTypes }}" + skip-event-types = "{{ join "," .Values.eventHandler.skipEventTypes }}" {{- end }} - {{- if .Values.eventHandler.skipSessionTypes }} + {{- if .Values.eventHandler.skipSessionTypes }} skip-session-types = "{{ join "," .Values.eventHandler.skipSessionTypes }}" {{- end }} + {{- if .Values.eventHandler.startTime }} + start-time = {{ .Values.eventHandler.startTime | quote }} + {{- end }} + {{- if .Values.eventHandler.dryRun }} + dry-run = {{ .Values.eventHandler.dryRun }} + {{- end }} + {{- if .Values.eventHandler.concurrency }} + concurrency = {{ .Values.eventHandler.concurrency }} + {{- end }} + {{- if .Values.eventHandler.lock }} + {{- if .Values.eventHandler.lock.enabled }} + lock-enabled = {{ .Values.eventHandler.lock.enabled }} + {{- end }} + {{- if .Values.eventHandler.lock.failedAttemptsCount }} + lock-failed-attempts-count = {{ .Values.eventHandler.lock.failedAttemptsCount }} + {{- end }} + {{- if .Values.eventHandler.lock.period }} + lock-period = {{ .Values.eventHandler.lock.period | quote }} + {{- end }} + {{- if .Values.eventHandler.lock.for }} + lock-for = {{ .Values.eventHandler.lock.for | quote }} + {{- end }} + {{- end }} [teleport] addr = {{ coalesce .Values.teleport.address .Values.tbot.teleportProxyAddress .Values.tbot.teleportAuthAddress | quote }} @@ -32,3 +55,4 @@ data: ca = "/var/lib/teleport/plugins/event-handler/ca.crt" cert = "/var/lib/teleport/plugins/event-handler/client.crt" key = "/var/lib/teleport/plugins/event-handler/client.key" + max-connections = {{ default (mul .Values.eventHandler.concurrency 2) .Values.fluentd.maxConnections }} diff --git a/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap index 6b3e84fe11814..cb3e54779a4e4 100644 --- a/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap @@ -7,7 +7,13 @@ should match the snapshot: timeout = "10s" batch = 20 window-size = "24h" - debug = false + debug = true + start-time = "2025-01-01T00:00:00.000Z" + dry-run = true + concurrency = 2 + lock-enabled = true + lock-failed-attempts-count = 3 + lock-period = "1m" [teleport] addr = "teleport.example.com:1234" @@ -20,6 +26,7 @@ should match the snapshot: ca = "/var/lib/teleport/plugins/event-handler/ca.crt" cert = "/var/lib/teleport/plugins/event-handler/client.crt" key = "/var/lib/teleport/plugins/event-handler/client.key" + max-connections = 4 kind: ConfigMap metadata: labels: diff --git a/examples/chart/event-handler/tests/configmap_test.yaml b/examples/chart/event-handler/tests/configmap_test.yaml index 2142f7f2cc6f1..60291704a9103 100644 --- a/examples/chart/event-handler/tests/configmap_test.yaml +++ b/examples/chart/event-handler/tests/configmap_test.yaml @@ -4,6 +4,13 @@ templates: tests: - it: should match the snapshot set: + eventHandler: + debug: true + startTime: "2025-01-01T00:00:00.000Z" + dryRun: true + concurrency: 2 + lock: + enabled: true teleport: address: teleport.example.com:1234 fluentd: diff --git a/examples/chart/event-handler/values.schema.json b/examples/chart/event-handler/values.schema.json index aa414c8c8061d..3f76116aed944 100644 --- a/examples/chart/event-handler/values.schema.json +++ b/examples/chart/event-handler/values.schema.json @@ -351,17 +351,26 @@ "timeout": { "$id": "#/properties/eventHandler/properties/timeout", "type": "string", - "default": "10s" + "default": "10s", + "examples": [ + "10s" + ] }, "batch": { "$id": "#/properties/eventHandler/properties/batch", - "type": "number", - "default": 20 + "type": "integer", + "default": 20, + "examples": [ + 20 + ] }, "window-size": { "$id": "#/properties/eventHandler/properties/window-size", "type": "string", - "default": "24h" + "default": "24h", + "examples": [ + "24h" + ] }, "debug": { "$id": "#/properties/eventHandler/properties/debug", @@ -394,6 +403,82 @@ "examples": [ ["print", "desktop.recording"] ] + }, + "startTime": { + "$id": "#/properties/eventHandler/properties/startTime", + "type": "string", + "default": "", + "examples": [ + "2025-01-01T00:00:00.000Z" + ] + }, + "dryRun": { + "$id": "#/properties/eventHandler/properties/dryRun", + "type": "boolean", + "default": false, + "examples": [ + false + ] + }, + "concurrency": { + "$id": "#/properties/eventHandler/properties/concurrency", + "type": "integer", + "default": 5, + "examples": [ + 5 + ] + }, + "lock": { + "$id": "#/properties/eventHandler/properties/lock", + "type": "object", + "default": { + "enabled": false + }, + "examples": [ + { + "enabled": true, + "failedAttemptsCount": 3, + "period": "1m", + "for": "5s" + } + ], + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "$id": "#/properties/eventHandler/properties/lock/enabled", + "type": "boolean", + "default": false, + "examples": [ + true + ] + }, + "failedAttemptsCount": { + "$id": "#/properties/eventHandler/properties/lock/failedAttemptsCount", + "type": "integer", + "default": 3, + "examples": [ + 3 + ] + }, + "period": { + "$id": "#/properties/eventHandler/properties/lock/period", + "type": "string", + "default": "1m", + "examples": [ + "1m" + ] + }, + "for": { + "$id": "#/properties/eventHandler/properties/lock/for", + "type": "string", + "default": "5s", + "examples": [ + "5s" + ] + } + } } }, "additionalProperties": true @@ -481,6 +566,14 @@ "default": "client.key" } } + }, + "maxConnections": { + "$id": "#/properties/fluentd/properties/maxConnections", + "type": "integer", + "default": 0, + "examples": [ + 10 + ] } }, "additionalProperties": true diff --git a/examples/chart/event-handler/values.yaml b/examples/chart/event-handler/values.yaml index 787d22ca5ef02..b0679ab46c683 100644 --- a/examples/chart/event-handler/values.yaml +++ b/examples/chart/event-handler/values.yaml @@ -5,9 +5,10 @@ # # Plugin specific options # + +# teleport -- contains the configuration describing how the plugin connects to +# your Teleport cluster. teleport: - # When the address is empty, `tbot.teleportProxyAddress` - # or `tbot.teleportAuthAddress` will be used if they are set. # teleport.address(string) -- is the address of the Teleport cluster the plugin # connects to. The address must contain both the domain name and the port of # the Teleport cluster. It can be either the address of the auth servers or the @@ -45,33 +46,70 @@ teleport: # `"auth_id"`, you can omit this field. identitySecretPath: "auth_id" +# eventHandler -- contains the configuration used by the plugin to forward Teleport events. eventHandler: + # eventHandler.storagePath(string) -- is the storage directory for the event handler. storagePath: "/var/lib/teleport/plugins/event-handler/storage" + # eventHandler.timeout(string) -- is the polling timeout. timeout: "10s" + # eventHandler.batch(int) -- is the fetch batch size. batch: 20 - # The window size configures the duration of the time window for the event handler + # eventHandler.windowSize(string) -- configures the duration of the time window for the event handler # to request events from Teleport. By default, this is set to 24 hours. # Reduce the window size if the events backend cannot manage the event volume # for the default window size. # The window size should be specified as a duration string, parsed by Go's time.ParseDuration. windowSize: "24h" - # Optional setting to enable debug logging - # debug: true - # Optional setting for event types to forward - # types: ["TYPE1", "TYPE2"] - # Optional setting for audit event types to skip - # skipEventTypes: ["TYPE1"] - # Optional setting for session recording event types to skip - # skipSessionTypes: ["TYPE1"] - + # eventHandler.debug(bool) -- enables debug logging. + debug: false + # eventHandler.types(list) -- is the list of event types to forward. + # When unset, the event handler forwards all events. + types: [] + # eventHandler.skipEventTypes(list) -- is the list of audit event types to skip. + skipEventTypes: [] + # eventHandler.skipSessionTypes(list) -- is the list of session recording event types to skip. + # When unset, the event handler skips spammy and binary events. + # + # See the [Teleport-event-handler README](https://github.com/gravitational/teleport/blob/1d2bd5eb8fc3500deb7d7108f6835efde98b7b24/integrations/event-handler/README.md) + # for a list of default skipped events. + skipSessionTypes: [] + # eventHandler.startTime(string) -- is the start time to start ingestion from (RFC3339 format). + startTime: "" + # eventHandler.dryRun(bool) -- enables dry run without sending events to fluentd. + dryRun: false + # eventHandler.concurrency(int) -- is the number of concurent sessions to process. By default, this is set to 5. + concurrency: 5 + lock: + # eventHandler.lock.enabled(bool) -- controls whether user auto-locking is enabled. + enabled: false + # eventHandler.lock.failedAttemptsCount(int) -- is the number of failed attempts in the `lockPeriod` which + # triggers locking. By default, this is set to 3. + failedAttemptsCount: 3 + # eventHandler.lock.period(string) -- is the time period where `lock-failed-attempts-count` failed attempts + # will trigger locking. By default, this is set to 1 minute. + period: "1m" + # eventHandler.lock.for(string) -- is the time period for which user gets lock. + for: "" + +# fluentd -- contains the configuration for the fluentd forwarder. fluentd: + # fluentd.url(string) -- is the Fluentd URL where the events will be sent. url: "" + # fluentd.sessionUrl(string) -- is the Fluentd URL where the session logs will be sent. sessionUrl: "" certificate: + # fluentd.certificate.secretName(string) -- is the secret containing the credentials to connect to Fluentd. + # It must to contain the CA certificate, the client key and the client certificate. secretName: "" + # fluentd.certificate.caPath(string) -- is the name of the key which contains the CA certificate inside the secret. caPath: "ca.crt" + # fluentd.certificate.certPath(string) -- is the name of the key which contains the client's certificate inside the secret. certPath: "client.crt" + # fluentd.certificate.keyPath(string) -- is the name of the key which contains the client's private key inside the secret. keyPath: "client.key" + # fluentd.maxConnections(int) -- is the maximum number of connections to Fluentd. By default, or when set to 0, + # this becomes `eventHandler.concurrency` * 2. + maxConnections: 0 # tbot -- controls the optional tbot deployment that obtains and renews # credentials for the plugin to connect to Teleport. diff --git a/integrations/event-handler/README.md b/integrations/event-handler/README.md index d1ef8d4ad4c7b..04930e0a062b0 100644 --- a/integrations/event-handler/README.md +++ b/integrations/event-handler/README.md @@ -21,7 +21,7 @@ You may specify configuration options via command line arguments, environment va |---------------------------|-------------------------------------------------------------------------------------------------------|---------------------------------| | teleport-addr | Teleport host and port | FDFWD_TELEPORT_ADDR | | teleport-ca | Teleport TLS CA file | FDFWD_TELEPORT_CA | -| teleport-cert | Teleport TLS certificate file | FDWRD_TELEPORT_CERT | +| teleport-cert | Teleport TLS certificate file | FDFWD_TELEPORT_CERT | | teleport-key | Teleport TLS key file | FDFWD_TELEPORT_KEY | | teleport-identity | Teleport identity file | FDFWD_TELEPORT_IDENTITY | | teleport-refresh-enabled | Controls if the identity file should be reloaded from disk after the initial start on interval. | FDFWD_TELEPORT_REFRESH_ENABLED | @@ -31,15 +31,24 @@ You may specify configuration options via command line arguments, environment va | fluentd-ca | fluentd TLS CA file | FDFWD_FLUENTD_CA | | fluentd-cert | Fluentd TLS certificate file | FDFWD_FLUENTD_CERT | | fluentd-key | Fluentd TLS key file | FDFWD_FLUENTD_KEY | +| fluentd-max-connections | Maximum number of connections to Fluentd | FDFWD_MAX_CONNECTIONS | | storage | Storage directory | FDFWD_STORAGE | | batch | Fetch batch size | FDFWD_BATCH | | types | Comma-separated list of event types to forward | FDFWD_TYPES | -| skip-event-types | Comma-separated list of event types to skip | FDFWD_SKIP_EVENT_TYPES | +| skip-event-types | Comma-separated list of event types to skip | FDFWD_SKIP_EVENT_TYPES | | skip-session-types | Comma-separated list of session event types to skip | FDFWD_SKIP_SESSION_TYPES | | start-time | Minimum event time (RFC3339 format) | FDFWD_START_TIME | | timeout | Polling timeout | FDFWD_TIMEOUT | | cursor | Start cursor value | FDFWD_CURSOR | | debug | Debug logging | FDFWD_DEBUG | +| dry-run | Simulates execution without sending events to Fluentd | FDFWD_DRY_RUN | +| exit-on-last-event | Exit when last event is processed | FDFWD_EXIT_ON_LAST_EVENT | +| concurrency | Number of concurrent sessions | FDFWD_CONCURRENCY | +| window-size | Window size to process events | FDFWD_WINDOW_SIZE | +| lock-enabled | Enable user auto-locking | FDFWD_LOCKING_ENABLED | +| lock-failed-attempts-count| Number of failed attempts in lock-period which triggers locking | FDFWD_LOCKING_FAILED_ATTEMPTS | +| lock-period | Time period where lock-failed-attempts-count failed attempts will trigger locking | FDFWD_LOCKING_PERIOD | +| lock-for | Time period for which user gets lock | FDFWD_LOCKING_FOR | TOML configuration keys are the same as CLI args. Teleport and Fluentd variables can be grouped into sections. See [example TOML](example/config.toml). You can specify TOML file location using `--config` CLI flag. diff --git a/integrations/event-handler/cli.go b/integrations/event-handler/cli.go index e9624c6a70f57..b22e6fb3a4198 100644 --- a/integrations/event-handler/cli.go +++ b/integrations/event-handler/cli.go @@ -19,6 +19,7 @@ package main import ( "context" "log/slog" + "runtime" "strings" "time" @@ -37,17 +38,17 @@ type FluentdConfig struct { FluentdSessionURL string `help:"fluentd session url" required:"true" env:"FDFWD_FLUENTD_SESSION_URL"` // FluentdCert is a path to fluentd cert - FluentdCert string `help:"fluentd TLS certificate file" type:"existingfile" env:"FDWRD_FLUENTD_CERT"` + FluentdCert string `help:"fluentd TLS certificate file" type:"existingfile" env:"FDFWD_FLUENTD_CERT,FDWRD_FLUENTD_CERT"` // FluentdKey is a path to fluentd key - FluentdKey string `help:"fluentd TLS key file" type:"existingfile" env:"FDWRD_FLUENTD_KEY"` + FluentdKey string `help:"fluentd TLS key file" type:"existingfile" env:"FDFWD_FLUENTD_KEY,FDWRD_FLUENTD_KEY"` // FluentdCA is a path to fluentd CA - FluentdCA string `help:"fluentd TLS CA file" type:"existingfile" env:"FDWRD_FLUENTD_CA"` + FluentdCA string `help:"fluentd TLS CA file" type:"existingfile" env:"FDFWD_FLUENTD_CA,FDWRD_FLUENTD_CA"` // FluentdMaxConnections caps the number of connections to fluentd. Defaults to a dynamic value // calculated relative to app-level concurrency. - FluentdMaxConnections int `help:"Maximum number of connections to fluentd" env:"FDWRD_MAX_CONNECTIONS"` + FluentdMaxConnections int `help:"Maximum number of connections to fluentd" env:"FDFWD_MAX_CONNECTIONS,FDWRD_MAX_CONNECTIONS"` } // TeleportConfig is Teleport instance configuration @@ -70,7 +71,7 @@ type TeleportConfig struct { TeleportCA string `help:"Teleport TLS CA file" type:"existingfile" env:"FDFWD_TELEPORT_CA"` // TeleportCert is a path to Teleport cert file - TeleportCert string `help:"Teleport TLS certificate file" type:"existingfile" env:"FDWRD_TELEPORT_CERT"` + TeleportCert string `help:"Teleport TLS certificate file" type:"existingfile" env:"FDFWD_TELEPORT_CERT,FDWRD_TELEPORT_CERT"` // TeleportKey is a path to Teleport key file TeleportKey string `help:"Teleport TLS key file" type:"existingfile" env:"FDFWD_TELEPORT_KEY"` @@ -142,19 +143,19 @@ type IngestConfig struct { StartTime *time.Time `help:"Minimum event time in RFC3339 format" env:"FDFWD_START_TIME"` // Timeout is the time poller will wait before the new request if there are no events in the queue - Timeout time.Duration `help:"Polling timeout" default:"5s" env:"FDFWD_TIMEOUT"` + Timeout time.Duration `help:"Polling timeout" default:"10s" env:"FDFWD_TIMEOUT"` // DryRun is the flag which simulates execution without sending events to fluentd - DryRun bool `help:"Events are read from Teleport, but are not sent to fluentd. Separate storage is used. Debug flag."` + DryRun bool `help:"Events are read from Teleport, but are not sent to fluentd. Separate storage is used. Debug flag." env:"FDFWD_DRY_RUN"` // ExitOnLastEvent exit when last event is processed - ExitOnLastEvent bool `help:"Exit when last event is processed"` + ExitOnLastEvent bool `help:"Exit when last event is processed" env:"FDFWD_EXIT_ON_LAST_EVENT"` // Concurrency sets the number of concurrent sessions to ingest - Concurrency int `help:"Number of concurrent sessions" default:"5"` + Concurrency int `help:"Number of concurrent sessions" default:"5" env:"FDFWD_CONCURRENCY"` - //WindowSize is the size of the window to process events - WindowSize time.Duration `help:"Window size to process events" default:"24h"` + // WindowSize is the size of the window to process events + WindowSize time.Duration `help:"Window size to process events" default:"24h" env:"FDFWD_WINDOW_SIZE"` } // LockConfig represents locking configuration @@ -251,6 +252,15 @@ func (c *StartCmdConfig) Validate() error { // Dump dumps configuration values to the log func (c *StartCmdConfig) Dump(ctx context.Context, log *slog.Logger) { // Log configuration variables + log.DebugContext(ctx, "Initializing plugin", + "name", "teleport-event-handler", + "version", slog.GroupValue( + slog.String("teleport", Version), + slog.String("teleport_git", Gitref), + slog.String("go", runtime.Version()), + ), + ) + log.InfoContext(ctx, "Using storage", "storage", c.StorageDir) log.InfoContext(ctx, "Using batch size", "batch", c.BatchSize) log.InfoContext(ctx, "Using concurrency", "concurrency", c.Concurrency) log.InfoContext(ctx, "Using type filter", "types", c.Types) @@ -281,10 +291,14 @@ func (c *StartCmdConfig) Dump(ctx context.Context, log *slog.Logger) { } if c.LockEnabled { - log.InfoContext(ctx, "Auto-locking enabled", "count", c.LockFailedAttemptsCount, "period", c.LockPeriod) + log.InfoContext(ctx, "Auto-locking enabled", "count", c.LockFailedAttemptsCount, "period", c.LockPeriod, "for", c.LockFor) } if c.DryRun { log.WarnContext(ctx, "Dry run! Events are not sent to Fluentd. Separate storage is used.") } + + if c.ExitOnLastEvent { + log.WarnContext(ctx, "Exit on last event setting enabled") + } }