RizTech Academy logo
RizTech Academy
Account FoundationsLesson 3 of 435 min

Human and machine access without long-lived keys

The previous lesson said to prefer roles and temporary credentials over long-lived keys. This lesson makes that concrete: how do humans and machines actually get into AWS without access keys sitting around waiting to leak? The answer is different for people (single sign-on) and for services (roles attached to the compute), and getting both right removes the largest category of AWS security incidents. This lesson is human and machine access without long-lived keys.

The problem with access keys

An IAM access key is a long-lived secret (an access key ID and a secret access key). It is the classic way to authenticate to AWS from the CLI or an SDK — and the classic way to get breached, because:

  • It does not expire. Once created, it works until someone explicitly deletes it. A key leaked today can be used months from now.
  • It gets committed to Git. Developers paste keys into config files, .envs, and scripts, and one gets pushed to a repository — where bots scanning public (and leaked private) repos find and abuse it within minutes. This is one of the most common real AWS breaches.
  • It is copied around. Keys end up in laptops, CI configs, and shared docs, multiplying the chances of a leak and making rotation painful.

So the goal is to eliminate long-lived keys wherever possible, replacing them with identities that get short-lived, automatically-expiring credentials. Humans and machines get there by different routes.

Humans: single sign-on with IAM Identity Center

People should not have IAM users with access keys. Instead they sign in through single sign-on (SSO), using AWS IAM Identity Center (formerly AWS SSO):

  • Each person has one identity (in Identity Center, or federated from your existing identity provider — Google Workspace, Okta, Entra ID). They log in once, with MFA.
  • They are granted access to specific accounts and roles (permission sets) — e.g. "read-only in production, admin in development".
  • When they need the CLI, aws sso login opens a browser sign-in and gives them temporary credentials for the chosen account and role, expiring after a few hours. Nothing long-lived is stored.

The everyday experience:

aws sso login --profile my-dev-admin       # browser sign-in, MFA; gets temporary credentials
aws s3 ls --profile my-dev-admin            # use them; they expire automatically

This gives you central control (grant and revoke people's access in one place, with MFA enforced), an audit trail of who assumed what, and — crucially — no access keys to leak, because each session's credentials expire on their own. Federating from an existing identity provider means people use their normal company login, and removing someone's access is one action in the identity provider. SSO is the standard way humans access AWS now, and it is a large security upgrade over IAM users.

Machines: roles attached to compute

Applications and services also must authenticate to AWS — an app reading from S3, a pipeline deploying to EKS — and they too should hold no keys. The mechanism is assigning a role to the compute, so it receives temporary credentials automatically:

  • EC2 instances get an instance profile (a role). The AWS SDK on the instance automatically retrieves and refreshes temporary credentials from the instance metadata — the app stores nothing.
  • EKS pods use IAM Roles for Service Accounts (IRSA) (or EKS Pod Identity): a Kubernetes service account is mapped to an IAM role, and pods using it get temporary AWS credentials automatically. Your containerised app gets exactly the AWS permissions it needs, with no keys in the image or environment.
  • Lambda functions have an execution role — the function assumes it and gets temporary credentials for the duration of the invocation.
  • ECS tasks get a task role, the same idea for containers on ECS.

In every case the pattern is identical: you attach a role to the compute, and AWS injects short-lived credentials automatically. The application code just uses the AWS SDK normally and never sees or stores a key. This is how a service gets least-privilege AWS access (the IAM lesson) with zero long-lived secrets — and it is why a well-run AWS environment has almost no access keys at all.

CI/CD: OIDC instead of stored keys

One more machine case worth calling out, because it is a common leak point: your CI/CD pipeline (GitHub Actions) needs to deploy to AWS. The old way stored an access key as a CI secret — a long-lived key sitting in your pipeline config, exactly what you are trying to avoid. The modern way is OIDC federation: GitHub Actions presents a signed token to AWS, AWS trusts GitHub as an identity provider, and the workflow assumes a role to get temporary credentials — no stored AWS key at all.

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy
          aws-region: eu-west-1
      # the job now has temporary AWS credentials — no access key was stored

This closes the last common place a long-lived key hides. Between SSO for humans, roles for services, and OIDC for CI, a mature AWS setup stores essentially no access keys — which is the goal, because the key you do not have cannot leak. (The pipelines module returns to this.)

Check your work

Access keys are long-lived secrets that don't expire, get committed to Git (bots find them in minutes), and get copied around — the top AWS breach. Goal: eliminate long-lived keys, replacing them with short-lived, auto-expiring credentials.

Humans → SSO (IAM Identity Center): one identity (or federated from Google/Okta/Entra) with MFA; granted accounts + roles via permission sets; aws sso login gives temporary credentials that expire. Central grant/revoke, audit trail, no keys to leak. The standard way people access AWS.

Machines → roles on the compute: EC2 instance profile, EKS IRSA/Pod Identity, Lambda execution role, ECS task role — AWS injects short-lived credentials automatically; the app stores nothing and uses the SDK normally. Least privilege with zero secrets.

CI/CD → OIDC: GitHub Actions presents a signed token; AWS trusts it; the workflow assumes a role for temporary credentials — no stored access key (configure-aws-credentials with role-to-assume). Between SSO, roles and OIDC, a mature setup stores essentially no keys.

Practice

  1. List three concrete ways an IAM access key leaks, and why long-lived keys are the biggest AWS security risk.
  2. Explain how a human accesses AWS via IAM Identity Center, including how CLI credentials are obtained and why they are safe.
  3. Explain how an application on EC2 gets AWS permissions with no key stored, and name the mechanism.
  4. Explain IRSA (or Pod Identity) for EKS and what problem it solves for containerised apps.
  5. Explain how OIDC lets a GitHub Actions pipeline deploy to AWS without a stored access key.
  6. Describe what a fully "keyless" AWS setup looks like across humans, services and CI.

Official documentation

Next: billing alarms and tagging, set up on day one.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship