Skip to content

feat(datadog_agent source): add API key validation#25536

Open
xfocus3 wants to merge 1 commit into
vectordotdev:masterfrom
xfocus3:feat/datadog-agent-api-key-validation-6809
Open

feat(datadog_agent source): add API key validation#25536
xfocus3 wants to merge 1 commit into
vectordotdev:masterfrom
xfocus3:feat/datadog-agent-api-key-validation-6809

Conversation

@xfocus3
Copy link
Copy Markdown

@xfocus3 xfocus3 commented May 30, 2026

Summary

Closes #6809.

Adds API key validation to the datadog_agent source, allowing it to restrict which Datadog API keys are accepted. This supports basic authentication and prevents unknown API keys from being used, as requested in the issue.

Two new options are added:

  • valid_api_keys (list of strings, default empty): the API keys permitted to send events to this source. When non-empty, the API key carried by an incoming request — extracted from the URL path, the dd-api-key header, or the dd-api-key query parameter (the existing extraction order) — is checked against this list. When empty (the default), all API keys are accepted and no validation is performed, so existing configurations are unaffected.
  • drop_on_invalid_api_key (bool, default false): controls behavior when a request carries an API key that is not in valid_api_keys. When true, the request is rejected with a 403 Forbidden response. When false, the unrecognized key is simply not stored in the event metadata, but the events are still accepted. Has no effect when valid_api_keys is empty.

Example

[sources.dd]
type = "datadog_agent"
address = "0.0.0.0:8080"
valid_api_keys = ["0123456789abcdef0123456789abcdef"]
drop_on_invalid_api_key = true

Implementation notes

  • Validation is centralized in ApiKeyExtractor::extract_and_validate, which returns an ApiKeyValidation enum (Accepted(Option<key>) / Rejected). The existing extract logic and extraction order are unchanged.
  • The check is applied at all request endpoints (logs, traces, and metrics: sketches, series v1, series v2). A rejected request returns a shared 403 Forbidden error.
  • The allow list is stored as an Arc<HashSet<String>> for cheap clones and O(1) lookups.

How did you test this PR?

  • cargo check --lib --no-default-features --features sources-datadog_agent — passes
  • cargo test --lib --no-default-features --features sources-datadog_agent datadog_agent:: — passes (40 tests, including a new api_key_validation unit test covering: no allow list, header match, URL-path match, unknown key with drop, missing key with drop, and unknown key without drop)
  • cargo fmt --check — passes
  • cargo clippy --lib --no-default-features --features sources-datadog_agent -- -D warnings — passes

Change Type

  • Bug fix
  • New feature
  • Dependencies
  • Non-functional (chore, refactoring, docs)
  • Performance

Is this a breaking change?

  • Yes
  • No

When valid_api_keys is left at its default (empty), behavior is identical to before.

Does this PR include user facing changes?

  • Yes. Please add a changelog fragment based on our guidelines.
  • No. A maintainer will apply the no-changelog label to this PR.

References

Add two options to the `datadog_agent` source to validate incoming
Datadog API keys:

- `valid_api_keys`: a list of permitted API keys. When non-empty, the API
  key carried by a request (URL, `dd-api-key` header, or query parameter)
  is checked against it. When empty (the default), all keys are accepted
  and no validation is performed, preserving existing behavior.
- `drop_on_invalid_api_key`: when `true`, requests with an unrecognized key
  are rejected with a 403 Forbidden response; when `false` (the default),
  the unrecognized key is simply not stored but the events are accepted.

This supports basic authentication and prevents unknown API keys from
being used. Validation is applied across the logs, metrics, and traces
endpoints.

Closes vectordotdev#6809
@xfocus3 xfocus3 requested review from a team as code owners May 30, 2026 12:47
@github-actions github-actions Bot added docs review on hold The documentation team reviews PRs only after a PR is approved by the COSE team. domain: sources Anything related to the Vector's sources domain: external docs Anything related to Vector's external, public documentation and removed docs review on hold The documentation team reviews PRs only after a PR is approved by the COSE team. labels May 30, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cf42c4aff

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

header: Option<String>,
query_params: Option<String>,
) -> ApiKeyValidation {
let api_key = self.extract(path, header, query_params);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Decouple validation from API-key storage

When store_api_key = false, extract() returns None before it ever reads the path/header/query key, so valid_api_keys cannot be used independently of metadata storage. In a config with valid_api_keys set and drop_on_invalid_api_key = true, even requests carrying an allowed key are rejected as missing; users who disable key forwarding to sinks therefore cannot enable the new validation feature.

Useful? React with 👍 / 👎.

/// `drop_on_invalid_api_key`.
#[configurable(metadata(docs::advanced))]
#[serde(default)]
valid_api_keys: Vec<String>,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat allow-listed API keys as sensitive

Datadog API keys are credentials, but storing valid_api_keys as plain Strings means they are included verbatim in the derived Debug output for DatadogAgentConfig and the generated schema is not marked sensitive. In contexts that log or expose component config, this can leak every allow-listed key; existing credential fields in this repo use SensitiveString specifically to redact these values.

Useful? React with 👍 / 👎.

Comment on lines 47 to +49
.decode(&encoding_header, body, path.as_str())
.and_then(|body| {
decode_log_body(
body,
source.api_key_extractor.extract(
path.as_str(),
api_token,
query_params.dd_api_key,
),
&source,
)
let api_key = match source.api_key_extractor.extract_and_validate(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject invalid keys before decoding bodies

With drop_on_invalid_api_key = true, this endpoint still reads and decodes/decompresses the request body before running the new API-key check. An unauthenticated request with a bad key and malformed or very large compressed body will consume decode work and return the decode error instead of the intended 403; the same post-decode validation pattern appears in the metrics and traces handlers, even though validation only needs path/header/query data.

Useful? React with 👍 / 👎.

format!("Error decoding Datadog traces: {error:?}"),
)
})
let api_key = match source.api_key_extractor.extract_and_validate(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the APM stats route too

The new validation is only added inside the trace-payload branch, while build_warp_filter still ORs in build_stats_filter() for /api/v0.2/stats, which accepts every POST with a 200 and has no access to source.api_key_extractor. With drop_on_invalid_api_key = true, an invalid or missing key is therefore rejected for /api/v0.2/traces but still accepted on the companion stats endpoint, leaving a bypass in the advertised request-level API key restriction.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: external docs Anything related to Vector's external, public documentation domain: sources Anything related to the Vector's sources

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add API key validation in Datadog logs source

1 participant