langgenius / langgenius/dify

Support AWS KMS as a tenant credential key provider

Open
#41,468 2 comments 2 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
156k
Forks
24.6k
Avg merge
22h 9m
Merged PRs (30d)
610

Description

### Self Checks

- [X] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
- [X] I have searched for existing issues, including closed ones.
- [X] I confirm that I am using English to submit this report.
- [X] Please do not modify this template :) and fill in all the required fields.

### 1. Is this request related to a challenge you're experiencing? Tell me about your story.

`KEY_PROVIDER_TYPE` currently accepts `local` and `azure-keyvault`. With `local`, the RSA private key that decrypts every tenant credential is written to the `STORAGE_TYPE` backend, so on a self-hosted deployment it sits on the same disk as the ciphertext it protects:

```
storage/privkeys//private.pem (0644)
```

Anyone who can read that volume — a host compromise, a copied EBS snapshot, an unencrypted backup — gets both halves at once. That is also the first thing an enterprise security review asks about, and "next to the application" is a hard answer to defend.

#39933 solved this for Azure by keeping the key in Key Vault. AWS deployments have no equivalent, even though the original request (#32328) asked for AWS Secrets Manager, Azure Key Vault and HashiCorp Vault together, and only Azure shipped.

### 2. Additional context or comments

I would like to add an `aws-kms` provider. `BaseKeyProvider` already has everything needed, and `boto3` is already a dependency (used by the S3 storage backend), so no new dependency is introduced.

Proposed design, which deliberately does **not** mirror the Azure provider one-for-one:

- **One symmetric KMS key for all tenants, separated by encryption context** rather than a key per tenant. Per-tenant keys bill per key and would require `kms:CreateKey` at runtime, a permission operators are reluctant to grant an application. A `dify:tenant_id` encryption context still binds each wrapped data key to its tenant cryptographically (KMS refuses a mismatched context), appears in CloudTrail, and can be enforced in IAM via the `kms:EncryptionContext:dify:tenant_id` condition key. Dify would need only `kms:GenerateDataKey` and `kms:Decrypt`.
- **No key version pinned in the envelope.** A KMS CiphertextBlob already names the backing key that produced it and KMS retains superseded backing keys, so automatic rotation keeps old credentials decryptable with nothing to pin — the concern `AzureKeyVaultKeyProvider` documents at length does not arise. (Automatic rotation is also only offered for symmetric keys, which is a further argument against copying the per-tenant asymmetric model.)
- Envelope layout and error handling kept identical to the Azure provider, including translating botocore failures into `ValueError` so `core/provider_manager.py` and `services/model_load_balancing_service.py` keep behaving as they do today.

New settings would be `AWS_KMS_KEY_ID` (required), `AWS_KMS_REGION` and `AWS_KMS_ENDPOINT_URL` (both optional). Credentials resolve through the default boto3 chain, so no long-lived secret has to be handed to Dify to reach the key that protects the other secrets.

I have an implementation ready with unit tests that mock the AWS SDK (no network calls, matching the approach in `test_azure_keyvault_key_provider.py`); `make lint`, the import-linter contracts and the key provider tests all pass. Happy to open the PR, or to adjust the design first if a per-tenant key or a Secrets Manager based approach is preferred.

@wylswz since you built the key provider abstraction in #39933 — does this direction look right to you?

Contributor guide

Open the contributing guide

Research direction

Start with the existing BaseKeyProvider and AzureKeyVaultKeyProvider, then read core/provider_manager.py, services/model_load_balancing_service.py, and test_azure_keyvault_key_provider.py. Add the AWS KMS provider using the stated settings, envelope behavior, encryption context, and botocore error handling; done means mocked unit tests, key provider tests, import-linter contracts, and make lint pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, python
Domain
backend, cloud, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.