Skip to content

Encrypted Channel Configurations#1218

Draft
TomasLongo wants to merge 1 commit intoopensearch-project:mainfrom
sternadsoftware:poc-secure-chanelle-settings
Draft

Encrypted Channel Configurations#1218
TomasLongo wants to merge 1 commit intoopensearch-project:mainfrom
sternadsoftware:poc-secure-chanelle-settings

Conversation

@TomasLongo
Copy link
Copy Markdown

Encrypted Channel Configurations

Currently, Webhook-Urls (and headers) like Chime, Slack, Teams, etc. are stored in plain text in OpenSearch. This PR addresses this limitation by introducing symmetrically encrypted webhook urls at rest.

URLs are opaque in the index and user facing APIs while beeing transparent at runtime.

Keys are provisioned manually via the opensearch-keystore tool and read inside the plugin using the SecureSetting pattern.

Architecture

Two new Classes are introduced:

FieldEncryptionService (notifications/util/FieldEncryptionService.kt)

  • AES-256-GCM authenticated encryption with a fresh random 12-byte nonce per write
  • Ciphertext wire format: enc:v1:<Base64(nonce || ciphertext || GCM-tag)> — the enc:v1: sentinel enables backward-compatible plaintext pass-through on read and future key-rotation versioning
  • Passthrough mode: when no key is configured the service is a no-op, so the feature can be deployed before a key is provisioned without data loss
  • close() zeroizes key material via the Destroyable interface

ConfigEncryptionTransformer (notifications/util/ConfigEncryptionTransformer.kt)

  • Wraps FieldEncryptionService and applies encrypt/decrypt to the sensitive fields of a NotificationConfig object
  • Covers: Slack.url, Chime.url, MicrosoftTeams.url, Mattermost.url, Webhook.url, and all Webhook.headerParams values
Changes in common-utils are necessary

Channel objects (like Slack, Chime, ...) perform a strict url validation when beeing constructed. Handling ciphertexts makes this not feasible anymore. Validation of urls should be, and is already covered by the ui.

NOTE: Tests will fail, as long as common-utils is not updated

Point of Encryption

URLs are encrypted when creating or updating channel configurations. Encryption when updating also enables a lazy migration path.

Pass Through Mode

For backward compatibility, tbe process checks if the url is an encrypted value during decryption, by checking if the url is prefixed with enc:v1. Unencryped values are simply passed on as is and lazily encryped, when the channel configuration is updated.

Limitations

  • Search for terms in URLs won't work anymore
    • Tests covering the functionality have been removed
  • Key-Rotation is not included but planned as a follow-up (the enc:v1 prefix of the cipher text lays the groundwork)
  • GET Enpoints return the cyphertext for encrypted fields. Masking fields could be a hardenining follow-up
  • The secret key is held in memory for the lifespan of the plugin. Re-reading the key at every request is not possible since the key store is closed after initialization and throws a 'key store closed' error.

Migration Paths

Lazy, by updating channel configs (currently working)

Passthrough-Mode enables lazy migration. Unencrypted channel configs are read with their legacy plain-text data and encrypted upon beeing updated.

Bulk, via admin endpoint (open for discussion)

An admin-only endpoint could be implemented that encrypts legacy channel configs in one pass.

Security Considerations

Lifespan of the decrypted config

The channel config is decrypted right before sending a message. Destroying the now plain-text fields of the config is at the mercy of the GC, since the backing field for the sensitive information is of type String which we can not destroy manually.

A possible approach would introduce dedicated data objects that read sensitive channel information into a ByteArray/char[] in order to zero it after a message has been sent. (Alternatively, the data objects in common-util are modified to support destruction of sensitive data)

Related Issues

Resolves #[Issue number to be closed when this PR is merged]

Check List

  • New functionality includes testing.
  • New functionality has been documented.
  • API changes companion pull request created.
  • Commits are signed per the DCO using --signoff.
  • Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@TomasLongo TomasLongo force-pushed the poc-secure-chanelle-settings branch from 07c2c02 to 9d63dd0 Compare April 28, 2026 11:37
Signed-off-by: Tomas Longo <tlongo@sternad.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant