Skip to content

Feature: Bring Your Own Opensearch - #135

Merged
alix-graylog merged 7 commits into
mainfrom
byo-os
Jul 30, 2026
Merged

Feature: Bring Your Own Opensearch#135
alix-graylog merged 7 commits into
mainfrom
byo-os

Conversation

@alix-graylog

@alix-graylog alix-graylog commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds support for pointing Graylog at an existing, self-managed OpenSearch cluster instead of the bundled Graylog Data Node. Set datanode.enabled: false and opensearch.enabled: true, give it a host list plus credentials, and the chart wires up GRAYLOG_ELASTICSEARCH_HOSTS and the CA trust for you.

The main target is clusters provisioned by the OpenSearch Kubernetes Operator, since that's what most people building OpenSearch in Kubernetes end up using, but nothing here is operator-specific — any reachable 2.x cluster works.

Details

  • New opensearch values block: hosts, auth (existing secret or inline user/pass), tls (enabled, caSecret, caKey). Documented in values.yaml and added to values.schema.json.
  • Connection string lives in its own secret (<release>-graylog-opensearch) rather than the main Graylog secret. global.existingSecretName suppresses the chart-managed secret, so folding the hosts in there would have silently broken BYO-secret users — this way the two features compose.
  • Credentials are spliced into each host URI after the scheme (https://user:pass@host:9200), which is the form Graylog expects. Both halves are percent-encoded, so operator-generated passwords with reserved characters work without anyone having to pre-encode them.
  • auth.existingSecret is resolved with lookup at install/upgrade time. Under helm template/--dry-run it renders without credentials — called out in the docs so it doesn't read as a bug.
  • Reworked the Graylog init container truststore logic. It now always rebuilds from the JDK CA bundle into a temp file and mvs it into place, so a failed init can't leave a half-built truststore behind, and public CAs (license checks, GeoIP, HTTP notifications) keep working. The OpenSearch CA is imported under its own alias; the existing BYO-cert path (byoc / byoc-ca) reuses the same store, so both can be active at once.
  • Sets GRAYLOG_SELFSIGNED_STARTUP=false when external OpenSearch is enabled — that flag drives Data Node discovery and has to be off for Graylog to honour elasticsearch_hosts.
  • Pod template gets a checksum/opensearch-secret annotation. The secret is consumed via envFrom, so without it a host or credential change would update the Secret and leave running pods on the stale connection string.
  • Render-time validation: both indexers enabled, neither enabled, empty host list, scheme-less host entries, a half-filled inline credential pair, or a wrong usernameKey/passwordKey all fail the render with an actionable message instead of producing pods that start and then can't reach an indexer.
  • Data Node ConfigMap and Secret are now gated on datanode.enabled — previously they rendered unconditionally.
  • Docs: new docs/bring-your-own-opensearch.md (requirements, config, credential handling, TLS, caveats), a examples/values/values-byo-opensearch.yaml starting point, and a README section. NOTES.txt reports the external cluster instead of a Data Node replica count.

Linked issues

PR Checklist

Please check the items that apply to your change.

  • Tests added/updated
  • Documentation updated
  • This PR includes a new feature
  • This PR includes a bugfix
  • This PR includes a refactor

Testing Checklist

Static Validation

  • Linter check passes: helm lint ./charts/graylog
  • Helm renders local template sucessfully: helm template graylog ./charts/graylog --validate

Installation

  • Fresh installation completes successfully: helm install graylog ./charts/graylog
  • All pods reach Running state: kubectl rollout status statefulset/graylog
  • Helm tests pass: helm test graylog

Functional (if applicable)

  • Web UI accessible and login works
  • DataNodes visible in System > Cluster Configuration — n/a, no Data Node in this mode
  • Inputs can be created and receive data

Upgrade (if applicable)

  • Upgrade from previous release succeeds
  • Scaling up/down works correctly
  • Configuration changes apply correctly

Specific to this PR

  • Installed against an OpenSearch cluster managed by the OpenSearch Kubernetes Operator, TLS on, CA pulled from the operator's <cluster>-ca secret, credentials from the operator's admin credentials secret. Graylog connects, index sets are created, messages are written and searchable.
  • Credentials with URI-reserved characters connect without manual escaping.
  • Both datanode.enabled and opensearch.enabled true, and both false, fail at render with the expected messages.
  • Truststore contains the OpenSearch CA alongside the default JDK CAs (keytool -list in the running pod).
  • 29 helm-unittest cases across tests/byo_opensearch_test.yaml and tests/init_graylog_test.yaml.

Notes for reviewers

  • Verify all applicable tests above pass
  • Validate that the linked issues are no longer reproducible, if applicable
  • Sync up with the author before merging
  • The commit history should be preserved - use rebase-merge or standard merge options when applicable

Two known limitations, both documented in the caveats section:

  • Rotating the OpenSearch CA needs a Graylog pod restart, since the truststore is built at init.
  • Single-node operator clusters can deadlock during the bootstrap → node handoff. That's an operator issue, not a chart one, but it's easy to hit while testing — use at least 3 cluster-manager-eligible replicas.

Worth a close look at the init container rewrite in config/init-graylog.yaml. It touches the existing BYO Graylog certificate path, not just the new OpenSearch one, so it affects users who aren't enabling this feature at all.

annotations:
{{- include "graylog.annotations" . | nindent 4 }}
data:
GRAYLOG_ELASTICSEARCH_HOSTS: {{ include "graylog.opensearch.hosts" . | b64enc }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may need a URL encoding guard it looks like graylog.opensearch.hosts contains the username and password from the Opensearch created secret

A generated password with e.g. @ could cause url parsing issues.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed this, thanks!

Resolve OpenSearch basic-auth credentials as "user:pass" (empty string if none).
Inline values win; otherwise read from opensearch.auth.existingSecret via lookup.
*/}}
{{- define "graylog.opensearch.credentials" -}}

@bemcculley-graylog bemcculley-graylog Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: Might be worth adding a guard here for a set username and no pass and vice-versa

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll make an issue for this to get addressed in the sweep.

@alix-graylog alix-graylog self-assigned this Jul 29, 2026
@alix-graylog alix-graylog added blocker If not finished by release date, the release will be postponed. feature New feature. labels Jul 29, 2026
@alix-graylog
alix-graylog marked this pull request as ready for review July 30, 2026 17:50
@alix-graylog
alix-graylog merged commit 5d531c1 into main Jul 30, 2026
9 checks passed
@alix-graylog
alix-graylog deleted the byo-os branch July 30, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocker If not finished by release date, the release will be postponed. feature New feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants