Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.provisionr.io/llms.txt

Use this file to discover all available pages before exploring further.

Sarah got promoted from Sales Engineer to Engineering Manager. Congratulations, Sarah. Her HRIS record updates: job_title: "Engineering Manager", department: "Engineering". The policy engine recalculates her access: Should add: Engineering Manager group. People management tools. Budget dashboards. Should remove: Salesforce (no longer in Sales). Sales Team Slack channels. Customer-facing tools. The orchestration layer provisions the new access and revokes the old access. Within 30 seconds, Sarah loses access to: All her customer accounts in Salesforce. Sales team communications. Customer success collaboration tools. She’s in the middle of handing off three enterprise deals to her replacement. She needs Salesforce access for another month. She needs Sales Slack access to coordinate handoffs. She needs customer context to brief her replacement. The automation just broke her transition. This is why organizations need graceful deprecation—the practice of removing access gradually, with defined overlap periods, rather than revoking everything immediately when someone’s role changes.

The Problem with Immediate Revocation

Policy-based access is correct in principle: When someone’s role changes, their access should match their new role. Policy-based access is wrong in practice: Role changes aren’t instantaneous. There’s a transition period where people need:
  • Access from their old role (to hand off responsibilities)
  • Access from their new role (to start new responsibilities)
  • Time to adjust (customer context can’t be transferred instantly)
If old access is immediately revoked:
1

Handoffs break

Knowledge transfer requires access to the systems where knowledge lives.
2

Productivity drops

People spend time searching for who can help instead of working.
3

Frustration rises

“I can’t do my job because IT revoked everything.”
4

Shadow IT emerges

Manual workarounds, shared credentials.
Graceful deprecation with defined transition periods demonstrates controlled change management for access rights. The documented grace periods, with clear expiration dates and automatic revocation, satisfy SOC 2 CC6.2 (access modification) and ISO 27001 A.9.2.5 (review of user access rights) while acknowledging business continuity needs.

Graceful Deprecation Patterns

Different types of access need different deprecation strategies:

Pattern 1: Grace Period (Keep Access Temporarily)

Use case: Access that should be removed eventually, but the user needs overlap during transition.
role_transition:
  user: "sarah.chen@company.com"
  old_role: "Sales Engineer"
  new_role: "Engineering Manager"
  effective_date: "2024-11-24"

  access_changes:
    # Remove Salesforce, but with 30-day grace period
    - resource: "salesforce:profile:sales-engineer"
      action: "remove"
      grace_period: "30 days"
      expires_at: "2024-12-24"
      justification: "30 days to hand off customer accounts"

    # Remove Sales Team Slack, 14-day grace period
    - resource: "slack:channel:#sales-team"
      action: "remove"
      grace_period: "14 days"
      expires_at: "2024-12-08"
      justification: "2 weeks to coordinate handoffs"
Implementation: Instead of immediately revoking, the system:
  1. Marks access as “deprecated” (still active but scheduled for removal)
  2. Sets expiration date based on grace period
  3. Notifies user: “Your Salesforce access will be removed in 30 days”
  4. Auto-revokes on expiration date
State model:
Active → Deprecated → Expired (revoked)
         ↑           ↑
         Grace period

Pattern 2: Downgrade (Reduce Permissions, Don’t Remove)

Use case: User still needs some access, but at a lower privilege level.
role_transition:
  user: "sarah.chen@company.com"
  old_role: "Sales Engineer"
  new_role: "Engineering Manager"

  access_changes:
    # Keep GitLab access, but downgrade from Developer to Reporter
    - resource: "gitlab:group:customer-solutions"
      action: "downgrade"
      old_permission: "developer"
      new_permission: "reporter"
      justification: "Still needs visibility into customer solutions, but no longer contributing code"

    # Keep production access, but downgrade from Read/Write to Read-Only
    - resource: "aws:prod-environment"
      action: "downgrade"
      old_permission: "read-write"
      new_permission: "read-only"
      justification: "Manager needs visibility but shouldn't be making changes"
