-
Notifications
You must be signed in to change notification settings - Fork 3
Session Recordings
The Gateway records interactive sessions (e.g., kubectl exec, SSH shell) in Asciicast v2 format (playable with the Twingate session player or asciinema play) and emits them as structured JSON audit logs to stderr. Each log entry has logger: "gateway.audit" and contains the recording content in the asciicast field, with an asciicast_sequence_num that increments on each flush (long sessions produce multiple entries). Since recordings are just structured logs on stderr, they can be routed to any storage backend using standard log pipelines (Vector, Fluentd, Fluent Bit, etc.).
Vector is an open-source observability pipeline that can collect, transform, and route logs. This example uses the Vector Helm chart to filter session recordings from Gateway pods and export them as .cast files to Google Cloud Storage.
Prior to configuring Vector, ensure the following prerequisites are met:
- Create a Google Cloud Storage bucket for log storage.
- Establish a Service Account in Google Cloud Platform with appropriate bucket write permissions. We'll be using this user with Workload Identity to authenticate the Vector pods.
- Apply the
vector.dev/twingate-gateway=truelabel to the target Gateway pods by applying the Gateway'spodLabelssetting in itsvalues.yaml.
Create a configuration file named values.yaml that defines the Vector logs processing pipeline. This configuration implements the following workflow:
- Collects structured JSON logs from Kubernetes pods labeled with
vector.dev/twingate-gateway=true - Processes and filters logs containing session recordings (identified by the
asciicastfield) - Exports the filtered recordings as
.castfiles to the designated Google Cloud Storage bucket
role: Agent
logLevel: "info"
env:
- name: VECTOR_SELF_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
rbac:
create: true
serviceAccount:
create: true
annotations:
iam.gke.io/gcp-service-account: <SERVICE_ACCOUNT_EMAIL> # TODO: replace this
name: vector
customConfig:
data_dir: /vector-data-dir
api:
enabled: true
address: 0.0.0.0:8686
playground: false
sources:
gateway_logs:
type: kubernetes_logs
extra_label_selector: vector.dev/twingate-gateway=true
internal_metrics:
type: internal_metrics
transforms:
gateway_json_logs:
type: remap
inputs:
- gateway_logs
drop_on_abort: true
metric_tag_values: single
source: |-
parsed_json = parse_json!(.message)
if parsed_json == null {
abort
}
if parsed_json.logger != "gateway.audit" {
abort
}
. = parsed_json
timezone: local
session_logging:
type: remap
inputs:
- gateway_json_logs
drop_on_abort: true
metric_tag_values: single
source: |-
if .asciicast == null {
abort
}
parsed_ts = parse_timestamp!(.ts, "%Y-%m-%dT%H:%M:%S%.3fZ")
. = {
"filename_ts_part": format_timestamp!(parsed_ts, "%Y%m%d%H%M%S"),
"user_id": replace!(.user.username, r'@|\.', "_"),
"conn_id": .conn_id,
"message": .asciicast,
"asciicast_sequence_num": .asciicast_sequence_num
}
timezone: local
sinks:
gcs:
type: gcp_cloud_storage
inputs:
- session_logging
bucket: <YOUR_GCS_BUCKET_NAME> # TODO: replace this
key_prefix: sessionrecordings/{{"{{"}} .user_id {{"}}"}}_{{"{{"}} .filename_ts_part {{"}}"}}_{{"{{"}} .asciicast_sequence_num {{"}}"}}
filename_extension: cast
filename_append_uuid: false
compression: none
encoding:
codec: text
batch:
max_events: 1
timeout_secs: 1Add the vector helm repository:
helm repo add vector https://helm.vector.dev
helm repo updateThen install Vector in a dedicated namespace:
helm install vector vector/vector -n vector --create-namespace -f values.yamlCopyright © 2025 Twingate.
Kubernetes
SSH
Web App
Operations
Development
Migration