hanzhenfang commented on issue #13351:
URL: https://github.com/apache/apisix/issues/13351#issuecomment-4630719373
Hi, @Baoyuantop. I have reproduced the issue underlying Admin API `PATCH`
re-encryption behavior with a minimal local Docker Compose environment.
### Environment
- APISIX: `apache/apisix:3.16.0-debian`
- etcd: `bitnamilegacy/etcd:3.6.4`
- Deployment mode: traditional mode with etcd
- Data encryption: enabled by default in this image
- Upstream services: `nginx:alpine`
- Admin API key used locally: `my-secret-admin-key`
### Reproduction summary
I used a route containing two plugins:
- `openid-connect`, which declares encrypted fields such as `client_secret`
- `response-rewrite`, used only as a sibling plugin to PATCH
After creating the route, the raw etcd value showed that
`openid-connect.client_secret` was encrypted once.
Then I sent a `PATCH` request that only modified the sibling
`response-rewrite` plugin. The PATCH payload did not include `openid-connect`
and did not touch `client_secret`.
However, after the PATCH, the raw etcd value of
`openid-connect.client_secret` changed and became longer. In my local run the
encrypted value length changed like this:
1. After initial route creation: length `24`
2. After the first PATCH to `response-rewrite`: length `44`
3. After a second PATCH to `response-rewrite`: length `64`
This strongly suggests that the already encrypted `client_secret` is being
encrypted again on every PATCH, even when the encrypted field is unrelated to
the PATCH payload.
### Suspected code path
Based on the local behavior, the likely issue is in the generic Admin API
PATCH write path rather than in `openid-connect` itself.
1. The PATCH handler reads the existing resource from etcd.
At this point, encrypted plugin fields are still stored as ciphertext in
the resource value.
2. The PATCH handler applies the requested patch or merge directly onto that
etcd value.
This means the merged resource now contains a mix of newly patched
plaintext fields and pre-existing encrypted fields.
3. The merged resource is passed through the normal resource validation path.
During this step, the resource-level encryption hook is called again
before writing the resource back to etcd.
4. For routes, that encryption hook walks all configured plugins, not only
the plugin or field included in the PATCH request.
Therefore, encrypted fields in sibling plugins are processed again.
5. The plugin encryption helper encrypts every field listed in
`encrypt_fields` whenever that field exists.
It does not appear to check whether the value is already ciphertext, and
the PATCH path does not appear to decrypt the old etcd value before
re-encrypting the merged result.
So the effective flow looks like:
1. Read old route from etcd with encrypted fields still encrypted
2. Patch only a sibling plugin
3. Validate the merged route
4. Re-run encryption for all plugin `encrypt_fields`
5. Store the already encrypted field with one more encryption layer
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]