Skip to content

Implement verifier integration#17386

Merged
jeniawhite merged 23 commits intomainfrom
evgb-VerifierIntegration
Mar 24, 2026
Merged

Implement verifier integration#17386
jeniawhite merged 23 commits intomainfrom
evgb-VerifierIntegration

Conversation

@jeniawhite
Copy link
Copy Markdown
Contributor

Proposed commit message

Adds the Permission Verifier integration package (verifier_otel) so Cloud Connectors can run permission checks for their integrations and send results to Elasticsearch via the OTEL Collector’s Verifier receiver.

Cloud Connector deployments need to confirm that IAM/API credentials have the permissions required by each attached integration. This integration configures the Elastic distribution’s Verifier receiver so that:

  • Verification runs (on-demand or scheduled) with the connector’s credentials.
  • Results are sent as OTEL logs to Elasticsearch with policy/integration/permission context.
  • Users can see which permissions are granted, denied, or errored and fix configuration.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

Author's Checklist

  • [ ]

How to test this PR locally

Related issues

Screenshots

@jeniawhite jeniawhite added the enhancement New feature or request label Feb 12, 2026
@jeniawhite jeniawhite requested a review from a team as a code owner February 12, 2026 05:14
@jeniawhite jeniawhite marked this pull request as draft February 12, 2026 05:15
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 12, 2026

Vale Linting Results

Summary: 2 warnings, 2 suggestions found

⚠️ Warnings (2)
File Line Rule Message
packages/verifier_otel/_dev/build/docs/README.md 34 Elastic.Latinisms Latin terms and abbreviations are a common source of confusion. Use 'versus' instead of 'vs'.
packages/verifier_otel/docs/README.md 34 Elastic.Latinisms Latin terms and abbreviations are a common source of confusion. Use 'versus' instead of 'vs'.
💡 Suggestions (2)
File Line Rule Message
packages/verifier_otel/_dev/build/docs/README.md 34 Elastic.Wordiness Consider using 'because' instead of 'since'.
packages/verifier_otel/docs/README.md 34 Elastic.Wordiness Consider using 'because' instead of 'since'.

The Vale linter checks documentation changes against the Elastic Docs style guide.

To use Vale locally or report issues, refer to Elastic style guide for Vale.

@andrewkroh andrewkroh added New Integration Issue or pull request for creating a new integration package. documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. labels Feb 12, 2026
@jeniawhite jeniawhite marked this pull request as ready for review February 18, 2026 22:33
Comment thread packages/verifier_otel/docs/README.md Outdated
|-----------|-------------|
| `policy.id` | Policy identifier |
| `policy.name` | Policy name |
| `integration.id` | Integration instance identifier |
Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye Feb 20, 2026

Choose a reason for hiding this comment

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

Thinking about the Integration Type field — would it make sense to map this directly to policy_template from manifest.yml instead? Since Fleet's package policy API already models around policy_template, we'd get consistency end-to-end and avoid any mapping logic on the Kibana side.

Would also propose embedding package metadata alongside the integration

{
  "policy_template": "guardduty",
  "package_policy_id": "",
  "package": {
    "name": "aws",
    "title": "AWS",
    "version": "6.2.0"
  }
  "namespace": "default"
}

This makes the Agentless API request fully self-describing — no lookups needed, clean audit trail, and the vocabulary stays consistent with Fleet. One thing worth noting in the spec: policy_template alone isn't globally unique across packages, so the safe unique key is the composite of package.name + policy_template (which this shape already captures).

Comment thread packages/verifier_otel/manifest.yml Outdated
text: On Demand
- value: scheduled
text: Scheduled
- name: providers.aws.credentials.role_arn
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Prefixing will add maintenance overhead on the Kibana side. We've already had to deal with mapping prefixes for AWS package fields that are named differently across CSPM, Asset Inventory, and AWS packages. A lot of work went into normalizing these down to role_arn, external_id, and default_region across both the AWS package and Cloud Connector saved object — prefixing would undo that.

Suggestion: keep the normalized snake_case fields as-is and add a provider meta field to carry the context that would otherwise be encoded in prefixes:

{
  "provider": "aws",
  "role_arn": "",
  "external_id": "",
  "default_region": ""
}

OR

If some namespacing is preferred, a credentials_ snake_case prefix is a reasonable middle ground — it's consistent, flat, and readable without introducing a new translation layer:

{
  "provider": "aws",
  "credentials_role_arn": "",
  "credentials_external_id": "",
  "default_region": ""
}

default_region sits outside the prefix since it's config, not auth. Hopefully, this keeps the shape flat while still giving credential fields a clear grouping and keeps fields stable and reusable across integrations without Kibana needing to own a translation layer for every package's naming conventions.

verification_type: on_demand
# AWS Provider Credentials
providers.aws.credentials.role_arn: arn:aws:iam::123456789012:role/TestRole
providers.aws.credentials.external_id: test-external-id
Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye Feb 20, 2026

Choose a reason for hiding this comment

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

Assuming a role behaves differently depending on whether you're targeting a single account vs an organization (management) account in cloudbeat. How about when verifying permissions?

Do you need additional account_type as metadata to help verify permissions?

// Cloud connector SO Model
{
        mappings: {
        dynamic: false,
        properties: {
          name: { type: 'keyword' },
          namespace: { type: 'keyword' },
          cloudProvider: { type: 'keyword' },
          accountType: { type: 'keyword' },
          vars: { type: 'flattened' },
          created_at: { type: 'date' },
          updated_at: { type: 'date' },
        },
   }
}


| Integration Type | Permissions Verified |
|-----------------|---------------------|
| `aws_cloudtrail` | cloudtrail:LookupEvents, DescribeTrails, s3:GetObject, ListBucket, sqs:ReceiveMessage |
Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye Feb 20, 2026

Choose a reason for hiding this comment

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

So is the permission matrix base on least-privilege principle so each permission will be scope to integration type as opposed global permissions shared by integration package?

@jeniawhite
Copy link
Copy Markdown
Contributor Author

@claude

Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye left a comment

Choose a reason for hiding this comment

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

Looks great so far! This is my early feedback and I'm verifying if anything is need on Kibana side, I will have subsequent review soon.

@narph narph requested a review from a team February 23, 2026 16:24
Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye left a comment

Choose a reason for hiding this comment

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

Temporary blocked merge until we align on data model changes to avoid accidental merge.

@Omolola-Akinleye Omolola-Akinleye self-requested a review March 4, 2026 14:06
| `permission.action` | Permission being checked (for example, `cloudtrail:LookupEvents`) |
| `permission.category` | Permission category (for example, `data_access`) |
| `permission.status` | Result: `granted`, `denied`, `error`, or `skipped` |
| `permission.required` | Whether this permission is required |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jeniawhite just one more thought when I sync'd with Oleg. He mentioned there can be IAM Policy with multiple permissions which I didn't think about. What is the relationship between verification and handling IAM Policy/permissions.

For instance,if user could update IAM policy include multiple permissions. Will each verification doc check multiple permissions?

IAM Policy AmazonS3ReadOnlyAccess for Amazon S3.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:List*",
        "s3:Describe*",
        "s3-object-lambda:Get*",
        "s3-object-lambda:List*"
      ],
      "Resource": "*"
    }
  ]
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Current state of the verifier maps the required actions per integration and these are the actions that are being verified and send as events. If we'd like we can verify the IAM roles as well by attempting to assume them (without triggering actions). This would require changes to the verifier by adding an additional type of verification (non API...). We'll need to understand what we want to verify for the integration and have it as part of the registry. If we decide to only assume then there are cons like SCP rules that might block requests and misaligned action configurations. Should I create discussion around this topic? @Omolola-Akinleye @olegsu

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When we ask customers in documentation page that in order for an integration to work properly we need an access to builtit, support by aws role, this is how I expect it to be reflected in case the trust was revoked.

@Omolola-Akinleye Omolola-Akinleye self-requested a review March 9, 2026 15:48
Comment thread packages/verifier_otel/manifest.yml
@jeniawhite jeniawhite marked this pull request as draft March 13, 2026 06:38
account_type: "single_account"

credentials_project_id: "my-gcp-project-123"
credentials_workload_identity_provider: "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

credentials_workload_identity_provider makes sense but I notice our integrations use term audience can we keep it consistent here as well? I think GCP Docs treats the url as audience as well.

Comment thread packages/verifier_otel/_dev/build/docs/README.md
policy_id: "policy-aws-security"
policy_name: "AWS Security Monitoring"

policy_template: "cloudtrail"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thinking about scale how are we going verify a cloud connector that have mutilple packages such as CSPM and Asset Inventory) or single package with multiple policy templates (guard duty and cloud trail)

  • If we want verify permission for multiple integration types for AWS which Guard Duty and Cloud trail. Should policy templates be an array in this case?

  • We have edge case where two packages that share the same IAM Policy Security Audit; hence, can use the same cloud connector. How should we verifying multiple packages that share a cloud connector?

Copy link
Copy Markdown
Contributor

@Omolola-Akinleye Omolola-Akinleye left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the changes!

@jeniawhite jeniawhite marked this pull request as ready for review March 24, 2026 03:49
@elasticmachine
Copy link
Copy Markdown

💚 Build Succeeded

History

@jeniawhite jeniawhite merged commit 8733fdf into main Mar 24, 2026
11 checks passed
@jeniawhite jeniawhite deleted the evgb-VerifierIntegration branch March 24, 2026 04:15
@andrewkroh andrewkroh added the Integration:verifier_otel Permission Verifier label Mar 24, 2026
Omolola-Akinleye added a commit to elastic/kibana that referenced this pull request Apr 6, 2026
…257516)

## Summary

The `verify_permissions_task` is a scheduled Fleet background task that
validates cloud connector credentials by deploying a short-lived
OTel-based verifier agent. It runs every 5 minutes and processes **one
connector at a time** to avoid resource contention.

- Remove the otel_verifier_logs_status_change_task and all references
from plugin.ts — this mock-based status-update task is no longer needed;
status will be handled differently when the real verification index is
available.

- Clean up unused cloud connector saved object fields (verification_id,
verification_timestamp, verification_permissions) and their associated
types (VerificationResultDocument, VerificationPermissionResult,
PermissionStatus) that had no active writers.

- Trim the SO model version 4 to only include the 3 actively used
verification fields.

- Add comprehensive unit tests for the permission verifier task (11
tests covering registration, scheduling, feature flag gating,
eligibility filtering, policy template aggregation, connector status
updates, failure handling, and TTL-based cleanup).

**High-Level Overview: Permission Verifier Task**
The verify_permissions_task is a scheduled Fleet background task (runs
every 5 minutes) that validates cloud connector credentials by deploying
an OTel-based verifier agent. It operates in three phases:

1. **Cleanup** — Deletes any expired verifier agent policies whose TTL
(5 min) has elapsed, ensuring at most one active verification deployment
at a time.

2. **Pre-filter** — Queries package policies with cloud_connector_id to
build a map of connector ID to verification info (aggregated policy
templates + package metadata). Only connectors with installed
integrations are candidates.

3. **Verify** — Picks the first eligible connector (based on 6 criteria:
never verified, recently created/updated, due for re-verification,
failed with cooldown expired, or no status set) and creates a single
verifier agent policy containing all policy templates for that
connector. On success, stamps verification_started_at; on failure, marks
verification_status: failed.

The verifier agent policy uses the[ verifier_otel integration
package,](elastic/integrations#17386) which runs
an OTel Collector with a custom Verifier receiver that checks the
connector's cloud credentials against the required permissions for each
policy template.

### Verifying Cloud Connector Permisstions with Otel Verifier Flow

```mermaid
sequenceDiagram
    participant TM as Task Manager
    participant VT as Verify Permissions Task
    participant SO as Saved Objects
    participant AP as Agent Policy Service
    participant Agent as OTel Verifier Agent
    participant ES as Elasticsearch

    TM->>VT: Run task (every 5 min)
    
    Note over VT: Phase 1 — Cleanup
    VT->>AP: List verifier policies (is_verifier: true)
    AP-->>VT: Active verifier policies
    loop Each expired policy (age > 5 min TTL)
        VT->>AP: deleteVerifierPolicy(policyId)
    end

    Note over VT: Gate check — one at a time
    VT->>AP: List verifier policies (is_verifier: true)
    AP-->>VT: Active policies
    alt Non-expired verifier exists
        VT-->>TM: Skip (deployment in flight)
    end

    Note over VT: Phase 2 — Pre-filter
    VT->>SO: Find package policies with cloud_connector_id
    SO-->>VT: Package policies
    Note over VT: Build map: connector → {policyTemplates, packageInfo}
    VT->>SO: Find cloud connectors by ID
    SO-->>VT: Cloud connectors

    Note over VT: Phase 3 — Verify first eligible connector
    loop Each connector (break after first eligible)
        alt Not eligible (recently verified, in backoff window, etc.)
            Note over VT: Skip
        else Eligible
            VT->>AP: createVerifierPolicy(connector, verificationInfo)
            AP->>AP: Create agent policy (is_verifier: true)
            AP->>AP: Create verifier_otel package policy
            AP->>AP: Deploy policy to agentless
            AP-->>VT: {policyId}
            
            Note over Agent: Agent enrolls and runs OTel Collector
            Agent->>Agent: Verifier receiver checks cloud permissions
            Agent->>ES: Write verification results to logs-verifier_otel.*
            
            VT->>SO: Update connector (status: pending, started_at: now)
        end
    end
    
    VT-->>TM: Task complete
```

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Julia Bardi <90178898+juliaElastic@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. enhancement New feature or request Integration:verifier_otel Permission Verifier New Integration Issue or pull request for creating a new integration package.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants