The access problem single sign-on solves
The usual cloud access story goes like this. Early on, each engineer gets an IAM user with a password and access keys. Keys end up in dotfiles, shell history and the odd Slack message. MFA is on for some people. When someone leaves, their IAM user is removed, probably, if somebody remembers. With five accounts it becomes five sets of users to maintain.
Single sign-on replaces this with one identity per person, short-lived credentials and central offboarding. It is a core part of our ClickOps and cloud setup service, and it pairs with the root account hardening work, because once people sign in through SSO nobody should need the root user day to day.
What good looks like
- Every human signs in through the company identity provider, with MFA enforced there.
- No IAM users with access keys exist for people.
- Access is assigned to groups, which map to a small, documented set of permission sets.
- Production write access is held by few people, for limited sessions.
- Leavers lose cloud access when their account is disabled in the identity provider, without a separate cleanup task.
- Permission sets and assignments are defined in code and reviewed.
How it works on AWS
Identity Center lives in the management account (or a delegated administrator account) and is enabled at the organisation level. It integrates with Organizations, so accounts you add later can receive assignments straight away.
Identity source
You can use the built-in directory, which is fine for a team of a few people, or connect an external provider. For Google Workspace, Okta or Entra ID, SAML handles sign-in and SCIM handles automatic provisioning of users and groups. We prefer SCIM so that group membership in the identity provider is the source of truth.
Permission sets and assignments
A permission set is defined once and instantiated as a role in each account where it is assigned. In Terraform:
data "aws_ssoadmin_instances" "this" {}
resource "aws_ssoadmin_permission_set" "developer" {
name = "Developer"
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
session_duration = "PT4H"
}
resource "aws_ssoadmin_managed_policy_attachment" "developer_power" {
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
managed_policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
permission_set_arn = aws_ssoadmin_permission_set.developer.arn
}
resource "aws_ssoadmin_account_assignment" "dev_group_nonprod" {
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
permission_set_arn = aws_ssoadmin_permission_set.developer.arn
principal_id = var.developers_group_id
principal_type = "GROUP"
target_id = var.nonprod_account_id
target_type = "AWS_ACCOUNT"
}
PowerUserAccess is a convenient starting point but still broad. We usually replace it with a custom policy once usage is understood, and combine it with guardrails from service control policies so that even a permissive role cannot disable logging or leave approved regions.
Daily use
Engineers configure a named profile once with aws configure sso, then run:
aws sso login --profile acme-dev
aws sts get-caller-identity --profile acme-dev
Credentials are cached and expire. Tools that read the AWS profile, including Terraform, the AWS SDKs and kubectl via aws eks get-token, pick them up without any key files. We test this with your actual workflows before declaring it done.
Machines are different
SSO is for people. Pipelines should use OIDC federation, where the CI provider presents a signed token and assumes a role scoped to a repository and branch. No stored secret exists to leak. This is covered further in our CI/CD pipeline work.
How it works on Azure
Azure access runs through Microsoft Entra ID. Users and groups already exist there, so the task is mostly structure: groups assigned Azure RBAC roles at management group or subscription scope, conditional access policies requiring MFA and compliant devices where licences allow, and Privileged Identity Management so that Owner and Contributor are activated just in time rather than held permanently. Guest and contractor access is handled with time-limited access reviews.
Decisions and trade-offs
Built-in directory or external provider? The built-in directory is simple but creates a second place to manage people. If you already run Google Workspace or Entra ID, connect it.
Session length. Longer sessions are convenient and riskier. Four to eight hours is common for developers, shorter for administrator sets.
Many fine-grained sets or few broad ones? Too many permission sets are unmanageable; too few push everyone to admin. We start with four or five and add only when a real need appears.
When not to bother. A one-person company with a single account and a hardware-key-protected login can defer this. The moment a second person needs access, set it up, because retrofitting is harder than starting.
Designing the groups and sets
The part that takes judgement is deciding what the groups should be. We begin by listing what people actually do, not job titles. A typical small platform has these:
- Platform administrators: full rights in infrastructure and security accounts, a short session, and approval-based access to production.
- Developers: broad rights in non-production, read-only and log access in production.
- Read-only and audit: view access across all accounts, which suits auditors, finance and managers.
- Billing: access to cost tools without the ability to change resources.
- Break-glass: a locked, alarmed path used only in emergencies.
Contractors get their own group with an expiry date, so access is not left running after the engagement. We also decide where just-in-time elevation is worth the effort. For production, a developer might request a temporary administrator session with a recorded reason, rather than holding standing rights. That adds a small delay and removes a large risk, a trade most growing companies accept once they have customer data to protect.
Common failure modes
- Admin for everyone. Convenience wins during the first outage and never reverses.
- Group sprawl. Hundreds of overlapping groups nobody understands.
- No break-glass plan. If the identity provider has an outage, you cannot reach AWS. We document an emergency IAM role with hardware MFA, sealed and alarmed.
- Forgotten service accounts. Old access keys stay active because no human owns them.
Delivery and handover
Configuration is delivered as Terraform, with a table showing which group holds which permission set in which account. We run a short session for your engineers on CLI login and troubleshooting, and agree how access requests and reviews will work. The wider process is in team onboarding and access.
How to tell it is working
- No active IAM user access keys belong to humans.
- Disabling a person in the identity provider removes cloud access the same day.
- Your list of who can write to production fits on one screen.
- CloudTrail shows federated role sessions, not long-lived users.
If you want an independent look at how your team currently signs in, book a consultation.