A long-lived access key is a password that never expires. It ends up in a repo, a CI pipeline, a developer laptop, a config file. It leaks once and stays valid forever.
IAM's better idea was to stop issuing them. A role is a set of permissions nothing owns — something a service, a function or a person temporarily becomes. Assume it and you receive credentials that expire in an hour. The leak now has a clock on it, and rotation is automatic because nothing was ever stored.
EC2 instances and Lambda functions pick their role up from the environment, so no key is written down anywhere at all.
Two rules carry the rest. Grant the verb, not the service: s3:GetObject on one bucket prefix instead of s3:* on everything. And remember that an explicit deny overrides any allow, from anywhere — an organization-level deny beats an account policy and a role policy both saying yes.
The safest secret is the one that was never created, and expires if it was.
