AlinsRan commented on issue #2832:
URL: 
https://github.com/apache/apisix-ingress-controller/issues/2832#issuecomment-5450970890

   Thanks for writing this up, and for laying out both options.
   
   We'd rather take the second one: add `secretRef` to `PluginConfig`, and not 
make `ApisixPluginConfig` usable as an `ExtensionRef` target.
   
   The problem with the first option is that the two CRDs decide ownership in 
different ways, and referencing one from the other puts those two ways in 
conflict.
   
   `ApisixPluginConfig` carries `spec.ingressClassName` and is reconciled 
against it (`FindMatchingIngressClass` in `apisixpluginconfig_controller.go`). 
`PluginConfig` has no class field at all. It is only ever reached through an 
`ExtensionRef`, so it inherits ownership from the route's parent Gateway and 
that Gateway's `GatewayClass`.
   
   Once an HTTPRoute can point at an `ApisixPluginConfig`, the two can 
disagree, and there is no good answer when they do. Take a route attached to a 
Gateway of class `a` that references an `ApisixPluginConfig` with 
`ingressClassName: b`. If we read it, `ingressClassName` stops meaning anything 
on that path. If we refuse it, we report `ResolvedRefs=False` for an object 
that plainly exists and that another controller is happily reconciling. Either 
way the field means one thing for the apiv2 path and something else for the 
Gateway API path, and the object's status ends up being written by a controller 
that isn't the one consuming it.
   
   There's a smaller reason too: `ApisixPluginConfig` isn't published as an 
independent resource today. It's inlined during `ApisixRoute` translation 
(`internal/adc/translator/apisixroute.go`). Making it an `ExtensionRef` target 
would hand it a lifecycle it doesn't currently have, which is a fair amount of 
new surface for something `PluginConfig` can cover directly.
   
   Roughly what we have in mind:
   
   ```yaml
   apiVersion: v1
   kind: Secret
   metadata:
     name: oidc-credentials
     namespace: default
   stringData:
     client_id: my-client
     client_secret: "s3cr3t"
     session.secret: "8f2a...at least 32 bytes..."
   ---
   apiVersion: apisix.apache.org/v1alpha1
   kind: PluginConfig
   metadata:
     name: oidc
     namespace: default
   spec:
     plugins:
       - name: openid-connect
         secretRef:
           name: oidc-credentials
         config:
           discovery: https://idp.example.com/.well-known/openid-configuration
           scope: openid profile
           bearer_only: false
   ```
   
   The `HTTPRoute` side is unchanged:
   
   ```yaml
   apiVersion: gateway.networking.k8s.io/v1
   kind: HTTPRoute
   metadata:
     name: httpbin
     namespace: default
   spec:
     parentRefs:
       - name: apisix
     rules:
       - matches:
           - path:
               type: PathPrefix
               value: /
         filters:
           - type: ExtensionRef
             extensionRef:
               group: apisix.apache.org
               kind: PluginConfig
               name: oidc
         backendRefs:
           - name: httpbin
             port: 80
   ```
   
   Each key in the Secret is merged into `config`, so the plugin ends up 
receiving:
   
   ```json
   {
     "discovery": "https://idp.example.com/.well-known/openid-configuration";,
     "scope": "openid profile",
     "bearer_only": false,
     "client_id": "my-client",
     "client_secret": "s3cr3t",
     "session": { "secret": "8f2a..." }
   }
   ```
   
   A few things worth knowing about that merge, since they'll shape what you 
can put in the Secret:
   
   A key containing dots nests, which is how `session.secret` above lands under 
`session`. Secret values are always merged as strings, so fields that need a 
number or a boolean (`session.timeout`, `ssl_verify`) have to stay in `config` 
— APISIX's schema will reject them otherwise. Keys in the Secret win over the 
same key in `config`.
   
   Two behaviours we want to be deliberate about: a `secretRef` pointing at a 
Secret that doesn't exist should fail rather than publish the plugin without 
its credentials — the precedent is `validateSecrets` on the `ApisixRoute` path, 
not the quieter handling on the consumer path. And the field will be a 
`SecretReference` (`name` plus optional `namespace`) to match the rest of 
v1alpha1, with cross-namespace references honouring `ReferenceGrant` the same 
way `Consumer` already does.
   
   In the meantime, `$env://` works today without any change on our side, since 
`config` is passed through to APISIX as-is. The catch is that the value has to 
live in the data plane's environment, so it can't vary per `PluginConfig` — 
probably fine for a shared session secret, not for per-tenant client 
credentials.
   
   Worth mentioning that this doesn't overlap with #2831 as much as it might 
look. `secretRef` reads the Secret and materialises the plaintext into the 
pushed configuration; `$secret://` leaves the value out of the configuration 
entirely and has the data plane fetch it at request time. Different trade-offs, 
and we'd like both — this one because it only needs a Kubernetes Secret, that 
one because the secret never has to be in the config at all.
   


-- 
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]

Reply via email to