Overview
Multi-tenant applications need strong isolation between tenants while sharing common infrastructure. Bedrock Cloud provides built-in multi-tenancy with complete isolation between customers.
Bedrock Cloud Multi-tenant Architecture
Tenant A (customer boundary)
└── Workspace
└── Project (authorization configured here)
├── Production
└── Staging
Tenant B (completely isolated)
└── Workspace
└── Project
├── Production
└── Staging
Each tenant is completely isolated. Users, roles, and permissions in one tenant cannot access another tenant’s resources.
Setting Up Multi-tenancy
1. Create Tenants via Management API
# Create Acme tenant
curl -X POST 'https://api.example.com/tenants' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"name": "Acme Corp",
"slug": "acme-corp",
"kind": "standard",
"planKey": "pro",
"maxUsers": 50
}'
# Create Globex tenant
curl -X POST 'https://api.example.com/tenants' \
-d '{
"name": "Globex Inc",
"slug": "globex-inc",
"kind": "standard",
"planKey": "pro",
"maxUsers": 100
}'
2. Build Tenant Structure
# Create workspace for Acme
curl -X POST 'https://api.example.com/workspaces' \
-d '{"tenantId": "tenant_acme", "name": "Main"}'
# Create project
curl -X POST 'https://api.example.com/projects' \
-d '{
"tenantId": "tenant_acme",
"workspaceId": "workspace_main",
"name": "CRM Application"
}'
# Create environments
curl -X POST 'https://api.example.com/environments' \
-d '{"tenantId": "tenant_acme", "projectId": "project_crm", "name": "Production"}'
curl -X POST 'https://api.example.com/environments' \
-d '{"tenantId": "tenant_acme", "projectId": "project_crm", "name": "Staging"}'
3. Define Project-Level Roles
Roles and permissions are defined at the Project level:
# Create roles for the CRM project
curl -X POST 'https://api.example.com/roles/batch' \
-d '[
{"name": "Admin", "description": "Full project access", "scopeId": "scope_project_crm"},
{"name": "Sales Rep", "description": "Sales data access", "scopeId": "scope_project_crm"},
{"name": "Viewer", "description": "Read only", "scopeId": "scope_project_crm"}
]'
Tenant Isolation
Users Can Only Access Their Tenant
# Create user via Management API
curl -X POST 'https://api.example.com/users' \
-d '{
"kindeId": "kp_acme_user_1",
"email": "user@acme.com",
"firstName": "Acme",
"lastName": "User",
"defaultTenantId": "tenant_acme"
}'
# Add to project with a role
curl -X POST 'https://api.example.com/memberships' \
-d '{"subjectId": "subject_acme_user", "scopeId": "scope_project_crm"}'
curl -X POST 'https://api.example.com/role-assignments' \
-d '{"roleId": "role_sales_rep", "membershipId": "membership_acme_user_crm"}'
# This user has NO access to Globex tenant
# They can only access Acme's CRM project and its environments
Verifying Tenant Isolation
// Acme user tries to access Globex project
const decision = await bedrock . evaluate ({
actor: { subjectId: "subject_acme_user" , subjectType: "user" },
scopeId: "scope_project_globex_crm" , // Different tenant!
action: "read" ,
resource: { resourceType: "customer" }
});
// Result: DENIED
// User has no membership in any Globex scope
Agents in Multi-tenant Environments
Tenant-specific Agents
Each tenant can have their own AI agents scoped to their projects:
# Create Acme's sales assistant agent
curl -X POST 'https://api.example.com/subjects' \
-d '{
"subjectType": "agent",
"externalId": "acme-sales-assistant",
"displayName": "Acme Sales Assistant",
"meta": {"model": "claude-3", "purpose": "sales-support"}
}'
# Add to Acme's CRM project only
curl -X POST 'https://api.example.com/memberships' \
-d '{"subjectId": "subject_acme_agent", "scopeId": "scope_project_crm"}'
# Assign a restricted role
curl -X POST 'https://api.example.com/role-assignments' \
-d '{"roleId": "role_viewer", "membershipId": "membership_agent_crm"}'
# This agent can ONLY access Acme's CRM project
Agent Delegation
Agents should act on behalf of users for proper access control:
// Agent acting on behalf of a sales rep
const decision = await bedrock . evaluate ({
actor: { subjectId: "subject_acme_agent" , subjectType: "agent" },
onBehalfOf: { subjectId: "subject_sales_rep" , subjectType: "user" },
scopeId: "scope_project_crm" ,
action: "read" ,
resource: { resourceType: "customer" }
});
// Both agent AND user must have the permission
Permission Patterns
Project-Level Permissions
# Create permissions at project level
curl -X POST 'https://api.example.com/permissions/batch' \
-d '[
{"scopeId": "scope_project_crm", "action": "read", "resourceType": "customer", "resourcePattern": "*", "key": "customer:read:*"},
{"scopeId": "scope_project_crm", "action": "write", "resourceType": "customer", "resourcePattern": "*", "key": "customer:write:*"},
{"scopeId": "scope_project_crm", "action": "delete", "resourceType": "customer", "resourcePattern": "*", "key": "customer:delete:*"},
{"scopeId": "scope_project_crm", "action": "export", "resourceType": "report", "resourcePattern": "*", "key": "report:export:*"}
]'
Environment-Specific Overrides
# Disable delete in production environment
curl -X POST 'https://api.example.com/scope-overrides/permissions' \
-d '{
"childScopeId": "scope_env_production",
"permissionId": "perm_delete",
"state": "disabled"
}'
# Only Admins can export in production
curl -X POST 'https://api.example.com/scope-overrides/role-permissions' \
-d '{
"childScopeId": "scope_env_production",
"roleId": "role_sales_rep",
"permissionId": "perm_export",
"state": "disabled"
}'
Querying Tenant Access
Determine which projects a user has access to:
async function getUserProjects ( subjectId : string , tenantId : string ) {
// Get all memberships for this subject
const memberships = await fetch (
`/memberships?subjectId= ${ subjectId } `
);
// Filter to projects within this tenant
const projectMemberships = memberships . filter ( m =>
m . scopeId . startsWith ( 'scope_project_' ) &&
m . tenantId === tenantId
);
return projectMemberships . map ( m => m . scopeId );
}
// Check access to a specific project
async function canAccessProject ( subjectId : string , projectScopeId : string ) {
const decision = await bedrock . evaluate ({
actor: { subjectId , subjectType: "user" },
scopeId: projectScopeId ,
action: "read" ,
resource: { resourceType: "*" }
});
return decision . allowed ;
}
Best Practices
Define authorization at the Project level
Roles and permissions should be defined at the project level, not the tenant level. This allows each project to have its own authorization model.
Use environment overrides for production
Apply overrides to production environments to restrict dangerous operations.
Scope agents to specific projects
Don’t give agents tenant-wide access. Scope them to the specific projects they need.
Use delegation for agent actions
When agents act on behalf of users, use the onBehalfOf field to ensure proper access control.
Use externalId on tenants and users to map to your billing/CRM systems.
Next Steps