identity access management

Implementing Zero Standing Privilege with CyberArk

Deploy CyberArk Secure Cloud Access to eliminate standing privileges in hybrid and multi-cloud environments using just-in-time access with time, entitlement, and approval controls.

cloud-securitycyberarkjit-accessleast-privilegepamzero-standing-privilege
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Zero Standing Privileges (ZSP) is a security model where no user or identity retains persistent privileged access. Instead, elevated access is provisioned dynamically on a just-in-time (JIT) basis and automatically revoked after use. CyberArk implements ZSP through its Secure Cloud Access (SCA) module, which creates ephemeral, scoped roles in cloud environments (AWS, Azure, GCP) that exist only for the duration of a session. The TEA framework -- Time, Entitlements, and Approvals -- governs every privileged access session.

When to Use

  • When deploying or configuring implementing zero standing privilege with cyberark capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • CyberArk Identity Security Platform (Privilege Cloud or self-hosted)
  • CyberArk Secure Cloud Access (SCA) license
  • Cloud provider accounts (AWS, Azure, GCP) with admin access for integration
  • ITSM integration (ServiceNow, Jira) for approval workflows
  • CyberArk Vault configured with safe management

Core Concepts

TEA Framework (Time, Entitlements, Approvals)

Component Description Configuration
Time Duration of the privileged session Min 15 minutes, max 8 hours, default 1 hour
Entitlements Permissions granted during the session Dynamically scoped IAM roles/policies
Approvals Authorization workflow before access Auto-approve, manager approval, or multi-level

ZSP Architecture

User requests access via CyberArk

        ├── CyberArk evaluates request against policies:
        │   ├── Is user eligible for this access?
        │   ├── Does the request comply with TEA policies?
        │   └── Is approval required?

        ├── [If approval needed] → Route to approver (ITSM/ChatOps)

        ├── Upon approval:
        │   ├── CyberArk creates ephemeral IAM role in target cloud
        │   ├── Scopes permissions to minimum required entitlements
        │   ├── Sets session TTL (time-bound)
        │   └── Provisions temporary credentials

        ├── User accesses cloud resources via session
        │   ├── All actions logged and recorded
        │   └── Session monitored for policy violations

        └── Session expires:
            ├── Ephemeral role deleted
            ├── Temporary credentials revoked
            └── Zero standing privileges remain

CyberArk Components

Component Role
Identity Security Platform Central management and policy engine
Privilege Cloud Vault Stores privileged credentials and keys
Secure Cloud Access Creates/destroys ephemeral cloud roles
Endpoint Privilege Manager Controls local admin and app elevation
Privileged Session Manager Records and monitors privileged sessions

Workflow

Step 1: Integrate Cloud Providers

AWS Integration:

  1. Create a CyberArk integration role in AWS IAM
  2. Configure cross-account trust policy allowing CyberArk to assume roles
  3. Create IAM policies that define maximum allowed entitlements
  4. Register AWS accounts in CyberArk SCA
{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::CYBERARK_ACCOUNT:role/CyberArkSCARole"
        },
        "Action": "sts:AssumeRole",
        "Condition": {
            "StringEquals": {
                "sts:ExternalId": "cyberark-external-id"
            }
        }
    }]
}

Azure Integration:

  1. Register CyberArk as an enterprise application in Microsoft Entra ID
  2. Grant CyberArk application permissions: Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory
  3. Create custom Azure roles with scoped permissions
  4. Register Azure subscriptions in CyberArk SCA

GCP Integration:

  1. Create a service account for CyberArk in GCP
  2. Grant IAM Admin and Service Account Admin roles
  3. Configure workload identity federation for cross-cloud access
  4. Register GCP projects in CyberArk SCA

Step 2: Define Access Policies

Create policies that map job functions to cloud entitlements:

# CyberArk SCA Policy Example
policy_name: "developer-aws-read-access"
description: "Read-only access to AWS production for developers"
target_cloud: "aws"
target_accounts: ["123456789012", "987654321098"]
 
time_policy:
  max_duration: "4h"
  default_duration: "1h"
  business_hours_only: true
  timezone: "America/New_York"
 
entitlement_policy:
  aws_managed_policies:
    - "arn:aws:iam::aws:policy/ReadOnlyAccess"
  deny_actions:
    - "iam:*"
    - "organizations:*"
    - "sts:*"
  resource_restrictions:
    - "arn:aws:s3:::production-*"
 
approval_policy:
  approval_required: true
  approvers:
    - type: "manager"
    - type: "group"
      group: "cloud-security-team"
  auto_approve_conditions:
    - previous_approved_same_policy: true
      within_days: 7
  escalation_timeout: "2h"
  escalation_approver: "cloud-security-lead"

Step 3: Configure Session Monitoring

Set up privileged session recording and real-time monitoring:

  1. Enable session recording for all ZSP sessions
  2. Configure keystroke logging for SSH/RDP sessions
  3. Set up real-time alerts for suspicious activities:
    • Attempts to escalate privileges during session
    • Access to resources outside policy scope
    • Session duration exceeding 2x the normal pattern
  4. Forward session metadata to SIEM

Step 4: Implement Approval Workflows

Integrate with ITSM tools for access request and approval:

  • ServiceNow: CyberArk SCA connector creates ServiceNow tickets for approval
  • Slack/Teams: ChatOps bot for quick approvals within messaging platforms
  • Jira: Integration for development-related access requests
  • Auto-Approval: Configure rules for low-risk, previously approved requests

Step 5: Migrate from Standing Privileges

Phase 1: DISCOVERY (Weeks 1-2)
    ├── Inventory all standing privileged roles across cloud accounts
    ├── Map users to their standing role assignments
    ├── Analyze CloudTrail/activity logs for actual permission usage
    └── Identify roles that can be converted to JIT
 
Phase 2: POLICY CREATION (Weeks 3-4)
    ├── Create ZSP policies based on actual usage analysis
    ├── Define TEA parameters for each policy
    ├── Configure approval workflows
    └── Test policies with pilot users
 
Phase 3: MIGRATION (Weeks 5-8)
    ├── Assign ZSP policies to pilot group
    ├── Remove standing privileges from pilot users
    ├── Monitor for access issues and adjust policies
    ├── Expand to additional teams incrementally
    └── Remove all standing privileges organization-wide
 
Phase 4: GOVERNANCE (Ongoing)
    ├── Monthly review of ZSP policy effectiveness
    ├── Quarterly entitlement optimization
    ├── Monitor for policy drift or standing privilege re-creation
    └── Report ZSP metrics to security leadership

Validation Checklist

  • Cloud providers integrated with CyberArk SCA
  • TEA policies defined for all privileged access scenarios
  • Approval workflows configured and tested
  • Session recording and monitoring enabled
  • All standing privileged roles identified for migration
  • Pilot group successfully using ZSP without standing privileges
  • Break-glass procedure defined for emergency access
  • SIEM integration receiving session and access logs
  • Auto-approval rules configured for low-risk, repeat access
  • Organization-wide migration plan approved and scheduled
  • KPI tracking: reduction in standing privilege assignments

References

Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.7 KB

API Reference: CyberArk Zero Standing Privilege

CyberArk PVWA REST API v2

Authentication

POST /api/auth/CyberArk/Logon
Body: {"username": "admin", "password": "pass"}
Returns: Session token string

Key Endpoints

Method Endpoint Description
GET /api/Safes List all safes
GET /api/Safes/{name}/Members List safe members and permissions
GET /api/Platforms List configured platforms
GET /api/Accounts List privileged accounts
GET /api/LiveSessions List active privileged sessions
POST /api/Accounts/{id}/CheckIn Release exclusive account access

Safe Member Permissions

Permission ZSP Implication
useAccounts Can initiate privileged sessions
retrieveAccounts Can retrieve passwords
listAccounts Can see account inventory
requestsAuthorizationLevel1 Dual-control approval required

Session Properties

Field Description
User Session initiator
AccountName Target privileged account
Duration Session length in seconds
RemoteMachine Target host

TEA Framework

Component API Field Purpose
Time MaxSessionDuration Auto-revoke after timeout
Entitlements AllowedPermissions Scoped access per session
Approvals requestsAuthorizationLevel Require approval workflow

References

standards.md1.6 KB

Zero Standing Privilege with CyberArk - Standards Reference

Zero Trust Frameworks

NIST SP 800-207 - Zero Trust Architecture

  • Never trust, always verify
  • Least privilege access to resources
  • Microsegmentation and policy enforcement points
  • Dynamic, risk-based access policies

CISA Zero Trust Maturity Model

  • Identity pillar: JIT/JEA access for all identities
  • Advanced maturity: Automated privilege provisioning/deprovisioning
  • Optimal maturity: Continuous verification with ephemeral access

TEA Framework Components

Time

  • Session duration: minimum required for task completion
  • CyberArk default: 1 hour, configurable 15 min to 8 hours
  • Business hours enforcement optional
  • Auto-termination on session inactivity

Entitlements

  • Principle of least privilege
  • Dynamic role creation scoped to specific resources
  • Permission boundaries to prevent escalation
  • Entitlement analytics for right-sizing

Approvals

  • Risk-based approval routing
  • Multi-level approval for critical access
  • Auto-approval for previously approved, low-risk requests
  • ITSM integration (ServiceNow, Jira) for audit trail

Compliance Requirements

SOC 2 - CC6

  • CC6.1: Logical access security restricted
  • CC6.3: Access authorized, modified, removed timely
  • ZSP provides evidence of no standing privileges

PCI DSS v4.0

  • 7.2.1: Access limited to least privilege
  • 7.2.4: Access reviewed at least every 6 months
  • ZSP eliminates the review burden by removing standing access

SOX Section 404

  • Separation of duties enforcement
  • Access to financial systems must be controlled
  • JIT access provides clear audit trail of who accessed what, when
workflows.md3.6 KB

Zero Standing Privilege with CyberArk - Workflows

JIT Access Request Workflow

Developer needs to access AWS production environment

    ├── Opens CyberArk Secure Cloud Access portal

    ├── Selects target: AWS Account "Production" (123456789012)

    ├── Selects policy: "Developer Production Read Access"

    ├── Specifies duration: 2 hours

    ├── Provides justification: "Investigating PROD-1234 latency issue"

    ├── Submits request

    ├── CyberArk evaluates TEA policy:
    │   ├── Time: 2 hours within allowed range
    │   ├── Entitlements: Read-only production access
    │   └── Approval: Manager approval required

    ├── Approval request sent to manager (Slack/email)

    ├── Manager approves

    ├── CyberArk provisions ephemeral IAM role:
    │   ├── Creates role with ReadOnlyAccess + resource restrictions
    │   ├── Sets session duration to 2 hours
    │   └── Generates temporary STS credentials

    ├── Developer accesses AWS console/CLI with temp credentials
    │   └── All actions recorded in session log

    └── After 2 hours: role deleted, credentials revoked

Standing Privilege Migration Workflow

Phase 1: DISCOVERY AND ANALYSIS
    ├── Export all IAM users/roles with standing admin access
    ├── Analyze CloudTrail logs for actual permission usage
    ├── Identify which permissions are actually used vs. assigned
    ├── Calculate right-sized policy for each use case
    └── Map standing privileges to CyberArk ZSP policies
 
Phase 2: POLICY CREATION
    ├── Create CyberArk SCA policies for each access pattern
    ├── Define TEA parameters:
    │   ├── Maximum session duration per policy
    │   ├── Entitlement scope (AWS managed policies + custom)
    │   └── Approval requirements (auto vs. manual)
    ├── Configure approval workflows
    └── Test policies with pilot group
 
Phase 3: PILOT MIGRATION (2-4 weeks)
    ├── Assign ZSP policies to pilot users
    ├── Remove standing privileges from pilot users
    ├── Monitor for access denied errors
    ├── Adjust policies based on feedback
    └── Measure: request volume, approval time, session duration
 
Phase 4: FULL MIGRATION (4-8 weeks)
    ├── Migrate teams in waves (1 team per week)
    ├── Remove standing privileges after ZSP confirmed working
    ├── Configure auto-detect for new standing privilege creation
    └── Report metrics to security leadership
 
