Chapter 05: Permissions Boundaries and Service Control Policies
9/1/25About 24 min
Chapter 05: Permissions Boundaries and Service Control Policies
Learning Objectives
- Understand the concept and working mechanism of permissions boundaries
- Master the configuration and management of service control policies (SCPs)
- Learn the policy inheritance mechanism of AWS Organizations
- Implement enterprise-level permission governance strategies
- Master best practices for permissions boundaries and SCPs
Permission Governance Architecture Diagram
5.1 Permissions Boundary Basics
5.1.1 Concept and Working Principle of Permissions Boundaries
Core Concepts of Permissions Boundaries
A permissions boundary is an advanced feature used to set the maximum permissions for an IAM entity (user or role). It does not grant permissions but defines the upper limit of permissions.
- Working Mechanism: The intersection of the permissions boundary and the identity policy
- Scope: Applies only to users and roles, not to groups
- Policy Type: Must use a managed policy (cannot use an inline policy)
import boto3
import json
from datetime import datetime, timedelta
def understand_permissions_boundary():
"""
Understand the working principle of permissions boundaries
"""
# Example of the working mechanism of a permissions boundary
working_mechanism = {
"concept": "A permissions boundary defines the maximum permission scope",
"formula": "Effective permissions = Identity policy permissions ∩ Permissions boundary permissions",
"key_points": [
"A permissions boundary does not grant permissions, it only limits them",
"Both the identity policy and the permissions boundary must allow the action",
"A deny from either side results in a final deny",
"Used to implement permission delegation and governance"
]
}
# Example scenarios for permissions boundaries
scenarios = {
"developer_boundary": {
"description": "Limit the maximum permissions of developers",
"identity_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*", # The identity policy allows all actions
"Resource": "*"
}
]
},
"permissions_boundary": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*",
"ec2:Describe*",
"logs:*"
], # The permissions boundary only allows specific services
"Resource": "*"
}
]
},
"effective_permissions": [
"s3:*", "dynamodb:*", "lambda:*",
"ec2:Describe*", "logs:*"
],
"explanation": "Although the identity policy allows all permissions, the permissions boundary limits the available services"
},
"service_restriction": {
"description": "Prevent access to high-risk services",
"identity_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"ec2:*",
"iam:ListUsers"
],
"Resource": "*"
}
]
},
"permissions_boundary": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
},
{
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:AttachRolePolicy",
"organizations:*"
],
"Resource": "*"
}
]
},
"effective_permissions": [
"s3:*", "ec2:*", "iam:ListUsers"
],
"blocked_actions": [
"iam:CreateRole", "iam:DeleteRole",
"iam:AttachRolePolicy", "organizations:*"
],
"explanation": "The deny statement in the permissions boundary prevents high-risk IAM operations"
}
}
print("📋 Permissions boundary working mechanism:")
print(f"Concept: {working_mechanism['concept']}")
print(f"Formula: {working_mechanism['formula']}")
print("\nKey points:")
for point in working_mechanism['key_points']:
print(f" • {point}")
print("\n📝 Permissions boundary scenario examples:")
for scenario_name, scenario_info in scenarios.items():
print(f"\n{scenario_name}:")
print(f" Description: {scenario_info['description']}")
print(f" Effective permissions: {', '.join(scenario_info['effective_permissions'])}")
if 'blocked_actions' in scenario_info:
print(f" Blocked actions: {', '.join(scenario_info['blocked_actions'])}")
print(f" Explanation: {scenario_info['explanation']}")
return working_mechanism, scenarios
def create_permissions_boundary_manager():
"""
Create a permissions boundary manager
"""
class PermissionsBoundaryManager:
def __init__(self):
self.iam = boto3.client('iam')
def create_boundary_policy(self, policy_name, policy_document, description=""):
"""Create a permissions boundary policy"""
try:
response = self.iam.create_policy(
PolicyName=policy_name,
PolicyDocument=json.dumps(policy_document),
Description=description or f"Permissions boundary policy: {policy_name}",
Tags=[
{
'Key': 'Type',
'Value': 'PermissionsBoundary'
},
{
'Key': 'CreatedBy',
'Value': 'PermissionsBoundaryManager'
}
]
)
policy_arn = response['Policy']['Arn']
print(f"✅ Permissions boundary policy created successfully: {policy_arn}")
return policy_arn
except Exception as e:
print(f"❌ Failed to create permissions boundary policy: {str(e)}")
return None
def set_user_boundary(self, username, boundary_policy_arn):
"""Set a permissions boundary for a user"""
try:
self.iam.put_user_permissions_boundary(
UserName=username,
PermissionsBoundary=boundary_policy_arn
)
print(f"✅ Permissions boundary for user {username} set successfully")
return True
except Exception as e:
print(f"❌ Failed to set user permissions boundary: {str(e)}")
return False
def set_role_boundary(self, role_name, boundary_policy_arn):
"""Set a permissions boundary for a role"""
try:
self.iam.put_role_permissions_boundary(
RoleName=role_name,
PermissionsBoundary=boundary_policy_arn
)
print(f"✅ Permissions boundary for role {role_name} set successfully")
return True
except Exception as e:
print(f"❌ Failed to set role permissions boundary: {str(e)}")
return False
def remove_user_boundary(self, username):
"""Remove a user's permissions boundary"""
try:
self.iam.delete_user_permissions_boundary(UserName=username)
print(f"✅ Permissions boundary for user {username} removed")
return True
except Exception as e:
print(f"❌ Failed to remove user permissions boundary: {str(e)}")
return False
def remove_role_boundary(self, role_name):
"""Remove a role's permissions boundary"""
try:
self.iam.delete_role_permissions_boundary(RoleName=role_name)
print(f"✅ Permissions boundary for role {role_name} removed")
return True
except Exception as e:
print(f"❌ Failed to remove role permissions boundary: {str(e)}")
return False
def get_entity_boundary(self, entity_type, entity_name):
"""Get an entity's permissions boundary information"""
try:
if entity_type == 'user':
response = self.iam.get_user(UserName=entity_name)
entity_info = response['User']
elif entity_type == 'role':
response = self.iam.get_role(RoleName=entity_name)
entity_info = response['Role']
else:
raise ValueError("Entity type must be 'user' or 'role'")
boundary_info = {
'entity_name': entity_name,
'entity_type': entity_type,
'has_boundary': 'PermissionsBoundary' in entity_info,
'boundary_arn': entity_info.get('PermissionsBoundary', {}).get('PermissionsBoundaryArn'),
'boundary_type': entity_info.get('PermissionsBoundary', {}).get('PermissionsBoundaryType')
}
print(f"📋 {entity_type.title()} {entity_name} permissions boundary information:")
print(f" Has permissions boundary: {boundary_info['has_boundary']}")
if boundary_info['has_boundary']:
print(f" Permissions boundary ARN: {boundary_info['boundary_arn']}")
print(f" Permissions boundary type: {boundary_info['boundary_type']}")
return boundary_info
except Exception as e:
print(f"❌ Failed to get permissions boundary information: {str(e)}")
return None
def simulate_permissions_with_boundary(self, entity_arn, actions, resources,
boundary_policy_arn=None):
"""Simulate permission evaluation with a permissions boundary"""
try:
simulate_params = {
'PolicySourceArn': entity_arn,
'ActionNames': actions,
'ResourceArns': resources
}
# Add the permissions boundary to the simulation parameters if specified
if boundary_policy_arn:
simulate_params['PermissionsBoundaryPolicyInputList'] = [
boundary_policy_arn
]
response = self.iam.simulate_principal_policy(**simulate_params)
simulation_results = []
for result in response['EvaluationResults']:
simulation_results.append({
'action': result['EvalActionName'],
'resource': result['EvalResourceName'],
'decision': result['EvalDecision'],
'matched_statements': len(result.get('MatchedStatements', [])),
'missing_context_values': result.get('MissingContextValues', [])
})
print("📊 Permission simulation results:")
for result in simulation_results:
status = "✅" if result['decision'] == 'allowed' else "❌"
print(f" {status} {result['action']} on {result['resource']}: {result['decision']}")
return simulation_results
except Exception as e:
print(f"❌ Permission simulation failed: {str(e)}")
return []
return PermissionsBoundaryManager()
# Demonstrate permissions boundary concepts
mechanism, scenarios = understand_permissions_boundary()
# Create a permissions boundary manager
boundary_manager = create_permissions_boundary_manager()
5.1.2 Permissions Boundary Policy Templates
def create_boundary_policy_templates():
"""
Create common permissions boundary policy templates
"""
templates = {
"developer_boundary": {
"name": "DeveloperPermissionsBoundary",
"description": "Permissions boundary for developers, restricting access to production environments and sensitive services",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDevelopmentServices",
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*",
"apigateway:*",
"cloudformation:*",
"ec2:Describe*",
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"logs:*",
"cloudwatch:*",
"sns:*",
"sqs:*"
],
"Resource": "*"
},
{
"Sid": "DenyProductionResources",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": ["us-east-1"] # Deny production region
}
}
},
{
"Sid": "DenyHighRiskActions",
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:CreateUser",
"iam:DeleteUser",
"organizations:*",
"account:*",
"billing:*",
"support:*"
],
"Resource": "*"
},
{
"Sid": "DenyExpensiveInstanceTypes",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAnyValue:StringNotEquals": {
"ec2:InstanceType": [
"t2.micro",
"t2.small",
"t2.medium",
"t3.micro",
"t3.small",
"t3.medium"
]
}
}
}
]
}
},
"read_only_boundary": {
"name": "ReadOnlyPermissionsBoundary",
"description": "Read-only permissions boundary, allowing only read and describe operations",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadOnlyActions",
"Effect": "Allow",
"Action": [
"*:Get*",
"*:List*",
"*:Describe*",
"*:Read*",
"s3:GetObject*",
"s3:ListBucket*"
],
"Resource": "*"
},
{
"Sid": "DenyWriteActions",
"Effect": "Deny",
"Action": [
"*:Create*",
"*:Delete*",
"*:Update*",
"*:Put*",
"*:Modify*",
"*:Set*",
"*:Add*",
"*:Remove*",
"*:Attach*",
"*:Detach*"
],
"Resource": "*"
}
]
}
},
"service_specific_boundary": {
"name": "S3DynamoDBOnlyBoundary",
"description": "Permissions boundary that only allows access to S3 and DynamoDB services",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3DynamoDBOnly",
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*"
],
"Resource": "*"
},
{
"Sid": "AllowBasicAWSServices",
"Effect": "Allow",
"Action": [
"sts:GetCallerIdentity",
"sts:AssumeRole",
"iam:GetUser",
"iam:GetRole",
"iam:ListAttachedUserPolicies",
"iam:ListAttachedRolePolicies"
],
"Resource": "*"
}
]
}
},
"time_based_boundary": {
"name": "BusinessHoursBoundary",
"description": "Permissions boundary that only allows access during business hours",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDuringBusinessHours",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "08:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "18:00Z"
},
"ForAllValues:StringEquals": {
"aws:RequestedWeekDay": [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday"
]
}
}
},
{
"Sid": "AllowEmergencyAccess",
"Effect": "Allow",
"Action": [
"cloudwatch:*",
"logs:*",
"sns:Publish",
"ec2:Describe*"
],
"Resource": "*"
}
]
}
},
"tag_based_boundary": {
"name": "TagBasedAccessBoundary",
"description": "Tag-based access control permissions boundary",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowTaggedResourceAccess",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Department": "${aws:PrincipalTag/Department}",
"aws:ResourceTag/Project": "${aws:PrincipalTag/Project}"
}
}
},
{
"Sid": "AllowResourceTagging",
"Effect": "Allow",
"Action": [
"ec2:CreateTags",
"s3:PutObjectTagging",
"dynamodb:TagResource"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedTag/Department": "${aws:PrincipalTag/Department}",
"aws:RequestedTag/Project": "${aws:PrincipalTag/Project}"
}
}
},
{
"Sid": "DenyUntaggedResourceCreation",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"s3:CreateBucket",
"dynamodb:CreateTable"
],
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestedTag/Department": "true"
}
}
}
]
}
}
}
print("📋 Permissions boundary policy templates:")
for template_name, template_info in templates.items():
print(f"\n{template_name}:")
print(f" Name: {template_info['name']}")
print(f" Description: {template_info['description']}")
print(f" Number of statements: {len(template_info['policy']['Statement'])}")
return templates
def deploy_boundary_templates():
"""
Deploy permissions boundary templates
"""
templates = create_boundary_policy_templates()
boundary_manager = create_permissions_boundary_manager()
deployed_policies = {}
for template_name, template_info in templates.items():
print(f"\nDeploying template: {template_name}")
# Create the permissions boundary policy
policy_arn = boundary_manager.create_boundary_policy(
policy_name=template_info['name'],
policy_document=template_info['policy'],
description=template_info['description']
)
if policy_arn:
deployed_policies[template_name] = {
'arn': policy_arn,
'name': template_info['name'],
'description': template_info['description']
}
print("\n📋 Deployed permissions boundary policies:")
for template_name, policy_info in deployed_policies.items():
print(f" {template_name}: {policy_info['arn']}")
return deployed_policies
# Create and deploy permissions boundary templates
templates = create_boundary_policy_templates()
# Display details of the developer permissions boundary policy
print("\n📝 Developer permissions boundary policy details:")
dev_boundary = templates['developer_boundary']['policy']
print(json.dumps(dev_boundary, indent=2, ensure_ascii=False))
5.2 Service Control Policies (SCPs)
5.2.1 Basic Concepts of SCPs
def understand_service_control_policies():
"""
Understand the concepts and functions of Service Control Policies (SCPs)
"""
scp_concepts = {
"definition": "Service Control Policies (SCPs) are a governance mechanism in AWS Organizations used to limit the maximum permissions for organizational units (OUs) and accounts",
"key_features": [
"Only limit permissions, do not grant them",
"Apply at the organizational unit and account levels",
"Support an inheritance mechanism, where child units inherit SCPs from parent units",
"Take effect as an intersection with IAM policies",
"The management account is not restricted by SCPs by default"
],
"scp_types": {
"allow_lists": {
"description": "Explicitly list allowed actions",
"behavior": "Only explicitly allowed actions can be performed",
"use_case": "Strictly control environments, such as production"
},
"deny_lists": {
"description": "Explicitly list denied actions",
"behavior": "All actions are allowed except those explicitly denied",
"use_case": "Flexible control, blocking specific high-risk operations"
}
},
"inheritance_model": {
"description": "SCPs support an inheritance mechanism",
"rules": [
"Child OUs inherit all SCPs from their parent OU",
"Accounts inherit all SCPs from their containing OU",
"The intersection of multiple SCPs is taken",
"Any action denied by any SCP is denied"
]
}
}
# Example of an SCP inheritance hierarchy
organization_structure = {
"Root": {
"scp": ["FullAWSAccess"], # Default SCP
"children": {
"Production OU": {
"scp": ["ProductionRestrictions", "NoDeleteProtection"],
"children": {
"Prod Account 1": {"scp": []},
"Prod Account 2": {"scp": ["ExtraSecurityRestrictions"]}
}
},
"Development OU": {
"scp": ["DevelopmentRestrictions"],
"children": {
"Dev Account 1": {"scp": []},
"Dev Account 2": {"scp": ["CostControlSCP"]}
}
},
"Security OU": {
"scp": ["SecurityAuditAccess"],
"children": {
"Security Account": {"scp": []}
}
}
}
}
}
# Interaction between SCPs and IAM policies
policy_interaction = {
"scenario": "A user performs an EC2 action in a production account",
"identity_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*"
}
]
},
"scp_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "ec2:TerminateInstances",
"Resource": "*"
}
]
},
"effective_permissions": [
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances"
# ec2:TerminateInstances is denied by the SCP
],
"explanation": "Although the identity policy allows all EC2 actions, the SCP denies the TerminateInstances action"
}
print("📋 Service Control Policy (SCP) concepts:")
print(f"Definition: {scp_concepts['definition']}")
print("\nKey features:")
for feature in scp_concepts['key_features']:
print(f" • {feature}")
print("\nSCP types:")
for scp_type, type_info in scp_concepts['scp_types'].items():
print(f" {scp_type}:")
print(f" Description: {type_info['description']}")
print(f" Behavior: {type_info['behavior']}")
print(f" Use case: {type_info['use_case']}")
print("\nInheritance mechanism rules:")
for rule in scp_concepts['inheritance_model']['rules']:
print(f" • {rule}")
print("\n📝 Policy interaction example:")
print(f"Scenario: {policy_interaction['scenario']}")
print(f"Effective permissions: {', '.join(policy_interaction['effective_permissions'])}")
print(f"Explanation: {policy_interaction['explanation']}")
return scp_concepts, organization_structure, policy_interaction
def create_scp_manager():
"""
Create an SCP manager
"""
class SCPManager:
def __init__(self):
self.organizations = boto3.client('organizations')
def create_scp_policy(self, policy_name, policy_document, description=""):
"""Create an SCP policy"""
try:
response = self.organizations.create_policy(
Name=policy_name,
Description=description or f"Service Control Policy: {policy_name}",
Type='SERVICE_CONTROL_POLICY',
Content=json.dumps(policy_document)
)
policy_id = response['Policy']['PolicySummary']['Id']
policy_arn = response['Policy']['PolicySummary']['Arn']
print(f"✅ SCP policy created successfully:")
print(f" ID: {policy_id}")
print(f" ARN: {policy_arn}")
return {
'policy_id': policy_id,
'policy_arn': policy_arn,
'policy_name': policy_name
}
except Exception as e:
print(f"❌ Failed to create SCP policy: {str(e)}")
return None
def attach_scp_to_target(self, policy_id, target_id):
"""Attach an SCP to a target (OU or account)"""
try:
self.organizations.attach_policy(
PolicyId=policy_id,
TargetId=target_id
)
print(f"✅ SCP policy {policy_id} attached to target {target_id}")
return True
except Exception as e:
print(f"❌ Failed to attach SCP policy: {str(e)}")
return False
def detach_scp_from_target(self, policy_id, target_id):
"""Detach an SCP from a target"""
try:
self.organizations.detach_policy(
PolicyId=policy_id,
TargetId=target_id
)
print(f"✅ SCP policy {policy_id} detached from target {target_id}")
return True
except Exception as e:
print(f"❌ Failed to detach SCP policy: {str(e)}")
return False
def list_organization_structure(self):
"""List the organization structure"""
try:
# Get the root node
response = self.organizations.list_roots()
if not response['Roots']:
print("❌ No organization root found")
return None
root = response['Roots'][0]
print(f"📋 Organization structure:")
print(f"Root node: {root['Name']} ({root['Id']})")
# Recursively get the organization structure
structure = {
'root': root,
'organizational_units': self._get_ous_recursive(root['Id']),
'accounts': []
}
# Get all accounts
accounts_response = self.organizations.list_accounts()
structure['accounts'] = accounts_response['Accounts']
return structure
except Exception as e:
print(f"❌ Failed to get organization structure: {str(e)}")
return None
def _get_ous_recursive(self, parent_id, level=1):
"""Recursively get organizational units"""
try:
response = self.organizations.list_organizational_units_for_parent(
ParentId=parent_id
)
ous = []
indent = " " * level
for ou in response['OrganizationalUnits']:
print(f"{indent}OU: {ou['Name']} ({ou['Id']})")
ou_info = {
'ou': ou,
'children': self._get_ous_recursive(ou['Id'], level + 1),
'accounts': []
}
# Get accounts under the OU
accounts_response = self.organizations.list_accounts_for_parent(
ParentId=ou['Id']
)
for account in accounts_response['Accounts']:
print(f"{indent} Account: {account['Name']} ({account['Id']})")
ou_info['accounts'].append(account)
ous.append(ou_info)
return ous
except Exception as e:
print(f"❌ Failed to get OU information: {str(e)}")
return []
def list_policies_for_target(self, target_id):
"""List all SCP policies for a target"""
try:
response = self.organizations.list_policies_for_target(
TargetId=target_id,
Filter='SERVICE_CONTROL_POLICY'
)
policies = response['Policies']
print(f"📋 SCP policies for target {target_id}:")
for policy in policies:
print(f" Policy: {policy['Name']} ({policy['Id']})")
print(f" Description: {policy['Description']}")
print(f" Type: {policy['Type']}")
return policies
except Exception as e:
print(f"❌ Failed to get target policies: {str(e)}")
return []
def get_effective_policies_for_account(self, account_id):
"""Get the effective SCP policies for an account"""
try:
response = self.organizations.list_policies_for_target(
TargetId=account_id,
Filter='SERVICE_CONTROL_POLICY'
)
direct_policies = response['Policies']
# Get the parent OU path of the account
parent_response = self.organizations.list_parents(
ChildId=account_id
)
inherited_policies = []
for parent in parent_response['Parents']:
parent_policies = self._get_inherited_policies(parent['Id'])
inherited_policies.extend(parent_policies)
all_policies = {
'direct_policies': direct_policies,
'inherited_policies': inherited_policies,
'account_id': account_id
}
print(f"📋 Effective SCP policies for account {account_id}:")
print(f" Directly attached policies: {len(direct_policies)}")
print(f" Inherited policies: {len(inherited_policies)}")
return all_policies
except Exception as e:
print(f"❌ Failed to get effective account policies: {str(e)}")
return None
def _get_inherited_policies(self, ou_id):
"""Get policies inherited from a parent OU"""
inherited = []
try:
# Get policies for the current OU
response = self.organizations.list_policies_for_target(
TargetId=ou_id,
Filter='SERVICE_CONTROL_POLICY'
)
inherited.extend(response['Policies'])
# Recursively get policies from the parent OU
parents_response = self.organizations.list_parents(
ChildId=ou_id
)
for parent in parents_response['Parents']:
if parent['Type'] == 'ORGANIZATIONAL_UNIT':
parent_policies = self._get_inherited_policies(parent['Id'])
inherited.extend(parent_policies)
except Exception as e:
print(f"Warning: Error getting inherited policies: {str(e)}")
return inherited
return SCPManager()
# Demonstrate SCP concepts
scp_concepts, org_structure, policy_interaction = understand_service_control_policies()
# Create an SCP manager
scp_manager = create_scp_manager()
print("\n📝 SCP policy interaction example:")
print("Identity policy ∩ SCP policy = Effective permissions")
print(json.dumps(policy_interaction, indent=2, ensure_ascii=False))
5.2.2 SCP Policy Templates
def create_scp_policy_templates():
"""
Create common SCP policy templates
"""
scp_templates = {
"production_protection_scp": {
"name": "ProductionProtectionSCP",
"description": "Protect production environment resources, prevent accidental deletion and modification",
"type": "deny_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDeletionOfCriticalResources",
"Effect": "Deny",
"Action": [
"rds:DeleteDBInstance",
"rds:DeleteDBCluster",
"s3:DeleteBucket",
"ec2:TerminateInstances",
"dynamodb:DeleteTable",
"lambda:DeleteFunction",
"cloudformation:DeleteStack"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "Production"
}
}
},
{
"Sid": "DenyModificationOfProductionBackups",
"Effect": "Deny",
"Action": [
"rds:DeleteDBSnapshot",
"rds:DeleteDBClusterSnapshot",
"ec2:DeleteSnapshot",
"dynamodb:DeleteBackup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "Production"
}
}
},
{
"Sid": "PreventNetworkChanges",
"Effect": "Deny",
"Action": [
"ec2:DeleteVpc",
"ec2:DeleteSubnet",
"ec2:DeleteSecurityGroup",
"ec2:DeleteRouteTable",
"ec2:DeleteInternetGateway"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "Production"
}
}
}
]
}
},
"cost_control_scp": {
"name": "CostControlSCP",
"description": "Control costs, restrict the use of expensive AWS services and instance types",
"type": "deny_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExpensiveInstanceTypes",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAnyValue:StringNotEquals": {
"ec2:InstanceType": [
"t2.nano", "t2.micro", "t2.small", "t2.medium",
"t3.nano", "t3.micro", "t3.small", "t3.medium",
"m5.large", "m5.xlarge"
]
}
}
},
{
"Sid": "DenyExpensiveServices",
"Effect": "Deny",
"Action": [
"sagemaker:*",
"redshift:*",
"emr:*",
"databrew:*",
"glue:*"
],
"Resource": "*"
},
{
"Sid": "DenyLargeRDSInstances",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {
"ForAnyValue:StringNotEquals": {
"rds:db-instance-class": [
"db.t2.micro",
"db.t2.small",
"db.t3.micro",
"db.t3.small"
]
}
}
},
{
"Sid": "LimitRegions",
"Effect": "Deny",
"NotAction": [
"iam:*",
"sts:*",
"organizations:*",
"support:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"us-east-1",
"us-west-2"
]
}
}
}
]
}
},
"security_compliance_scp": {
"name": "SecurityComplianceSCP",
"description": "Enforce security compliance requirements, ensure encryption and secure configurations",
"type": "deny_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireSSLRequestsOnly",
"Effect": "Deny",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
},
{
"Sid": "DenyUnencryptedS3Uploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": [
"AES256",
"aws:kms"
]
}
}
},
{
"Sid": "RequireEBSEncryption",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:volume/*",
"Condition": {
"Bool": {
"ec2:Encrypted": "false"
}
}
},
{
"Sid": "DenyPublicS3Buckets",
"Effect": "Deny",
"Action": [
"s3:PutBucketPublicAccessBlock",
"s3:PutBucketAcl",
"s3:PutBucketPolicy"
],
"Resource": "*",
"Condition": {
"Bool": {
"s3:x-amz-public-read": "true"
}
}
},
{
"Sid": "RequireRDSEncryption",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {
"Bool": {
"rds:StorageEncrypted": "false"
}
}
}
]
}
},
"development_allowlist_scp": {
"name": "DevelopmentAllowListSCP",
"description": "Allowlist for development environments, only allowing development-related services",
"type": "allow_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDevelopmentServices",
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*",
"apigateway:*",
"cloudformation:*",
"cloudwatch:*",
"logs:*",
"sns:*",
"sqs:*",
"ec2:Describe*",
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:CreateTags",
"iam:GetRole",
"iam:GetUser",
"iam:PassRole",
"sts:*"
],
"Resource": "*"
},
{
"Sid": "AllowInstanceManagement",
"Effect": "Allow",
"Action": [
"ec2:TerminateInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Environment": "Development"
}
}
}
]
}
},
"audit_readonly_scp": {
"name": "AuditReadOnlySCP",
"description": "Read-only access for audit accounts, for security auditing and compliance checks",
"type": "allow_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadOnlyAccess",
"Effect": "Allow",
"Action": [
"*:Get*",
"*:List*",
"*:Describe*",
"*:Read*",
"support:*",
"trustedadvisor:*"
],
"Resource": "*"
},
{
"Sid": "AllowConfigAndCloudTrail",
"Effect": "Allow",
"Action": [
"config:*",
"cloudtrail:*"
],
"Resource": "*"
},
{
"Sid": "AllowSecurityServices",
"Effect": "Allow",
"Action": [
"inspector:*",
"guardduty:*",
"macie:*",
"securityhub:*",
"access-analyzer:*"
],
"Resource": "*"
}
]
}
},
"emergency_access_scp": {
"name": "EmergencyAccessSCP",
"description": "Emergency access control, providing limited access in emergency situations",
"type": "allow_list",
"policy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowEmergencyAccess",
"Effect": "Allow",
"Action": [
"cloudwatch:*",
"logs:*",
"sns:Publish",
"ses:SendEmail",
"ec2:Describe*",
"ec2:StartInstances",
"ec2:StopInstances",
"rds:Describe*",
"rds:StartDBInstance",
"rds:StopDBInstance"
],
"Resource": "*"
},
{
"Sid": "AllowIncidentResponse",
"Effect": "Allow",
"Action": [
"ec2:CreateSnapshot",
"ec2:CreateImage",
"s3:GetObject",
"s3:PutObject"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Emergency": "true"
}
}
}
]
}
}
}
print("📋 SCP policy templates:")
for template_name, template_info in scp_templates.items():
print(f"\n{template_name}:")
print(f" Name: {template_info['name']}")
print(f" Description: {template_info['description']}")
print(f" Type: {template_info['type']}")
print(f" Number of statements: {len(template_info['policy']['Statement'])}")
return scp_templates
def deploy_scp_templates():
"""
Deploy SCP policy templates to the organization
"""
templates = create_scp_policy_templates()
scp_manager = create_scp_manager()
deployed_scps = {}
for template_name, template_info in templates.items():
print(f"\nDeploying SCP template: {template_name}")
# Create the SCP policy
scp_result = scp_manager.create_scp_policy(
policy_name=template_info['name'],
policy_document=template_info['policy'],
description=template_info['description']
)
if scp_result:
deployed_scps[template_name] = scp_result
deployed_scps[template_name]['type'] = template_info['type']
print("\n📋 Deployed SCP policies:")
for template_name, scp_info in deployed_scps.items():
print(f" {template_name}:")
print(f" ID: {scp_info['policy_id']}")
print(f" Type: {scp_info['type']}")
return deployed_scps
# Create SCP templates
scp_templates = create_scp_policy_templates()
# Display details of the production protection SCP
print("\n📝 Production protection SCP policy details:")
prod_scp = scp_templates['production_protection_scp']['policy']
print(json.dumps(prod_scp, indent=2, ensure_ascii=False))
# Display details of the cost control SCP
print("\n📝 Cost control SCP policy details:")
cost_scp = scp_templates['cost_control_scp']['policy']
print(json.dumps(cost_scp, indent=2, ensure_ascii=False))
5.3 Organizational Units and Policy Inheritance
5.3.1 Organizational Architecture Design
def design_organization_architecture():
"""
Design the AWS organizational architecture and policy inheritance hierarchy
"""
# Typical enterprise organizational architecture
organization_design = {
"Root": {
"description": "Organization root",
"attached_scps": ["FullAWSAccess"],
"children": {
"Security OU": {
"description": "Accounts related to security and compliance",
"attached_scps": ["SecurityComplianceSCP", "AuditReadOnlySCP"],
"accounts": [
{
"name": "Security Account",
"purpose": "Centralized security management and monitoring",
"services": ["GuardDuty", "SecurityHub", "Config", "CloudTrail"]
},
{
"name": "Log Archive Account",
"purpose": "Centralized log storage and analysis",
"services": ["CloudWatch Logs", "S3", "Elasticsearch"]
}
]
},
"Production OU": {
"description": "Production environment accounts",
"attached_scps": ["ProductionProtectionSCP", "SecurityComplianceSCP"],
"children": {
"Core Services OU": {
"description": "Core business services",
"attached_scps": [],
"accounts": [
{
"name": "Prod Web Services",
"purpose": "Web application and API services"
},
{
"name": "Prod Database",
"purpose": "Database services"
}
]
},
"Analytics OU": {
"description": "Data analytics and BI",
"attached_scps": ["DataAnalyticsSCP"],
"accounts": [
{
"name": "Prod Analytics",
"purpose": "Data warehouse and analytics"
}
]
}
}
},
"Development OU": {
"description": "Development and testing environments",
"attached_scps": ["CostControlSCP", "DevelopmentAllowListSCP"],
"children": {
"Dev OU": {
"description": "Development environment",
"attached_scps": [],
"accounts": [
{
"name": "Dev Team A",
"purpose": "Development environment for Team A"
},
{
"name": "Dev Team B",
"purpose": "Development environment for Team B"
}
]
},
"Test OU": {
"description": "Testing environment",
"attached_scps": ["TestEnvironmentSCP"],
"accounts": [
{
"name": "Integration Test",
"purpose": "Integration testing environment"
},
{
"name": "Performance Test",
"purpose": "Performance testing environment"
}
]
}
}
},
"Shared Services OU": {
"description": "Shared services accounts",
"attached_scps": ["SharedServicesSCP"],
"accounts": [
{
"name": "Network Account",
"purpose": "Network and connectivity management"
},
{
"name": "DNS Account",
"purpose": "Domain name resolution services"
},
{
"name": "Backup Account",
"purpose": "Cross-account backup management"
}
]
}
}
}
}
# Policy inheritance matrix
inheritance_matrix = {
"Security Account": {
"direct_scps": [],
"inherited_from_ou": ["SecurityComplianceSCP", "AuditReadOnlySCP"],
"inherited_from_root": ["FullAWSAccess"],
"effective_scps": ["FullAWSAccess", "SecurityComplianceSCP", "AuditReadOnlySCP"]
},
"Prod Web Services": {
"direct_scps": [],
"inherited_from_ou": ["ProductionProtectionSCP", "SecurityComplianceSCP"],
"inherited_from_root": ["FullAWSAccess"],
"effective_scps": ["FullAWSAccess", "ProductionProtectionSCP", "SecurityComplianceSCP"]
},
"Dev Team A": {
"direct_scps": [],
"inherited_from_ou": ["CostControlSCP", "DevelopmentAllowListSCP"],
"inherited_from_parent_ou": ["CostControlSCP", "DevelopmentAllowListSCP"],
"inherited_from_root": ["FullAWSAccess"],
"effective_scps": ["FullAWSAccess", "CostControlSCP", "DevelopmentAllowListSCP"]
}
}
# Policy conflict resolution principles
conflict_resolution = {
"principles": [
"Most restrictive principle: The intersection of multiple SCPs takes effect",
"Deny takes precedence: Any action denied by any SCP is denied",
"Downward inheritance: Child OUs and accounts inherit all SCPs from their parents",
"Cumulative effect: All applicable SCPs are evaluated"
],
"examples": {
"scenario_1": {
"description": "Parent OU allows EC2, child OU denies large instance types",
"parent_scp": "Allow: ec2:*",
"child_scp": "Deny: ec2:RunInstances for large instance types",
"result": "Small instance types are allowed, large instance types are denied"
},
"scenario_2": {
"description": "Combination of an allowlist SCP and a denylist SCP",
"allow_list": "Allow: s3:*, ec2:*, dynamodb:*",
"deny_list": "Deny: s3:DeleteBucket",
"result": "S3 and EC2 actions are allowed, but deleting S3 buckets is not"
}
}
}
print("📋 AWS organizational architecture design:")
print_organization_structure(organization_design["Root"], 0)
print("\n📊 Policy inheritance matrix example:")
for account, inheritance in inheritance_matrix.items():
print(f"\n{account}:")
print(f" Directly attached: {inheritance.get('direct_scps', [])}")
print(f" Inherited from OU: {inheritance.get('inherited_from_ou', [])}")
print(f" Inherited from root: {inheritance.get('inherited_from_root', [])}")
print(f" Effective SCPs: {inheritance['effective_scps']}")
print("\n📝 Policy conflict resolution principles:")
for principle in conflict_resolution['principles']:
print(f" • {principle}")
print("\nExample scenarios:")
for scenario, details in conflict_resolution['examples'].items():
print(f"\n{scenario}: {details['description']}")
for key, value in details.items():
if key != 'description':
print(f" {key}: {value}")
return organization_design, inheritance_matrix, conflict_resolution
def print_organization_structure(node, level):
"""Print the organization structure tree"""
indent = " " * level
if level == 0:
print(f"{node.get('description', 'Root')}")
# Print attached SCPs
if 'attached_scps' in node and node['attached_scps']:
print(f"{indent} 📋 SCPs: {', '.join(node['attached_scps'])}")
# Print accounts
if 'accounts' in node:
for account in node['accounts']:
print(f"{indent} 💼 Account: {account['name']}")
print(f"{indent} Purpose: {account['purpose']}")
# Recursively print child OUs
if 'children' in node:
for child_name, child_node in node['children'].items():
print(f"{indent}📁 {child_name}")
print(f"{indent} {child_node.get('description', '')}")
print_organization_structure(child_node, level + 1)
def create_organization_management_system():
"""
Create an organization management system
"""
class OrganizationManagementSystem:
def __init__(self):
self.organizations = boto3.client('organizations')
self.iam = boto3.client('iam')
def create_organizational_unit(self, parent_id, ou_name):
"""Create an organizational unit"""
try:
response = self.organizations.create_organizational_unit(
ParentId=parent_id,
Name=ou_name
)
ou_id = response['OrganizationalUnit']['Id']
print(f"✅ Organizational unit created successfully: {ou_name} ({ou_id})")
return ou_id
except Exception as e:
print(f"❌ Failed to create organizational unit: {str(e)}")
return None
def move_account_to_ou(self, account_id, source_parent_id, destination_parent_id):
"""Move an account to a specified OU"""
try:
self.organizations.move_account(
AccountId=account_id,
SourceParentId=source_parent_id,
DestinationParentId=destination_parent_id
)
print(f"✅ Account {account_id} moved to the new OU")
return True
except Exception as e:
print(f"❌ Failed to move account: {str(e)}")
return False
def get_account_inheritance_path(self, account_id):
"""Get the inheritance path of an account"""
try:
inheritance_path = []
current_id = account_id
while True:
parents_response = self.organizations.list_parents(
ChildId=current_id
)
if not parents_response['Parents']:
break
parent = parents_response['Parents'][0]
inheritance_path.append({
'id': parent['Id'],
'type': parent['Type']
})
# Stop if the root is reached
if parent['Type'] == 'ROOT':
break
current_id = parent['Id']
# Reverse the path to go from root to leaf
inheritance_path.reverse()
print(f"📋 Inheritance path for account {account_id}:")
for i, node in enumerate(inheritance_path):
indent = " " * i
print(f"{indent}{node['type']}: {node['id']}")
return inheritance_path
except Exception as e:
print(f"❌ Failed to get inheritance path: {str(e)}")
return []
def calculate_effective_scps(self, target_id):
"""Calculate the effective SCP policies for a target"""
try:
all_scps = []
current_id = target_id
# Get SCPs for each node in the inheritance path
while True:
# Get SCPs for the current node
try:
policies_response = self.organizations.list_policies_for_target(
TargetId=current_id,
Filter='SERVICE_CONTROL_POLICY'
)
node_scps = policies_response['Policies']
all_scps.extend(node_scps)
except Exception as e:
print(f"Warning: Failed to get policies for node {current_id}: {str(e)}")
# Get the parent node
try:
parents_response = self.organizations.list_parents(
ChildId=current_id
)
if not parents_response['Parents']:
break
parent = parents_response['Parents'][0]
# Stop if the root is reached
if parent['Type'] == 'ROOT':
# Get SCPs for the root
try:
root_policies = self.organizations.list_policies_for_target(
TargetId=parent['Id'],
Filter='SERVICE_CONTROL_POLICY'
)
all_scps.extend(root_policies['Policies'])
except:
pass
break
current_id = parent['Id']
except Exception as e:
print(f"Warning: Failed to get parent node: {str(e)}")
break
# Deduplicate (based on policy ID)
unique_scps = {}
for scp in all_scps:
unique_scps[scp['Id']] = scp
effective_scps = list(unique_scps.values())
print(f"📊 Effective SCP policies for target {target_id}:")
print(f" Total: {len(effective_scps)}")
for scp in effective_scps:
print(f" {scp['Name']} ({scp['Id']})")
return effective_scps
except Exception as e:
print(f"❌ Failed to calculate effective SCPs: {str(e)}")
return []
def validate_organization_structure(self):
"""Validate the integrity and compliance of the organization structure"""
try:
validation_results = {
'total_accounts': 0,
'total_ous': 0,
'accounts_without_scps': [],
'ous_without_scps': [],
'compliance_violations': [],
'recommendations': []
}
# Get all accounts
accounts_response = self.organizations.list_accounts()
accounts = accounts_response['Accounts']
validation_results['total_accounts'] = len(accounts)
# Check the SCP configuration for each account
for account in accounts:
account_id = account['Id']
effective_scps = self.calculate_effective_scps(account_id)
if not effective_scps:
validation_results['accounts_without_scps'].append(account_id)
# Check for basic security SCPs
has_security_scp = any(
'security' in scp['Name'].lower() or 'compliance' in scp['Name'].lower()
for scp in effective_scps
)
if not has_security_scp:
validation_results['compliance_violations'].append({
'account_id': account_id,
'violation': 'Missing security compliance SCP'
})
# Generate recommendations
if validation_results['accounts_without_scps']:
validation_results['recommendations'].append(
"Configure appropriate SCP policies for all accounts"
)
if validation_results['compliance_violations']:
validation_results['recommendations'].append(
"Ensure all accounts have basic security compliance SCPs"
)
print("📋 Organization structure validation report:")
print(f" Total accounts: {validation_results['total_accounts']}")
print(f" Accounts without SCPs: {len(validation_results['accounts_without_scps'])}")
print(f" Compliance violations: {len(validation_results['compliance_violations'])}")
print(f" Number of recommendations: {len(validation_results['recommendations'])}")
return validation_results
except Exception as e:
print(f"❌ Failed to validate organization structure: {str(e)}")
return None
return OrganizationManagementSystem()
# Design the organizational architecture
org_design, inheritance_matrix, conflict_resolution = design_organization_architecture()
# Create an organization management system
org_mgmt = create_organization_management_system()
print("\n📝 Organizational architecture best practices:")
best_practices = [
"Create an OU structure based on environment and function",
"Attach SCP policies at the appropriate level",
"Use descriptive OU and account names",
"Regularly audit and validate policy inheritance",
"Test the impact of policy changes on lower levels",
"Maintain policy documentation and change records"
]
for i, practice in enumerate(best_practices, 1):
print(f" {i}. {practice}")
5.4 Integrated Application of Permissions Boundaries and SCPs
5.4.1 Multi-layered Permission Control Architecture
def create_multi_layer_permission_architecture():
"""
Create a multi-layered permission control architecture that combines permissions boundaries and SCPs
"""
# Multi-layered permission control model
permission_layers = {
"layer_1_organization_scp": {
"level": "Organization level",
"description": "Outermost control, defines the maximum permissions within the organization",
"scope": "All accounts and OUs",
"purpose": "Compliance, security, cost control",
"examples": ["Disable high-risk services", "Region restrictions", "Instance type restrictions"]
},
"layer_2_ou_scp": {
"level": "OU level",
"description": "Permission control at the business unit level",
"scope": "All accounts within a specific OU",
"purpose": "Environment isolation, customization for business needs",
"examples": ["Production environment protection", "Development environment restrictions", "Test environment control"]
},
"layer_3_account_scp": {
"level": "Account level",
"description": "Account-specific permission restrictions",
"scope": "A single account",
"purpose": "Account-specific needs, fine-grained control",
"examples": ["Additional restrictions for a specific account", "Temporary access control"]
},
"layer_4_permissions_boundary": {
"level": "IAM entity level",
"description": "Maximum permissions boundary for IAM users and roles",
"scope": "A single IAM entity",
"purpose": "Permission delegation, developer permission restrictions",
"examples": ["Developer permissions boundary", "Contractor access restrictions"]
},
"layer_5_identity_policy": {
"level": "Identity policy level",
"description": "The actual granted permissions",
"scope": "IAM identity",
"purpose": "Specific permission grants",
"examples": ["User policies", "Role policies", "Group policies"]
}
}
# Permission calculation formula
permission_formula = {
"effective_permissions": "ORG_SCP ∩ OU_SCP ∩ ACCOUNT_SCP ∩ PERMISSIONS_BOUNDARY ∩ IDENTITY_POLICY",
"evaluation_order": [
"1. Explicit Deny Check (a Deny at any level immediately denies)",
"2. Organization SCP Evaluation",
"3. OU SCP Evaluation",
"4. Account SCP Evaluation",
"5. Permissions Boundary Evaluation",
"6. Identity Policy Evaluation",
"7. Final permissions = Intersection of all levels"
]
}
# Practical application scenarios
application_scenarios = {
"enterprise_developer": {
"description": "Permission control for enterprise developers",
"layers": {
"org_scp": {
"name": "CompanySecuritySCP",
"rules": ["Disable high-risk services", "Region restrictions", "Must encrypt"]
},
"ou_scp": {
"name": "DevelopmentSCP",
"rules": ["Cost control", "Instance type restrictions", "Development service allowlist"]
},
"permissions_boundary": {
"name": "DeveloperBoundary",
"rules": ["Cannot create IAM roles", "Cannot access production resources"]
},
"identity_policy": {
"name": "DeveloperPolicy",
"rules": ["Full access to the development environment"]
}
},
"effective_permissions": [
"S3, DynamoDB, Lambda access in the development environment",
"EC2 access with restricted instance types",
"CloudWatch and log access",
"Cannot access production resources",
"Cannot create IAM resources"
]
},
"production_admin": {
"description": "Permission control for production environment administrators",
"layers": {
"org_scp": {
"name": "CompanySecuritySCP",
"rules": ["Disable high-risk services", "Region restrictions", "Must encrypt"]
},
"ou_scp": {
"name": "ProductionSCP",
"rules": ["Prevent deletion of critical resources", "Requires MFA", "Audit logs"]
},
"permissions_boundary": {
"name": "ProductionAdminBoundary",
"rules": ["Cannot modify security configurations", "Cannot delete backups"]
},
"identity_policy": {
"name": "ProductionAdminPolicy",
"rules": ["Production environment management permissions", "Monitoring and log access"]
}
},
"effective_permissions": [
"Production resource management",
"Monitoring and alarm configuration",
"Performance optimization and scaling",
"Cannot delete critical resources",
"Cannot modify security configurations"
]
}
}
print("📋 Multi-layered permission control architecture:")
for layer_name, layer_info in permission_layers.items():
print(f"\n{layer_info['level']}:")
print(f" Description: {layer_info['description']}")
print(f" Scope: {layer_info['scope']}")
print(f" Purpose: {layer_info['purpose']}")
print(f" Examples: {', '.join(layer_info['examples'])}")
print(f"\n📊 Permission calculation formula:")
print(f"Effective permissions = {permission_formula['effective_permissions']}")
print("\nEvaluation order:")
for step in permission_formula['evaluation_order']:
print(f" {step}")
print("\n📝 Application scenario examples:")
for scenario_name, scenario_info in application_scenarios.items():
print(f"\n{scenario_name}: {scenario_info['description']}")
print(" Permission layers:")
for layer, config in scenario_info['layers'].items():
print(f" {layer}: {config['name']}")
for rule in config['rules']:
print(f" - {rule}")
print(" Effective permissions:")
for permission in scenario_info['effective_permissions']:
print(f" ✓ {permission}")
return permission_layers, permission_formula, application_scenarios
def create_permission_testing_framework():
"""
Create a permission testing framework to validate multi-layered permission controls
"""
class PermissionTestingFramework:
def __init__(self):
self.iam = boto3.client('iam')
self.organizations = boto3.client('organizations')
def create_test_scenario(self, scenario_name, test_config):
"""Create a test scenario"""
test_scenario = {
'scenario_name': scenario_name,
'test_cases': [],
'setup_resources': [],
'cleanup_resources': []
}
# Create test cases based on the configuration
for action in test_config['actions_to_test']:
test_case = {
'action': action['action'],
'resource': action['resource'],
'expected_result': action['expected'],
'description': action.get('description', f"Test {action['action']}")
}
test_scenario['test_cases'].append(test_case)
return test_scenario
def run_permission_simulation(self, principal_arn, test_cases,
permissions_boundary=None, context_entries=None):
"""Run a permission simulation test"""
try:
simulation_results = []
for test_case in test_cases:
simulate_params = {
'PolicySourceArn': principal_arn,
'ActionNames': [test_case['action']],
'ResourceArns': [test_case['resource']]
}
if permissions_boundary:
simulate_params['PermissionsBoundaryPolicyInputList'] = [
permissions_boundary
]
if context_entries:
simulate_params['ContextEntries'] = context_entries
response = self.iam.simulate_principal_policy(**simulate_params)
for result in response['EvaluationResults']:
actual_decision = result['EvalDecision']
expected_decision = test_case['expected_result']
test_result = {
'test_case': test_case['description'],
'action': result['EvalActionName'],
'resource': result['EvalResourceName'],
'expected': expected_decision,
'actual': actual_decision,
'passed': actual_decision.lower() == expected_decision.lower(),
'matched_statements': len(result.get('MatchedStatements', [])),
'missing_context': result.get('MissingContextValues', [])
}
simulation_results.append(test_result)
# Generate a test report
self._generate_test_report(simulation_results)
return simulation_results
except Exception as e:
print(f"❌ Permission simulation test failed: {str(e)}")
return []
def _generate_test_report(self, results):
"""Generate a test report"""
passed_tests = sum(1 for r in results if r['passed'])
total_tests = len(results)
pass_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0
print(f"\n📊 Permission test report:")
print(f" Total tests: {total_tests}")
print(f" Passed tests: {passed_tests}")
print(f" Failed tests: {total_tests - passed_tests}")
print(f" Pass rate: {pass_rate:.1f}%")
print(f"\nDetailed results:")
for result in results:
status = "✅" if result['passed'] else "❌"
print(f" {status} {result['test_case']}")
print(f" Action: {result['action']}")
print(f" Resource: {result['resource']}")
print(f" Expected: {result['expected']}, Actual: {result['actual']}")
if result['missing_context']:
print(f" Missing context: {', '.join(result['missing_context'])}")
def test_multi_layer_permissions(self):
"""Test multi-layered permission control scenarios"""
# Developer scenario tests
developer_tests = {
'actions_to_test': [
{
'action': 's3:GetObject',
'resource': 'arn:aws:s3:::dev-bucket/*',
'expected': 'allowed',
'description': 'Read from S3 in the development environment'
},
{
'action': 's3:GetObject',
'resource': 'arn:aws:s3:::prod-bucket/*',
'expected': 'denied',
'description': 'Read from S3 in the production environment (should be denied)'
},
{
'action': 'iam:CreateRole',
'resource': '*',
'expected': 'denied',
'description': 'Create an IAM role (should be denied by the permissions boundary)'
},
{
'action': 'ec2:RunInstances',
'resource': 'arn:aws:ec2:us-west-2:*:instance/*',
'expected': 'allowed',
'description': 'Run a small instance (development environment)'
},
{
'action': 'ec2:RunInstances',
'resource': 'arn:aws:ec2:us-east-1:*:instance/*',
'expected': 'denied',
'description': 'Run an instance in a forbidden region'
}
]
}
print("🧪 Developer multi-layer permission test scenario:")
developer_scenario = self.create_test_scenario(
"Developer Multi-Layer Test",
developer_tests
)
# Display test cases
for test_case in developer_scenario['test_cases']:
print(f" Test: {test_case['description']}")
print(f" Action: {test_case['action']}")
print(f" Resource: {test_case['resource']}")
print(f" Expected: {test_case['expected_result']}")
return developer_scenario
def validate_policy_consistency(self, policy_set):
"""Validate the consistency of a policy set"""
consistency_issues = []
# Check for conflicting allow and deny statements
allow_actions = set()
deny_actions = set()
for policy_name, policy_doc in policy_set.items():
for statement in policy_doc.get('Statement', []):
actions = statement.get('Action', [])
if isinstance(actions, str):
actions = [actions]
if statement.get('Effect') == 'Allow':
allow_actions.update(actions)
elif statement.get('Effect') == 'Deny':
deny_actions.update(actions)
# Find conflicts
conflicts = allow_actions.intersection(deny_actions)
if conflicts:
consistency_issues.append({
'type': 'Allow-Deny conflict',
'details': f"The following actions are both allowed and denied: {list(conflicts)}"
})
# Check policy complexity
total_statements = sum(
len(policy.get('Statement', []))
for policy in policy_set.values()
)
if total_statements > 50:
consistency_issues.append({
'type': 'Policy complexity is too high',
'details': f"Total statements: {total_statements}, simplification is recommended"
})
print("📋 Policy consistency validation:")
if consistency_issues:
print(" Issues found:")
for issue in consistency_issues:
print(f" ⚠️ {issue['type']}: {issue['details']}")
else:
print(" ✅ No policy conflicts found")
return consistency_issues
return PermissionTestingFramework()
# Create a multi-layered permission architecture
layers, formula, scenarios = create_multi_layer_permission_architecture()
# Create a permission testing framework
test_framework = create_permission_testing_framework()
# Run multi-layered permission tests
developer_test_scenario = test_framework.test_multi_layer_permissions()
# Example of policy consistency validation
policy_set = {
'OrganizationSCP': {
'Statement': [
{
'Effect': 'Deny',
'Action': 'ec2:RunInstances',
'Resource': '*',
'Condition': {
'StringNotEquals': {
'aws:RequestedRegion': ['us-west-2']
}
}
}
]
},
'PermissionsBoundary': {
'Statement': [
{
'Effect': 'Allow',
'Action': 'ec2:*',
'Resource': '*'
},
{
'Effect': 'Deny',
'Action': 'iam:*',
'Resource': '*'
}
]
}
}
consistency_results = test_framework.validate_policy_consistency(policy_set)
5.5 Permission Governance Best Practices
5.5.1 Governance Policy Implementation Framework
def create_governance_framework():
"""
Create a permission governance policy implementation framework
"""
governance_framework = {
"governance_principles": {
"least_privilege": {
"principle": "Principle of Least Privilege",
"description": "Grant only the minimum permissions required to perform a task",
"implementation": [
"Use permissions boundaries to limit maximum permissions",
"Regularly audit and clean up unnecessary permissions",
"Adopt a Just-In-Time access model",
"Implement role-based access control"
]
},
"defense_in_depth": {
"principle": "Defense in Depth",
"description": "Multi-layered security controls ensure system security",
"implementation": [
"Organization-level SCP + OU-level SCP + Account-level controls",
"Dual protection with permissions boundaries and identity policies",
"Network security + Application security + Data security",
"Multi-dimensional protection with monitoring, auditing, and alerting"
]
},
"zero_trust": {
"principle": "Zero Trust Principle",
"description": "Never trust, always verify any user or device",
"implementation": [
"Enforce MFA authentication",
"Context-based dynamic authorization",
"Continuous monitoring and verification",
"Principle of minimum blast radius"
]
},
"automation_first": {
"principle": "Automation First",
"description": "Reduce human error and improve efficiency through automation",
"implementation": [
"Automated policy deployment and management",
"Automated compliance checks and remediation",
"Automated permission auditing and reporting",
"Automated incident response and handling"
]
}
},
"implementation_phases": {
"phase_1_assessment": {
"name": "Assessment Phase",
"duration": "2-4 weeks",
"objectives": [
"Assess the current permission status",
"Identify security risks and compliance issues",
"Develop a governance roadmap",
"Obtain management support"
],
"deliverables": [
"Permission audit report",
"Risk assessment report",
"Governance policy document",
"Implementation plan"
]
},
"phase_2_foundation": {
"name": "Foundation Phase",
"duration": "4-8 weeks",
"objectives": [
"Establish the organizational structure",
"Deploy basic SCP policies",
"Set up permissions boundary templates",
"Configure monitoring and auditing"
],
"deliverables": [
"Organizational unit structure",
"Basic SCP policy set",
"Permissions boundary template library",
"Monitoring and alerting configuration"
]
},
"phase_3_migration": {
"name": "Migration Phase",
"duration": "6-12 weeks",
"objectives": [
"Migrate existing resources to the new architecture",
"Apply permissions boundaries to IAM entities",
"Update existing policies",
"Train team members"
],
"deliverables": [
"Resource migration complete",
"Permissions boundary deployment complete",
"Policy updates complete",
"Training materials and records"
]
},
"phase_4_optimization": {
"name": "Optimization Phase",
"duration": "Ongoing",
"objectives": [
"Continuous monitoring and optimization",
"Regular permission audits",
"Policy improvements and updates",
"Compliance maintenance"
],
"deliverables": [
"Regular audit reports",
"Optimization recommendations",
"Policy update records",
"Compliance evidence documents"
]
}
},
"governance_metrics": {
"security_metrics": [
"Number of high-privilege accounts",
"Percentage of unused permissions",
"Permissions boundary coverage rate",
"SCP policy coverage rate",
"Number of security incidents"
],
"compliance_metrics": [
"Policy compliance rate",
"Number of audit findings",
"Time to remediation",
"Compliance check frequency",
"Documentation completeness"
],
"operational_metrics": [
"Permission request processing time",
"Automation coverage rate",
"Policy change frequency",
"Training participation rate",
"User satisfaction"
]
}
}
print("📋 Permission governance framework:")
print("\n🎯 Governance principles:")
for principle_key, principle in governance_framework["governance_principles"].items():
print(f"\n{principle['principle']}:")
print(f" Description: {principle['description']}")
print(" Implementation methods:")
for method in principle['implementation']:
print(f" • {method}")
print("\n📅 Implementation phases:")
for phase_key, phase in governance_framework["implementation_phases"].items():
print(f"\n{phase['name']} ({phase['duration']}):")
print(" Objectives:")
for objective in phase['objectives']:
print(f" • {objective}")
print(" Deliverables:")
for deliverable in phase['deliverables']:
print(f" ✓ {deliverable}")
print("\n📊 Governance metrics:")
for metric_type, metrics in governance_framework["governance_metrics"].items():
print(f"\n{metric_type.replace('_', ' ').title()}:")
for metric in metrics:
print(f" • {metric}")
return governance_framework
def create_automated_governance_system():
"""
Create an automated governance system
"""
class AutomatedGovernanceSystem:
def __init__(self):
self.iam = boto3.client('iam')
self.organizations = boto3.client('organizations')
self.cloudwatch = boto3.client('cloudwatch')
self.sns = boto3.client('sns')
def setup_governance_automation(self):
"""Set up governance automation"""
automation_components = {
"policy_drift_detection": {
"description": "Detect policy configuration drift",
"implementation": "Lambda function + CloudWatch Events",
"frequency": "Daily",
"actions": ["Detect policy changes", "Generate alerts", "Automated remediation"]
},
"permission_usage_analysis": {
"description": "Analyze permission usage",
"implementation": "Lambda function + CloudTrail log analysis",
"frequency": "Weekly",
"actions": ["Identify unused permissions", "Generate optimization recommendations", "Update policies"]
},
"compliance_monitoring": {
"description": "Continuous compliance monitoring",
"implementation": "Config Rules + Lambda",
"frequency": "Real-time",
"actions": ["Check compliance status", "Generate reports", "Trigger remediation"]
},
"access_review_automation": {
"description": "Automated access reviews",
"implementation": "Lambda function + SES notifications",
"frequency": "Quarterly",
"actions": ["Generate review reports", "Send notifications", "Track approvals"]
}
}
print("🤖 Governance automation components:")
for component_name, component in automation_components.items():
print(f"\n{component['description']}:")
print(f" Implementation: {component['implementation']}")
print(f" Frequency: {component['frequency']}")
print(" Automated actions:")
for action in component['actions']:
print(f" • {action}")
return automation_components
def create_governance_dashboard(self):
"""Create a governance dashboard"""
dashboard_config = {
"dashboard_name": "IAM-Governance-Dashboard",
"widgets": [
{
"type": "metric",
"title": "Number of high-privilege users",
"metrics": ["Custom/IAM/HighPrivilegeUsers"],
"period": 300
},
{
"type": "metric",
"title": "Permissions boundary coverage rate",
"metrics": ["Custom/IAM/PermissionsBoundaryCoverage"],
"period": 300
},
{
"type": "metric",
"title": "SCP policy coverage rate",
"metrics": ["Custom/IAM/SCPCoverage"],
"period": 300
},
{
"type": "log",
"title": "Permission violation events",
"log_group": "/aws/iam/violations",
"query": "fields @timestamp, @message | filter @message like /VIOLATION/"
}
],
"alerts": [
{
"name": "HighPrivilegeUserAlert",
"description": "Anomalous increase in the number of high-privilege users",
"metric": "Custom/IAM/HighPrivilegeUsers",
"threshold": 5,
"comparison": "GreaterThanThreshold"
},
{
"name": "PolicyViolationAlert",
"description": "Policy violation event",
"metric": "Custom/IAM/PolicyViolations",
"threshold": 1,
"comparison": "GreaterThanOrEqualToThreshold"
}
]
}
print("📊 Governance dashboard configuration:")
print(f"Dashboard name: {dashboard_config['dashboard_name']}")
print("\nWidgets:")
for widget in dashboard_config['widgets']:
print(f" {widget['title']} ({widget['type']})")
print("\nAlerts:")
for alert in dashboard_config['alerts']:
print(f" {alert['name']}: {alert['description']}")
return dashboard_config
def generate_governance_report(self):
"""Generate a governance report"""
try:
governance_report = {
"report_date": datetime.now().strftime('%Y-%m-%d'),
"summary": {},
"findings": [],
"recommendations": [],
"metrics": {}
}
# Collect account statistics
accounts = self.organizations.list_accounts()['Accounts']
governance_report["summary"]["total_accounts"] = len(accounts)
# Analyze each account
high_risk_accounts = 0
accounts_with_boundaries = 0
for account in accounts:
try:
# Check the account's permission configuration
account_analysis = self._analyze_account_permissions(account['Id'])
if account_analysis['high_risk']:
high_risk_accounts += 1
if account_analysis['has_boundaries']:
accounts_with_boundaries += 1
except Exception as e:
governance_report["findings"].append({
"type": "Analysis error",
"account": account['Id'],
"description": f"Could not analyze account: {str(e)}"
})
governance_report["summary"]["high_risk_accounts"] = high_risk_accounts
governance_report["summary"]["boundary_coverage"] = (
accounts_with_boundaries / len(accounts) * 100
) if len(accounts) > 0 else 0
# Generate recommendations
if high_risk_accounts > 0:
governance_report["recommendations"].append(
f"Found {high_risk_accounts} high-risk accounts, immediate review is recommended"
)
if governance_report["summary"]["boundary_coverage"] < 80:
governance_report["recommendations"].append(
f"Permissions boundary coverage is only {governance_report['summary']['boundary_coverage']:.1f}%, increasing coverage is recommended"
)
print("📋 Governance report generated:")
print(f" Report date: {governance_report['report_date']}")
print(f" Total accounts: {governance_report['summary']['total_accounts']}")
print(f" High-risk accounts: {governance_report['summary']['high_risk_accounts']}")
print(f" Permissions boundary coverage: {governance_report['summary']['boundary_coverage']:.1f}%")
print(f" Issues found: {len(governance_report['findings'])}")
print(f" Number of recommendations: {len(governance_report['recommendations'])}")
return governance_report
except Exception as e:
print(f"❌ Failed to generate governance report: {str(e)}")
return None
def _analyze_account_permissions(self, account_id):
"""Analyze account permission configurations"""
analysis = {
"account_id": account_id,
"high_risk": False,
"has_boundaries": False,
"issues": []
}
try:
# This should implement the specific account permission analysis logic
# Since it requires cross-account access, this is just an example framework
# Check for permissions boundaries (needs to be executed in the target account)
# analysis["has_boundaries"] = self._check_permissions_boundaries(account_id)
# Check for high-risk configurations (needs to be executed in the target account)
# analysis["high_risk"] = self._check_high_risk_configurations(account_id)
# Simplified simulated analysis
import random
analysis["has_boundaries"] = random.choice([True, False])
analysis["high_risk"] = random.choice([True, False])
except Exception as e:
analysis["issues"].append(f"Analysis failed: {str(e)}")
return analysis
def implement_remediation_actions(self, findings):
"""Implement remediation actions"""
remediation_results = []
for finding in findings:
result = {
"finding": finding,
"action_taken": "None",
"success": False,
"details": ""
}
try:
if finding['type'] == 'Missing permissions boundary':
# Automatically apply a default permissions boundary
result["action_taken"] = "Apply default permissions boundary"
result["success"] = True
result["details"] = "DeveloperPermissionsBoundary has been applied"
elif finding['type'] == 'SCP policy missing':
# Recommend attaching an appropriate SCP
result["action_taken"] = "Generate SCP recommendation"
result["success"] = True
result["details"] = "SCP policy recommendation has been generated"
elif finding['type'] == 'High-privilege user':
# Generate a permission review task
result["action_taken"] = "Create review task"
result["success"] = True
result["details"] = "A permission review ticket has been created"
except Exception as e:
result["details"] = f"Remediation failed: {str(e)}"
remediation_results.append(result)
print("🔧 Remediation action execution results:")
for result in remediation_results:
status = "✅" if result["success"] else "❌"
print(f" {status} {result['finding']['type']}: {result['action_taken']}")
if result["details"]:
print(f" Details: {result['details']}")
return remediation_results
return AutomatedGovernanceSystem()
# Create a governance framework
governance_framework = create_governance_framework()
# Create an automated governance system
governance_system = create_automated_governance_system()
# Set up governance automation
automation_setup = governance_system.setup_governance_automation()
# Create a governance dashboard
dashboard_config = governance_system.create_governance_dashboard()
# Generate a governance report
governance_report = governance_system.generate_governance_report()
print("\n📝 Governance implementation recommendations:")
implementation_tips = [
"Start with a small pilot and gradually expand to the entire organization",
"Ensure there is sufficient training and documentation support",
"Establish clear roles and responsibilities",
"Regularly review and update governance policies",
"Maintain a balance with business needs",
"Establish a rapid response mechanism for emergencies"
]
for i, tip in enumerate(implementation_tips, 1):
print(f" {i}. {tip}")
Summary
This chapter provided an in-depth look at advanced applications of AWS permissions boundaries and service control policies:
- Permissions Boundaries: Learned the concept, working principle, and policy templates of permissions boundaries to implement maximum permission limits for users and roles
- Service Control Policies: Mastered the basic concepts, policy types, and templates of SCPs to implement organization-level permission governance
- Organizational Architecture: Understood the hierarchical structure and policy inheritance mechanism of AWS Organizations to design a reasonable OU architecture
- Integrated Application: Learned about multi-layered permission control architecture, combining permissions boundaries and SCPs to achieve defense in depth
- Governance Framework: Established a complete permission governance system, including automated monitoring, auditing, and remediation
By completing this chapter, you should be able to:
- Skillfully configure and manage permissions boundary policies
- Design and implement service control policies
- Establish a reasonable AWS organizational architecture and policy inheritance hierarchy
- Implement multi-layered permission control and defense-in-depth strategies
- Establish an automated permission governance and monitoring system
- Formulate and execute enterprise-level permission management best practices
In the next chapter, we will learn about IAM security best practices and monitoring and auditing mechanisms.