Blog "Zero Standing Privileges: Why Service Accounts Don't Need Permanent Access"

"Zero Standing Privileges: Why Service Accounts Don't Need Permanent Access"

Zero Standing Privileges: Why Service Accounts Don't Need Permanent Access

Here's the uncomfortable truth about service accounts: in most organizations, every service account, API key, and machine identity has permanent, always-on access to whatever systems it can reach.

The CI/CD pipeline has write access to production. The third-party log aggregator has read access to every application. The API key provisioned for a legacy integration has admin permissions on the database. They all sit there, active, 24/7, whether they need that access today or not.

This isn't because anyone intended it. It's because the default state is "access granted, until someone revokes it" — and revocation rarely happens.

Zero Standing Privileges (ZSP) inverts that model. Access is granted on-demand, scoped to the specific task, and automatically expires. The service account that needs to run a backup has permissions for exactly the duration of the backup. The agent that deploys code has access only to the repositories it's deploying. Nothing is "always on" unless it has a permanent business reason to be.


The Default State Is the Problem

Every service account you'll ever provision comes with the same implicit contract: grant it the permissions it needs to do its job, and that access stays active indefinitely.

This is the wrong default.

Here's why:

Permission creep. A service account gets created with the minimum scope needed to work. But then requirements change. The integration needs to write to a second system. The deployment pipeline needs to also handle database migrations. The agent needs read access to archives. Each change adds permissions. Almost none of them ever get removed. Over time, every service account becomes overscoped relative to what it actually needs today.

The "it might break something" problem. If you revoke a service account's admin access because it only uses one permission, how do you know something else isn't silently depending on it? The safe play is to leave it alone. So it stays. This is how service accounts end up with permissions they've been unused for three years.

No temporal boundaries. A service account provisioned in 2022 has no concept of "this is outdated." It has no expiration date. It doesn't expire on its own. It requires someone to explicitly decide to revoke it — which happens either never, or when an incident forces the issue.

Absence of urgency. Active threats get attention. A service account that hasn't been used in six months but still has admin access looks like a low-priority cleanup task. It's not. It's a vulnerability sitting on your network, and it will stay there.

The result: the access surface of service accounts in most organizations is orders of magnitude larger than it needs to be. And because nobody is constantly monitoring that surface, unauthorized or unnecessary access can hide indefinitely.


Why Permanent Access Is the Real Risk

The permanent-access model creates three categories of security and operational risk:

Lateral movement. A compromised service account with permanent, broad access becomes a pivot point in your environment. An attacker who steals a database credential that once had write access but only currently needs read access has more surface than they should. An agent credential provisioned with admin-level access to five systems but only using one becomes a blast radius waiting to happen.

Credential theft compounding. When credentials are stolen, the blast radius is proportional to the access they grant. A stolen API key that has admin permissions — even if those are only "needed sometimes" — is a critical incident. A credential that's scoped to read-only access for a specific resource is a severity-2 issue. Narrower permissions mean narrower blast radii.

Compliance drift. Your access review says every service account is scoped to the minimum permissions needed for its role. But "role" doesn't account for temporal needs. A service account that needs admin access for quarterly maintenance and read-only access 99% of the time is being over-scoped for 99% of its operational life. Your audit evidence doesn't distinguish between "this service account always needs these permissions" and "this one needs these permissions right now, today."

Unintended dependencies. Because revocation is friction, legacy systems stay connected to service accounts they may or may not actually depend on. A microservice that reads from a database through a service account that also grants write access to a different schema doesn't need the write permission. But changing it to read-only requires coordinating with ops to verify nothing breaks. It's easier to leave it. So it stays overprivileged.


What Zero Standing Privileges Actually Means

Zero Standing Privileges is the inversion of the default:

Access is granted on-demand, not pre-provisioned. Instead of a service account having permissions constantly, it requests access when it needs it. The request is evaluated (does this account actually need this access right now?), approved if appropriate, and granted for a specific, limited time window.

