identity access management

Implementing Just-In-Time Access Provisioning

Implement Just-In-Time (JIT) access provisioning to eliminate standing privileges by granting temporary, time-bound access only when needed. This skill covers JIT architecture design, approval workflows, automatic expiration, integration with PAM and IGA platforms, and alignment with zero trust principles.

access-controliamidentityjitleast-privilegeprovisioningzero-trust
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Implement Just-In-Time (JIT) access provisioning to eliminate standing privileges by granting temporary, time-bound access only when needed. This skill covers JIT architecture design, approval workflows, automatic expiration, integration with PAM and IGA platforms, and alignment with zero trust principles.

When to Use

  • When deploying or configuring implementing just in time access provisioning 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

  • Familiarity with identity access management concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Objectives

  • Design JIT access request and approval workflows
  • Implement time-bound access grants with automatic expiration
  • Configure risk-based approval routing (auto-approve low-risk, multi-approval for high-risk)
  • Integrate JIT with PAM for privileged access elevation
  • Monitor and audit all JIT access grants and usage
  • Reduce attack surface by eliminating standing privileges

Key Concepts

JIT Access Models

  1. Broker and Remove: Grant access through approval, auto-remove after time window
  2. Elevation on Demand: User has base access, elevates to privileged upon request
  3. Account Creation/Deletion: Temporary account created, destroyed after use
  4. Group Membership Toggle: Add to privileged group temporarily, auto-remove

Zero Standing Privilege (ZSP) Principle

  • No user has permanent privileged access
  • All privileged access requires explicit request with business justification
  • Access automatically expires after defined time window
  • All access events logged and auditable

Workflow

Step 1: Identify Eligible Access Types

  • Privileged admin access (domain admin, root, DBA)
  • Production environment access
  • Sensitive data access (PII, financial, healthcare)
  • Emergency/break-glass access
  • Third-party vendor access

Step 2: Design Approval Workflows

  • Self-service request portal with justification requirement
  • Auto-approve for pre-authorized low-risk access (< 1 hour)
  • Single approver for medium-risk (manager or resource owner)
  • Dual approval for high-risk (manager + security team)
  • Emergency bypass with post-facto review

Step 3: Implement Time-Bound Access

  • Configure maximum access duration per resource type
  • Implement countdown timer with extension request capability
  • Auto-revoke at expiration regardless of session state
  • Grace period notification (15 min before expiry)
  • Automatic session termination on access expiry

Step 4: Integration Architecture

  • Connect to IAM/IGA platform for provisioning/de-provisioning
  • Integrate with PAM for privileged credential checkout
  • Connect to ITSM for ticket correlation
  • Forward events to SIEM for monitoring
  • API integration for programmatic access requests

Step 5: Monitoring and Compliance

  • Log all JIT requests, approvals, grants, and revocations
  • Alert on access used beyond approved scope
  • Track access not used (request but never connected)
  • Measure mean time to access (request to grant)
  • Report on access patterns for baseline optimization

Security Controls

Control NIST 800-53 Description
Temporary Access AC-2(2) Automated temporary account management
Least Privilege AC-6 Time-bound minimum access
Access Enforcement AC-3 Automated access grant/revoke
Audit AU-3 Complete JIT access audit trail
Risk Assessment RA-3 Risk-based approval routing

Common Pitfalls

  • Setting time windows too long, negating JIT benefits
  • Not implementing automatic revocation at expiration
  • Complex approval workflows causing access delays for legitimate needs
  • Not providing emergency bypass for critical incidents
  • Failing to audit approved but unused JIT access

Verification

  • JIT request workflow functional end-to-end
  • Access automatically revoked at expiration
  • Approval routing correct for all risk levels
  • Emergency access bypass works with post-review
  • All JIT events logged to SIEM
  • Standing privileges reduced by measurable percentage
  • Mean time to access meets business SLA
Source materials

References and resources

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

References 3

api-reference.md1.6 KB

API Reference: Implementing Just-In-Time Access Provisioning

Azure AD PIM API (JIT for Azure)

import requests
headers = {"Authorization": "Bearer <token>"}
# Activate eligible role
requests.post(
    "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequests",
    headers=headers,
    json={"action": "selfActivate", "roleDefinitionId": ROLE_ID,
          "directoryScopeId": "/", "justification": "Incident response",
          "scheduleInfo": {"expiration": {"type": "afterDuration", "duration": "PT4H"}}})

JIT Risk-Based Approval

Risk Level Approval Max Duration
Low Auto-approve 4 hours
Medium Manager 8 hours
High Manager + Security 4 hours
Critical CISO + Manager + Security 2 hours

AWS IAM Access Analyzer

# Find unused permissions for JIT conversion
aws accessanalyzer list-findings --analyzer-arn ARN --filter '{"status": {"eq": ["ACTIVE"]}}'

CyberArk PAS REST API (JIT Privileged Access)

# Request JIT access
curl -X POST "https://VAULT/PasswordVault/api/MyRequests" \
  -H "Authorization: $TOKEN" \
  -d '{"AccountId": "ACC_ID", "Reason": "Maintenance", "TicketingSystemName": "ServiceNow"}'

Key Metrics

Metric Target
Avg approval time < 15 min
Auto-approval rate 40-60% (low risk)
Standing privilege reduction > 80%
Expired access auto-revoked 100%

References

standards.md1.1 KB

Standards and References - Just-In-Time Access Provisioning

NIST Standards

  • NIST SP 800-207: Zero Trust Architecture - Section 3 (Logical Components)
  • NIST SP 800-53 Rev 5:
    • AC-2(2): Automated Temporary and Emergency Account Management
    • AC-2(3): Disable Accounts
    • AC-6: Least Privilege
    • AC-6(5): Privileged Accounts
  • NIST SP 1800-35: Implementing a Zero Trust Architecture

Zero Trust Frameworks

  • CISA Zero Trust Maturity Model: Identity pillar - dynamic access provisioning
  • DoD Zero Trust Reference Architecture: JIT/JEA requirements
  • Forrester ZTX: Extended Zero Trust with JIT access

Tools and Platforms

  • Microsoft Entra PIM: Privileged Identity Management with JIT elevation
  • CyberArk JIT: Privileged access on-demand
  • SailPoint: Identity governance with access request workflows
  • HashiCorp Boundary: Just-in-time access to infrastructure
  • StrongDM: Dynamic access management

Compliance

  • SOX: Least privilege for financial system access
  • PCI DSS 4.0: Requirement 7.2 - Access based on need to know
  • HIPAA: Minimum necessary standard for PHI access
workflows.md2.3 KB

Just-In-Time Access Provisioning Workflows

Workflow 1: Standard JIT Access Request

Steps:

  1. User submits access request via self-service portal
  2. Request includes: target resource, duration, business justification
  3. System calculates risk score based on resource sensitivity and user context
  4. Risk-based routing:
    • Low risk (< 1 hr, non-privileged): Auto-approve
    • Medium risk: Route to resource owner for approval
    • High risk (privileged, production): Dual approval required
  5. Approver notified via email/Slack/Teams
  6. Approver reviews and approves/denies with comments
  7. On approval: system provisions access with time-bound constraint
  8. User notified of access grant with expiration time
  9. At expiration: system automatically revokes access
  10. All events logged for audit trail

Workflow 2: Emergency JIT Access (Break-Glass)

Steps:

  1. User declares emergency and requests immediate access
  2. System grants access immediately without pre-approval
  3. Access limited to shorter maximum duration (e.g., 2 hours)
  4. Security team notified of emergency access grant
  5. User must provide justification within 24 hours
  6. Manager and security team perform post-facto review
  7. If review finds access unjustified: security incident opened
  8. All emergency access events flagged in audit reports

Workflow 3: Privileged Elevation with PAM Integration

Steps:

  1. User requests privilege elevation through JIT portal
  2. Approval obtained per risk-based workflow
  3. JIT system triggers PAM credential checkout
  4. PSM session initiated with time-bound credential
  5. User performs privileged operations via isolated session
  6. Session recorded for audit
  7. At expiration: session terminated, credential checked in, password rotated
  8. JIT access record closed

Workflow 4: Vendor/Third-Party JIT Access

Steps:

  1. Internal sponsor submits access request on behalf of vendor
  2. Request includes: vendor identity, scope, duration, project reference
  3. Dual approval required (sponsor manager + security)
  4. Temporary account created with MFA enrollment
  5. Access restricted to specified resources only
  6. Network access limited to authorized segments
  7. Session monitoring enabled
  8. Account deactivated at expiration
  9. Account deleted after 30-day retention period

Scripts 2

agent.py8.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for implementing and auditing Just-In-Time access provisioning."""

import json
import argparse
from datetime import datetime
from collections import Counter


def audit_jit_requests(requests_path):
    """Audit JIT access requests for compliance and anomalies."""
    with open(requests_path) as f:
        data = json.load(f)
    requests_list = data if isinstance(data, list) else data.get("requests", [])
    findings = []
    by_status = Counter()
    by_resource = Counter()

    for req in requests_list:
        status = req.get("status", "unknown").lower()
        by_status[status] += 1
        by_resource[req.get("resource", "unknown")] += 1

        duration_hours = req.get("duration_hours", req.get("duration", 0))
        if duration_hours > 8:
            findings.append({
                "request_id": req.get("id", ""),
                "issue": f"Long access duration: {duration_hours}h",
                "severity": "MEDIUM",
                "user": req.get("requestor", req.get("user", "")),
            })
        if duration_hours > 24:
            findings[-1]["severity"] = "HIGH"

        if status == "approved" and not req.get("approver"):
            findings.append({
                "request_id": req.get("id", ""),
                "issue": "Auto-approved without approver record",
                "severity": "HIGH",
            })

        granted = req.get("granted_at", "")
        expired = req.get("expired_at", req.get("revoked_at", ""))
        if granted and not expired and status == "active":
            granted_dt = datetime.fromisoformat(granted.replace("Z", ""))
            if (datetime.utcnow() - granted_dt).total_seconds() > duration_hours * 3600:
                findings.append({
                    "request_id": req.get("id", ""),
                    "issue": "Access not revoked after expiration",
                    "severity": "CRITICAL",
                    "user": req.get("requestor", ""),
                })

    return {
        "total_requests": len(requests_list),
        "by_status": dict(by_status),
        "by_resource": dict(by_resource.most_common(10)),
        "findings": findings,
        "anomaly_count": len(findings),
    }


def audit_standing_privileges(privileges_path):
    """Identify standing privileges that should be converted to JIT."""
    with open(privileges_path) as f:
        data = json.load(f)
    privs = data if isinstance(data, list) else data.get("privileges", [])
    candidates = []

    for priv in privs:
        role = priv.get("role", priv.get("permission", "")).lower()
        usage = priv.get("last_used", priv.get("last_access", ""))
        is_privileged = any(k in role for k in [
            "admin", "root", "owner", "superuser", "dba", "operator"])

        days_unused = 0
        if usage:
            try:
                usage_dt = datetime.fromisoformat(usage.replace("Z", ""))
                days_unused = (datetime.utcnow() - usage_dt).days
            except ValueError:
                pass

        if is_privileged and days_unused > 30:
            candidates.append({
                "user": priv.get("user", priv.get("identity", "")),
                "role": priv.get("role", ""),
                "resource": priv.get("resource", priv.get("target", "")),
                "days_unused": days_unused,
                "severity": "CRITICAL" if days_unused > 90 else "HIGH",
                "recommendation": "Convert to JIT access",
            })
        elif is_privileged:
            candidates.append({
                "user": priv.get("user", ""),
                "role": priv.get("role", ""),
                "days_unused": days_unused,
                "severity": "MEDIUM",
                "recommendation": "Evaluate for JIT conversion",
            })

    return {
        "total_privileges": len(privs),
        "jit_candidates": len(candidates),
        "critical_standing": sum(1 for c in candidates if c["severity"] == "CRITICAL"),
        "details": candidates[:30],
    }


def calculate_jit_metrics(requests_path):
    """Calculate JIT program operational metrics."""
    with open(requests_path) as f:
        data = json.load(f)
    requests_list = data if isinstance(data, list) else data.get("requests", [])

    approval_times = []
    durations = []
    auto_approved = 0
    total = len(requests_list)

    for req in requests_list:
        if req.get("auto_approved", False):
            auto_approved += 1

        requested = req.get("requested_at", "")
        approved = req.get("approved_at", "")
        if requested and approved:
            try:
                r_dt = datetime.fromisoformat(requested.replace("Z", ""))
                a_dt = datetime.fromisoformat(approved.replace("Z", ""))
                approval_times.append((a_dt - r_dt).total_seconds() / 60)
            except ValueError:
                pass

        duration = req.get("duration_hours", 0)
        if duration:
            durations.append(duration)

    return {
        "total_requests": total,
        "auto_approved_rate": round(auto_approved / total * 100, 1) if total else 0,
        "avg_approval_time_min": round(sum(approval_times) / len(approval_times), 1) if approval_times else 0,
        "avg_duration_hours": round(sum(durations) / len(durations), 1) if durations else 0,
        "max_duration_hours": max(durations) if durations else 0,
        "p95_approval_time_min": sorted(approval_times)[int(len(approval_times) * 0.95)] if approval_times else 0,
    }


def generate_jit_policy():
    """Generate JIT access provisioning policy."""
    return {
        "risk_levels": {
            "low": {
                "approval": "auto-approve",
                "max_duration": "4h",
                "examples": ["Read-only database access", "Log viewer"],
            },
            "medium": {
                "approval": "manager-approve",
                "max_duration": "8h",
                "examples": ["Application admin", "Deploy permissions"],
            },
            "high": {
                "approval": "manager + security team",
                "max_duration": "4h",
                "examples": ["Production database write", "IAM admin"],
            },
            "critical": {
                "approval": "CISO + manager + security team",
                "max_duration": "2h",
                "examples": ["Domain admin", "Root access", "Key management"],
            },
        },
        "controls": {
            "session_recording": True,
            "break_glass_procedure": True,
            "automatic_revocation": True,
            "audit_logging": True,
            "notification_on_grant": True,
        },
    }


def main():
    parser = argparse.ArgumentParser(description="JIT Access Provisioning Agent")
    parser.add_argument("--requests", help="JIT requests log JSON")
    parser.add_argument("--privileges", help="Standing privileges JSON")
    parser.add_argument("--action", choices=["audit", "standing", "metrics", "policy", "full"],
                        default="full")
    parser.add_argument("--output", default="jit_access_report.json")
    args = parser.parse_args()

    report = {"generated_at": datetime.utcnow().isoformat(), "results": {}}

    if args.action in ("audit", "full") and args.requests:
        result = audit_jit_requests(args.requests)
        report["results"]["audit"] = result
        print(f"[+] JIT audit: {result['total_requests']} requests, {result['anomaly_count']} issues")

    if args.action in ("standing", "full") and args.privileges:
        result = audit_standing_privileges(args.privileges)
        report["results"]["standing"] = result
        print(f"[+] Standing privs: {result['jit_candidates']} JIT candidates")

    if args.action in ("metrics", "full") and args.requests:
        metrics = calculate_jit_metrics(args.requests)
        report["results"]["metrics"] = metrics
        print(f"[+] Avg approval: {metrics['avg_approval_time_min']}min")

    if args.action in ("policy", "full"):
        policy = generate_jit_policy()
        report["results"]["policy"] = policy
        print("[+] JIT policy generated")

    with open(args.output, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
process.py13.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Just-In-Time Access Provisioning Engine

Manages JIT access requests, approval workflows, time-bound grants,
automatic revocation, and audit logging for zero-standing-privilege
implementations.
"""