Phase 5: CONTINUOUS GOVERNANCE
    ├── Weekly: Review and right-size ZSP policies
    ├── Monthly: Audit for any standing privilege re-creation
    ├── Quarterly: Entitlement optimization report
    └── Alert on: New standing admin roles created outside CyberArk

Emergency Break-Glass Workflow

CyberArk SCA unavailable or network issue

    ├── Retrieve break-glass credentials from:
    │   ├── Physical safe (sealed envelope)
    │   ├── Or secondary vault (Azure Key Vault / AWS Secrets Manager)

    ├── Authenticate with break-glass credentials

    ├── Perform emergency actions

    ├── Document all actions taken

    └── Post-incident:
        ├── Rotate break-glass credentials
        ├── Review session logs for the emergency access
        ├── File incident report
        └── Verify no unauthorized changes made

Scripts 2

agent.py7.1 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for auditing CyberArk Zero Standing Privilege (ZSP) configuration via REST API."""

import os
import requests
import json
import argparse
from datetime import datetime, timezone
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


def authenticate(base_url, username, password, auth_method="CyberArk"):
    """Authenticate to CyberArk PVWA and obtain session token."""
    url = f"{base_url}/api/auth/{auth_method}/Logon"
    payload = {"username": username, "password": password}
    resp = requests.post(url, json=payload, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    token = resp.json().strip('"')
    print(f"[*] Authenticated to CyberArk PVWA as {username}")
    return {"Authorization": token}


def list_safes(base_url, headers):
    """List all safes to audit access policies."""
    url = f"{base_url}/api/Safes"
    resp = requests.get(url, headers=headers, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    safes = resp.json().get("value", [])
    print(f"[*] Found {len(safes)} safes")
    for s in safes[:20]:
        print(f"  {s['safeName']} (retention: {s.get('numberOfDaysRetention', 'N/A')} days)")
    return safes


def audit_safe_members(base_url, headers, safe_name):
    """Audit members and permissions of a specific safe."""
    url = f"{base_url}/api/Safes/{safe_name}/Members"
    resp = requests.get(url, headers=headers, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    members = resp.json().get("value", [])
    findings = []
    for m in members:
        perms = m.get("permissions", {})
        if perms.get("useAccounts") and perms.get("retrieveAccounts"):
            if not m.get("memberType") == "Role":
                findings.append({
                    "safe": safe_name, "member": m.get("memberName"),
                    "issue": "Standing retrieve+use privileges (not JIT)",
                    "severity": "HIGH",
                })
                print(f"  [!] {m.get('memberName')} has standing access to {safe_name}")
    return findings


def list_platforms(base_url, headers):
    """List platforms to verify JIT/ZSP configuration."""
    url = f"{base_url}/api/Platforms"
    resp = requests.get(url, headers=headers, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    platforms = resp.json().get("Platforms", [])
    print(f"[*] Found {len(platforms)} platforms")
    for p in platforms:
        print(f"  {p.get('general', {}).get('name', 'Unknown')} - "
              f"Active: {p.get('general', {}).get('active', False)}")
    return platforms


def check_jit_sessions(base_url, headers, days=7):
    """Check recent privileged sessions for JIT compliance."""
    url = f"{base_url}/api/LiveSessions"
    resp = requests.get(url, headers=headers, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    sessions = resp.json().get("LiveSessions", [])
    print(f"[*] Active privileged sessions: {len(sessions)}")
    long_sessions = []
    for s in sessions:
        duration = s.get("Duration", 0)
        if duration > 3600:
            long_sessions.append({
                "user": s.get("User"), "target": s.get("AccountName"),
                "duration_sec": duration, "severity": "MEDIUM",
            })
            print(f"  [!] Long session: {s.get('User')} -> {s.get('AccountName')} "
                  f"({duration // 60} min)")
    return long_sessions


def audit_accounts_standing_access(base_url, headers):
    """Find privileged accounts with standing (non-JIT) access enabled."""
    url = f"{base_url}/api/Accounts"
    params = {"limit": 100, "offset": 0}
    resp = requests.get(url, headers=headers, params=params, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    accounts = resp.json().get("value", [])
    findings = []
    for a in accounts:
        props = a.get("platformAccountProperties", {})
        if not props.get("JITEnabled", False):
            findings.append({
                "account": a.get("name"), "safe": a.get("safeName"),
                "platform": a.get("platformId"), "issue": "JIT not enabled",
                "severity": "HIGH",
            })
    print(f"[*] Accounts without JIT: {len(findings)}/{len(accounts)}")
    return findings


def generate_report(safe_findings, session_findings, account_findings, output_path):
    """Generate ZSP compliance audit report."""
    report = {
        "audit_date": datetime.now(timezone.utc).isoformat(),
        "summary": {
            "standing_access_findings": len(safe_findings),
            "long_session_findings": len(session_findings),
            "non_jit_accounts": len(account_findings),
        },
        "safe_findings": safe_findings,
        "session_findings": session_findings,
        "account_findings": account_findings,
    }
    with open(output_path, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"\n[*] Report saved to {output_path}")


def main():
    parser = argparse.ArgumentParser(description="CyberArk Zero Standing Privilege Audit Agent")
    parser.add_argument("action", choices=["safes", "audit-safe", "platforms",
                                           "sessions", "accounts", "full-audit"])
    parser.add_argument("--url", required=True, help="CyberArk PVWA base URL")
    parser.add_argument("--username", required=True)
    parser.add_argument("--password", required=True)
    parser.add_argument("--safe", help="Specific safe name to audit")
    parser.add_argument("-o", "--output", default="zsp_audit.json")
    args = parser.parse_args()

    headers = authenticate(args.url, args.username, args.password)
    if args.action == "safes":
        list_safes(args.url, headers)
    elif args.action == "audit-safe" and args.safe:
        audit_safe_members(args.url, headers, args.safe)
    elif args.action == "platforms":
        list_platforms(args.url, headers)
    elif args.action == "sessions":
        check_jit_sessions(args.url, headers)
    elif args.action == "accounts":
        audit_accounts_standing_access(args.url, headers)
    elif args.action == "full-audit":
        safes = list_safes(args.url, headers)
        sf = []
        for s in safes:
            sf.extend(audit_safe_members(args.url, headers, s["safeName"]))
        sess = check_jit_sessions(args.url, headers)
        acct = audit_accounts_standing_access(args.url, headers)
        generate_report(sf, sess, acct, args.output)


if __name__ == "__main__":
    main()
process.py6.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Zero Standing Privilege Audit Tool

Discovers standing privileged access across AWS, Azure, and GCP,
compares against CyberArk ZSP policies, and identifies accounts
that should be migrated to just-in-time access.

Requirements:
    pip install boto3 requests
"""

import json
import logging
import sys
from datetime import datetime, timedelta, timezone

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("zsp_audit")


class StandingPrivilegeDiscovery:
    """Discover standing privileged access across cloud environments."""

    def __init__(self):
        self.findings = []

    def discover_aws_standing_privileges(self, profile_name=None):
        """Find AWS IAM users/roles with standing admin access."""
        try:
            import boto3
        except ImportError:
            logger.error("boto3 required: pip install boto3")
            return []

        session = boto3.Session(profile_name=profile_name)
        iam = session.client("iam")

        admin_policy_arns = {
            "arn:aws:iam::aws:policy/AdministratorAccess",
            "arn:aws:iam::aws:policy/PowerUserAccess",
            "arn:aws:iam::aws:policy/IAMFullAccess",
        }

        standing = []

        # Check IAM users
        paginator = iam.get_paginator("list_users")
        for page in paginator.paginate():
            for user in page["Users"]:
                username = user["UserName"]
                attached = iam.list_attached_user_policies(UserName=username)
                user_policies = {p["PolicyArn"] for p in attached["AttachedPolicies"]}

                has_admin = bool(user_policies & admin_policy_arns)

                # Check groups
                groups = iam.list_groups_for_user(UserName=username)
                for group in groups["Groups"]:
                    grp_policies = iam.list_attached_group_policies(
                        GroupName=group["GroupName"]
                    )
                    for gp in grp_policies["AttachedPolicies"]:
                        if gp["PolicyArn"] in admin_policy_arns:
                            has_admin = True

                if has_admin:
                    access_keys = iam.list_access_keys(UserName=username)
                    active_keys = [
                        k for k in access_keys["AccessKeyMetadata"]
                        if k["Status"] == "Active"
                    ]

                    standing.append({
                        "cloud": "AWS",
                        "identity_type": "User",
                        "identity": username,
                        "privilege_level": "Admin",
                        "policies": list(user_policies & admin_policy_arns),
                        "active_access_keys": len(active_keys),
                        "created": user["CreateDate"].isoformat(),
                        "last_used": str(user.get("PasswordLastUsed", "Never")),
                        "recommendation": "Migrate to CyberArk ZSP",
                    })

        # Check IAM roles (non-service-linked)
        role_paginator = iam.get_paginator("list_roles")
        for page in role_paginator.paginate():
            for role in page["Roles"]:
                if role["Path"].startswith("/aws-service-role/"):
                    continue

                role_policies = iam.list_attached_role_policies(
                    RoleName=role["RoleName"]
                )
                role_admin_policies = {
                    p["PolicyArn"] for p in role_policies["AttachedPolicies"]
                } & admin_policy_arns

                if role_admin_policies:
                    standing.append({
                        "cloud": "AWS",
                        "identity_type": "Role",
                        "identity": role["RoleName"],
                        "privilege_level": "Admin",
                        "policies": list(role_admin_policies),
                        "created": role["CreateDate"].isoformat(),
                        "recommendation": "Convert to ephemeral CyberArk SCA role",
                    })

        self.findings.extend(standing)
        logger.info(f"Discovered {len(standing)} AWS standing privileged identities")
        return standing

    def generate_migration_plan(self):
        """Generate a migration plan to move from standing to ZSP."""
        if not self.findings:
            return {"status": "No standing privileges found"}

        plan = {
            "generated_at": datetime.now(timezone.utc).isoformat(),
            "total_standing_privileges": len(self.findings),
            "by_cloud": {},
            "by_type": {},
            "migration_waves": [],
        }

        # Categorize
        for finding in self.findings:
            cloud = finding["cloud"]
            plan["by_cloud"][cloud] = plan["by_cloud"].get(cloud, 0) + 1
            id_type = finding["identity_type"]
            plan["by_type"][id_type] = plan["by_type"].get(id_type, 0) + 1

        # Create migration waves
        users = [f for f in self.findings if f["identity_type"] == "User"]
        roles = [f for f in self.findings if f["identity_type"] == "Role"]

        wave_size = 5
        wave_num = 1

        for i in range(0, len(users), wave_size):
            batch = users[i:i + wave_size]
            plan["migration_waves"].append({
                "wave": wave_num,
                "type": "Users",
                "identities": [u["identity"] for u in batch],
                "count": len(batch),
                "suggested_week": f"Week {wave_num}",
            })
            wave_num += 1

        for i in range(0, len(roles), wave_size):
            batch = roles[i:i + wave_size]
            plan["migration_waves"].append({
                "wave": wave_num,
                "type": "Roles",
                "identities": [r["identity"] for r in batch],
                "count": len(batch),
                "suggested_week": f"Week {wave_num}",
            })
            wave_num += 1

        return plan

    def export_report(self, output_path):
        """Export standing privilege findings and migration plan."""
        report = {
            "report_title": "Standing Privilege Discovery Report",
            "generated_at": datetime.now(timezone.utc).isoformat(),
            "findings": self.findings,
            "migration_plan": self.generate_migration_plan(),
        }

        with open(output_path, "w") as f:
            json.dump(report, f, indent=2)

        logger.info(f"Report exported to {output_path}")
        return report


if __name__ == "__main__":
    print("=" * 60)
    print("Zero Standing Privilege Audit Tool")
    print("=" * 60)
    print()
    print("Usage:")
    print("  discovery = StandingPrivilegeDiscovery()")
    print("  discovery.discover_aws_standing_privileges(profile='prod')")
    print("  plan = discovery.generate_migration_plan()")
    print("  discovery.export_report('zsp_report.json')")

Assets 1

template.mdtext/markdown · 1.2 KB
Keep exploring