Chapter 09: Federated Identity and Single Sign-On
Learn SAML federation, OIDC, AWS SSO configuration, and enterprise identity management integration
Haiyue
49min
Chapter 9: Federated Identity and Single Sign-On
Learning Objectives
- Understand federated identity concepts and architecture
- Configure SAML 2.0 identity federation
- Implement OpenID Connect (OIDC) integration
- Master AWS SSO (Identity Center) configuration
- Establish enterprise-level single sign-on solutions
Federated Identity Architecture Diagram
🔄 正在渲染 Mermaid 图表...
9.1 Federated Identity Basics
9.1.1 Federated Identity Concepts and Architecture
import boto3
import json
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta
import base64
import urllib.parse
def understand_identity_federation():
"""
Understanding federated identity concepts and architecture
"""
federation_concepts = {
"identity_federation": {
"definition": "Identity federation allows users from external identity providers to access AWS resources without creating IAM users in AWS",
"benefits": [
"Single sign-on experience",
"Centralized identity management",
"Reduced password management complexity",
"Support for enterprise-level identity providers",
"Temporary credentials enhance security"
],
"key_components": [
"Identity Provider (IdP)",
"Service Provider (SP) - AWS",
"Identity Assertion",
"Trust Relationship",
"Role Mapping"
]
},
"federation_types": {
"saml_federation": {
"description": "Enterprise-level federation based on SAML 2.0 protocol",
"use_cases": ["Enterprise Active Directory", "ADFS", "Third-party IdP"],
"workflow": [
"User authenticates at enterprise IdP",
"IdP generates SAML assertion",
"User redirects to AWS SAML endpoint",
"AWS validates assertion and provides temporary credentials",
"User accesses AWS resources with temporary credentials"
]
},
"oidc_federation": {
"description": "Web identity federation based on OpenID Connect",
"use_cases": ["Mobile apps", "Web applications", "Third-party login"],
"workflow": [
"User authenticates through OIDC provider",
"Obtain identity token",
"Call AWS STS with token",
"Obtain temporary AWS credentials",
"Access AWS resources"
]
},
"web_identity_federation": {
"description": "Direct integration with web identity providers",
"use_cases": ["Amazon Cognito", "Google", "Facebook login"],
"workflow": [
"User logs in through Web IdP",
"Obtain identity token",
"Directly use AssumeRoleWithWebIdentity",
"Obtain temporary AWS credentials"
]
}
}
}
# Trust model for federated identity
trust_model = {
"trust_establishment": {
"identity_provider_setup": "Configure identity provider in AWS",
"trust_policy_creation": "Create trust policy to allow IdP to assume roles",
"attribute_mapping": "Map IdP attributes to AWS roles",
"condition_validation": "Validate federation conditions and constraints"
},
"security_considerations": [
"Validate integrity and authenticity of SAML assertions",
"Use appropriate conditions to restrict role access",
"Regularly rotate encryption keys",
"Monitor and audit federated access",
"Implement least privilege principle"
]
}
print("📋 Federated Identity Concepts:")
print(f"Definition: {federation_concepts['identity_federation']['definition']}")
print("\nBenefits:")
for benefit in federation_concepts['identity_federation']['benefits']:
print(f" • {benefit}")
print("\nKey Components:")
for component in federation_concepts['identity_federation']['key_components']:
print(f" • {component}")
print("\n📋 Federation Types:")
for fed_type, details in federation_concepts['federation_types'].items():
print(f"\n{fed_type.replace('_', ' ').title()}:")
print(f" Description: {details['description']}")
print(f" Use Cases: {', '.join(details['use_cases'])}")
return federation_concepts, trust_model
class IdentityFederationManager:
"""Identity Federation Manager"""
def __init__(self):
self.iam = boto3.client('iam')
self.sts = boto3.client('sts')
def create_saml_identity_provider(self, provider_name, metadata_document):
"""Create SAML identity provider"""
try:
response = self.iam.create_saml_provider(
SAMLMetadataDocument=metadata_document,
Name=provider_name,
Tags=[
{'Key': 'Type', 'Value': 'SAML'},
{'Key': 'Purpose', 'Value': 'Federation'},
{'Key': 'CreatedDate', 'Value': datetime.now().strftime('%Y-%m-%d')}
]
)
provider_arn = response['SAMLProviderArn']
print(f"✅ SAML identity provider created successfully: {provider_arn}")
return provider_arn
except Exception as e:
print(f"❌ Failed to create SAML identity provider: {str(e)}")
return None
def create_oidc_identity_provider(self, provider_url, client_ids, thumbprints):
"""Create OIDC identity provider"""
try:
response = self.iam.create_open_id_connect_provider(
Url=provider_url,
ClientIDList=client_ids,
ThumbprintList=thumbprints,
Tags=[
{'Key': 'Type', 'Value': 'OIDC'},
{'Key': 'Purpose', 'Value': 'WebIdentityFederation'}
]
)
provider_arn = response['OpenIDConnectProviderArn']
print(f"✅ OIDC identity provider created successfully: {provider_arn}")
return provider_arn
except Exception as e:
print(f"❌ Failed to create OIDC identity provider: {str(e)}")
return None
# Demonstrate federated identity concepts
federation_concepts, trust_model = understand_identity_federation()
federation_manager = IdentityFederationManager()
print("\n📋 Trust Model Components:")
for component, description in trust_model['trust_establishment'].items():
print(f" {component.replace('_', ' ').title()}: {description}")
9.2 SAML 2.0 Federation Configuration
9.2.1 Enterprise-Level SAML Integration
def configure_saml_federation():
"""
Configure SAML 2.0 federated identity
"""
class SAMLFederationManager:
def __init__(self):
self.iam = boto3.client('iam')
self.sts = boto3.client('sts')
def setup_enterprise_saml_federation(self, config):
"""Setup enterprise SAML federation"""
# 1. Create SAML identity provider
provider_arn = self._create_saml_provider(config)
if not provider_arn:
return None
# 2. Create federated roles
federation_roles = self._create_federation_roles(provider_arn, config)
# 3. Configure attribute mapping
attribute_mapping = self._setup_attribute_mapping(config)
# 4. Generate IdP configuration guide
idp_config = self._generate_idp_configuration(provider_arn, federation_roles)
return {
'provider_arn': provider_arn,
'federation_roles': federation_roles,
'attribute_mapping': attribute_mapping,
'idp_configuration': idp_config
}
def _create_saml_provider(self, config):
"""Create SAML identity provider"""
# Example SAML metadata (simplified version)
metadata_template = f'''<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="{config['entity_id']}">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
{config['signing_certificate']}
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="{config['sso_url']}"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="{config['sso_url']}"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>'''
try:
response = self.iam.create_saml_provider(
SAMLMetadataDocument=metadata_template,
Name=config['provider_name']
)
return response['SAMLProviderArn']
except Exception as e:
print(f"❌ Failed to create SAML provider: {str(e)}")
return None
def _create_federation_roles(self, provider_arn, config):
"""Create federated roles"""
roles = {}
for role_config in config['roles']:
role_name = role_config['name']
# SAML federation trust policy
trust_policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": provider_arn
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
}
# Add additional conditions
if role_config.get('conditions'):
trust_policy['Statement'][0]['Condition'].update(role_config['conditions'])
try:
# Create role
role_response = self.iam.create_role(
RoleName=role_name,
AssumeRolePolicyDocument=json.dumps(trust_policy),
Description=f'SAML federated role: {role_name}',
MaxSessionDuration=role_config.get('session_duration', 3600)
)
role_arn = role_response['Role']['Arn']
# Attach permission policies
for policy in role_config.get('policies', []):
if policy['type'] == 'managed':
self.iam.attach_role_policy(
RoleName=role_name,
PolicyArn=policy['arn']
)
elif policy['type'] == 'inline':
self.iam.put_role_policy(
RoleName=role_name,
PolicyName=policy['name'],
PolicyDocument=json.dumps(policy['document'])
)
roles[role_name] = {
'arn': role_arn,
'saml_role_value': f"{role_arn},{provider_arn}"
}
print(f"✅ Federated role created successfully: {role_name}")
except Exception as e:
print(f"❌ Failed to create federated role {role_name}: {str(e)}")
return roles
def _setup_attribute_mapping(self, config):
"""Setup attribute mapping"""
attribute_mapping = {
"required_attributes": {
"https://aws.amazon.com/SAML/Attributes/Role": {
"description": "AWS roles that users can assume",
"format": "{RoleArn},{ProviderArn}",
"example": "arn:aws:iam::123456789012:role/SAMLRole,arn:aws:iam::123456789012:saml-provider/CompanySAML"
},
"https://aws.amazon.com/SAML/Attributes/RoleSessionName": {
"description": "Role session name",
"format": "string",
"example": "user.email"
}
},
"optional_attributes": {
"https://aws.amazon.com/SAML/Attributes/SessionDuration": {
"description": "Session duration (seconds)",
"format": "number",
"example": "3600"
},
"custom_attributes": config.get('custom_attributes', {})
}
}
return attribute_mapping
def _generate_idp_configuration(self, provider_arn, roles):
"""Generate IdP configuration guide"""
config_guide = {
"aws_saml_endpoint": "https://signin.aws.amazon.com/saml",
"provider_arn": provider_arn,
"attribute_mappings": {
"Role": "https://aws.amazon.com/SAML/Attributes/Role",
"RoleSessionName": "https://aws.amazon.com/SAML/Attributes/RoleSessionName"
},
"role_mappings": {}
}
for role_name, role_info in roles.items():
config_guide["role_mappings"][role_name] = {
"role_arn": role_info['arn'],
"saml_attribute_value": role_info['saml_role_value']
}
return config_guide
def create_adfs_integration(self):
"""Create ADFS integration example"""
adfs_config = {
'provider_name': 'CompanyADFS',
'entity_id': 'https://adfs.company.com/adfs/services/trust',
'sso_url': 'https://adfs.company.com/adfs/ls/',
'signing_certificate': 'MIICertificateDataHere...',
'roles': [
{
'name': 'SAML-Developers',
'policies': [
{
'type': 'managed',
'arn': 'arn:aws:iam::aws:policy/PowerUserAccess'
}
],
'conditions': {
"StringEquals": {
"SAML:Department": "Engineering"
}
},
'session_duration': 14400 # 4 hours
},
{
'name': 'SAML-Administrators',
'policies': [
{
'type': 'managed',
'arn': 'arn:aws:iam::aws:policy/AdministratorAccess'
}
],
'conditions': {
"StringEquals": {
"SAML:Role": "Administrator"
},
"Bool": {
"SAML:MultiFactorAuthPresent": "true"
}
},
'session_duration': 3600 # 1 hour
},
{
'name': 'SAML-ReadOnly',
'policies': [
{
'type': 'managed',
'arn': 'arn:aws:iam::aws:policy/ReadOnlyAccess'
}
]
}
]
}
return self.setup_enterprise_saml_federation(adfs_config)
def test_saml_assertion(self, saml_response):
"""Test SAML assertion"""
try:
# Decode SAML response
decoded_response = base64.b64decode(saml_response)
# Parse SAML assertion (simplified version)
root = ET.fromstring(decoded_response)
# Extract role information
roles = []
for attr in root.iter():
if 'Role' in attr.tag:
roles.append(attr.text)
# Use STS AssumeRoleWithSAML
if roles:
role_parts = roles[0].split(',')
role_arn = role_parts[0]
provider_arn = role_parts[1]
response = self.sts.assume_role_with_saml(
RoleArn=role_arn,
PrincipalArn=provider_arn,
SAMLAssertion=saml_response
)
print("✅ SAML assertion validated successfully")
return response['Credentials']
except Exception as e:
print(f"❌ SAML assertion test failed: {str(e)}")
return None
return SAMLFederationManager()
# Demonstrate SAML federation configuration
saml_manager = configure_saml_federation()
# Create ADFS integration
print("🔧 Configuring Enterprise ADFS Integration:")
# adfs_integration = saml_manager.create_adfs_integration()
print("📋 ADFS Integration Configuration Steps:")
print(" 1. ✅ Create SAML identity provider")
print(" 2. ✅ Configure federated roles (Developer, Administrator, Read-only)")
print(" 3. ✅ Setup attribute mapping")
print(" 4. ✅ Generate IdP configuration guide")
9.3 OpenID Connect (OIDC) Integration
9.3.1 Web Identity Federation
def configure_oidc_federation():
"""
Configure OpenID Connect federated identity
"""
class OIDCFederationManager:
def __init__(self):
self.iam = boto3.client('iam')
self.sts = boto3.client('sts')
def setup_oidc_provider(self, provider_config):
"""Setup OIDC identity provider"""
try:
# Create OIDC provider
response = self.iam.create_open_id_connect_provider(
Url=provider_config['issuer_url'],
ClientIDList=provider_config['client_ids'],
ThumbprintList=provider_config['thumbprints'],
Tags=[
{'Key': 'Provider', 'Value': provider_config['name']},
{'Key': 'Type', 'Value': 'OIDC'}
]
)
provider_arn = response['OpenIDConnectProviderArn']
print(f"✅ OIDC provider created successfully: {provider_arn}")
# Create federated roles
roles = self._create_oidc_roles(provider_arn, provider_config)
return {
'provider_arn': provider_arn,
'roles': roles,
'client_config': self._generate_client_config(provider_arn, roles)
}
except Exception as e:
print(f"❌ Failed to create OIDC provider: {str(e)}")
return None
def _create_oidc_roles(self, provider_arn, config):
"""Create OIDC federated roles"""
roles = {}
for role_config in config['roles']:
role_name = role_config['name']
# Build trust policy
conditions = {
"StringEquals": {
f"{config['issuer_url'].replace('https://', '')}:aud": config['client_ids'][0]
}
}
# Add additional conditions
if role_config.get('conditions'):
conditions.update(role_config['conditions'])
trust_policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": provider_arn
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": conditions
}
]
}
try:
# Create role
role_response = self.iam.create_role(
RoleName=role_name,
AssumeRolePolicyDocument=json.dumps(trust_policy),
Description=f'OIDC federated role: {role_name}'
)
role_arn = role_response['Role']['Arn']
# Attach permission policies
for policy in role_config.get('policies', []):
self._attach_policy_to_role(role_name, policy)
roles[role_name] = role_arn
print(f"✅ OIDC role created successfully: {role_name}")
except Exception as e:
print(f"❌ Failed to create OIDC role {role_name}: {str(e)}")
return roles
def _attach_policy_to_role(self, role_name, policy):
"""Attach policy to role"""
if policy['type'] == 'managed':
self.iam.attach_role_policy(
RoleName=role_name,
PolicyArn=policy['arn']
)
elif policy['type'] == 'inline':
self.iam.put_role_policy(
RoleName=role_name,
PolicyName=policy['name'],
PolicyDocument=json.dumps(policy['document'])
)
def _generate_client_config(self, provider_arn, roles):
"""Generate client configuration"""
return {
'provider_arn': provider_arn,
'available_roles': roles,
'assume_role_endpoint': 'https://sts.amazonaws.com/',
'token_usage': {
'id_token': 'Used for authentication',
'access_token': 'Used for API access',
'refresh_token': 'Used to refresh tokens'
}
}
def setup_google_oidc(self):
"""Setup Google OIDC integration"""
google_config = {
'name': 'GoogleOIDC',
'issuer_url': 'https://accounts.google.com',
'client_ids': ['your-google-client-id.apps.googleusercontent.com'],
'thumbprints': ['1f494a0f3e59b0c9e89de97c9eac32d1ba7c6cfb'], # Google certificate thumbprint
'roles': [
{
'name': 'GoogleUser-S3Access',
'policies': [
{
'type': 'inline',
'name': 'GoogleUserS3Policy',
'document': {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::user-data/${accounts.google.com:sub}/*"
}
]
}
}
],
'conditions': {
"StringLike": {
"accounts.google.com:email": "*@company.com"
}
}
}
]
}
return self.setup_oidc_provider(google_config)
def setup_github_actions_oidc(self):
"""Setup GitHub Actions OIDC integration"""
github_config = {
'name': 'GitHubActions',
'issuer_url': 'https://token.actions.githubusercontent.com',
'client_ids': ['sts.amazonaws.com'],
'thumbprints': ['6938fd4d98bab03faadb97b34396831e3780aea1'],
'roles': [
{
'name': 'GitHubActions-DeployRole',
'policies': [
{
'type': 'inline',
'name': 'GitHubDeployPolicy',
'document': {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::deployment-bucket/*"
},
{
"Effect": "Allow",
"Action": [
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration"
],
"Resource": "arn:aws:lambda:*:*:function:prod-*"
}
]
}
}
],
'conditions': {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:company/repository:*"
}
}
}
]
}
return self.setup_oidc_provider(github_config)
def test_web_identity_token(self, id_token, role_arn, session_name="WebIdentitySession"):
"""Test web identity token"""
try:
response = self.sts.assume_role_with_web_identity(
RoleArn=role_arn,
RoleSessionName=session_name,
WebIdentityToken=id_token
)
credentials = response['Credentials']
print("✅ Web identity token validated successfully")
print(f" AccessKeyId: {credentials['AccessKeyId'][:10]}...")
print(f" Expiration: {credentials['Expiration']}")
return credentials
except Exception as e:
print(f"❌ Web identity token validation failed: {str(e)}")
return None
def generate_client_code_examples(self, provider_config):
"""Generate client code examples"""
examples = {
'javascript': f'''
// JavaScript example - Getting AWS credentials using OIDC token
const AWS = require('aws-sdk');
async function assumeRoleWithWebIdentity(idToken, roleArn) {{
const sts = new AWS.STS();
try {{
const result = await sts.assumeRoleWithWebIdentity({{
RoleArn: roleArn,
RoleSessionName: 'WebSession',
WebIdentityToken: idToken
}}).promise();
// Create AWS service client using temporary credentials
const s3 = new AWS.S3({{
accessKeyId: result.Credentials.AccessKeyId,
secretAccessKey: result.Credentials.SecretAccessKey,
sessionToken: result.Credentials.SessionToken
}});
return s3;
}} catch (error) {{
console.error('AssumeRole failed:', error);
throw error;
}}
}}
''',
'python': f'''
# Python example - Getting AWS credentials using OIDC token
import boto3
def assume_role_with_web_identity(id_token, role_arn):
sts = boto3.client('sts')
try:
response = sts.assume_role_with_web_identity(
RoleArn=role_arn,
RoleSessionName='WebSession',
WebIdentityToken=id_token
)
credentials = response['Credentials']
# Create AWS service client using temporary credentials
s3 = boto3.client(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
return s3
except Exception as e:
print(f"AssumeRole failed: {{e}}")
raise
''',
'github_actions': '''
# GitHub Actions workflow example
name: Deploy to AWS
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActions-DeployRole
role-session-name: GitHubActions-Deploy
aws-region: us-east-1
- name: Deploy to S3
run: |
aws s3 sync ./build s3://deployment-bucket/
'''
}
return examples
return OIDCFederationManager()
# Demonstrate OIDC federation configuration
oidc_manager = configure_oidc_federation()
# Setup different OIDC providers
print("🔧 Configuring OIDC Federated Identity:")
# Google OIDC integration
print("\n📱 Google OIDC Integration:")
# google_integration = oidc_manager.setup_google_oidc()
# GitHub Actions integration
print("\n🔧 GitHub Actions OIDC Integration:")
# github_integration = oidc_manager.setup_github_actions_oidc()
print("\n📋 OIDC Integration Configuration Complete:")
print(" ✅ Google identity provider configured")
print(" ✅ GitHub Actions integration configured")
print(" ✅ Web identity federated roles created")
print(" ✅ Client code examples generated")
# Generate client code examples
code_examples = oidc_manager.generate_client_code_examples({})
print("\n📝 Client integration code generated")
9.4 AWS SSO (Identity Center) Configuration
9.4.1 Enterprise-Level Single Sign-On Solution
def configure_aws_sso():
"""
Configure AWS SSO (Identity Center)
"""
class AWSIdentityCenterManager:
def __init__(self):
self.sso_admin = boto3.client('sso-admin')
self.identitystore = boto3.client('identitystore')
self.organizations = boto3.client('organizations')
def setup_identity_center(self, config):
"""Setup AWS Identity Center"""
try:
# Get SSO instance information
sso_instances = self.sso_admin.list_instances()
if not sso_instances['Instances']:
print("❌ No AWS SSO instance found, please enable AWS SSO first")
return None
sso_instance = sso_instances['Instances'][0]
instance_arn = sso_instance['InstanceArn']
identity_store_id = sso_instance['IdentityStoreId']
print(f"✅ Found SSO instance: {instance_arn}")
# Configure permission sets
permission_sets = self._create_permission_sets(instance_arn, config)
# Configure account assignments
account_assignments = self._setup_account_assignments(
instance_arn, identity_store_id, permission_sets, config
)
# Configure external identity source
if config.get('external_identity_source'):
self._configure_external_identity_source(instance_arn, config)
return {
'instance_arn': instance_arn,
'identity_store_id': identity_store_id,
'permission_sets': permission_sets,
'account_assignments': account_assignments
}
except Exception as e:
print(f"❌ Failed to configure Identity Center: {str(e)}")
return None
def _create_permission_sets(self, instance_arn, config):
"""Create permission sets"""
permission_sets = {}
for ps_config in config['permission_sets']:
try:
# Create permission set
response = self.sso_admin.create_permission_set(
Name=ps_config['name'],
Description=ps_config.get('description', ''),
InstanceArn=instance_arn,
SessionDuration=ps_config.get('session_duration', 'PT1H'), # 1 hour
RelayState=ps_config.get('relay_state', '')
)
ps_arn = response['PermissionSet']['PermissionSetArn']
# Attach AWS managed policies
for policy_arn in ps_config.get('managed_policies', []):
self.sso_admin.attach_managed_policy_to_permission_set(
InstanceArn=instance_arn,
PermissionSetArn=ps_arn,
ManagedPolicyArn=policy_arn
)
# Add inline policy
if ps_config.get('inline_policy'):
self.sso_admin.put_inline_policy_to_permission_set(
InstanceArn=instance_arn,
PermissionSetArn=ps_arn,
InlinePolicy=json.dumps(ps_config['inline_policy'])
)
# Configure permissions boundary
if ps_config.get('permissions_boundary'):
self.sso_admin.put_permissions_boundary_to_permission_set(
InstanceArn=instance_arn,
PermissionSetArn=ps_arn,
PermissionsBoundary={
'ManagedPolicyArn': ps_config['permissions_boundary']
}
)
permission_sets[ps_config['name']] = ps_arn
print(f"✅ Permission set created successfully: {ps_config['name']}")
except Exception as e:
print(f"❌ Failed to create permission set {ps_config['name']}: {str(e)}")
return permission_sets
def _setup_account_assignments(self, instance_arn, identity_store_id, permission_sets, config):
"""Setup account assignments"""
assignments = []
# Get accounts in organization
accounts = self.organizations.list_accounts()
account_map = {acc['Name']: acc['Id'] for acc in accounts['Accounts']}
for assignment in config.get('account_assignments', []):
try:
account_id = account_map.get(assignment['account_name'], assignment.get('account_id'))
ps_arn = permission_sets.get(assignment['permission_set'])
if not account_id or not ps_arn:
print(f"⚠️ Skipping assignment - account or permission set not found: {assignment}")
continue
# Assign to users
if assignment.get('users'):
for user_name in assignment['users']:
user_id = self._get_user_id(identity_store_id, user_name)
if user_id:
self.sso_admin.create_account_assignment(
InstanceArn=instance_arn,
TargetId=account_id,
TargetType='AWS_ACCOUNT',
PermissionSetArn=ps_arn,
PrincipalType='USER',
PrincipalId=user_id
)
assignments.append({
'type': 'user',
'principal': user_name,
'account': account_id,
'permission_set': assignment['permission_set']
})
# Assign to groups
if assignment.get('groups'):
for group_name in assignment['groups']:
group_id = self._get_group_id(identity_store_id, group_name)
if group_id:
self.sso_admin.create_account_assignment(
InstanceArn=instance_arn,
TargetId=account_id,
TargetType='AWS_ACCOUNT',
PermissionSetArn=ps_arn,
PrincipalType='GROUP',
PrincipalId=group_id
)
assignments.append({
'type': 'group',
'principal': group_name,
'account': account_id,
'permission_set': assignment['permission_set']
})
print(f"✅ Account assignment configured successfully: {assignment['permission_set']} -> {assignment['account_name']}")
except Exception as e:
print(f"❌ Account assignment failed: {str(e)}")
return assignments
def _get_user_id(self, identity_store_id, user_name):
"""Get user ID"""
try:
response = self.identitystore.list_users(
IdentityStoreId=identity_store_id,
Filters=[
{
'AttributePath': 'UserName',
'AttributeValue': user_name
}
]
)
if response['Users']:
return response['Users'][0]['UserId']
except Exception as e:
print(f"⚠️ Failed to get user ID for {user_name}: {str(e)}")
return None
def _get_group_id(self, identity_store_id, group_name):
"""Get group ID"""
try:
response = self.identitystore.list_groups(
IdentityStoreId=identity_store_id,
Filters=[
{
'AttributePath': 'DisplayName',
'AttributeValue': group_name
}
]
)
if response['Groups']:
return response['Groups'][0]['GroupId']
except Exception as e:
print(f"⚠️ Failed to get group ID for {group_name}: {str(e)}")
return None
def _configure_external_identity_source(self, instance_arn, config):
"""Configure external identity source"""
external_config = config['external_identity_source']
if external_config['type'] == 'ActiveDirectory':
# Configure AD connector
print("🔗 Configuring Active Directory connector...")
# Actual implementation requires calling appropriate APIs
elif external_config['type'] == 'SAML':
# Configure SAML identity source
print("🔗 Configuring SAML identity source...")
# Actual implementation requires calling appropriate APIs
def create_enterprise_sso_config(self):
"""Create enterprise SSO configuration example"""
config = {
'permission_sets': [
{
'name': 'AdministratorAccess',
'description': 'Full administrator access',
'session_duration': 'PT4H', # 4 hours
'managed_policies': [
'arn:aws:iam::aws:policy/AdministratorAccess'
],
'permissions_boundary': 'arn:aws:iam::123456789012:policy/AdminPermissionsBoundary'
},
{
'name': 'DeveloperAccess',
'description': 'Developer access permissions',
'session_duration': 'PT8H', # 8 hours
'managed_policies': [
'arn:aws:iam::aws:policy/PowerUserAccess'
],
'inline_policy': {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"organizations:*"
],
"Resource": "*"
}
]
}
},
{
'name': 'ReadOnlyAccess',
'description': 'Read-only access permissions',
'session_duration': 'PT12H', # 12 hours
'managed_policies': [
'arn:aws:iam::aws:policy/ReadOnlyAccess'
]
},
{
'name': 'DatabaseAdmin',
'description': 'Database administrator permissions',
'session_duration': 'PT4H',
'inline_policy': {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:*",
"dynamodb:*",
"elasticache:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::database-backups/*"
}
]
}
}
],
'account_assignments': [
{
'account_name': 'Production',
'permission_set': 'AdministratorAccess',
'groups': ['Administrators']
},
{
'account_name': 'Production',
'permission_set': 'DatabaseAdmin',
'groups': ['DatabaseAdmins']
},
{
'account_name': 'Development',
'permission_set': 'DeveloperAccess',
'groups': ['Developers']
},
{
'account_name': 'Development',
'permission_set': 'ReadOnlyAccess',
'users': ['john.doe', 'jane.smith']
}
],
'external_identity_source': {
'type': 'ActiveDirectory',
'domain': 'company.com',
'directory_id': 'd-1234567890'
}
}
return self.setup_identity_center(config)
return AWSIdentityCenterManager()
# Demonstrate AWS SSO configuration
sso_manager = configure_aws_sso()
print("🔧 Configuring AWS Identity Center:")
# enterprise_sso = sso_manager.create_enterprise_sso_config()
print("\n📋 Identity Center Configuration Complete:")
print(" ✅ Permission sets created (Administrator, Developer, Read-only, Database Administrator)")
print(" ✅ Account assignments configured")
print(" ✅ External identity source configured")
print(" ✅ Session management configured")
print("\n🔗 User Access Flow:")
print(" 1. User accesses SSO portal")
print(" 2. Authenticates through enterprise identity provider")
print(" 3. Selects AWS account and role to access")
print(" 4. Obtains temporary credentials to access AWS resources")
Summary
This chapter introduced complete solutions for AWS federated identity and single sign-on:
- Federated Identity Basics: Understanding federated identity concepts, architecture, and trust models
- SAML 2.0 Integration: Enterprise-level SAML federation configuration and ADFS integration
- OIDC Integration: Web identity federation and GitHub Actions integration
- AWS SSO: Identity Center configuration and enterprise-level single sign-on
Through federated identity, you can achieve:
- Unified enterprise identity management
- Secure single sign-on experience
- Flexible role mapping and permission management
- Seamless integration with existing identity infrastructure
In the next chapter, we will learn about IAM access analysis and auditing mechanisms.