Skip to content

Verify & confirm

Verification is completed by automated in-product checks and customer-run trust-boundary checks. No message or support action is a completion gate. See Docs authority & product state.

1. Confirm credential readiness

Role: Engineer or Admin with connector settings access.

Run automated credential validation in the guided setup. It checks the exact tenant, connector identity, trust condition, resource scope, and provider reachability. A connector cannot advance on a warning or a partially validated credential.

Success evidence: credential state is Validated, with a timestamp and scope summary.

Recovery: fix the named credential field or trust condition. Rotate the credential if its provenance is uncertain, then rerun validation.

2. Prove the read-only trust boundary

Automated credential validation runs the live checks for every cloud: it authenticates as the Venturi identity, runs a positive read probe for each granted service, and confirms that deny-expected writes fail. Positive reads are proven there for AWS, Google Cloud, and Azure alike.

The customer-run check differs by cloud because each module’s local tooling can reach a different part of the boundary. Run it after terraform apply from the module directory (infra/<cloud>/onboarding) that you extracted from the pinned Terraform artifact in guided setup and applied with your terraform.tfvars. Each tab lists the command, what it checks, and the pass condition.

Run: the role’s trust policy accepts only the generated Venturi principal, so the module’s scripts/verify.sh, which assumes the role, can run only under that principal; automated credential validation performs the live read and denied-write checks from it. From your own account, list every policy the role holds, then spot-check writes with the IAM policy simulator. The caller needs iam:ListAttachedRolePolicies, iam:ListRolePolicies, iam:GetRolePolicy, and iam:SimulatePrincipalPolicy.

Bash
ROLE_ARN="$(terraform output -raw role_arn)"
ROLE_NAME="${ROLE_ARN##*/}"
aws iam list-attached-role-policies --role-name "$ROLE_NAME" \
  --query 'AttachedPolicies[].PolicyArn' --output json
for POLICY in $(aws iam list-role-policies --role-name "$ROLE_NAME" \
    --query 'PolicyNames[]' --output text); do
  echo "$POLICY"
  aws iam get-role-policy --role-name "$ROLE_NAME" --policy-name "$POLICY" \
    --query 'PolicyDocument.Statement' --output json
done
aws iam simulate-principal-policy \
  --policy-source-arn "$ROLE_ARN" \
  --action-names iam:CreateUser s3:CreateBucket ce:CreateAnomalyMonitor \
    cloudwatch:PutMetricData logs:CreateLogGroup cur:PutReportDefinition \
  --query 'EvaluationResults[].[EvalActionName,EvalDecision]' \
  --output table

Checks: the policy listing is the complete check: it shows every managed and inline policy on the role, so you can confirm that each statement allows only the read actions in the AWS access boundary. The simulator is a spot check: it evaluates the role’s policies, plus any service control policies, for the 6 write actions that verify.sh probes, and a policy that allowed another write action would not show there. Under the Venturi principal, verify.sh runs a read probe for Cost Explorer, IAM, Organizations, Price List, CloudWatch metrics, and CloudTrail, plus the CUR bucket when CUR_BUCKET is set and Bedrock unless SKIP_BEDROCK=1. It does not probe CloudWatch Logs reads. It attempts the same 6 writes.

Pass: the attached-policy list is []; the inline policies (3 with Bedrock access enabled, 2 without) contain only Allow statements for the access-boundary read actions; and no simulator row shows allowed, each showing implicitDeny or explicitDeny. A verify.sh run that cannot assume the role exits 2, a successful write exits 1, and a failed read prints MISS but still exits 0.

Tested identities: the policy listing and the simulator run as your own IAM caller, and the simulator evaluates the Venturi role named by role_arn without calling any service as that role. verify.sh and automated credential validation call each service as the generated Venturi principal after it assumes the role, so only they test that principal with live calls.

Incomplete: a verify.sh run from your own account exits 2 because it cannot assume the role, so it tested no read or write; automated credential validation supplies that live result. A MISS line from a run under the Venturi principal still exits 0, but its read stays unproven until you add the named permission and rerun automated credential validation.

Run:

Bash
export PROJECT_ID="my-prod-project"
gcloud auth login
SERVICE_ACCOUNT_EMAIL="$(terraform output -raw service_account_email)" \
  ./scripts/verify.sh

The script calls gcloud with the account from gcloud auth login, not the Application Default Credentials that Terraform uses, so sign in as the principal that runs the check.

Checks: the service account exists and has no user-managed keys; the script prints a role: line for each project-scope role binding; a Workload Identity Pool exists in the project; and a write call, such as BigQuery dataset creation, made while impersonating the service account is denied. The script does not list dataset-scope bindings; terraform output granted_roles summarizes them. The script’s allowlist is broader than the module: it prints roles/bigquery.dataViewer, roles/iam.serviceAccountTokenCreator, and roles/iam.workloadIdentityUser at project scope as OK, with no SEC line. At project scope, roles/bigquery.dataViewer reads every dataset in the project, including Vertex AI request-response logging tables, and either of the other 2 roles lets its holder obtain tokens for service accounts in the project, including write-capable ones. The allowlist check therefore does not prove that no write-capable role is bound; the exact role-line rule below does. The impersonation needs roles/iam.serviceAccountTokenCreator on the service account for the person running the script. To exercise the write probe, grant it for the check and remove it afterward; without it, the write probe is reported as SKIP, and automated credential validation runs the denied-write probes as Venturi’s identity.

Pass: exit 0 with no SEC or MISS lines, and project-scope role lines that are exactly role: roles/monitoring.viewer, role: roles/logging.viewer, and role: roles/serviceusage.serviceUsageConsumer, the project roles the module grants with billing_dataset_only = true and billing_dataset_id set. Any other role: line, including roles/bigquery.dataViewer, roles/iam.serviceAccountTokenCreator, or roles/iam.workloadIdentityUser, is a security finding. A write-probe SKIP does not fail the check. A security finding the script detects exits 1, and a missing service account or unreadable IAM policy exits 2. MISS and SKIP lines and allowlisted extra roles still exit 0, so read the output.

Tested identities: verify.sh reads the service account, its keys, the project IAM policy, and the Workload Identity Pool as the account from gcloud auth login. Only its write probe tests the Venturi service account, by impersonating it. Automated credential validation runs the positive reads and the denied-write probes as the Venturi identity.

Incomplete: a write-probe SKIP means the script tested no denied write for the service account; automated credential validation supplies that result. A MISS line leaves its check unproven until you resolve it and rerun the script.

Run: while still signed in as the setup operator, capture the Terraform outputs; a Reader-only identity cannot read Terraform state kept in the azurerm backend. Then sign in to az as an identity that holds only Reader on the subscription, not the Owner, User Access Administrator, or Role Based Access Control Administrator session that ran terraform apply, and run the checks.

Bash
export SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
CLIENT_ID="$(terraform output -raw client_id)"
OBJECT_ID="$(terraform output -raw object_id)"
export CLIENT_ID OBJECT_ID
az login
az account set --subscription "$SUBSCRIPTION_ID"
./scripts/verify.sh
az role assignment list --assignee "$OBJECT_ID" --all --output table

Run az login as the Reader-only identity.

Checks: the service principal exists; each of its role assignments at subscription scope is an allowlisted read role; a federated identity credential exists; at most 1 password credential exists; and 3 write probes are denied (a Contributor role assignment for the service principal, a resource group, and an action group). The write probes run as the identity signed in to az, not as the service principal. From the Reader-only identity they are always denied, so they test only that identity and prove nothing about the service principal. The service principal’s boundary is proven by the --all listing, which shows its role assignments at every scope, and by automated credential validation, which runs its denied-write probes as the service principal. The script’s allowlist is not that proof: it checks subscription scope only, and it also accepts roles the module never grants, including Reader and Data Access, which can read and write all data in a storage account through its account keys, and Billing Reader.

If you run the script from a privileged session instead, its write probes can succeed. Under an Owner session, the role-assignment and resource-group probes succeed: the script reports 2 security findings, removes the Contributor assignment it created, and leaves a venturi-verify-must-fail-<timestamp> resource group for you to delete. Under a User Access Administrator or Role Based Access Control Administrator session, only the role-assignment probe succeeds: the script reports 1 security finding, removes the assignment, and creates no resource group.

With APIM or Event Hubs access enabled and its resource ID set, the workspace-scope Log Analytics Reader or namespace-scope Azure Event Hubs Data Receiver assignment sits below the subscription, so the script does not list it; the --all listing shows it with its scope. If the resource ID is empty, the module assigns the role at subscription scope. The script accepts Log Analytics Reader there without a finding, although at that scope it reaches every workspace in the subscription, and it reports Azure Event Hubs Data Receiver as outside its allowlist.

Pass: exit 0 with no SEC or MISS lines; with APIM access enabled, no role: Log Analytics Reader line; and an --all listing that shows only Reader, Cost Management Reader, and Monitoring Reader on the subscription, plus Log Analytics Reader on the named workspace and Azure Event Hubs Data Receiver on the named namespace when those grants are enabled. A security finding exits 1, and a missing service principal or unreadable role assignment list exits 2. In the client-secret fallback, a MISS line for the absent federated credential is expected; resolve every other MISS.

Tested identities: verify.sh and the --all listing run as the Reader-only identity signed in to az. The listing reads the service principal’s role assignments, and the script’s write probes exercise the Reader-only identity alone. Automated credential validation runs the denied-write probes as the service principal.

Incomplete: the script’s denied write probes leave the service principal’s write boundary unproven; the --all listing and automated credential validation supply it. Any MISS line other than the expected client-secret fallback line leaves its check unproven until you resolve it and rerun the script.

Success evidence: automated credential validation passes its positive reads and denied writes, the customer-run check for your cloud meets its pass condition, and every deny-expected write leaves provider state unchanged. Record which identity ran each check. A result listed as incomplete leaves that part of the boundary unproven until the check that the tab names for it passes.

Recovery: remove any write grant immediately. For a failed read, add only the named permission at the narrowest resource scope, then rerun the failed probe and the complete boundary check. Troubleshooting maps each result to its fix.

3. Inspect attribution evidence

Role: Engineer or authorized viewer with /invocations access.

Open /invocations and inspect the 1st AttributionRecord produced from the connected source or accepted provider export file. The surface shows only records inside the signed-in user’s role scope, so record the user and role that run this check. An event accepted by the ingestion API (202 Accepted) or recorded by the proxy appears there within approximately 30 seconds. Confirm:

  • source and evidence lineage;
  • identity and cost mapping;
  • coverage and explicit unknowns;
  • source and record freshness;
  • confidence and export eligibility.

Success evidence: the record is visible and its evidence links resolve to the accepted source or file. This is the engineering active-use milestone. The check is incomplete when no record from the source appears or when the source sits outside the checking role’s scope; an incomplete check confirms neither active use nor a source failure.

Recovery: follow the record’s missing-evidence, unknown, or stale state back to the named provider, identity, cost-mapping, or deployment step. Do not replace an unknown with an unsupported value.

4. Verify persona completion

Persona-complete production onboarding is a separate gate. Product, Security, Engineering, and Finance must each complete real in-product actions. Finance completion requires acceptance of a chargeback-eligible export. There is no admin or support override.

Use the Enterprise readiness checklist for the required evidence. Support remains an optional recovery path.

Give feedback on this page

Sign in to send feedback. Opens in a new tab.

Copy page details
Docs feedback: Verify & confirm
Page: https://docs.venturi.systems/reference/verification/