import json
import datetime
import secrets
from typing import Dict, List, Optional
from dataclasses import dataclass, field
from enum import Enum


class RiskLevel(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class RequestStatus(Enum):
    PENDING = "pending"
    APPROVED = "approved"
    DENIED = "denied"
    ACTIVE = "active"
    EXPIRED = "expired"
    REVOKED = "revoked"
    EMERGENCY = "emergency"


@dataclass
class JITAccessRequest:
    """A just-in-time access request."""
    request_id: str
    requester: str
    target_resource: str
    resource_type: str  # server, database, application, cloud_role
    requested_duration_minutes: int
    justification: str
    risk_level: RiskLevel = RiskLevel.MEDIUM
    status: RequestStatus = RequestStatus.PENDING
    approvers: List[str] = field(default_factory=list)
    approved_by: List[str] = field(default_factory=list)
    denied_by: str = ""
    created_at: str = ""
    granted_at: str = ""
    expires_at: str = ""
    revoked_at: str = ""
    is_emergency: bool = False
    ticket_id: str = ""


@dataclass
class ResourcePolicy:
    """Policy for a protected resource."""
    resource_pattern: str
    resource_type: str
    max_duration_minutes: int
    risk_level: RiskLevel
    auto_approve: bool = False
    required_approvals: int = 1
    approver_roles: List[str] = field(default_factory=list)
    mfa_required: bool = True
    session_recording: bool = False


class JITAccessEngine:
    """Manages the full JIT access lifecycle."""

    def __init__(self):
        self.requests: Dict[str, JITAccessRequest] = {}
        self.policies: List[ResourcePolicy] = []
        self.audit_log: List[Dict] = []

    def add_policy(self, policy: ResourcePolicy):
        """Register a resource access policy."""
        self.policies.append(policy)

    def _get_policy(self, resource: str, resource_type: str) -> Optional[ResourcePolicy]:
        """Find matching policy for a resource."""
        for policy in self.policies:
            if policy.resource_type == resource_type:
                if policy.resource_pattern == "*" or policy.resource_pattern in resource:
                    return policy
        return None

    def _generate_request_id(self) -> str:
        return f"JIT-{datetime.datetime.now().strftime('%Y%m%d')}-{secrets.token_hex(4).upper()}"

    def _log_event(self, event_type: str, request_id: str, details: Dict):
        """Record audit event."""
        self.audit_log.append({
            "timestamp": datetime.datetime.now().isoformat(),
            "event_type": event_type,
            "request_id": request_id,
            **details
        })

    def submit_request(self, requester: str, target_resource: str,
                       resource_type: str, duration_minutes: int,
                       justification: str, is_emergency: bool = False,
                       ticket_id: str = "") -> JITAccessRequest:
        """Submit a new JIT access request."""
        policy = self._get_policy(target_resource, resource_type)
        if not policy:
            raise ValueError(f"No policy found for resource type: {resource_type}")

        # Enforce maximum duration
        actual_duration = min(duration_minutes, policy.max_duration_minutes)
        if is_emergency:
            actual_duration = min(actual_duration, 120)  # 2-hour max for emergency

        request = JITAccessRequest(
            request_id=self._generate_request_id(),
            requester=requester,
            target_resource=target_resource,
            resource_type=resource_type,
            requested_duration_minutes=actual_duration,
            justification=justification,
            risk_level=policy.risk_level,
            created_at=datetime.datetime.now().isoformat(),
            is_emergency=is_emergency,
            ticket_id=ticket_id
        )

        if is_emergency:
            # Emergency: grant immediately, require post-facto review
            request.status = RequestStatus.EMERGENCY
            now = datetime.datetime.now()
            request.granted_at = now.isoformat()
            request.expires_at = (now + datetime.timedelta(minutes=actual_duration)).isoformat()
            self._log_event("EMERGENCY_GRANT", request.request_id, {
                "requester": requester,
                "resource": target_resource,
                "duration_minutes": actual_duration,
                "justification": justification
            })
        elif policy.auto_approve and policy.risk_level == RiskLevel.LOW:
            # Auto-approve low-risk
            request.status = RequestStatus.APPROVED
            request.approved_by = ["AUTO"]
            self._log_event("AUTO_APPROVED", request.request_id, {
                "requester": requester,
                "resource": target_resource,
                "reason": "Low-risk auto-approve policy"
            })
            self._activate_access(request)
        else:
            # Route for approval
            request.approvers = policy.approver_roles
            request.status = RequestStatus.PENDING
            self._log_event("REQUEST_SUBMITTED", request.request_id, {
                "requester": requester,
                "resource": target_resource,
                "required_approvals": policy.required_approvals,
                "approvers": policy.approver_roles
            })

        self.requests[request.request_id] = request
        return request

    def approve_request(self, request_id: str, approver: str) -> JITAccessRequest:
        """Approve a JIT access request."""
        request = self.requests.get(request_id)
        if not request:
            raise ValueError(f"Request not found: {request_id}")
        if request.status not in (RequestStatus.PENDING,):
            raise ValueError(f"Request {request_id} is not pending approval")

        request.approved_by.append(approver)
        policy = self._get_policy(request.target_resource, request.resource_type)
        required = policy.required_approvals if policy else 1

        self._log_event("APPROVAL_RECORDED", request_id, {
            "approver": approver,
            "approvals_count": len(request.approved_by),
            "required": required
        })

        if len(request.approved_by) >= required:
            request.status = RequestStatus.APPROVED
            self._activate_access(request)

        return request

    def deny_request(self, request_id: str, denier: str, reason: str = "") -> JITAccessRequest:
        """Deny a JIT access request."""
        request = self.requests.get(request_id)
        if not request:
            raise ValueError(f"Request not found: {request_id}")

        request.status = RequestStatus.DENIED
        request.denied_by = denier
        self._log_event("REQUEST_DENIED", request_id, {
            "denied_by": denier,
            "reason": reason
        })
        return request

    def _activate_access(self, request: JITAccessRequest):
        """Activate the approved access grant."""
        now = datetime.datetime.now()
        request.status = RequestStatus.ACTIVE
        request.granted_at = now.isoformat()
        request.expires_at = (now + datetime.timedelta(
            minutes=request.requested_duration_minutes
        )).isoformat()

        self._log_event("ACCESS_ACTIVATED", request.request_id, {
            "requester": request.requester,
            "resource": request.target_resource,
            "granted_at": request.granted_at,
            "expires_at": request.expires_at
        })

    def check_expirations(self) -> List[JITAccessRequest]:
        """Check and revoke expired access grants."""
        now = datetime.datetime.now()
        expired = []

        for request in self.requests.values():
            if request.status in (RequestStatus.ACTIVE, RequestStatus.EMERGENCY):
                if request.expires_at:
                    expiry = datetime.datetime.fromisoformat(request.expires_at)
                    if now >= expiry:
                        request.status = RequestStatus.EXPIRED
                        request.revoked_at = now.isoformat()
                        expired.append(request)
                        self._log_event("ACCESS_EXPIRED", request.request_id, {
                            "requester": request.requester,
                            "resource": request.target_resource,
                            "expired_at": request.revoked_at
                        })

        return expired

    def revoke_access(self, request_id: str, reason: str = "") -> JITAccessRequest:
        """Manually revoke an active access grant."""
        request = self.requests.get(request_id)
        if not request:
            raise ValueError(f"Request not found: {request_id}")

        request.status = RequestStatus.REVOKED
        request.revoked_at = datetime.datetime.now().isoformat()
        self._log_event("ACCESS_REVOKED", request_id, {
            "requester": request.requester,
            "resource": request.target_resource,
            "reason": reason
        })
        return request

    def get_active_grants(self) -> List[JITAccessRequest]:
        """List all currently active access grants."""
        return [r for r in self.requests.values()
                if r.status in (RequestStatus.ACTIVE, RequestStatus.EMERGENCY)]

    def get_metrics(self) -> Dict:
        """Calculate JIT access metrics."""
        all_requests = list(self.requests.values())
        total = len(all_requests)
        if total == 0:
            return {"total": 0}

        by_status = {}
        for r in all_requests:
            by_status[r.status.value] = by_status.get(r.status.value, 0) + 1

        emergency_count = sum(1 for r in all_requests if r.is_emergency)

        # Calculate mean time to access
        approved = [r for r in all_requests if r.granted_at and r.created_at]
        if approved:
            total_wait = sum(
                (datetime.datetime.fromisoformat(r.granted_at) -
                 datetime.datetime.fromisoformat(r.created_at)).total_seconds()
                for r in approved
            )
            mean_tta = total_wait / len(approved) / 60  # minutes
        else:
            mean_tta = 0

        return {
            "total_requests": total,
            "by_status": by_status,
            "emergency_grants": emergency_count,
            "active_grants": len(self.get_active_grants()),
            "mean_time_to_access_minutes": round(mean_tta, 1),
            "audit_events": len(self.audit_log)
        }

    def generate_report(self) -> str:
        """Generate JIT access report."""
        metrics = self.get_metrics()
        active = self.get_active_grants()

        lines = [
            "=" * 70,
            "JUST-IN-TIME ACCESS PROVISIONING REPORT",
            "=" * 70,
            f"Report Date: {datetime.datetime.now().isoformat()}",
            f"Total Requests: {metrics['total_requests']}",
            f"Active Grants: {metrics['active_grants']}",
            f"Emergency Grants: {metrics['emergency_grants']}",
            f"Mean Time to Access: {metrics['mean_time_to_access_minutes']} minutes",
            f"Audit Events: {metrics['audit_events']}",
            "-" * 70,
            "",
            "STATUS BREAKDOWN:",
        ]
        for status, count in metrics.get("by_status", {}).items():
            lines.append(f"  {status}: {count}")
        lines.append("")

        if active:
            lines.append("ACTIVE GRANTS:")
            lines.append("-" * 40)
            for r in active:
                flag = " [EMERGENCY]" if r.is_emergency else ""
                lines.append(f"  {r.request_id}: {r.requester} -> {r.target_resource}{flag}")
                lines.append(f"    Expires: {r.expires_at}")
                lines.append(f"    Justification: {r.justification}")
            lines.append("")

        lines.append("=" * 70)
        return "\n".join(lines)


def main():
    """Demo JIT access engine."""
    engine = JITAccessEngine()

    # Define resource policies
    engine.add_policy(ResourcePolicy(
        resource_pattern="*", resource_type="read_only",
        max_duration_minutes=60, risk_level=RiskLevel.LOW,
        auto_approve=True, required_approvals=0
    ))
    engine.add_policy(ResourcePolicy(
        resource_pattern="*", resource_type="production_server",
        max_duration_minutes=240, risk_level=RiskLevel.HIGH,
        auto_approve=False, required_approvals=2,
        approver_roles=["manager", "security_team"],
        session_recording=True
    ))
    engine.add_policy(ResourcePolicy(
        resource_pattern="*", resource_type="database_admin",
        max_duration_minutes=120, risk_level=RiskLevel.CRITICAL,
        auto_approve=False, required_approvals=2,
        approver_roles=["dba_lead", "security_team"],
        mfa_required=True, session_recording=True
    ))

    # Submit requests
    r1 = engine.submit_request("alice", "docs-server", "read_only", 30,
                               "Need to check documentation")
    r2 = engine.submit_request("bob", "prod-web-01", "production_server", 120,
                               "Deploy hotfix for CVE-2026-1234", ticket_id="INC-5678")
    r3 = engine.submit_request("charlie", "prod-db-01", "database_admin", 60,
                               "Critical production outage", is_emergency=True)

    # Approve prod server access
    engine.approve_request(r2.request_id, "manager_dave")
    engine.approve_request(r2.request_id, "security_eve")

    print(engine.generate_report())


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.7 KB
Keep exploring