Skip to content

[DSIP-105][API] Encrypt sensitive definition params with PasswordUtils - #18659

Open
det101 wants to merge 21 commits into
apache:devfrom
det101:feature-18587-sensitive-encrypt
Open

det101 wants to merge 21 commits into
apache:devfrom
det101:feature-18587-sensitive-encrypt

Conversation

@det101

@det101 det101 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Purpose

Implements #18587 (subtask of #17937 / DSIP-105). Depends on #18586 / #18585.

Reuse PasswordUtils for definition-time at-rest protection of sensitive=true values when datasource.encryption.enable=true. Do not change datasource CRUD. Runtime instance params stay plaintext materialization; API/UI still return masked copies only.

Changes

  • Definition create/update: merge keep-original (******) then encode new sensitive plaintext; skip re-encode when value equals existing sensitive DB value
  • Instance update: merge only (no encode)
  • Start path: decrypt definition globals before restoreStartParams
  • Master: decrypt definition globals before instance materialization; decrypt localParams in TaskExecutionContext / prepare-params so Worker receives plaintext
  • Same-cluster Copy unchanged (JSON copied as-is)

Tests

  • Unit tests for encode on create, keep-original no double-encrypt, false→true keep-original then encode, encryption flag on/off, start-path decrypt, Master localParams decrypt

Related issues

@SbloodyS SbloodyS added feature new feature DSIP labels Sep 24, 2026
@SbloodyS SbloodyS added this to the 3.5.0 milestone Sep 24, 2026

@SbloodyS SbloodyS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Encrypt definition snapshots created by instance edits

updateWorkflowInstance() is not an instance-only persistence path. It calls saveTaskDefine() and saveWorkflowDefine(), which write definition history even when syncDefine=false and also update current definitions when syncDefine=true.

Passing false to mergeLocalParams() therefore persists newly entered sensitive local values as plaintext in definition tables. The merged runtime globalParams are also passed directly into workflowDefinition.set(), so even keeping an existing sensitive global unchanged can copy its plaintext instance value back into the definition.

Please preserve plaintext instance globals while encrypting the copies persisted as task/workflow definitions. Add service-level coverage for instance edits with encryption enabled and both syncDefine values; the new utility tests do not cover this persistence path.

det101 and others added 2 commits October 9, 2026 17:00
Instance edits persist task and workflow definition history, so sensitive values written there must be encoded while instance global params stay plaintext.
@det101

det101 commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

@SbloodyS Thanks for the review. Addressed in 5454ea3.

updateWorkflowInstance() writes definition history through saveTaskDefine() / saveWorkflowDefine() even when syncDefine=false, and updates the current definitions when syncDefine=true. The instance and those definition snapshots are now handled separately:

  • Task localParams go through mergeLocalParams() before saveTaskDefine(). That method always encodes. The encode=false overload is removed, so a newly entered sensitive local value is not stored as plaintext in the definition log.
  • Instance global_params still use merge() against the instance plaintext and stay plaintext.
  • The copy passed to workflowDefinition.set() uses mergeAndEncode() against the workflow definition's stored ciphertext. An unchanged ****** keeps that ciphertext instead of copying the instance plaintext back into the definition.

Service coverage is in WorkflowInstanceServiceTest#testUpdateWorkflowInstanceEncryptsDefinitionSnapshotsForBothSyncDefine, with encryption enabled and both syncDefine=true and syncDefine=false. It checks that new sensitive values are encoded on the definition snapshot, keep-original values stay the existing ciphertext, and instance globals remain plaintext.

@SbloodyS SbloodyS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Encrypt the instance-resolved globals when saving definition snapshots

WorkflowInstanceServiceImpl.java:470–474

updateWorkflowInstance() resolves ****** against the instance globals, but then resolves the same submitted placeholder again against the latest workflow definition when building the encrypted snapshot.

For example, if the definition contains secret A and the instance was started with override B, an unchanged ****** preserves B in the instance but saves A in the definition snapshot. With syncDefine=true, the synchronized definition therefore differs from the edited instance. If the parameter was removed from the latest definition, the second merge can instead reject an otherwise valid instance edit.

Build the encrypted snapshot from the already-resolved instance values, preserving plaintext instance storage and avoiding double encoding. Add service-level coverage where the instance value differs from the definition value, for both syncDefine settings; the current test uses matching values and misses this case.

det101 and others added 2 commits October 13, 2026 16:30
…bals

Address review feedback: when editing a workflow instance, build the
encrypted definition snapshot from already-resolved instance globals
instead of merging ****** against the latest definition again. Keep
instance global_params plaintext and encode only at the definition
persist boundary. Add coverage for instance override differing from
definition for both syncDefine values.
@det101

det101 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

@SbloodyS Thanks for the follow-up review. Addressed in 4ce442a.

Instance-resolved definition snapshot

updateWorkflowInstance() no longer merges ****** a second time against the latest workflow definition. The definition snapshot is built from the already-resolved instance globals (instanceGlobalParams), then encoded only at the persist boundary before saveWorkflowDefine(). Instance global_params stay plaintext.

This covers the case where the definition has secret A and the instance was started with override B: an unchanged ****** keeps B on the instance and encodes B (not A) into the definition snapshot for both syncDefine=true and syncDefine=false.

Coverage is in WorkflowInstanceServiceTest#assertInstanceEditUsesInstanceOverrideForDefinitionSnapshot.

Crypto closer to load/persist boundaries

We also tightened the encode/decode placement so sensitive definition values are handled as close as possible to DB I/O:

  • Persist: encode task localParams / workflow globalParams immediately before saveTaskDefine / saveWorkflowDefine (definition create/update and instance-edit definition snapshots). Business logic (merge, permission, DAG checks) stays on plaintext.
  • Load: decode right after reading definition rows for start/backfill (decodeAfterLoad), and once when Master assembles the workflow definition; task localParams stay ciphertext in the graph / task_instance and are decrypted only when building the worker TaskExecutionContext.

Happy to adjust further if anything still looks off.

@SbloodyS SbloodyS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@SbloodyS SbloodyS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please fix the failed CI.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants