Read and write roles, and the write gate

Investigate only, approved changes only or both on one credential; what counts as a write for every connector type; and the write gate as a control matrix.

Concept · Updated 2026-10-27 · Describes release 0.1.164

Every connection is used in one of three ways, and every tool call is classified as a read or a write in one place for all connector types. This page owns both rules. The connect form, secrets, Test and the row actions are on Manage connections; the write side step by step is Write connections and approved fixes.

Read role vs write role

Choose Use this connection for. This controls which platform workflows can use the credential; it does not grant cloud IAM permissions.

Connect datasource: Use this connection for decides whether the credential investigates, executes approved changes, or both; Allow use for approved plans is the separate consent.
Connect datasource: Use this connection for decides whether the credential investigates, executes approved changes, or both; Allow use for approved plans is the separate consent.
Choice Investigation, chat and discovery Approved execution
Investigate only (read, default) Read operations Unavailable
Approved changes only (separate credential) (write) Credential excluded Available only after Allow use for approved plans is enabled
Investigate and approved changes (same credential) (read_write) Read operations through the same read-only tool boundary Available only after Allow use for approved plans is enabled

Allow use for approved plans starts off. Changing the connection's use clears this consent; enabling it never approves an individual plan. Turning it off blocks subsequent execution; a shared connection remains available for investigation. Changing credential, scope, use or consent requires a fresh execution review.

Moving an Approved changes only (separate credential) connection to another use hands its stored credential to investigations and private agents, so it is a release decision: it needs approvals.decide as well as datasources.manage (of the builtin roles, only the owner holds both). Pointing such a connection somewhere else is the same decision, because Test and operation discovery send its stored credential to the address in its settings: once it holds a stored credential, a change to its settings needs approvals.decide too. An operator's change of use or of those settings is refused with 403; the operator can still rename it, describe it, replace its credential and switch it on or off.

A separate execution credential is excluded from investigation tool registries. The planner sees only capability and scope metadata. A shared credential is available to read tools, but an investigation cannot use its cloud write permissions: writes still go through the exact approved Change executor. Separate credentials also enforce this separation in the provider's IAM; shared credentials depend on the platform's read boundary as well as their provider scope.

An enabled AWS/Azure execution credential with consent can be saved with Save and check access. That runs a safe identity/read check, never a mutation probe and never proof of all future write permissions. Without consent, Save remediation credential saves it without that check. Audit perms on the connection's row in Data sources inspects grants where supported; the exact action is checked again before dispatch.

Chat reads the platform records your role allows. With chat.estate, it may also query live read-only connections; write-role credentials stay excluded and mutating calls are denied. Collected telemetry additionally requires the active lakehouse feature and its read permission.

Split a powerful credential in two

Use this when you want investigation credentials to have no provider write permissions.

  1. Connect the read half first. Give it a narrow viewer credential. Choose Investigate only and Connect and verify. Requires datasources.manage.
  2. Wait for the read check to succeed. A queued private-agent check is still waiting for a result.
  3. Press Audit perms and confirm the verdict reads least-privilege OK. If it reads over-privileged, scope the credential down at the source and re-check before going further.
  4. Connect the write half as a second datasource of the same type, with a distinct name (prod-eks-remediate, core-switch-config). Choose Approved changes only (separate credential).
  5. Give the write half only the permission the intended fix needs — push to one repository, restart one workload, write one device config section — and nothing else.
  6. Enable Allow use for approved plans when ready. Save the connection, inspect any access-check result, then return to the incident or Change to review the exact proposed action and recovery checks.

A connection can support different approved actions inside its validated scope. For the simpler setup, choose Investigate and approved changes (same credential), connect a suitably scoped identity, and explicitly enable approved-plan use. Repository access is connected separately when a configuration change belongs in Git; cloud access does not grant repository permissions.

Several connections into one cloud account

Some organisations give each job its own role: one for operations reads, one with security-audit reads for compliance, one for the audit log. Each role can be its own connection into the same AWS account, and several app registrations can each be a connection into the same Azure subscription. Fixes still run only through your separate write connection, after approval.

Add the extra role. Name it aiops-…, with no path, and give it the same trust policy as your read role: sts:AssumeRole with this workspace's External ID, and sts:TagSession, for the platform role and the workspace reader role. In any-account mode that is all it needs: the platform assumes any aiops-* role whose trust names the workspace External ID. With roles prepared by platform staff (also the case with a private-network agent, whose own role is the workspace reader), the reader is granted only the roles staff prepared, so ask platform staff to also grant it sts:AssumeRole and sts:TagSession on the new role, and the platform role too where its grants name exact roles. Test runs as the platform role and cannot check the reader's grant: until staff add it, Estate x-ray scans and investigation reads through the new connection are refused. Connect it as Investigate only under its own name. An access-key connection needs one passing Test before the platform knows its account; until then it is grouped with no other connection.

Choose what each connection runs. Under Advanced · agent access and automation credentials, Jobs this connection runs lists the account-wide reads an AWS or Azure read connection makes beside its agent tool: four on both clouds, and Service map (Application Signals / X-Ray) and Built-in detection on AWS. All of them start ticked. When the role you type reaches an account another read connection already reaches, the form names that connection and what it runs; it warns, and never refuses the second connection.

Edit connection → Advanced · agent access and automation credentials → Jobs this connection runs: the account-wide jobs this credential performs, and the pillar allowlist beneath.
Edit connection → Advanced · agent access and automation credentials → Jobs this connection runs: the account-wide jobs this credential performs, and the pillar allowlist beneath.
Job What it reads Config key
Estate inventory Every resource the account lists (on AWS: tagging GetResources, Resource Explorer ListResources in a region where its index is on, and AWS Config's recorded inventory through SelectResourceConfig; on Azure: Resource Graph) and the typed network, compute and data structure behind the estate map, into the [estate] <connection> knowledge item. config_inventory: false leaves AWS Config out harvest_inventory
Platform checks (EST-01..06) The platform's own cloud checks: backups, public storage, open security groups, encryption at rest, audit logging and IAM hygiene platform_checks
Security findings sync Security Hub findings on AWS, Defender for Cloud assessments on Azure sync_findings
Change capture CloudTrail write events on AWS; the Activity Log and Change Analysis on Azure harvest_changes
Service map (Application Signals / X-Ray) (AWS) Application Signals ListServices and ListServiceDependencies, with X-Ray GetServiceGraph where Application Signals lists nothing in a region; hourly, into traced service dependencies, never trace content. A connection whose Pillar allowlist leaves out Incident is not read, although its Runs line still lists the job service_map
Built-in detection (AWS) CloudWatch ListMetrics and GetMetricData for the built-in rules, in the regions this connection evaluates; runs only while the workspace has Built-in detection on builtin_detection

An unticked job saves false under its key in the connection's configuration, and ticking it again removes the key. A connection without the key runs the job, so connections made before this setting keep running all of them. Saving re-tests the connection, as every edit does: on a connection that also runs approved changes, a pending approval bound to it needs a fresh review.

Divide the jobs the way your roles are divided.

What the platform does with one account behind several connections. A connection's account is the account of its role ARN, else the account its last Test proved for its current settings. An Azure connection's is the one subscription its jobs read (its Scope JSON subscriptions, else its subscription ID), and only when it reads that whole subscription: several subscriptions, or a resource group, leave it grouped with no other connection. The accounts in an AWS Scope JSON are intent and never group connections. For connections sharing an account:

The read/write gate in detail

Investigation datasource tools reject writes, even with a shared read/write credential. Supported mutations must be prepared and released through the Change executor. Approval gates for sensitive reads can still pause a run; approving one does not turn an investigation tool into a write executor. Guardrails and cost limits is the authority on which posture your deployment runs, and Configure the agents on how to add gates of your own; this section is the authority on what counts as a write.

Every connector type has a declared read surface, and the tool description tells the agent exactly what it is.

Two overrides with no portal control

Both are set on the datasource config through the REST or MCP API. Neither has a control on the Data sources page.

Tightening (gate_paths) forces specific paths to be gated even when they would otherwise classify as reads. Use it to put a sensitive endpoint behind a human decision.

Widening (read_post_paths) adds POST endpoints to the approval gate's read set for one datasource. It does not widen what an agent may call: the read floor every investigation, chat turn and estate x-ray applies classifies a call with the connector's own read set only, so in this release a POST outside that set is still refused, adopted or not. It applies to POST only, never to PUT, PATCH or DELETE, and any path containing a dangerous token (write, delete, exec, admin, control, import, bulk, restart, create, update, run and others) is rejected outright.

Widen a read set the reviewed way

Widening is deliberately a two-step, reviewed operation: the platform derives candidates from the API's own specification, and a human adopts them.

  1. Set an OpenAPI path on the datasource, if it does not have one. Requires datasources.manage.
  2. Call the discovery endpoint. It fetches the specification, derives the API's read and write surface in code, and records query-shaped POST endpoints as pending candidates — up to 50, trusted by nobody yet. It fails with a 400 if the datasource has no OpenAPI path, or if the spec cannot be fetched or parsed.
curl -X POST \
  -H "Authorization: Bearer $AIOPS_TOKEN" \
  "$AIOPS_URL/api/aiops/$TENANT_ID/datasources/$DS_ID/discover-operations"
  1. Review the returned candidates. Adopt only the ones you have confirmed are genuinely read-only.
curl -X POST \
  -H "Authorization: Bearer $AIOPS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"paths": ["reports/query", "search/execute"]}' \
  "$AIOPS_URL/api/aiops/$TENANT_ID/datasources/$DS_ID/adopt-read-paths"
  1. Confirm the behavior on a real call before relying on it.

You know it worked when the adopt response lists your paths under adopted with nothing under rejected. The next agent call to that endpoint is still refused in this release (see Widening above). Only pending candidates can be adopted — anything else is refused with a 400 — every adopted path is re-validated against the denylist, both endpoints require datasources.manage, and both are audited. Existing adopted paths are preserved when editing other connection fields.

Estate x-ray ignores widening

Estate x-ray does not use any of this. It runs on a credential-independent read-only registry where a gated call is denied outright rather than queued, it re-classifies with no operator configuration at all, it applies its own CLI read-verb floor instead of the connector's configured read verbs, and every denial is counted onto the scan as proof it wrote nothing. A scan therefore sees slightly less than an investigation does, on purpose.

The write gate as a control matrix

Investigation datasource tools reject writes, regardless of whether the connected credential has provider write permissions. Supported mutations are prepared and released through the Change executor. Approval gates may still pause sensitive read operations; approving a read gate does not allow an investigation tool to execute a mutation.

What counts as a write is decided by an intrinsic floor in code. Your per-agent approval list can only add gates on top of it; it can never remove one.

Tool family Runs without approval Gated
Command-line connectors kubectl reads the platform's own adapter verifies; no other binary, whatever verbs the operator declared read-only Everything else
Generic API connectors GET Every POST (a path adopted as a read included), and every PUT / PATCH / DELETE
AWS native Read action verbs (Describe*, List*, Get*, Query, Scan, Lookup*) — gating by HTTP method would pause every read, since AWS reads are form posts Credential and secret reads, statement execution, every mutating action
Azure native GET, plus a small read allowlist for POST All other POST, and PUT / PATCH / DELETE always
Google Cloud native GET Every other method
MCP server tools Only tools the server annotates readOnlyHint=true Everything else — deny by default, because nothing here can know a third-party tool's semantics
Network devices show / display reads Configuration lines
web_fetch Allowlisted domains Every other URL
http_get Never Always
web_search Always (PII-scrubbed query) Never
lake_query Always Never — see below

These guarantees apply independently of the chosen credential mode:

lake_query is deliberately ungated because it is read-only by construction, three ways: the DuckDB connection is opened read-only; external file access is disabled at connect time on every connection, so filesystem table functions cannot reach host files or another tenant's lake; and the SQL guard accepts a single SELECT/WITH statement only, rejecting DDL, writes, extensions and filesystem functions after stripping strings and comments.

Editing an agent's approval list or its toolsets requires pillars.manage, which by default only the owner role holds. Someone who merely operates or approves cannot widen the gate. Full detail: Configure the agents → Procedure: add an extra approval gate.

One thing we will not overstate. Untrusted-input fencing — every alert-derived string and every tool result enters the model inside <<<UNTRUSTED ... >>> delimiters, with a standing rule that fenced content is data and never instructions — is a mitigation, not a boundary. A determined prompt injection can still steer which reads the agent performs. The write gate and the always-gated http_get are the blast-radius limiter, and they are enforced in our code, outside the model's reach.

Review a change on the incident

An incident's Prepared change section names the change, target, connection, impact and recovery checks. For a prepared incident or standalone Change plan, the platform selects an enabled execution connection with Allow use for approved plans enabled whose capability and scope support the evidenced target, or asks you to choose between compatible connections. These steps do not need a saved remediation route. Expand Exact changes and execution method to inspect the API request, CLI arguments or repository edit. Authorized users can approve the reviewed action; other operators can request approval. Missing or ambiguous access is resolved on that incident before execution becomes available.

Review displays the actual API method/path/body, CLI arguments or repository edit that execution will use. Rollback and verification guidance is labelled separately: prose is not an executable command, and a validated restore action is shown only when available.

Unknown targets, unsupported operations and unconfirmed repository ownership require more evidence. A successful connection test is not approval, and a created PR is not a deployed fix. See Review and apply a fix.

Use cases

Proving least privilege at audit time

A compliance officer opens the page with datasources.view and, for each connector, reads the Role column: only the two remediation credentials carry a write use, and both read remediation only — kept out of every agent. He asks the platform owner to run Audit perms on the cloud connector; the dialog names the principal, lists the evaluated permissions, flags nothing as over-privileged, and states the gate classification — which read actions run freely, and that every write is gated regardless. He exports the evidence trail from Audit log, where each connect, edit, test, permission audit, operation discovery, read-path adoption and route change is recorded with actor and timestamp.

Next steps