Skip to main content

Use external Elasticsearch

If you already have an Elasticsearch cluster, you can connect the support stack to it instead of deploying one via ECK. This reduces resource usage and avoids running a second Elasticsearch instance.

warning

Kibana is automatically disabled in external mode because the ECK Kibana CR requires an ECK-managed Elasticsearch instance. Use your existing Kibana or access Elasticsearch directly.

Install with external Elasticsearch

  1. Set the following environment variables:

    export EXTERNAL_ELASTICSEARCH=true
    export EXTERNAL_ES_URL="https://my-es.example.com:9200"
    export EXTERNAL_ES_USERNAME="elastic"
    export EXTERNAL_ES_PASSWORD="YOUR_PASSWORD"

    If your external Elasticsearch uses a publicly trusted certificate (e.g., Elastic Cloud), no additional configuration is needed. If it uses a private CA certificate, also set:

    export EXTERNAL_ES_CA_FILE="/path/to/ca.crt"

    The installer creates the CA secret automatically from this file.

  2. Run the quickstart:

    nf-quickstart

    The installer automatically:

    • Skips the ECK operator and CRD installation
    • Creates a Kubernetes secret (external-es-creds) with your credentials
    • Generates a support-values.yml configured for external Elasticsearch
    • Sets up ILM policies and index templates on your external cluster

What changes in external mode

  • The ECK operator and CRDs are not installed.
  • No Elasticsearch or Kibana custom resources are created.
  • nf-data-connector, Filebeat, Metricbeat, Grafana, and the ILM jobs all connect to your external Elasticsearch using the credentials in external-es-creds.
  • Uninstall skips ECK cleanup automatically.
warning
Your cluster needs a node with the ingest role

nf-data-connector, Filebeat and Metricbeat write to Elasticsearch directly, and writes into the ziti.* data streams resolve an index-side default pipeline. If no node in your external cluster holds the ingest role, those bulk writes are rejected with There are no ingest nodes in this cluster and no telemetry is stored.

Switch to external Elasticsearch after installation

If you already have a default installation and want to switch to an external Elasticsearch cluster:

  1. Update your support-values.yml:

    elasticsearch:
    enabled: false
    external:
    url: "https://my-es.example.com:9200"
    credentialSecret: "my-es-creds"
    usernameKey: "username" # default
    passwordKey: "password" # default
    # Set to "" for publicly trusted certificates
    # Set to a secret name if your ES uses a private CA (see below)
    tlsCaSecret: ""
  2. Create the credential secret:

    kubectl create secret generic my-es-creds \
    --from-literal=username=elastic \
    --from-literal=password='YOUR_PASSWORD' \
    -n support
  3. Upgrade the support Helm chart to apply the changes:

    helm upgrade --install support ./helm-charts/support/ --values support-values.yml -n support

If your external Elasticsearch uses a private CA, create a CA secret and set tlsCaSecret to its name:

kubectl create secret generic my-es-ca \
--from-file=ca.crt=/path/to/ca.crt \
-n support
elasticsearch:
tlsCaSecret: "my-es-ca"

After upgrading, you can remove the ECK-managed Elasticsearch and Kibana resources and uninstall the ECK operator if it is no longer needed.

Index template for keyword fields

The Grafana dashboards and Ziti Console Enterprise rely on .keyword sub-fields for aggregations and filtering (e.g., identity.name.keyword, service.name.keyword). Elasticsearch's built-in default index template normally creates these automatically by mapping every string field as both text and keyword. However, some managed or custom Elasticsearch clusters may not include this default dynamic mapping.

The support chart's ILM/index-template job automatically applies this mapping to all ziti* indices; the Beats agents manage their own filebeat-* and metricbeat-* templates. If you are managing index templates on your external cluster yourself, or if the job does not run against your cluster, ensure that your external Elasticsearch has an index template covering ziti* patterns with the following dynamic mapping:

PUT _index_template/ziti-template
{
"index_patterns": ["ziti*"],
"template": {
"settings": {
"index": {
"lifecycle": {
"name": "default_policy"
},
"number_of_shards": 1,
"number_of_replicas": 1
}
},
"mappings": {
"properties": {
"initialState": { "type": "object", "dynamic": true },
"finalState": { "type": "object", "dynamic": true }
},
"dynamic_templates": [
{
"strings_as_keyword": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
},
"priority": 310,
"data_stream": {
"hidden": false
}
}

The connector writes data streams, so this template declares data_stream. Container logs are the exception: they land in a regular rolling index behind the ziti.logs-v2 write alias, which the chart covers with a second, higher-priority template (ziti-logs-template, patterns ["ziti.logs-*"], priority 320) so it is not captured by the data-stream template above.

This ensures that every string field indexed under ziti* gets both a full-text text mapping and a .keyword sub-field suitable for terms aggregations, sorting, and filtering.

tip

If your dashboards show "No results" for panels that use .keyword fields, a missing dynamic template is the most likely cause. You can verify by checking the mapping of an existing index:

curl -s -u elastic:PASSWORD "https://YOUR_ES:9200/ziti.circuit/_mapping" | jq '.[][].mappings.properties' | head -20

String fields should show "type": "text" with a "keyword" sub-field. If they only show "type": "text" or "type": "keyword" without the other, apply the index template above and reindex or wait for new data.