feat(remote-config)!: agentless RC fetcher - #2112
Conversation
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 18074d7 | Docs | Datadog PR Page | Give us feedback! |
📚 Documentation Check Results📦
|
Clippy Allow Annotation ReportTracked Clippy
By file and crateBy file
By crate
About This ReportThis report tracks Clippy allow annotations for specific rules, showing how they've changed in this PR. Decreasing the number of these annotations generally improves code quality. Panic-inducing macros in particular should be avoided. In the future, this report may become a PR-blocking quality gate. |
🔒 Cargo Deny Results📦
|
Replace unchecked `as` casts with `TryFrom` on `usize`/`i64`/`u64` conversions in the agentless fetcher's target length checks.
… constructor Previously `ConfigFetcherState::with_client` accepted any `AgentlessConfig` and silently downgraded to the agent endpoint when the hostname was empty or the endpoint could not be rewritten. Move the invariants into the type system: an `AgentlessConfig` value is always valid by construction, as we check that proof the hostname is non-empty and that the agentless endpoint was successfully rewritten. Downstream code (`with_client`, `MultiTargetFetcher::new`, sidecar `ShmRemoteConfigs::new`, ...) remains infallible.
Rebuilding both TUF clients from the embedded root on `apply()` failure threw away any root version already advanced through `Database::update_root`, forcing the backend to re-send the full root rotation chain on the next poll. Use `Client::purge_metadata()` to clear snapshot/targets/timestamp/delegations while keeping the trusted root, and swap the local+remote TUF repositories for fresh empty ones so no pre-failure metadata can be replayed.
…sConfig Remove the `config_root_override_path` / `director_root_override_path` knobs from `AgentlessConfig` and the associated `load_root` helper.
…mentation Restructure `RemoteConfigPath` so it stores the original wire string once (`raw: Box<str>`) plus `source`, `product`, and byte offsets for `config_id` and `name`.
| const ENV: &str = "testenv"; | ||
| const VERSION: &str = "1.2.3"; | ||
|
|
||
| fn get_hostname() -> String { |
There was a problem hiding this comment.
there's really no other way in rust to get the hostname besides running a command? It might not be present in some situations (pod with just the go binary for instance).
There was a problem hiding this comment.
This is just the example. I added this at the beginning instead of adding the hostname crate as a dependency, since this is not code that is shipped in the library.
In general we prefer if people using the library inject these parameters, although I'd understand if you preferred that the libdd-remote-config picks the hostname by default as this is more likely to be consistent across languages (for nodejs though, we cannot as we need to compile to WASM)
There was a problem hiding this comment.
then can you please add a comment about it before people copy paste this
Motivation
In some environments (serverless, Datadog studio), tracers can't rely on a Datadog Agent to proxy Remote Config requests. This PR adds an agentless mode to libdd-remote-config so the fetcher can talk directly to the RC backend, mirroring what the Go agent does today.
The protocol is different from the agent's /v0.7/config: the backend speaks protobuf and ships raw TUF metadata + target files that the client must verify locally. This means embedding TUF trust roots per site and running a full Uptane-style validation on every poll.
Changes
Add a new AgentlessFetcher in libdd-remote-config/src/fetch/agentless.rs:
Plug agentless mode into the existing ConfigFetcher:
Update the remote_config_fetch example to switch to agentless when DD_API_KEY + DD_SITE are set.
Additional Notes
Eventually this implementation could be extracted to be it's own crate and we could reuse it in other projects that need a rust client.
For this reason, the
agentless.rsmodule which contains the most of the implementation tries to encapsulate what is "RC agentless" and what is specific to the RC client in libdatadog.This is why the caching of target files is done in a wrapper type. This cache is currently quite complex as it permits storing files in shared memory for instance.
Currently this implementation is a simplification of the agent code in two ways:
How to test the change?
Also this has been tested in dd-trace-rs
DataDog/dd-trace-rs#263