Permissions are time-boxed. Access automatically expires. Not through a cleanup workflow or a manual revocation. The credential simply stops working after the authorized duration. A deployment pipeline gets credentials that are valid for 15 minutes. A database backup script gets credentials valid for the duration of the backup, plus five minutes. When time expires, access disappears.

Scope is minimal and explicit. Each access grant specifies exactly what can be accessed: this repository, not all of them; this schema, not the whole database; read-only, not write. There's no ambient "the system has admin access and we might need it sometime." Access is what it declares itself to be.

Denial is the default. If an access request doesn't have an explicit approval from a policy, it fails. You don't get permission because nobody said no — you get it because a policy says yes. An agent that requests write access to a production database gets denied unless there's an explicit policy authorizing agents to have that access.

Every access grant leaves an audit trail. When a service account accesses a resource under ZSP, the system records why it had access at that moment. Not just "this service account has access to X," but "on Tuesday at 3 PM, this service account was granted 15-minute write access to the production database because a deployment pipeline requested it to run a migration." The audit is not a spreadsheet snapshot. It's a historical record of every access grant and its justification.

This is different from traditional access control. It's not "this service account has permissions." It's "right now, at this moment, this service account is permitted to do this thing because an approval policy authorized it."


How Just-In-Time Access Works for Machine Identities

For human users, just-in-time (JIT) access is well-understood: a security engineer requests elevated access to debug an incident, gets temporary credentials, solves the problem, and the access expires. The same pattern works for service accounts, but the mechanics are different.

Programmatic approval workflows. Instead of a human clicking "approve," the decision is made by a policy engine. The approval logic can be: "CI/CD deployments can have 15-minute write access to production after code review approval" or "scheduled backup jobs can have 30-minute read access to all databases between 2-4 AM."

Ephemeral credentials. Instead of a service account having a permanent API key or password, JIT systems issue short-lived credentials — temporary tokens, temporary IAM roles, temporary SSH certificates — that are valid only for the authorized window. The API key used to deploy code at 3 PM isn't the same one used at 3:15 PM.

Automated expiration. The credential simply stops working when time expires. There's no cleanup workflow, no manual revocation. The token self-destructs. If the deployment finishes in 10 minutes but the credential is valid for 15, the extra 5 minutes just expire unused.

Fallback to permanent minimal access. Some service accounts legitimately need always-on access for continuous workloads (a monitoring agent, a cron job that runs every hour). ZSP doesn't eliminate that access — it reduces it. The monitoring agent gets the exact permissions needed for monitoring, nothing more. The cron gets the minimum scope for its scheduled task. Permanent access is rare, scoped tightly, and audited.


The Compliance Win

Your next SOC2 audit requires documented access reviews. Zero Standing Privileges gives you something auditors rarely see: evidence that you actually enforce least privilege.

Auditors see:

You're not just documenting that access reviews happened. You're documenting that you enforce least privilege in real time. That's the difference between audit theater and actual security.

Continuous enforcement vs. quarterly review theater. Human access reviews happen quarterly because quarterly is the audit requirement. But the environment changes daily. Service account permissions can drift in weeks. Zero Standing Privileges makes every access grant a mini-review: does this account actually need this right now? If not, the request fails.

The audit evidence is live, not a spreadsheet from three weeks ago that may no longer reflect reality.


The Operational Benefit

Security is the obvious win. But ZSP also solves a stubborn operational problem:

Fewer credentials to rotate. If 80% of your service accounts don't have standing permissions, you have 80% fewer permanent credentials that need rotation workflows. The accounts that do have standing access get rotated aggressively (30 days, not 90). The JIT credentials are single-use or auto-expiring.

Simpler offboarding. When an AI agent, integration, or service gets decommissioned, there are no lingering permanent credentials to hunt down and revoke. Standing access disappeared already (because the service is gone). Any temporary credentials in flight expire on schedule.

Faster incident response. If a service account is compromised, its standing access is already minimal. Any JIT credentials it was using have already expired. The blast radius is small and getting smaller as time passes.

Clearer ownership. Every access grant is tied to a policy, and every policy specifies an owner. "CI/CD deployments can have write access" is owned by the DevOps team. "Backup scripts can read databases" is owned by ops. When something goes wrong, ownership is clear. When policy needs to change, you know who to talk to.


How This Relates to Service Account Sprawl

Posts in this cluster build toward this solution:

Non-Human Identities: The Access Governance Blind Spot established that service accounts are completely ungoverned in most organizations — they outnumber human accounts, but governance platforms pretend they don't exist.

Service Account Sprawl: The NHI Problem Auditors Miss showed that the sprawl is compounding: without governance, service accounts accumulate faster than any cleanup process can clear them, and audit frameworks miss them entirely.

Zero Standing Privileges is the solution framework. You don't just inventory the sprawl — you apply a different governance model. Temporary access by default. Permanent access only when justified. Every grant audited, every decision policy-driven.

This is how you break the compounding problem. Not by doing more reviews or asking more questions in your audit. By inverting the default. Access that doesn't exist until it's explicitly authorized is access that can't sprawl.


Making It Real

Zero Standing Privileges sounds great in theory. Here's what it means in practice:

For CI/CD: Your deployment pipeline doesn't have permanent write access to repositories. When a deployment is triggered, a policy engine grants 15-minute write access to the specific repo being deployed. The deployment runs, the access expires. On the next deployment, new credentials. The blast radius of a compromised pipeline is 15 minutes of activity, not permanent access.

For scheduled tasks: Your database backup job runs every night. It doesn't have standing read access to the database. At 2 AM, the policy engine issues temporary credentials valid for one hour. The backup runs in 23 minutes. The credentials expire. The next night, new credentials. If someone steals the credentials, they're useless 37 minutes later.

For integrations: Your third-party log aggregator doesn't have perpetual read access to your CloudWatch logs. When it needs data, it requests access under a policy that says "log aggregators can have 4-hour read windows, max three per day." Access is granted, expires in 4 hours. The integration is documented, audited, time-limited.

For agents: Your AI agent doesn't have ambient admin access to your repositories. When it needs to deploy code, it requests specific access to specific repositories with a policy justification. Access is granted for the duration of the deployment. The agent can't use the same credentials five minutes later for something else.

This is automated. It's not friction-adding. It's the permission model itself.


Getting There From Here

You don't flip a switch and get Zero Standing Privileges tomorrow. The migration looks like:

1. Inventory and classify. Enumerate all service accounts. Classify which ones actually need standing access (continuous workloads) and which ones are candidates for JIT (batch jobs, integrations, ad-hoc tasks).

2. Define policies. For each class, define the approval policy. "Deployment pipelines get 15-minute write access after code review." "Backup jobs get read access for one hour." Build the policies into your access governance system.

3. Start with JIT for new accounts. New service accounts, API keys, and agent credentials go through JIT by default. Permanent access requires explicit justification and policy approval.

4. Migrate existing accounts. Over time, convert standing-access accounts to JIT. Start with the easiest ones (integrations with clear, repeatable access patterns). Build automation for the workflow.

5. Reduce standing-access scope. For the accounts that genuinely need standing access, audit and reduce their permissions to the absolute minimum. If a service account has admin access but only uses one permission in practice, remove the admin access.

This isn't a "rip out everything" migration. It's a gradual shift in the default.


The Audit Story Your Next Audit Needs

Your SOC2 2 auditor will ask: "How do you ensure that service account access is appropriate and current?"

You'll show them Zero Standing Privileges:

That's not theater. That's actual, enforced least privilege.


Ready to enforce zero standing privileges across your service accounts and machine identities? Book a demo with Vigil to see how to eliminate permanent access and replace it with just-in-time, time-boxed permissions that audit themselves.

See it in action

Vigil's live dashboard shows real access flags across a 10-user org — right now.

Explore Live Dashboard → Book a Demo