Developers

Tracking stale cloud ownership through personnel changes

When employees change roles or leave, their resource ownership tags often go unnoticed. A combination of queries, policies and process changes can catch orphaned infrastructure before it becomes a security problem.

6 min read
How to reassign resource ownership before someone’s last day

Cloud infrastructure ownership frequently drifts out of sync with organizational reality. When someone shifts teams or departs, their name remains attached to dozens of resources—sometimes for months—because updating those tags rarely falls into anyone's formal responsibilities. The result is approvals flowing to people who no longer work on a project, and security reviews discovering the problem long after the fact.

The term "last day" carries two meanings in this context. It might mean someone's final day at the company, but more commonly it refers to the last day they held responsibility for a particular system. Yet infrastructure ownership changes receive far less attention than the personnel moves that trigger them. When Marcus was promoted from platform engineering into a data platform role two years ago, his title and badge access got updated immediately. The forty-one environments still tagged with owner: marcus.reyes@company.com did not. Eight months later, an approval request for one of those environments landed in his queue. He clicked Approve despite not having touched the project in nearly a year, because reviewing and rejecting it would have taken more effort than simply authorizing it.

This pattern reflects systemic inattention rather than individual negligence. The infrastructure layer receives minimal scrutiny during promotions, lateral moves, or departures. Fixing it does not require overhauling organizational processes. Instead, three straightforward components—a database query, an access control policy, and one additional step in existing team transition procedures—can keep ownership tags synchronized with actual responsibilities.

1 – The query that flags an owner who's gone quiet

Maintaining accurate owner tags requires mapping email addresses to IAM usernames, then cross-referencing those tags against activity logs. AWS provides this data through the aws_iam_user_last_accessed_details table, which tracks when credentials last authenticated. This query identifies resources whose owners have not accessed anything in ninety days:

SELECT r.resource_id, r.owner, MAX(la.last_authenticated) AS owner_last_active
FROM (
  SELECT resource_id, tags ->> 'owner' AS owner
  FROM aws_ec2_instances
  WHERE tags ->> 'owner' IS NOT NULL
) r
JOIN aws_iam_user_last_accessed_details la
  ON la.user_name = split_part(r.owner, '@', 1)
GROUP BY r.resource_id, r.owner
HAVING MAX(la.last_authenticated) < now() - interval '90 days'
ORDER BY owner_last_active;

Entra ID maintains equivalent audit logs under a different structure. The userPrincipalName field already corresponds to the credential itself, eliminating the need to parse email addresses. A virtual machine's owner tag joins directly to the identity that performed the login:

SELECT r.resource_id, r.owner, MAX(s.created_date_time) AS owner_last_active
FROM (
  SELECT resource_id, tags ->> 'owner' AS owner
  FROM azure_compute_virtual_machines
  WHERE tags ->> 'owner' IS NOT NULL
) r
JOIN entraid_auditlogs_signins s
  ON s.user_principal_name = r.owner
GROUP BY r.resource_id, r.owner
HAVING MAX(s.created_date_time) < now() - interval '90 days'
ORDER BY owner_last_active;

GCP's approach differs because its IAM layer does not maintain equivalent access logs. The nearest available signal comes from the directory service that issued the identity—typically Google Workspace's own login records for the person behind the label:

SELECT r.resource_id, r.owner, MAX(w.last_login_time) AS owner_last_active
FROM (
  SELECT resource_id, labels ->> 'owner' AS owner
  FROM gcp_compute_instances
  WHERE labels ->> 'owner' IS NOT NULL
) r
JOIN googleworkspace_users w
  ON w.primary_email = r.owner
GROUP BY r.resource_id, r.owner
HAVING MAX(w.last_login_time) < now() - interval '90 days'
ORDER BY owner_last_active;

Ninety days of silence from someone responsible for a resource isn't definitive proof they moved, but it's the kind of sign worth fifteen minutes of someone's time instead of eight months of nobody's.

2 – The policy that prevents orphaned environments

Queries identify problems that have already developed. To prevent future ownership gaps, a simple tag is insufficient. Ownership should live within whatever role-based access system already governs the resource—an actual role assignment in cloud IAM, a Kubernetes RoleBinding, or a custom role in an infrastructure-as-code platform. This approach ensures a policy engine can enforce ownership rather than relying on a text string someone entered into a tags field. A basic Rego policy accomplishes this:

package ownership

# METADATA
# title: require an active owner
# description: A resource can't lose its last assigned Owner without a replacement.
deny[format(rego.metadata.rule())] {
    count(input.resource.roles.owner) == 0
}

format(meta) := meta.description

Implementation varies depending on existing infrastructure. A custom Terraform pipeline requires an OPA server integrated into the CI process, storage for role bindings that the policy reads, and ongoing synchronization as the organization chart evolves. Platforms like env zero eliminate this overhead: Custom Roles already cascade across organizational, project, and environment levels, so the policy evaluates against role assignments the platform was already tracking on its standard drift-check schedule. When wired in this way, attempting to remove someone's Owner role during offboarding or transfer without assigning a replacement fails immediately rather than waiting for someone to notice months later.

3 – The step every transfer checklist is missing

Most teams maintain some process for removing someone from a project—an offboarding checklist, a Slack message to IT, or similar. Few of these processes ask what that person still owns. Before revoking access, run the query from Section 1 against the person's name and send the results to their manager or team lead for reassignment. Complete the reassignment before access revocation. Avoid leaving it for someone to discover later.

Reassign first, then revoke. Don't leave it for someone to hopefully notice later.

Why this keeps happening

Departures dominate attention because they feel conclusive. Internal moves receive far less scrutiny, despite being arguably more frequent: nearly a third of roles were filled internally in 2024, an increase from the prior year. No offboarding checklist triggers because nobody left the company; yet someone is no longer the appropriate owner, even if they technically retain access. This mirrors a related problem: ensuring every resource has an owner in the first place. That earlier discussion focused on discovery. This one addresses what happens when owners change roles—an occurrence more common than someone's final day at the company.

Org charts will keep changing. Ownership needs to keep up.

These measures will not reduce the frequency of reorganizations. Internal moves are typically beneficial. What must change is whether ownership updates track team reassignments instead of remaining attached to an old position for the next year. A resource does not care who previously owned it; it only needs to know who owns it now.

Source: The New Stack · Reporting supplemented by The Silicon Ledger staff.