mlevkov opened a new issue, #3802:
URL: https://github.com/apache/iggy/issues/3802

   ## Summary
   
   The connectors runtime control API returns plugin configuration verbatim, 
credentials included, and its authentication is disabled by default. The 
default bind is loopback, so this is a hardening gap rather than a remote 
disclosure — but nothing warns an operator who moves the listener off loopback, 
which is a normal thing to do when running the runtime in a container.
   
   Filing publicly rather than to the security list because of the loopback 
default. Happy to move it if maintainers judge otherwise.
   
   ## Configuration returns secrets
   
   `core/connectors/runtime/src/api/source.rs::get_source_plugin_config` serves 
`source.config.plugin_config` as-is:
   
   ```rust
   let (content_type, config) = map_connector_config(config, format)?;
   ```
   
   `plugin_config` is the raw `serde_json::Value` parsed from TOML, so every 
credential an operator configured comes back in the clear. `GET 
/sources/{key}/configs` and `/configs/{version}` and `/configs/active` return 
the enclosing `SourceConfig`, which carries the same field. The sink routes 
mirror all of it. A repo-wide grep finds no redaction anywhere in 
`core/connectors/runtime/src` — the only `redact` hits are log-line truncation 
in `stream.rs`.
   
   For most connectors that means a database connection string. For 
`iggy_connector_http_source` (#3798) it also means a `management_token`, which 
mints webhook endpoints, and each endpoint's HMAC secret.
   
   ## Authentication is off by default
   
   `core/connectors/runtime/src/api/auth.rs::resolve_api_key`:
   
   ```rust
   if context.api_key.expose_secret().is_empty() {
       return Ok(next.run(request).await);
   }
   ```
   
   `core/connectors/runtime/config.toml` ships:
   
   ```toml
   address = "127.0.0.1:8081"
   api_key = "" # Optional API key for authentication to be passed as `api-key` 
header
   ```
   
   So out of the box the API is unauthenticated. Loopback confines that to 
local processes, which is a defensible posture for an admin API — the gap is 
that the two defaults compose into "any local process can read every connector 
credential", and an operator who changes `address` to `0.0.0.0` to reach the 
API from outside a container gets an unauthenticated endpoint serving 
credentials with no warning at any layer.
   
   ## Suggested fixes, roughly in order of value
   
   1. Redact credential-bearing fields in the config responses, or gate those 
specific routes behind a configured `api_key` regardless of the global default.
   2. Log a warning at startup when `api_key` is empty and `address` is not 
loopback.
   3. Document in the runtime README that the control API returns credentials 
in plaintext and should be treated as privileged.
   
   Related: #3801, which is why the plugin-side `SecretString` annotations do 
not help here.
   
   Found while preparing #3798, whose README now documents this exposure for 
its own users.
   


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