Implementation: The system modifies permission level instead of revoking entirely.

Pattern 3: Conditional Keep (Retain if Criteria Met)

Use case: Access should be removed unless specific conditions are met.
role_transition:
  user: "sarah.chen@company.com"
  old_role: "Sales Engineer"
  new_role: "Engineering Manager"

  access_changes:
    # Keep Salesforce IF managing customer-facing team
    - resource: "salesforce:profile:sales-engineer"
      action: "conditional_keep"
      condition:
        type: "team_property"
        check: "team.customer_facing == true"
      if_true: "keep"
      if_false: "remove_with_grace_period"
      grace_period: "30 days"
Implementation: The system evaluates the condition. If Sarah’s new team is customer-facing (Solutions Architecture, Customer Success, etc.), she keeps Salesforce. If not, it’s removed with grace period.

Pattern 4: Convert to Exception (Make Temporary Access Explicit)

Use case: Old role access becomes an exception with explicit expiration.
role_transition:
  user: "sarah.chen@company.com"
  old_role: "Sales Engineer"
  new_role: "Engineering Manager"

  access_changes:
    # Convert Salesforce access to explicit exception
    - resource: "salesforce:profile:sales-engineer"
      action: "convert_to_exception"
      exception:
        justification: "Role transition - need to hand off enterprise accounts"
        duration: "60 days"
        requires_approval: false  # Auto-approved for role transitions
        notification: true  # Notify user of expiration
Implementation: Old access is removed from policy-based provisioning and added as an exception. This makes the temporary nature explicit and tracks it separately.

Pattern 5: Manager Approval for Retention

Use case: IT doesn’t know if old access should persist. Let the manager decide.
role_transition:
  user: "sarah.chen@company.com"
  old_role: "Sales Engineer"
  new_role: "Engineering Manager"

  access_changes:
    - resource: "salesforce:profile:sales-engineer"
      action: "request_manager_approval"
      manager: "vp-engineering@company.com"
      approval_request:
        question: "Should Sarah retain Salesforce access in her new role?"
        context: "She's transitioning from Sales Engineer to Engineering Manager. Salesforce access is not in the Engineering Manager policy."
        options:
          - value: "remove_immediately"
            label: "Remove immediately"
          - value: "remove_with_grace"
            label: "Remove after 30-day handoff period"
          - value: "keep_permanent"
            label: "Keep permanently (if managing customer-facing team)"
Implementation: The system sends an approval request to the manager. Based on response:
  • Remove immediately
  • Remove with grace period
  • Keep permanently (and optionally update policy if this is a common pattern)

Implementation: Graceful Deprecation Engine

Data Model

from enum import Enum

class DeprecationAction(Enum):
    REMOVE = "remove"
    DOWNGRADE = "downgrade"
    CONDITIONAL_KEEP = "conditional_keep"
    CONVERT_TO_EXCEPTION = "convert_to_exception"
    REQUEST_APPROVAL = "request_approval"

class AccessDeprecation:
    def __init__(self, user, resource, action, **kwargs):
        self.id = generate_id()
        self.user = user
        self.resource = resource  # "system:resource_type:resource_id"
        self.action = action
        self.created_at = datetime.now()
        self.status = "pending"

        # Grace period settings
        self.grace_period = kwargs.get("grace_period")  # timedelta
        self.expires_at = None
        if self.grace_period:
            self.expires_at = datetime.now() + self.grace_period

        # Downgrade settings
        self.old_permission = kwargs.get("old_permission")
        self.new_permission = kwargs.get("new_permission")

        # Conditional settings
        self.condition = kwargs.get("condition")

        # Exception conversion settings
        self.exception_config = kwargs.get("exception_config")

        # Approval settings
        self.requires_approval = kwargs.get("requires_approval", False)
        self.approver = kwargs.get("approver")

        # Metadata
        self.justification = kwargs.get("justification")
        self.role_transition = kwargs.get("role_transition")

Deprecation Policy Configuration

# Define deprecation policies per access type

deprecation_policies:
  # Salesforce access
  - resource_pattern: "salesforce:*"
    on_role_change:
      from_departments: ["Sales", "Customer Success"]
      to_departments: ["Engineering", "Product", "Finance"]
      action: "remove"
      grace_period: "30 days"
      justification: "Standard handoff period for customer-facing roles"

  # GitLab access
  - resource_pattern: "gitlab:*"
    on_role_change:
      from_permissions: ["developer", "maintainer"]
      to_permissions: ["reporter"]
      action: "downgrade"
      new_permission: "reporter"
      justification: "Maintain visibility but remove write access"

  # Production access
  - resource_pattern: "aws:prod-*"
    on_role_change:
      from_roles: ["Engineer", "Senior Engineer"]
      to_roles: ["Engineering Manager", "Director"]
      action: "downgrade"
      old_permission: "read-write"
      new_permission: "read-only"
      justification: "Managers need visibility but shouldn't make direct changes"

  # Team-specific Slack channels
  - resource_pattern: "slack:channel:#team-*"
    on_role_change:
      action: "conditional_keep"
      condition:
        type: "team_membership"
        check: "user.new_team == channel.team"
      if_true: "keep"
      if_false: "remove_with_grace_period"
      grace_period: "14 days"

Role Transition Handler

def handle_role_transition(user, old_attributes, new_attributes):
    """Handle access changes when user's role changes"""

    # Calculate policy-based access for old and new roles
    old_access = policy_engine.calculate_access(old_attributes)
    new_access = policy_engine.calculate_access(new_attributes)

    # Calculate delta
    to_add = new_access - old_access
    to_remove = old_access - new_access
    to_keep = old_access & new_access

    # Handle additions (straightforward)
    for resource in to_add:
        provision_access(user, resource)

    # Handle removals (apply graceful deprecation)
    deprecations = []
    for resource in to_remove:
        # Find applicable deprecation policy
        policy = find_deprecation_policy(resource, old_attributes, new_attributes)

        if policy:
            # Create deprecation action
            deprecation = AccessDeprecation(
                user=user,
                resource=resource,
                action=policy.action,
                grace_period=policy.grace_period,
                old_permission=policy.old_permission,
                new_permission=policy.new_permission,
                condition=policy.condition,
                justification=policy.justification,
                role_transition={
                    "old_role": old_attributes.job_title,
                    "new_role": new_attributes.job_title,
                    "effective_date": new_attributes.effective_date
                }
            )

            # Execute deprecation
            result = deprecation.execute()
            deprecations.append(deprecation)

        else:
            # No policy - default to immediate removal (with warning)
            log_warning(f"No deprecation policy for {resource}. Removing immediately.")
            revoke_access(user, resource)

    # Handle resources that stay but might need permission updates
    for resource in to_keep:
        check_permission_changes(user, resource, old_attributes, new_attributes)

    return {
        "added": to_add,
        "removed": to_remove,
        "deprecations": deprecations
    }

Real-World Scenarios

Scenario 1: Sales Engineer to Engineering Manager

Attributes change:
old:
  job_title: "Sales Engineer"
  department: "Sales"
  team: "Enterprise Sales"

new:
  job_title: "Engineering Manager"
  department: "Engineering"
  team: "Solutions Engineering"
Access changes:
ResourceOld AccessNew AccessDeprecation Action
SalesforceSales Engineer profile(none)Remove after 30 days (customer handoff)
Slack #sales-teamMember(none)Remove after 14 days (coordination)
Slack #customer-successMember(none)Remove after 14 days
GitLab customer-solutionsDeveloperReporterDowngrade immediately (context, not code)
Slack #engineering(none)MemberAdd immediately
PeopleOps tools(none)Manager accessAdd immediately
Timeline:
  • Day 0: Promotion effective. Engineering access added immediately.
  • Day 1-14: Sarah has both Sales and Engineering access (overlap period)
  • Day 14: Sales Slack channels removed
  • Day 30: Salesforce removed
  • Day 30+: Only Engineering access remains

Scenario 2: Engineer to Senior Engineer (Promotion)

Attributes change:
old:
  job_title: "Engineer"
  level: "L3"

new:
  job_title: "Senior Engineer"
  level: "L4"
Access changes:
ResourceOld AccessNew AccessDeprecation Action
Production(none)Read-onlyAdd immediately
On-call tools(none)Full accessAdd immediately
GitLabDeveloperMaintainerUpgrade immediately
No deprecation needed—this is a promotion within the same department. Only additions and upgrades.

Scenario 3: Engineering Manager to Director (Promotion)

Attributes change:
old:
  job_title: "Engineering Manager"
  level: "M3"

new:
  job_title: "Director of Engineering"
  level: "M4"
Access changes:
ResourceOld AccessNew AccessDeprecation Action
ProductionRead-writeRead-onlyDowngrade immediately (managers don’t deploy)
Budget toolsTeam-levelOrg-levelUpgrade immediately
Strategic planning tools(none)Full accessAdd immediately
Rationale: Directors need less hands-on access and more strategic access.

User Communication

Users must know when their access will change.

On Role Transition

Subject: Your access is updating following your promotion

Hi Sarah,

Congratulations on your promotion to Engineering Manager!

Your access is being updated to match your new role:

Added immediately:
- Engineering Manager group
- People management tools (BambooHR, Lattice)
- Budget dashboards

Temporary access (will expire):
- Salesforce (expires Dec 24) - 30 days to hand off accounts
- Slack #sales-team (expires Dec 8) - 14 days for coordination

Downgraded:
- GitLab customer-solutions: Developer to Reporter (visibility maintained)

Questions about access? Reply to this email or ping #it-help.

— IT Team

Before Expiration

Subject: Reminder: Your Salesforce access expires in 7 days

Hi Sarah,

Your temporary Salesforce access expires in 7 days (Dec 24).

This access was granted during your transition from Sales Engineer to Engineering Manager for account handoffs.

If you still need Salesforce access:
[ Request Extension ] (requires VP approval)

If handoffs are complete:
No action needed - access will be automatically removed on Dec 24.

Questions? Reply to this email.

— IT Team

Monitoring Graceful Deprecation

Track these metrics: Active deprecations. How many access grants are in grace period? Average grace period duration. Are grace periods too long or too short? Extension rate. What percentage of deprecations are extended? Manual revocations. How often is access manually revoked before expiration? Dashboard:
Graceful Deprecation Dashboard

Active Deprecations: 18
├─ Expiring this week: 5
├─ Expiring this month: 13
└─ Extended (this month): 2

Average grace period: 24 days
Extension rate: 8% (healthy - most expire as planned)

Most common deprecations:
1. salesforce:* (8 active)
2. slack:#sales-* (4 active)
3. gitlab:customer-solutions (3 active)

The Bottom Line

Immediate revocation breaks role transitions. Graceful deprecation makes them smooth. Key patterns:
1

Grace period

Keep access temporarily—30 days for handoffs.
2

Downgrade

Reduce permission, don’t remove—Developer to Reporter.
3

Conditional keep

Retain if criteria met—customer-facing team keeps CRM.
4

Convert to exception

Make temporary access explicit.
5

Manager approval

Let the manager decide edge cases.
Implementation requirements:
  • Deprecation policies (define how each access type should be removed)
  • State tracking (active → deprecated → expired)
  • Scheduled removal (auto-revoke on expiration)
  • User notifications (communicate changes and timelines)
Timeline: 2-3 weeks to implement graceful deprecation on top of policy-based access. Access shouldn’t be yanked immediately when roles change. Give people time to transition. That’s the difference between automation that helps and automation that breaks things.
Next up: Building audit-ready compliance—how to make auditors appreciate the access management system.
Want to see graceful deprecation in action? Explore Provisionr’s transition policies