---
title: "Keep no long-lived access keys · Agent Wranglers"
url: https://agentwranglers.se/playbook/infrastructure/identity-and-access/no-long-lived-keys
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep no long-lived access keys

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Identity and access](https://agentwranglers.se/playbook/infrastructure/identity-and-access)
- Rule: Use short-lived credentials for every person, pipeline and service. Delete every static access key, and alert when a new one appears.
- How: People get temporary credentials through single sign-on. Pipelines use [OIDC federation](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/oidc-for-ci). Services use the [identity of the machine](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/workload-identity). Where a static key cannot be avoided, such as for an old third-party tool, scope it to one action and rotate it within 90 days. In Google Cloud, enforce the organization policy `iam.disableServiceAccountKeyCreation`.
- Check: The script below lists no active key, apart from documented exceptions younger than 90 days. Create a test key in a sandbox account, and the alert arrives within 15 minutes.

Example:

```python
import boto3
from datetime import datetime, timedelta, timezone

MAX_KEY_AGE = timedelta(days=90)
iam = boto3.client("iam")
now = datetime.now(timezone.utc)
for page in iam.get_paginator("list_users").paginate():
    for user in page["Users"]:
        for key in iam.list_access_keys(UserName=user["UserName"])["AccessKeyMetadata"]:
            if key["Status"] == "Active":
                too_old = now - key["CreateDate"] > MAX_KEY_AGE
                print(f"{user['UserName']} {key['AccessKeyId']} {'TOO OLD' if too_old else 'active'}")
```

```js
import { IAMClient, ListAccessKeysCommand, paginateListUsers } from '@aws-sdk/client-iam';

const MAX_KEY_AGE_MS = 90 * 24 * 60 * 60 * 1000;
const iam = new IAMClient({});
for await (const page of paginateListUsers({ client: iam }, {})) {
  for (const user of page.Users) {
    const { AccessKeyMetadata: keys } = await iam.send(new ListAccessKeysCommand({ UserName: user.UserName }));
    for (const key of keys.filter(k => k.Status === 'Active')) {
      const isTooOld = Date.now() - key.CreateDate.getTime() > MAX_KEY_AGE_MS;
      console.log(user.UserName, key.AccessKeyId, isTooOld ? 'TOO OLD' : 'active');
    }
  }
}
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/identity-and-access/no-long-lived-keys`.

- Previous: [Sign people in through single sign-on](https://agentwranglers.se/playbook/infrastructure/identity-and-access/single-sign-on-for-people)
- Next: [Give every role the least it needs](https://agentwranglers.se/playbook/infrastructure/identity-and-access/least-privilege-roles)
- [Identity and access](https://agentwranglers.se/playbook/infrastructure/identity-and-access)
