Skip to main content

Configure BYOC on Kubernetes

Choose customer-owned S3 replay storage below, or install a reference collector and connect the Speedscale Forwarder to it. For collector export, repeat the backend and exporter steps for every independent destination channel.

Prerequisites​

  • A Kubernetes cluster such as EKS, GKE, AKS, k3s, or minikube
  • kubectl configured for the cluster and Helm 3
  • A Speedscale API key with BYOC enabled
  • Credentials and an existing destination for the backend you select

Customer-owned S3 replay storage​

Customer-owned replay storage is available in the public speedscale/speedscale-operator chart and proxymock version 2.5.1169 or later. Set namespaced.forwarder.primaryTransport: byoc and namespaced.enabled: true when the installation must avoid cluster-scoped permissions, CRDs, and webhooks. The storage setting is separate from the Kubernetes permission setting. A classic operator installation is not yet supported by this mode.

Create the target namespace and the Speedscale API key Secret using your normal process. On EKS, bind the Forwarder service account to an IAM role with s3:PutObject, s3:GetObject, s3:ListBucket, and s3:DeleteObject on the chosen bucket and prefix. For a private S3-compatible service, create a Secret in the Speedscale namespace with AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Only the Forwarder receives these storage credentials. The bucket must already exist.

namespaced:
enabled: true
clusterName: banking-cluster
apiKeySecret: speedscale-apikey
forwarder:
primaryTransport: byoc
byoc:
bucket: customer-speedscale
region: us-east-1
prefix: speedscale/
serviceAccountAnnotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<FORWARDER_ROLE>

For private S3-compatible storage, remove serviceAccountAnnotations from the values above, create the credential Secret in the same namespace, then add the endpoint settings:

kubectl -n banking-app create secret generic s3-credentials \
--from-file=AWS_ACCESS_KEY_ID=/secure/path/to/access-key-id \
--from-file=AWS_SECRET_ACCESS_KEY=/secure/path/to/secret-access-key
namespaced:
forwarder:
byoc:
endpoint: https://s3.internal.example
pathStyle: true
credentialsSecret: s3-credentials

Use the endpoint URL and path-style setting required by your storage service. Do not configure forwarder.exporters for the same capture stream unless you intentionally want a second destination.

Plan the Cloud proxy and customer storage routes separately. EKS IAM roles for service accounts obtain credentials through AWS STS; a private EKS cluster needs an approved STS VPC endpoint and regional STS configuration. If the private S3 host should bypass the Cloud proxy, add that exact host to the chart-root no_proxy value. Confirm the proxy, KDC, STS, S3, and Kubernetes service routes with the customer network team.

helm repo add speedscale https://speedscale.github.io/operator-helm/
helm repo update
helm upgrade --install speedscale-operator speedscale/speedscale-operator \
--version 2.5.1169 -n banking-app -f values.yaml

The public chart must be rendered with the mode enabled before installation. Reject a rendered manifest containing CustomResourceDefinition, MutatingWebhookConfiguration, ValidatingWebhookConfiguration, ClusterRole, ClusterRoleBinding, or DaemonSet. The chart requires one Forwarder replica because report updates are serialized in that process. Its generic networkPolicy.enabled policy is rejected in this mode because it permits broad HTTPS egress. Supply a customer-specific policy after mapping the actual API, proxy, KDC, and storage routes. Do not assume that allowing app.speedscale.com through an authenticated proxy specifies the rest of the network design.

Use the namespaced sidecar capture guide to inject and check capture with proxymock cluster capture inject --sidecar. Use the namespaced replay guide to stage local traffic and start replay with proxymock cluster replay start --namespaced --snapshot-source local, which prevents a Cloud upload if local staging fails. To pull captured traffic directly from the bucket, follow Use BYOC Traffic with proxymock. The collector-export capture annotation in step 5 below does not apply to this installation.

This mode still uses the Speedscale API for account validation, registration, and configuration downloads. For a Kerberos-authenticated Cloud proxy, use the namespaced chart proxy setup and test it with the customer's proxy and realm before deployment. No Speedscale-managed AWS credential endpoint is needed for S3 access in this mode. Verify direct storage and replay after installing.

The numbered steps below configure collector export. Skip them for customer-owned S3 replay storage.

1. Add the Helm repositories​

helm repo add speedscale https://speedscale.github.io/operator-helm/
helm repo add speedscale-byoc https://speedscale.github.io/speedscale-byoc/
helm repo update

2. Create the Speedscale API key Secret​

kubectl create namespace speedscale
kubectl -n speedscale create secret generic speedscale-apikey \
--from-literal=SPEEDSCALE_API_KEY="<YOUR_API_KEY>" \
--from-literal=SPEEDSCALE_APP_URL="app.speedscale.com"

3. Install a backend collector​

