SSO and Identity Center

Identity and access management are critical foundations of any AWS environment. In the Lab, I immediately implement AWS Identity Center (SSO) to give secure, scalable, and centralised control over access to all accounts in the organisation.



Why Identity Center?

Setting up SSO lets us:

  • Centrally manage who has access to what
  • Assign fine-grained permissions across environments
  • Automate CLI and tool-based access using secure tokens
  • Support team workflows like DevOps, networking, and data with the right level of control

This isn’t just about security. Proper configuration allows us to move quickly and safely by using the right tools for the job. In an enterprise environment, where you're operating in a growing environment and onboarding new users, it's paramount to have a clean identity model that makes it easy to scale and maintain.



How it works

LabFoundation_IdentityCenter


With this setup:

  • Manage users by group
  • Assign broad permissions using managed policies
  • Define per-account overrides via custom IAM policies
  • You get automatic token vending for CLI and tool access

It scales cleanly and works for everything from sandbox accounts with near-full access to production accounts requiring strict control.



How it's built

In this example, we have the root account, where IAM Identity Center is configured, and a second account, let's call it 'Sandbox,' where we are provisioning access for users to work.

We define two layers of configuration using YAML files in our public repo:


1. Root Account – Org-Level Configuration

This file sets up:

  • Groups like DevOpsTeam, NetworkAdmins, DataEngineers
  • Permission Sets that include AWS-managed policies (e.g., AmazonEC2FullAccess)
  • Custom policy hooks that will enable per-account policies that give us control based on the account usage, e.g. nonprod vs. production

This gives us a consistent, organisation-wide way to manage access while allowing exceptions for specific accounts.


1AWSTemplateFormatVersion: "2010-09-09"
2Metadata:
3 Author: "ChrisMail"
4Description: "Created during the initial formation of the Labs environment"
5
6Parameters:
7 SsoInstanceId:
8 Type: String
9 Description: "The SSO instance id - looks like ssoins-a1a1a1a1a1a1a1a1a"
10
11 SsoIdentityStoreId:
12 Type: String
13 Description: "The SSO identity store - looks like d-a1a1a1a1a1"
14
15 WorkloadName:
16 Type: String
17 Default: "Labs"
18 Description: "The workload name"
19
20Resources:
21 ######################################################################################################
22 ################## Labs Network Administrator
23 SSOGroupNetworkAdmin:
24 Type: AWS::IdentityStore::Group
25 Properties:
26 Description: !Sub "${WorkloadName} Network Administratiors"
27 DisplayName: !Sub "${WorkloadName}.NetworkAdministrator"
28 IdentityStoreId: !Sub "${SsoIdentityStoreId}"
29
30 SSOPermissionSetNetworkAdmin:
31 Type: "AWS::SSO::PermissionSet"
32 Properties:
33 Name: !Sub "${WorkloadName}.NetworkAdministrator"
34 Description: "Provides access to the AWS VPC and Cloudformation services"
35 SessionDuration: "PT1H"
36 InstanceArn: !Sub "arn:${AWS::Partition}:sso:::instance/${SsoInstanceId}"
37 ManagedPolicies:
38 - !Sub "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess"
39 - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonVPCFullAccess"
40 - !Sub "arn:${AWS::Partition}:iam::aws:policy/AWSCloudFormationFullAccess"
41 - !Sub "arn:${AWS::Partition}:iam::aws:policy/AWSResourceAccessManagerFullAccess"
42 CustomerManagedPolicyReferences:
43 - Name: !Sub "${WorkloadName}.NetworkAdministrator"
44 Path: "/SSO/"
45
46 IAMPolicyNetworkAdministrator:
47 Type: "AWS::IAM::ManagedPolicy"
48 Properties:
49 ManagedPolicyName: !Sub "${WorkloadName}.NetworkAdministrator"
50 Path: "/SSO/"
51 PolicyDocument:
52 Version: "2012-10-17"
53 Statement:
54 - Sid: "BenignPermForCreate"
55 Effect: Allow
56 Action:
57 - iam:GetPolicy
58 Resource:
59 - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/SSO/*
60
61 ######################################################################################################
62 ################## ScyneLabs DevOpsTeam
63 SSOGroupDevOpsEngineer:
64 Type: AWS::IdentityStore::Group
65 Properties:
66 Description: !Sub "${WorkloadName} DevOps Team"
67 DisplayName: !Sub "${WorkloadName}.DevOpsEngineer"
68 IdentityStoreId: !Sub "${SsoIdentityStoreId}"
69
70 SSOPermissionSetDevOpsEngineer:
71 Type: "AWS::SSO::PermissionSet"
72 Properties:
73 Name: !Sub "${WorkloadName}.DevOpsEngineer"
74 Description: "Provides access to the AWS VPC and Cloudformation services"
75 SessionDuration: "PT1H"
76 InstanceArn: !Sub "arn:${AWS::Partition}:sso:::instance/${SsoInstanceId}"
77 ManagedPolicies:
78 - !Sub "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess"
79 CustomerManagedPolicyReferences:
80 - Name: !Sub "${WorkloadName}.DevOpsEngineer"
81 Path: "/SSO/"
82
83 IAMPolicyDevOpsEngineer:
84 Type: "AWS::IAM::ManagedPolicy"
85 Properties:
86 ManagedPolicyName: !Sub "${WorkloadName}.DevOpsEngineer"
87 Path: "/SSO/"
88 PolicyDocument:
89 Version: "2012-10-17"
90 Statement:
91 - Sid: "BenignPermForCreate"
92 Effect: Allow
93 Action:
94 - iam:GetPolicy
95 Resource:
96 - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/SSO/*"
97
98 ######################################################################################################
99 ################## ScyneLabs BillingTeam
100 SSOGroupBilling:
101 Type: AWS::IdentityStore::Group
102 Properties:
103 Description: !Sub "${WorkloadName} Billing"
104 DisplayName: !Sub "${WorkloadName}.Billing"
105 IdentityStoreId: !Sub "${SsoIdentityStoreId}"
106
107 SSOPermissionSetBilling:
108 Type: "AWS::SSO::PermissionSet"
109 Properties:
110 Name: !Sub "${WorkloadName}.Billing"
111 Description: "Provides access to the AWS billing and admin"
112 SessionDuration: "PT1H"
113 InstanceArn: !Sub "arn:${AWS::Partition}:sso:::instance/${SsoInstanceId}"
114 ManagedPolicies:
115 - !Sub "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess"
116 - !Sub "arn:${AWS::Partition}:iam::aws:policy/job-function/Billing"
117 CustomerManagedPolicyReferences:
118 - Name: !Sub "${WorkloadName}.Billing"
119 Path: "/SSO/"
120
121 IAMPolicyBilling:
122 Type: "AWS::IAM::ManagedPolicy"
123 Properties:
124 ManagedPolicyName: !Sub "${WorkloadName}.Billing"
125 Path: "/SSO/"
126 PolicyDocument:
127 Version: "2012-10-17"
128 Statement:
129 - Sid: "BenignPermForCreate"
130 Effect: Allow
131 Action:
132 - iam:GetPolicy
133 Resource:
134 - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/SSO/*
135
136
137 ######################################################################################################
138 ################## ScyneLabs ReadOnly - Good for things like former2 and other third party tools
139 SSOReadOnly:
140 Type: AWS::IdentityStore::Group
141 Properties:
142 Description: !Sub "${WorkloadName} ReadOnly"
143 DisplayName: !Sub "${WorkloadName}.ReadOnly"
144 IdentityStoreId: !Sub "${SsoIdentityStoreId}"


2. Sandbox Account – Account-Specific Policies

We define any custom policies used by the org-level setup in each account.

Note: The custom policy name and path must exactly match what’s declared in the root account file.


1AWSTemplateFormatVersion: "2010-09-09"
2Metadata:
3 Author: "ChrisMail"
4Description: "Created during the initial formation of the Labs environment"
5
6Parameters:
7 WorkloadName:
8 Type: String
9 Default: "Labs"
10 Description: "The workload name"
11
12Resources:
13 ######################################################################################################
14 ################## DevOps Engineer
15 IAMPolicyLabsDevOpsEngineer:
16 Type: "AWS::IAM::ManagedPolicy"
17 Properties:
18 ManagedPolicyName: !Sub "${WorkloadName}.DevOpsEngineer"
19 Path: "/SSO/"
20 PolicyDocument:
21 Version: "2012-10-17"
22 Statement:
23 - Sid: "FoundationProtection"
24 Effect: Deny
25 Action:
26 - iam:create*
27 - iam:update*
28 - iam:delete*
29 - lambda:*
30 - cloudformation:create*
31 - cloudformation:delete*
32 - cloudformation:update*
33 Resource:
34 - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/SSO/*"
35 - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:aws-controltower-*"
36 - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/StackSet-AWSControlTower*"
37 - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/SSO-*"
38 - Sid: "DevOpsEngineer"
39 Effect: Allow
40 Action:
41 - SomeApiAccessTo
42 Resource: "SomeNamedResources"
43
44 ######################################################################################################
45 ################## DevOps Engineer
46 IAMPolicyLabsNetworkAdmin:
47 Type: "AWS::IAM::ManagedPolicy"
48 Properties:
49 ManagedPolicyName: !Sub "${WorkloadName}.NetworkAdministrator"
50 Path: "/SSO/"
51 PolicyDocument:
52 Version: "2012-10-17"
53 Statement:
54 - Sid: "FoundationProtection"
55 Effect: Deny
56 Action:
57 - iam:create*
58 - iam:update*
59 - iam:delete*
60 - lambda:*
61 - cloudformation:create*
62 - cloudformation:delete*
63 - cloudformation:update*
64 Resource:
65 - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/SSO/*"
66 - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:aws-controltower-*"
67 - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/StackSet-AWSControlTower*"
68 - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/SSO-*"
69 - Sid: "VpcAdmin"
70 Effect: Allow
71 Action:
72 - SomeApiAccessTo
73 Resource: "SomeNamedResources"
74


3. Account Assignments – Hooking It All Together

Once groups and permission sets are defined, we attach accounts to the groups by:

  • Selecting which permission set the group should use in that account
  • Letting AWS Identity Center do the magic of provisioning roles, trust relationships, and session access

This is where the environment-level granularity comes in:

  • The same group (DevOpsTeam) might get admin access in NonProd, but read-only or limited custom access in Prod.


4. How to Use the CLI with SSO

Once Identity Center is set up, using the AWS CLI becomes secure and straightforward - no more juggling long-lived access keys or copy and pasting from the portal.


Step 1: Configure Your Profile

Add a profile to your ~/.aws/config file like this but with the details for your environment:

1[default]
2output = json
3region = ap-southeast-2
4
5[sso-session labsso]
6sso_start_url = https://your-sso-portal.awsapps.com/start
7sso_region = ap-southeast-2
8sso_registration_scopes = sso:account:access
9
10[profile Sandbox_DevOpsEngineer]
11sso_session = labsso
12sso_account_id = 123456789123
13sso_role_name = Labs.DevOpsEngineer
14
15[profile Sandbox_NetworkAdministrator]
16sso_session = labsso
17sso_account_id = 123456789123
18sso_role_name = Labs.NetworkAdministrator


Step 2: Authenticate with SSO

1aws sso login --sso-session labsso


Step 3: Use the CLI Normally

1aws s3 ls --profile "Sandbox_DevOpsEngineer"