2026-02-03

Non‑Human Identity & Automation: Securing Workloads, Pipelines, and Tooling at Scale

A practical, enterprise-focused guide to non-human identity risk and modern control patterns: workload identity, short-lived credentials, CI/CD federation with OIDC, secrets management, and governance at scale.

Modern IAM programs are increasingly shaped by identities that are not people: workloads, services, CI/CD pipelines, automation tooling, and (in some environments) early agentic systems.

These non‑human principals often have broad permissions, operate continuously, and authenticate using credentials that are easy to copy and difficult to govern at scale. The result is a familiar pattern in incidents: a single compromised pipeline token, service principal, or long‑lived secret becomes a high‑impact entry point.

The scale of this shift is significant. In many cloud-native environments, non-human identities outnumber human identities by 10:1 or more. A single Kubernetes cluster can have hundreds of service accounts. A typical enterprise GitHub organization might have dozens of deployment tokens and hundreds of OAuth app integrations. Each one is an authentication boundary that attackers understand better than most defenders.

This post is an enterprise‑neutral guide to the problem and the approaches that consistently work in real environments.


1) What "non‑human identity" includes (and why it matters)

Non‑human identity typically covers:

  • Workloads: Kubernetes pods, Docker containers, AWS Lambda functions, Cloud Run services, Azure Container Apps
  • Services: service-to-service calls via mTLS, internal APIs, microservices with service mesh identity (Istio, Linkerd)
  • Pipelines: GitHub Actions runners, GitLab CI jobs, Jenkins agents, CircleCI executors, Argo Workflows
  • Automation: Terraform Cloud/Enterprise, Atlantis, Ansible Tower, Crossplane controllers, GitOps operators (Flux, ArgoCD)
  • Cloud principals: AWS IAM roles, Azure service principals and managed identities, GCP service accounts, Kubernetes ServiceAccounts
  • Credentials: API keys (Stripe, Twilio, Datadog), bearer tokens, X.509 certificates, SSH keys, signing keys (cosign, Sigstore)

These identities matter because they often have one or more of the following properties:

PropertyWhy it matters
High privilege"Can deploy to production," "can read customer PII," "can rotate secrets"
High frequencyA pipeline might authenticate 1,000+ times/day; a human logs in once
Low visibilityNo MFA prompt, no "unusual login" alert, no user to call
Hard-to-assign ownershipCreated by a dev who left two years ago, used by three teams
Long-lived by defaultMany API keys and service account keys never expire unless you configure otherwise

2) Common failure modes (what breaks first)

Long‑lived secrets become infrastructure

Many organizations still rely on:

  • Static API keys with no expiration (AWS access keys created in 2019 still in use)
  • Long‑lived client secrets for OAuth apps (90-day or no expiry)
  • Shared deploy tokens used by multiple pipelines, repos, or teams
  • Credentials in CI variables without clear ownership or rotation schedule
  • Certificates that are not rotated operationally (3-year certs "because renewal is painful")

Real-world pattern: A credential scanning tool finds a Slack webhook URL, a Datadog API key, and an AWS access key in a public repo. The AWS key was last rotated 847 days ago. Whose is it? Unclear. Is it still used? Unknown. Can you revoke it safely? You'll find out in production.

Even when secrets are stored "securely" in HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault, the core issue remains: a copied credential is still a working credential until it expires or is revoked. If the credential lifetime is 90 days and your detection takes 30 days, the attacker has 60 days of access.

"Automation" becomes an ungoverned super‑admin

A single pipeline identity with broad permissions is convenient and hard to unwind:

  • The terraform-deploy service account that can create any resource in your cloud account
  • The github-actions IAM role with AdministratorAccess "because we kept hitting permission errors"
  • The Jenkins credential that has root SSH access to every server

Over time these become critical dependencies. Implementing least privilege feels risky ("what if we break the deploy?") until a compromise forces the change under pressure.

Example: In 2024, the CircleCI breach exposed environment variables and secrets stored in CircleCI's platform. Organizations with overprivileged pipeline credentials faced significantly higher blast radius than those who had scoped credentials per-project and environment.

Revocation is unclear or too slow

In many environments, it is not obvious how to quickly disable a compromised non‑human identity without breaking production:

  • Which services depend on this credential?
  • What happens if we rotate it right now at 3 AM?
  • Is there a runbook? Who has access to execute it?
  • Can we revoke without a deploy, or does the new credential require a code change?

That uncertainty increases dwell time. If revocation takes 4 hours of "figuring out dependencies," the attacker has 4 extra hours.


3) Target-state controls (what good looks like)

A practical target state usually converges on the same patterns:

A) Prefer workload identity over distributed secrets

Use identity that is attested by the platform (cluster, cloud provider, runtime) instead of distributing shared keys.

Platform-native options:

PlatformWorkload Identity Mechanism
AWS EKSIAM Roles for Service Accounts (IRSA) or EKS Pod Identity
GCP GKEWorkload Identity Federation
Azure AKSAzure AD Workload Identity
Kubernetes (any)SPIFFE/SPIRE with workload attestation
GitHub ActionsOIDC federation to AWS/GCP/Azure (no static secrets)
GitLab CIOIDC claims for cloud provider authentication

How it works (simplified): Instead of injecting a static credential into your workload, the platform attests "this is pod X in namespace Y running on node Z." That attestation is exchanged for a short-lived credential (typically via OIDC token exchange). The credential might live for 1 hour. There's nothing to steal that's useful tomorrow.

The intent is simple: credentials are not copied around; identity is asserted by the runtime and verified cryptographically.

For deeper implementation details: SPIFFE and SPIRE Architecture

B) Make credentials short‑lived by default

Short lifetimes reduce the usefulness of theft and force better automation:

Credential TypeTypical Long-LivedTarget Short-Lived
Access tokens90 days or no expiry1 hour or less
Refresh tokens1 year24 hours with rotation
Service account keysNever expiresDon't use; prefer workload identity
Certificates1-3 years24-72 hours (with automated renewal)
CI/CD secrets"Until someone rotates"Generated per-run via OIDC

Concrete mechanisms:

  • Federated issuance during a job/run: GitHub Actions → OIDC → aws sts assume-role-with-web-identity → 1-hour credentials
  • Dynamic secrets from Vault: App requests database credentials; Vault creates a Postgres role with 1-hour TTL; credentials auto-expire
  • Token exchange: Service A exchanges its identity token for a scoped token to call Service B

For implementation patterns: Dynamic Secrets and Credential Issuance

C) Scope identity to the smallest meaningful unit

Move from "one deploy identity" to identities scoped by:

Bad: One deploy-bot with access to all repos and all environments

Better:

repo: payments-service
environment: production
action: deploy
scope: write:deployments, read:packages

Practical scoping dimensions:

  • Repository/project: Each repo gets its own pipeline identity
  • Environment: Separate credentials for dev/staging/production
  • Stage: Build jobs can't deploy; deploy jobs can't access source
  • Operation: Read-only scanning identity vs. read-write deploy identity
  • Time: Credentials valid only during the job/workflow execution

This makes containment possible. Compromised payments-service-staging-deploy can't touch auth-service-production.

D) Treat ownership and inventory as first‑class requirements

You need to answer these questions quickly during an incident:

QuestionYou need
What non‑human identities exist?Automated inventory (cloud provider APIs, Kubernetes RBAC audit, secrets manager inventory)
Who owns each one?Metadata tags, ownership in CMDB/ServiceNow, CODEOWNERS equivalent for infrastructure
What systems can it access?Permission mapping (IAM policies, Kubernetes RBAC, network policies)
How does it authenticate?Auth method inventory (OIDC, mTLS, API key, SSH key)
How fast can it be revoked?Tested runbook, not a doc that says "contact the platform team"
Where is the audit trail?CloudTrail, Kubernetes audit logs, application logs, SIEM correlation

Without this, non‑human identity becomes "shadow IAM"—identities that exist but aren't governed.

Tools that help: Astrix, Oasis Security, Clutch Security, Silverfort (for NHI visibility); cloud-native tools like AWS IAM Access Analyzer, GCP Policy Analyzer; and CSPM platforms with identity coverage.

E) Ensure auditability ties back to engineering artifacts

For non‑human activity, "user: service-account-47" isn't useful. Audit needs to map to:

  • Which repo/commit: github.com/acme/payments@abc123
  • Which pipeline run: GitHub Actions run #4521 or Jenkins build #789
  • Which deployment artifact: payments-service:v2.3.1 image digest
  • Which approval: Link to the PR, the deployment approval in PagerDuty/Opsgenie, or the change ticket

Implementation: Pass trace context (OpenTelemetry trace ID, deployment ID, commit SHA) through your auth tokens as claims or headers. Your cloud provider logs, application logs, and SIEM can then correlate "this S3 access" with "that specific deploy."

This is how you make automation governable without slowing delivery.


4) A practical adoption sequence (how to start)

A sequence that works in many enterprises:

Phase 1: Inventory and classify (weeks 1-4)

  • Enumerate cloud IAM principals (service accounts, roles, service principals)
  • Enumerate Kubernetes ServiceAccounts and their RBAC bindings
  • Inventory CI/CD credentials (GitHub secrets, GitLab variables, Jenkins credentials)
  • List OAuth apps and API keys in SaaS platforms (Slack, Salesforce, etc.)
  • Assign ownership where known; flag orphans

Phase 2: Stop the bleeding (weeks 2-8, overlapping)

  • Enable secret scanning in repos (GitHub Advanced Security, GitGuardian, TruffleHog)
  • Rotate high-risk credentials (AWS root keys, production database passwords, admin tokens)
  • Eliminate shared deploy tokens; create per-repo credentials as interim step
  • Set expiration on credentials that currently have none

Phase 3: Federate CI/CD identity (months 2-4)

  • Implement OIDC federation for GitHub Actions → AWS/GCP/Azure
  • Remove static cloud credentials from CI/CD secrets
  • Scope federated roles by repo and environment
  • Test and validate with non-production first

Phase 4: Implement workload identity (months 3-6)

  • Enable IRSA/Workload Identity/Pod Identity for Kubernetes workloads
  • Migrate applications from mounted secrets to federated identity
  • Implement dynamic secrets from Vault/cloud secret managers where static credentials remain

Phase 5: Add governance (ongoing)

  • Document ownership for all non-human identities
  • Build revocation runbooks and test them quarterly
  • Implement lifecycle management (creation approval, periodic review, decommissioning)
  • Set up alerting for anomalous NHI behavior (unusual API calls, impossible travel, privilege escalation)

5) Learn IAM track: Non‑Human Identity and Automation

If you want a structured set of topics focused on the real systems that run production environments, start here:

Non‑Human Identity and Automation →

Topics include: