Wiz Hardening Guide
Cloud security platform hardening for connector security and RBAC controls
Overview
Wiz provides agentless cloud security to 40-50% of Fortune 100 through API access to cloud environments. While the agentless architecture minimizes agent-based risks, OAuth tokens and cloud connector credentials could expose comprehensive cloud security posture data and SBOM information across major financial institutions and enterprises. Wiz’s deep visibility into cloud configurations makes it a high-value target.
Intended Audience
- Security engineers managing CSPM tools
- Cloud security architects
- GRC professionals assessing cloud security
- Third-party risk managers evaluating security tools
How to Use This Guide
- L1 (Crawl): Essential controls for all organizations
- L2 (Walk): Enhanced controls for security-sensitive environments
- L3 (Run): Strictest controls for regulated industries
Scope
This guide covers Wiz-specific security configurations including authentication, cloud connector security, API access controls, and data protection.
Table of Contents
- Authentication & Access Controls
- Cloud Connector Security
- API Security
- Data Security
- Monitoring & Detection
- Compliance Quick Reference
1. Authentication & Access Controls
1.1 Enforce SSO with MFA
Profile Level: L1 (Crawl) NIST 800-53: IA-2(1)
Description
Require SAML SSO with MFA for all Wiz console access.
Rationale
Why This Matters:
- Wiz has visibility into all cloud infrastructure
- Compromised access exposes vulnerability data
- Attack planning facilitated by exposed security posture
Attack Prevented: Console account takeover, credential-stuffing and phishing against local logins, session reuse after offboarding, reconnaissance of the customer’s entire cloud attack surface via a compromised OAuth token
ClickOps Implementation
Step 1: Configure SAML SSO
- Navigate to: Settings → Authentication → SAML Configuration
- Configure:
- IdP Entity ID: From your identity provider
- SSO URL: IdP login endpoint
- Certificate: Upload IdP certificate
- Enable: Enforce SAML authentication
Step 2: Disable Local Accounts
- Navigate to: Settings → Authentication
- Disable: Allow local authentication
- Keep 1 break-glass account (documented, monitored)
Step 3: Configure Session Security
- Navigate to: Settings → Authentication → Session Settings
- Configure:
- Session timeout: 4 hours
- Idle timeout: 30 minutes
Code Implementation
Code Pack: Terraform
# Configure SAML SSO identity provider for Wiz console access
resource "wiz_saml_idp" "corporate_sso" {
count = var.saml_login_url != "" ? 1 : 0
name = var.saml_idp_name
login_url = var.saml_login_url
certificate = var.saml_certificate
issuer_url = var.saml_issuer_url != "" ? var.saml_issuer_url : var.saml_login_url
logout_url = var.saml_logout_url != "" ? var.saml_logout_url : null
use_provider_managed_roles = false
allow_manual_role_override = false
}
1.2 Implement Role-Based Access Control
Profile Level: L1 (Crawl) NIST 800-53: AC-3, AC-6
Description
Configure Wiz roles with least-privilege access.
Rationale
Why This Matters:
- Wiz aggregates vulnerability, misconfiguration, and attack-path data across the entire cloud estate, so broad default access exposes all of it to every user
- Least-privilege roles ensure analysts, developers, and auditors see only what their job requires, shrinking the blast radius of a single compromised account
- Project-based access scopes findings to specific teams and environments, preventing lateral visibility across tenants and business units
- Restricting Admin to a small, tightly controlled set limits who can alter platform settings, connectors, and integrations
Attack Prevented: Privilege escalation, insider data harvesting, lateral reconnaissance, unauthorized configuration changes
ClickOps Implementation
Step 1: Define Role Strategy
| Role | Permissions |
|---|---|
| Admin | Full platform access (limit to 2-3) |
| Security Analyst | View issues, run queries, NO settings |
| Developer | View assigned projects only |
| Auditor | Read-only access, reports |
| Integration | API access for specific use cases |
Step 2: Configure Custom Roles
- Navigate to: Settings → Access Control → Roles
- Create custom roles with minimum permissions
- Assign to user groups
Step 3: Implement Project-Based Access
- Navigate to: Settings → Projects
- Create projects for different teams/environments
- Assign users to specific projects only
Code Implementation
Code Pack: Terraform
# Map SAML groups to Wiz roles with least-privilege access
# Role strategy:
# - Admin: Full platform access (limit to 2-3 users)
# - Security Analyst: View issues, run queries, NO settings
# - Developer: View assigned projects only
# - Auditor: Read-only access, reports
# - Integration: API access for specific use cases
resource "wiz_saml_group_mapping" "rbac" {
count = var.saml_idp_id != "" && length(var.rbac_group_mappings) > 0 ? 1 : 0
saml_idp_id = var.saml_idp_id
dynamic "group_mapping" {
for_each = var.rbac_group_mappings
content {
provider_group_id = group_mapping.value.provider_group_id
role = group_mapping.value.role
projects = length(group_mapping.value.projects) > 0 ? group_mapping.value.projects : null
}
}
}
# Create project-based access boundaries for team segregation
resource "wiz_project" "team_projects" {
for_each = var.profile_level >= 1 ? toset(["security", "development", "audit"]) : toset([])
name = "hth-${each.key}"
description = "HTH hardened project for ${each.key} team - least-privilege boundary"
risk_profile {
business_impact = each.key == "security" ? "HBI" : "MBI"
}
}
2. Cloud Connector Security
2.1 Secure Cloud Connector Configuration
Profile Level: L1 (Crawl) NIST 800-53: IA-5, AC-6
Description
Harden cloud connector IAM permissions to minimum required.
Rationale
Why This Matters:
- Wiz connectors have read access to cloud resources across every subscribed account, so connector scope is effectively a second copy of your cloud permissions model
- Over-privileged connectors expand attack surface — a connector granted write or Contributor-equivalent rights turns a read-only posture tool into a change path into production
- Compromised connector credentials enable reconnaissance of the full cloud estate, including the misconfigurations an attacker would otherwise have to discover
- External IDs and dedicated identities keep the connector’s trust relationship scoped to Wiz specifically rather than to anyone who learns the role ARN
Attack Prevented: Confused-deputy assumption of the connector role, over-privileged connector abuse, cloud-wide reconnaissance from stolen connector credentials, unauthorized resource modification via an over-scoped connector
AWS Connector Best Practices
Step 1: Use Read-Only Policy
Code Pack: Terraform
# AWS connector with least-privilege IAM role (read-only)
# The IAM role referenced here should grant only:
# ec2:Describe*, s3:GetBucketLocation, s3:GetBucketPolicy,
# s3:ListAllMyBuckets, iam:GetAccountSummary, iam:ListRoles
# with an external ID condition on the trust policy.
resource "wiz_connector_aws" "hardened" {
count = var.aws_connector_role_arn != "" ? 1 : 0
name = var.aws_connector_name
enabled = true
auth_params = jsonencode({
"customerRoleARN" = var.aws_connector_role_arn
})
extra_config = jsonencode({
"optedInRegions" = var.aws_connector_regions
"excludedAccounts" = var.aws_connector_excluded_accounts
"skipOrganizationScan" = false
})
}
# GCP connector with Viewer role (read-only, organization-level)
resource "wiz_connector_gcp" "hardened" {
count = var.gcp_connector_organization_id != "" ? 1 : 0
name = var.gcp_connector_name
enabled = true
auth_params = jsonencode({
"isManagedIdentity" = true
"organization_id" = var.gcp_connector_organization_id
})
extra_config = jsonencode({
"projects" = []
"excludedProjects" = var.gcp_connector_excluded_projects
"includedFolders" = []
"excludedFolders" = []
"auditLogMonitorEnabled" = true
})
}
Code Pack: Config
# AWS IAM policy for Wiz connector (read-only)
cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"s3:GetBucketLocation",
"s3:GetBucketPolicy",
"s3:ListAllMyBuckets",
"iam:GetAccountSummary",
"iam:ListRoles"
],
"Resource": "*"
}
]
}
JSON
# AWS trust policy with External ID for Wiz role assumption
cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::WIZ_ACCOUNT_ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "YOUR_UNIQUE_EXTERNAL_ID"
}
}
}
]
}
JSON
Step 2: Enable AWS CloudTrail for Connector
- Monitor Wiz connector API calls
- Alert on unusual patterns
- Review access regularly
Step 3: Use External ID (see the Code Pack above for the trust policy JSON)
Azure Connector Best Practices
Step 1: Use Reader Role
- Assign Reader role at management group level
- Avoid Contributor or Owner roles
- Use managed identity where possible
Step 2: Restrict App Registration Permissions
- Create dedicated app registration
- Grant only Microsoft Graph read permissions
- Document and monitor app usage
GCP Connector Best Practices
Step 1: Use Viewer Role
- Assign Viewer role at organization level
- Create service account with minimal permissions
- Enable service account key rotation
2.2 Connector Credential Rotation
Profile Level: L2 (Walk) NIST 800-53: IA-5(1)
Description
Implement regular rotation of cloud connector credentials.
Rationale
Why This Matters:
- Cloud connector credentials grant Wiz standing read access to your entire cloud environment, making long-lived secrets a durable target if leaked
- Regular rotation bounds the window during which a stolen IAM external ID, Azure app secret, or GCP service-account key remains usable
- Scheduled rotation forces removal of forgotten or unused credentials that would otherwise persist indefinitely
- A rotation cadence creates an audit trail and clear ownership around connector secrets
Attack Prevented: Credential theft reuse, long-lived secret abuse, stale-credential persistence, connector hijacking
Implementation
| Cloud | Credential Type | Rotation |
|---|---|---|
| AWS | IAM Role | External ID rotation annually |
| Azure | App Registration | Secret rotation quarterly |
| GCP | Service Account Key | Key rotation quarterly |
Code Implementation
Code Pack: Terraform
# Credential rotation monitoring control
# Detects cloud connectors with credentials that have not been rotated
# within the organization's rotation policy window.
#
# Rotation schedule:
# AWS: External ID rotation annually
# Azure: App registration secret rotation quarterly
# GCP: Service account key rotation quarterly
resource "wiz_control" "connector_credential_rotation" {
count = var.profile_level >= 2 ? 1 : 0
name = "HTH: Connector Credential Rotation Monitoring"
description = "Detects cloud connectors with stale credentials that require rotation per HTH hardening guide section 2.2"
severity = "HIGH"
enabled = true
project_id = "*"
resolution_recommendation = "Rotate connector credentials according to schedule: AWS External ID annually, Azure app secret quarterly, GCP service account key quarterly. See https://howtoharden.com/guides/wiz/#22-connector-credential-rotation"
query = jsonencode({
type = [
"CLOUD_ACCOUNT"
]
select = true
where = {
status = {
EQUALS = [
"CONNECTED"
]
}
}
})
scope_query = jsonencode({
type = [
"SUBSCRIPTION"
]
select = true
})
}
3. API Security
3.1 Service Account Management
Profile Level: L1 (Crawl) NIST 800-53: IA-5
Description
Secure Wiz API service accounts.
Rationale
Why This Matters:
- Wiz API service accounts read sensitive vulnerability and posture data programmatically, so a shared or over-scoped account exposes that data to every integration holding it
- Purpose-specific accounts with minimum scopes ensure a compromised SIEM or ticketing integration cannot pivot beyond its intended permissions
- Quarterly credential rotation limits the lifetime of any leaked API token
- Separate accounts per integration make abuse attributable and revocation surgical
Attack Prevented: API token theft, over-privileged integration abuse, data exfiltration, credential sprawl
ClickOps Implementation
Step 1: Create Purpose-Specific Service Accounts
- Navigate to: Settings → Service Accounts
- Create accounts for:
- SIEM integration (read-only)
- Ticketing integration (limited write)
- Automation (specific scopes)
Step 2: Configure Minimum Scopes
| Integration | Required Scopes |
|---|---|
| SIEM | read:issues, read:vulnerabilities |
| Ticketing | read:issues, write:comments |
| Automation | Specific to use case |
Step 3: Rotate Credentials
- Set rotation schedule: Quarterly
- Update integrations with new credentials
- Revoke old credentials
Code Implementation
Code Pack: Terraform
# Create purpose-specific service accounts with minimum scopes
# Each integration gets its own account with only required permissions:
# SIEM: read:issues, read:vulnerabilities
# Ticketing: read:issues
# Automation: Specific to use case
resource "wiz_service_account" "integration" {
for_each = { for sa in var.service_accounts : sa.name => sa }
name = each.value.name
type = "THIRD_PARTY"
scopes = each.value.scopes
# Detect external credential rotation and force resource recreation
recreate_if_rotated = true
}
3.2 API Access Monitoring
Profile Level: L2 (Walk) NIST 800-53: AU-6
Description
Monitor API usage for anomalies.
Rationale
Why This Matters:
- API abuse — bulk pulls of findings, unusual query volume, or off-hours access — is often the first signal of a compromised service-account token
- Monitoring establishes a behavioral baseline so anomalous extraction of vulnerability data is detected before it becomes a breach
- Alerting on usage spikes enables rapid token revocation, shrinking the exfiltration window
- Visibility into API activity supports incident response and provides compliance evidence
Attack Prevented: Stealthy data exfiltration, compromised-token abuse, undetected reconnaissance, bulk scraping
Implementation
Code Pack: Terraform
# Scheduled report for API access audit
# Runs at the configured interval to detect anomalous API usage patterns
# such as unusual query volumes, new source IPs, or off-hours access.
resource "wiz_report_graph_query" "api_access_audit" {
count = var.profile_level >= 2 ? 1 : 0
name = var.api_audit_report_name
project_id = "*"
run_interval_hours = var.api_audit_interval_hours
query = jsonencode({
type = [
"USER_ACCOUNT"
]
select = true
where = {
type = {
EQUALS = [
"SERVICE"
]
}
}
})
}
# Control to detect service accounts with overly broad scopes
resource "wiz_control" "overprivileged_service_accounts" {
count = var.profile_level >= 2 ? 1 : 0
name = "HTH: Overprivileged Service Accounts"
description = "Detects Wiz service accounts with administrative or overly broad API scopes per HTH hardening guide section 3.2"
severity = "MEDIUM"
enabled = true
project_id = "*"
resolution_recommendation = "Review and reduce service account scopes to the minimum required for each integration. See https://howtoharden.com/guides/wiz/#32-api-access-monitoring"
query = jsonencode({
type = [
"USER_ACCOUNT"
]
select = true
where = {
type = {
EQUALS = [
"SERVICE"
]
}
isAdmin = {
EQUALS = true
}
}
})
scope_query = jsonencode({
type = [
"SUBSCRIPTION"
]
select = true
})
}
Code Pack: API Script
# Example Wiz GraphQL query for audit
query {
auditLogs(
first: 100
orderBy: {field: TIMESTAMP, direction: DESC}
filterBy: {actionType: [API_REQUEST]}
) {
nodes {
timestamp
actionType
user {
email
}
sourceIP
requestDetails
}
}
}
4. Data Security
4.1 Configure Data Export Controls
Profile Level: L2 (Walk) NIST 800-53: AC-3
Description
Control export of security findings and vulnerability data.
Rationale
Why This Matters:
- Wiz findings and vulnerability reports are effectively a map of exploitable weaknesses across your cloud, so uncontrolled export hands attackers a ready-made target list
- Restricting bulk export to Admins and logging every export limits who can remove this data and creates accountability
- Expiring, password-protected, internal-only share links prevent sensitive reports from leaking through forwarded or public URLs
- Alerting on large exports surfaces insider data theft or a compromised account exfiltrating posture data
Attack Prevented: Bulk data exfiltration, insider theft, leaked report links, attack-surface disclosure
ClickOps Implementation
Step 1: Restrict Export Permissions
- Limit bulk export to Admin role only
- Log all export activities
- Alert on large exports
Step 2: Configure Report Sharing
- Navigate to: Settings → Reports
- Configure:
- Internal sharing only
- Expiration on shared links
- Password protection
Code Implementation
Code Pack: Terraform
# Project-based data export boundary
# Restricts bulk export of security findings and vulnerability data
# by isolating sensitive findings into a controlled project with
# limited membership and Admin-only export permissions.
resource "wiz_project" "data_export_restricted" {
count = var.profile_level >= 2 ? 1 : 0
name = var.data_export_project_name
description = "HTH hardened project with restricted data export permissions. Bulk export limited to Admin role only."
risk_profile {
business_impact = "HBI"
has_exposed_api = "NO"
stores_data = "YES"
is_regulated = "YES"
sensitive_data_types = ["PII", "FINANCIAL"]
regulatory_standards = ["SOC", "NIST"]
}
}
# Control to detect unauthorized large data exports
resource "wiz_control" "data_export_monitoring" {
count = var.profile_level >= 2 ? 1 : 0
name = "HTH: Unauthorized Data Export Detection"
description = "Detects large or unauthorized exports of security findings and vulnerability data per HTH hardening guide section 4.1"
severity = "HIGH"
enabled = true
project_id = "*"
resolution_recommendation = "Review export activity. Limit bulk export to Admin role only. Configure report sharing with expiration and restrict to internal-only distribution. See https://howtoharden.com/guides/wiz/#41-configure-data-export-controls"
query = jsonencode({
type = [
"USER_ACCOUNT"
]
select = true
where = {
isAdmin = {
EQUALS = false
}
}
})
scope_query = jsonencode({
type = [
"SUBSCRIPTION"
]
select = true
})
}
5. Monitoring & Detection
5.1 Audit Logging
Profile Level: L1 (Crawl) NIST 800-53: AU-2, AU-3
Description
Enable Wiz audit logging and forward authentication, configuration-change, and API-access events to your SIEM for correlation and alerting.
Rationale
Why This Matters:
- Audit logs are the primary record of who accessed Wiz, what they changed, and which API calls ran, so without them a compromise is invisible and unforensicable
- Forwarding events to a SIEM enables correlation with cloud and identity telemetry, catching attack patterns that span systems
- Capturing authentication and configuration changes detects unauthorized role grants, connector edits, and disabled controls in near real time
- Centralized, exported logs survive tampering or deletion within the Wiz console itself
Attack Prevented: Undetected account compromise, audit-trail tampering, stealthy configuration changes, delayed breach detection
ClickOps Implementation
Step 1: Access Audit Logs
- Navigate to: Settings → Audit Log
- Review:
- Authentication events
- Configuration changes
- API access
Step 2: Export to SIEM
- Configure webhook or API integration
- Forward all audit events
- Create correlation rules
Detection Queries
Code Pack: Terraform
# Scheduled audit log report for SIEM export
# Captures authentication events, configuration changes, and API access
# at regular intervals for correlation and alerting.
resource "wiz_report_graph_query" "audit_log" {
name = var.audit_report_name
project_id = "*"
run_interval_hours = var.audit_report_interval_hours
query = jsonencode({
type = [
"USER_ACCOUNT"
]
select = true
where = {
status = {
EQUALS = [
"ACTIVE"
]
}
}
})
}
# Dedicated service account for SIEM integration (read-only audit access)
resource "wiz_service_account" "siem_export" {
name = "hth-siem-audit-export"
type = "THIRD_PARTY"
scopes = ["read:issues", "read:vulnerabilities"]
recreate_if_rotated = true
}
# Control to detect unusual data access patterns
resource "wiz_control" "unusual_data_access" {
name = "HTH: Unusual Data Access Pattern Detection"
description = "Detects unusual query volumes or access patterns that may indicate compromised credentials or insider threats per HTH hardening guide section 5.1"
severity = "MEDIUM"
enabled = true
project_id = "*"
resolution_recommendation = "Investigate the user or service account activity. Review source IPs, query volume, and timing. Correlate with SIEM alerts. See https://howtoharden.com/guides/wiz/#51-audit-logging"
query = jsonencode({
type = [
"USER_ACCOUNT"
]
select = true
where = {
status = {
EQUALS = [
"ACTIVE"
]
}
}
})
scope_query = jsonencode({
type = [
"SUBSCRIPTION"
]
select = true
})
}
6. Compliance Quick Reference
SOC 2 Mapping
| Control ID | Wiz Control | Guide Section |
|---|---|---|
| CC6.1 | SSO enforcement | 1.1 |
| CC6.2 | RBAC | 1.2 |
| CC6.7 | Data export controls | 4.1 |
Appendix A: References
Official Wiz Documentation:
- Documentation Portal — serves an automated-access challenge (HTTP 429 “Vercel Security Checkpoint”) to fetchers and headless clients; open it in a real browser
- Resource Center
- Wiz Research
- Cloud Threat Landscape — Incidents
- CVE Vulnerability Database
API Documentation:
- API endpoint:
https://api.<REGION>.app.wiz.io/graphql(GraphQL) - Wiz GitHub Organization
Compliance Frameworks:
- SOC 2 Type II, SOC 3, ISO 27001, ISO 27017, ISO 27018, ISO 27701, HIPAA, PCI, FedRAMP Moderate — Wiz’s attestations are published through its Trust Center, which is not linked here: Trust Centers are compliance-marketing surfaces rather than hardening documentation, and
trust.wiz.ioreturned HTTP 403 on verification - Wiz for Government (FedRAMP)
Security Incidents:
- No major public incidents involving Wiz as a victim identified
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2026-08-08 | 0.1.2 | draft | Repo-internal corrections only. Wiz’s Tier 1 documentation portal could not be reached this pass — docs.wiz.io serves an automated-access challenge (HTTP 429 Vercel Security Checkpoint) to fetchers and headless browsers — so no currency deltas were verifiable and none were applied; the control set is unchanged pending a browser-capable pass. Fixed 1.1’s **Attack Scenario:** key to **Attack Prevented:** (the cheat-sheet parser matches only the latter, so the cell was rendering without it) and added Attack Prevented to 2.1. Removed the duplicate empty “Appendix A: References” heading and renumbered Appendix B to A. Appendix A: removed the dead trust.wiz.io link (HTTP 403) and the wiz.io/trust-center Trust Center link (compliance marketing, not hardening documentation), and corrected the docs.wiz.io annotation from “(login required)” to the actual bot-challenge behavior. Tier 3/4 research out of scope for this pass. |
Claude Code (Opus 4.8) |
| 2026-06-29 | 0.1.1 | draft | Add cheat-sheet Description and Rationale for all controls | Claude Code (Opus 4.8) |
| 2025-12-14 | 0.1.0 | draft | Initial Wiz hardening guide | Claude Code (Opus 4.5) |
Contributing
Found an issue or want to improve this guide?
- Report outdated information: Open an issue with tag
content-outdated - Propose new controls: Open an issue with tag
new-control - Submit improvements: See Contributing Guide