Azure Entra and M365¶
Azure Entra is federated with Google Workspace via SAML and SCIM. Google is the authoritative identity source. Azure Entra receives users via SCIM sync and provides M365 application access.
Architecture¶
Google Workspace (authoritative identity)
│
├── SAML federation → Azure Entra (domain federation)
│ Users authenticate via Google SSO
│
└── SCIM provisioning → Azure Entra (user objects)
Group membership triggers license assignment
Google Workspace handles all authentication. Azure Entra stores user objects (synced from GWS via SCIM) and manages M365 licenses and application access.
Integration Components¶
| Component | Purpose |
|---|---|
SAML federation (setup_federation.yml) |
Federate cwiq.io domain so Azure accepts GWS as the identity provider |
| SCIM provisioning (GWS App Autoprovisioning) | Sync GWS users to Azure Entra user objects |
Group-based license assignment (assign_group_license.yml) |
Assign M365 licenses to Azure Entra groups |
M365 License Assignment¶
The primary operation for day-to-day use is assigning M365 licenses to users via the cwiq-io-m365 Google Workspace group:
- Admin adds user to
cwiq-io-m365GWS group (via "Onboard New Hire" template withgrant_m365=yes, or manually) - GWS SCIM autoprovisioning syncs the user to Azure Entra and adds them to the
cwiq-io-m365Entra group - Group-based license assignment automatically assigns M365 Business Premium to the new group member
- Propagation takes up to 10 minutes
License SKUs¶
| SKU Part Number | Product | Price |
|---|---|---|
SPB |
Microsoft 365 Business Premium | ~$22/user/month |
POWER_BI_STANDARD |
Microsoft Fabric Free | Free |
POWERAPPS_DEV |
Power Apps for Developer | Free |
FLOW_FREE |
Power Automate Free | Free |
Managing Group Licenses¶
ssh ansible@ansible-shared-cwiq-io
ansible-helper
# List available license SKUs in the tenant
ansible-playbook azure/assign_group_license.yml --tags list-skus
# Check current license status of the M365 group
ansible-playbook azure/assign_group_license.yml --tags status \
-e "license_group_name=cwiq-io-m365"
# Dry-run: preview what would happen
ansible-playbook azure/assign_group_license.yml \
-e "license_group_name=cwiq-io-m365 license_sku=SPB license_dry_run=true"
# Assign M365 Business Premium to a group
ansible-playbook azure/assign_group_license.yml \
-e "license_group_name=cwiq-io-m365 license_sku=SPB"
# Remove a license from a group
ansible-playbook azure/assign_group_license.yml --tags remove \
-e "license_group_name=cwiq-io-m365 license_sku=SPB"
Group-based licensing requires Azure AD P1
This feature is included in M365 Business Premium. License assignment propagates to all group members within minutes and applies automatically to future members.
SCIM Attribute Mapping¶
The GWS → Azure Entra SCIM sync maps these attributes:
| GWS Attribute | Azure Entra Attribute |
|---|---|
| Formatted name | displayName |
| First name | givenName |
| Last name | surname |
| Primary email | userPrincipalName (required) |
| Primary email | onPremisesImmutableId (required) |
| Alias name | mailNickname (required) |
| Title | jobTitle |
| Department | department |
| Locality | city |
| Country | country |
| Postal code | postalCode |
| Region | state |
| Address | streetAddress |
| Phone | mobilePhone |
Initial Setup (One-Time)¶
This section documents the federation and SCIM setup that has already been completed. Only needed for new deployments or disaster recovery.
Azure App Registration¶
- Azure Entra > App registrations > New registration
- Grant Microsoft Graph application permissions:
Domain-InternalFederation.ReadWrite.AllDomain.Read.AllUser.ReadWrite.AllGroup.ReadWrite.AllGroupMember.ReadWrite.AllOrganization.Read.All- Grant admin consent for the tenant
M365 SAML App in Google Workspace¶
- GWS Admin Console > Apps > Web and mobile apps > Add app > Microsoft 365 Web (SAML)
- Service provider details:
- Start URL:
https://portal.office.com - Name ID: Basic Information > Primary email
- SAML attribute mapping: see table above
- Download
GoogleIDPMetadata.xml - User access: enable only for
cwiq.iodomain (off for any others)
Domain Federation¶
# Configure federation (one-time, uses GoogleIDPMetadata.xml)
ansible-playbook azure/setup_federation.yml
SCIM Autoprovisioning (GWS)¶
- GWS > Apps > Web and mobile apps > Microsoft Office 365 > Autoprovisioning
- Authorize the app
- Configure attribute mapping as per the table above
- Set provisioning scope to
cwiq-io-pilotgroup - Deprovisioning settings: uncheck all "suspend account" options (GWS suspension should not propagate to Azure)
- Activate autoprovisioning
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
| User not appearing in Azure Entra | Not in cwiq-io-pilot GWS group |
Add user to cwiq-io-pilot group, wait for SCIM sync (up to 15 min) |
| M365 license not assigned | User not in cwiq-io-m365 GWS group |
Add user to cwiq-io-m365 GWS group |
| License propagation delayed | Normal Azure behavior | Wait up to 10 minutes after group membership change |
| "Permission denied" in playbook | App registration missing Graph permissions | Add required permissions and grant admin consent |
Related Documentation¶
- Identity: Google Workspace — GWS user/group management with GAM
- Authentik: User Lifecycle — Full onboarding flow including M365 grant