Install each collector in its own namespace. The chart README contains its complete IAM policy, credential, and configuration options.

Amazon S3 with static credentials​

kubectl create namespace byoc-s3
kubectl -n byoc-s3 create secret generic s3-creds \
--from-literal=accessKeyId="<AWS_ACCESS_KEY_ID>" \
--from-literal=secretAccessKey="<AWS_SECRET_ACCESS_KEY>"

helm upgrade --install byoc-s3 speedscale-byoc/fluentbit-s3 \
-n byoc-s3 \
--set s3.bucket="<S3_BUCKET>" \
--set s3.region="<AWS_REGION>" \
--set s3.credentialsSecret="s3-creds"

Amazon S3 with EKS IAM Roles for Service Accounts​

helm upgrade --install byoc-s3 speedscale-byoc/fluentbit-s3 \
-n byoc-s3 --create-namespace \
--set s3.bucket="<S3_BUCKET>" \
--set s3.region="<AWS_REGION>" \
--set irsa.enabled=true \
--set irsa.roleArn="arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>"

Native GCS storage​

The chart reuses an existing bucket. Its Google service account (GSA) therefore needs storage.objects.create to write objects and storage.buckets.get to check that the bucket exists. roles/storage.objectCreator contains only the first permission, so add a narrowly scoped custom role for the second.

Create the GSA and custom role, then grant both roles on the bucket:

gcloud iam service-accounts create byoc-gcs \
--project=<GCP_PROJECT>

gcloud iam roles create speedscaleByocBucketReader \
--project=<GCP_PROJECT> \
--title="Speedscale BYOC bucket reader" \
--permissions=storage.buckets.get \
--stage=GA

gcloud storage buckets add-iam-policy-binding gs://<GCS_BUCKET> \
--member="serviceAccount:byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com" \
--role="roles/storage.objectCreator"

gcloud storage buckets add-iam-policy-binding gs://<GCS_BUCKET> \
--member="serviceAccount:byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com" \
--role="projects/<GCP_PROJECT>/roles/speedscaleByocBucketReader"

The GCS exporter documents the extra bucket-read permission required by reuse_if_exists. The predefined Storage Object Creator role does not include it.

With Workload Identity Federation enabled on the cluster and node pool, link the deterministic Kubernetes service account (KSA) byoc-gcs in namespace byoc-gcs to the GSA. Both this IAM binding and the annotation in the Helm values are required by the GKE service-account linking procedure:

gcloud iam service-accounts add-iam-policy-binding \
byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:<GCP_PROJECT>.svc.id.goog[byoc-gcs/byoc-gcs]"

Configure the KSA name and GSA annotation in values-gcs.yaml:

gcs:
project: <GCP_PROJECT>
bucket: <GCS_BUCKET>
region: <GCS_REGION>
serviceAccount:
name: byoc-gcs
annotations:
iam.gke.io/gcp-service-account: byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com
helm upgrade --install byoc-gcs speedscale-byoc/gcs \
-n byoc-gcs --create-namespace \
-f values-gcs.yaml

Loki and Grafana​

helm upgrade --install byoc-grafana speedscale-byoc/grafana \
-n byoc-grafana --create-namespace

Elasticsearch and Kibana​

helm upgrade --install byoc-elasticsearch speedscale-byoc/elasticsearch \
-n byoc-elasticsearch --create-namespace

For Azure Blob, Datadog, Dynatrace, New Relic, and advanced values, select the chart from the backend guide and follow its README.

4. Configure named Forwarder exporters​

Add one entry under forwarder.exporters for every collector. Keep filters and DLP configuration explicit per destination:

forwarder:
exporters:
byoc_s3:
otel_endpoint: "http://otel-collector.byoc-s3.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard
byoc_gcs:
otel_endpoint: "http://byoc-gcs-gcs.byoc-gcs.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard
byoc_grafana:
otel_endpoint: "http://otel-collector.byoc-grafana.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard

Install or upgrade the operator with that values file:

helm upgrade --install speedscale-operator speedscale/speedscale-operator \
-n speedscale --create-namespace \
--set apiKeySecret=speedscale-apikey \
--set clusterName=<CLUSTER_NAME> \
-f values.yaml
caution

Use the receiver's actual protocol port. A reference collector normally uses OTLP/gRPC on 4317. Including http:// is recommended for compatibility with Forwarder versions older than v2.5.617; newer Forwarders also accept scheme-less gRPC endpoints.

5. Enable capture for collector export​

Annotate the workload you want to capture:

kubectl patch deployment my-app -p \
'{"spec":{"template":{"metadata":{"annotations":{"capture.speedscale.com/enabled":"true"}}}}}'

The operator restarts or injects the required capture component according to the selected installation mode. Send a known request through the workload, then verify each BYOC hop.