Dynamics 365 Security Model: Roles, Permissions, and Access Control
Introduction
Dynamics 365 security balances data protection with collaboration through a layered model: business units partition data ownership, security roles grant record-level permissions, field-level security restricts sensitive data, and hierarchy security enables manager access. This guide covers role configuration, privilege depths, team-based access, sharing, and audit trails for compliance.
Security Architecture Overview
Security Layers
User Authentication (Azure AD)
↓
Business Unit Assignment → Organizational hierarchy
↓
Security Roles → Record-level permissions (Create, Read, Write, Delete, Append, Assign, Share)
↓
Privilege Depth → Scope of access (None, User, Business Unit, Parent:Child BU, Organization)
↓
Field-Level Security → Column restrictions
↓
Hierarchy Security → Manager-subordinate access
↓
Record Sharing → Ad-hoc access grants
↓
Audit Logging → Track access and changes
Permission Model
| Privilege | Description | Example |
|---|---|---|
| Create | Add new records | Sales Rep creates Leads |
| Read | View records | Support Agent views Cases |
| Write | Modify existing records | Account Manager updates Accounts |
| Delete | Remove records | Admin deletes test data |
| Append | Associate records | Link Contact to Account |
| Append To | Be associated | Account accepts Contact link |
| Assign | Change owner | Manager reassigns Opportunity |
| Share | Grant access to others | Share Account with Sales Team |
Security Roles
Creating Custom Roles
Sales Representative role:
Business Management Tab:
├── Account: Read (Business Unit), Write (User), Create (User)
├── Contact: Read (Business Unit), Write (User), Create (User)
├── Lead: Read (Business Unit), Write, Delete (User), Create (User)
├── Opportunity: Read (Business Unit), Write, Delete (User), Create (User)
├── Quote: Read (User), Write (User), Create (User)
└── Order: Read (User)
Core Records Tab:
├── Activity: Read (Business Unit), Write (User), Create (User)
├── Email: Read (Business Unit), Write (User), Create (User)
├── Phone Call: Read (Business Unit), Write (User), Create (User)
└── Task: Read (Business Unit), Write (User), Create (User)
Customization Tab:
└── All: None (no customization access)
Business Management - Additional:
├── Price List: Read (Organization)
├── Product: Read (Organization)
└── Currency: Read (Organization)
Privilege depth meanings:
- None (⊗): No access
- User (👤): Own records only
- Business Unit (🏢): Records owned by users in same BU
- Parent: Child Business Units (🏢⇄): Current BU + child BUs
- Organization (🌐): All records across organization
Role Composition Pattern
Modular role design:
Base Role: "Employee Base"
├── Read (Organization): Account, Contact, Product
├── Read (Business Unit): Activity, Email
└── Write (User): Phone Call, Task
Sales Role: "Employee Base" + "Sales Team Member"
├── Inherits: Employee Base permissions
├── Adds: Lead (CRUD at User level)
├── Adds: Opportunity (CRUD at Business Unit level)
└── Adds: Quote (Create/Read/Write at User level)
Sales Manager Role: "Sales Team Member" + "Sales Manager Add-On"
├── Inherits: Sales Team Member
├── Elevates: Opportunity Read/Write to Parent:Child BU
├── Adds: Assign privileges for Leads/Opportunities
└── Adds: Share privileges for Accounts
System Administrator vs. Custom Admin
Delegated administration pattern:
System Administrator:
└── Full access to everything (use sparingly)
Custom Admin Role: "Environment Admin"
├── Full Customization privileges
├── User Management (Read/Write Organization)
├── Security Role Management (Read/Write Organization)
├── Business Unit (Read Organization)
├── Team (Read/Write Business Unit)
└── NO access to audit logs or system settings
Data Admin Role: "Data Steward"
├── Read/Write/Delete (Organization) for business tables
├── Import/Export privileges
├── Duplicate Detection
├── Bulk Delete
└── NO customization or user management
Business Units
Organizational Structure
Hierarchy design:
Contoso (Root BU)
├── Sales
│ ├── Sales North America
│ │ ├── Sales US East
│ │ └── Sales US West
│ ├── Sales EMEA
│ └── Sales APAC
├── Service
│ ├── Service Tier 1
│ └── Service Tier 2
└── Marketing
└── Marketing Campaigns
Data isolation rules:
- User sees records owned by users in their BU (if Read = Business Unit)
- Manager with Parent:Child BU sees their BU + all child BUs
- Records owned by BU, not individual users when team-owned
Creating Business Units
PowerShell automation:
# Connect to Dynamics 365
Install-Module Microsoft.Xrm.Data.PowerShell
$conn = Get-CrmConnection -ConnectionString "AuthType=Office365; Url=https://org.crm.dynamics.com; Username=admin@org.com; Password=****"
# Create Business Unit
$buId = New-CrmRecord -conn $conn -EntityLogicalName businessunit -Fields @{
"name" = "Sales EMEA"
"parentbusinessunitid" = @{
"LogicalName" = "businessunit"
"Id" = "parent-bu-guid"
}
}
# Move user to new BU
Set-CrmRecord -conn $conn -EntityLogicalName systemuser -Id "user-guid" -Fields @{
"businessunitid" = @{
"LogicalName" = "businessunit"
"Id" = $buId
}
}
Field-Level Security
Securing Sensitive Fields
Salary field protection:
Step 1: Enable field security
// Via SDK or Power Platform CLI
var attributeRequest = new RetrieveAttributeRequest
{
EntityLogicalName = "systemuser",
LogicalName = "annualincome"
};
var attributeResponse = (RetrieveAttributeResponse)service.Execute(attributeRequest);
var attributeMetadata = (MoneyAttributeMetadata)attributeResponse.AttributeMetadata;
attributeMetadata.IsSecured = true;
var updateRequest = new UpdateAttributeRequest
{
Attribute = attributeMetadata,
EntityName = "systemuser"
};
service.Execute(updateRequest);
Step 2: Create field security profile
Navigate to: Settings → Security → Field Security Profiles
Profile: "HR Salary Access"
├── Name: HR Salary Access
├── Members: [HR Manager, HR Director users]
└── Field Permissions:
└── Annual Income (systemuser)
├── Read: ✓
├── Update: ✓
└── Create: ✓
Profile: "Manager Salary View"
├── Members: [Department Managers team]
└── Field Permissions:
└── Annual Income (systemuser)
├── Read: ✓
├── Update: ✗
└── Create: ✗
Behavior:
- Users without profile membership: Field appears blank, cannot update
- Users with Read permission: See field value
- Users with Update permission: Can modify field
Programmatic Field Security
Check field access in plugin:
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var service = ((IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)))
.CreateOrganizationService(context.UserId);
if (context.MessageName == "Update" && context.InputParameters.Contains("Target"))
{
var target = (Entity)context.InputParameters["Target"];
if (target.Contains("annualincome"))
{
// Check if user has field security permission
var query = new QueryExpression("fieldpermission");
query.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, context.UserId);
query.Criteria.AddCondition("fieldsecurityprofileid", ConditionOperator.NotNull);
query.Criteria.AddCondition("canupdate", ConditionOperator.Equal, true);
query.Criteria.AddCondition("attributelogicalname", ConditionOperator.Equal, "annualincome");
var results = service.RetrieveMultiple(query);
if (results.Entities.Count == 0)
{
throw new InvalidPluginExecutionException("You do not have permission to update the Annual Income field.");
}
}
}
}
Hierarchy Security
Manager Access Configuration
Enable position hierarchy:
Settings → System Settings → General Tab
└── Enable Hierarchy Security: ✓
Settings → Hierarchy Security
├── Model: Manager Hierarchy (Position-based)
├── Depth: 3 levels
└── Enabled Entities:
├── Account
├── Contact
├── Opportunity
├── Lead
└── Case
How it works:
CEO Position
├── VP Sales (reports to CEO)
│ ├── Sales Manager NA (reports to VP Sales)
│ │ └── Sales Rep 1 (reports to Sales Manager NA)
│ └── Sales Manager EMEA
└── VP Service
└── Service Manager
With Hierarchy Security:
- CEO sees: All records (own + 3 levels down)
- VP Sales sees: Own + Sales Manager NA/EMEA + Sales Rep 1 records
- Sales Manager NA sees: Own + Sales Rep 1 records
- Sales Rep 1 sees: Only own records
Position setup:
Navigate to: Settings → Security → Positions
Position: "Sales Manager - North America"
├── Name: Sales Manager - North America
├── Parent Position: VP Sales
└── Users in Position:
└── John Doe (john@contoso.com)
Position: "Sales Representative"
├── Parent Position: Sales Manager - North America
└── Users in Position:
└── Jane Smith (jane@contoso.com)
Manager Hierarchy vs. Position Hierarchy
| Feature | Manager Hierarchy | Position Hierarchy |
|---|---|---|
| Based on | Manager field on User | Position entity relationships |
| Flexibility | Single manager only | Multiple users per position |
| Depth control | System-wide setting | Per-entity configuration |
| Changes | Automatic (user field) | Manual (position entity) |
| Best for | Simple hierarchies | Matrix organizations |
Teams and Ownership
Owner Teams vs. Access Teams
Owner Teams:
Team: "Sales EMEA Team"
├── Type: Owner
├── Business Unit: Sales EMEA
├── Security Roles: Sales Team Member
├── Members:
│ ├── User A (default team)
│ ├── User B (default team)
│ └── User C (additional team)
└── Owned Records:
├── Accounts: 150
├── Opportunities: 87
└── Quotes: 45
Behavior:
- Records assigned to team (not individual users)
- All members have role privileges on team-owned records
- Used for shared ownership (support queues, regional accounts)
Access Teams:
Access Team: Auto-created per Account record
Account: "Contoso Ltd"
├── Owner: John Doe
└── Access Team Members:
├── Jane (Sales Rep) - via Account Team template
├── Bob (Support) - via manual share
└── Alice (Marketing) - via record sharing
Access Rights (via Access Team Template):
- Jane: Read, Write, Append
- Bob: Read
- Alice: Read
Behavior:
- No explicit assignment, just shared access
- Different permissions per member
- Used for collaboration without changing ownership
Team Templates
Configure access team template:
Settings → Security → Access Team Templates
Template: "Account Team"
├── Entity: Account
├── Members:
│ └── (Added dynamically via Account Team subgrid)
└── Access Rights:
├── Read: ✓
├── Write: ✓
├── Append: ✓
├── Assign: ✗
└── Delete: ✗
Add to Account form:
└── Insert → Subgrid
├── Name: Account Team
├── Entity: Users
├── Team Template: Account Team
└── View: Associated Users
Record Sharing
Manual Sharing
Share opportunity with another user:
var grantAccessRequest = new GrantAccessRequest
{
Target = new EntityReference("opportunity", opportunityId),
PrincipalAccess = new PrincipalAccess
{
Principal = new EntityReference("systemuser", userId),
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess
}
};
service.Execute(grantAccessRequest);
UI: Share button on record:
Navigate to: Opportunity record → Share button
Share Opportunity
├── User/Team: [Select user or team]
├── Read: ✓
├── Write: ✓
├── Delete: ✗
├── Assign: ✗
└── Share: ✗ (cannot re-share)
Programmatic Sharing in Workflows
Power Automate: Share account with sales team:
Trigger: When an Account is created
├── Condition: Annual Revenue > $1M
├── Get Team: "Enterprise Sales Team"
└── Perform unbound action: GrantAccess
├── Target: @{triggerOutputs()?['body/accountid']}
├── PrincipalId: @{outputs('Get_Team')?['body/teamid']}
├── AccessMask: Read, Write, Append
Audit Logging
Enable Auditing
System-wide:
Settings → System Settings → Auditing Tab
├── Start Auditing: ✓
├── Audit user access: ✓
├── Log access: Read, Create, Update, Delete
└── Retention: 90 days (adjust per compliance requirements)
Per-entity:
Settings → Customizations → Entities → Account
└── Data Services
├── Auditing: ✓
└── Track changes: ✓
Settings → Customizations → Entities → Account → Fields
└── annualrevenue
├── Auditing: ✓ (track field-level changes)
Viewing Audit History
Via UI:
Account record → Related → Audit History
Displays:
├── Changed Date: 2025-10-13 14:23:00
├── Changed By: John Doe
├── Event: Update
└── Changes:
├── Annual Revenue: $500,000 → $750,000
└── Credit Limit: $50,000 → $75,000
Via SDK/API:
var query = new QueryExpression("audit");
query.Criteria.AddCondition("objectid", ConditionOperator.Equal, accountId);
query.Criteria.AddCondition("createdon", ConditionOperator.LastXDays, 30);
query.Orders.Add(new OrderExpression("createdon", OrderType.Descending));
var auditRecords = service.RetrieveMultiple(query);
foreach (var audit in auditRecords.Entities)
{
var auditDetails = service.Retrieve("audit", audit.Id, new ColumnSet(true));
// Parse AuditDetail XML for old/new values
}
Best Practices
- Principle of Least Privilege: Grant minimum necessary access
- Role Composition: Build modular roles, avoid duplicating base permissions
- Team Ownership: Use for shared queues and regional accounts
- Field Security: Protect PII, financial data, and sensitive fields
- Hierarchy Security: Enable for management visibility without role elevation
- Regular Audits: Review user access quarterly
- Document Roles: Maintain spreadsheet of role → permission mappings
Troubleshooting
User cannot see records they should access:
- Verify security role assignment (user may have multiple roles)
- Check business unit (user in wrong BU?)
- Confirm privilege depth (User vs. Business Unit vs. Organization)
- Review field-level security (field appears blank = no FLS permission)
"Access Denied" error in plugin:
- Plugin runs as calling user by default (limited by user's security)
- Use
CreateOrganizationService(null)to run as SYSTEM (full access) - Or register plugin step as "Run in User Context" = specific user
Key Takeaways
- Business units partition organizational data ownership
- Security roles define CRUD privileges with scoped depth (User/BU/Org)
- Field-level security restricts sensitive column access
- Hierarchy security enables manager visibility without role changes
- Teams enable shared ownership and collaborative access
- Audit logging tracks all data access and changes for compliance
Next Steps
- Implement Azure AD security groups for role assignment automation
- Configure data loss prevention policies
- Enable customer lockbox for Microsoft support access
- Use privileged access workstations for admin tasks
Additional Resources
Secure by design, collaborative by nature.