{"id":1025,"date":"2026-06-09T08:45:54","date_gmt":"2026-06-09T08:45:54","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1025"},"modified":"2026-06-09T08:45:55","modified_gmt":"2026-06-09T08:45:55","slug":"mongodb-the-complete-mongodb-atlas-authentication-authorization-tutorial","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/mongodb-the-complete-mongodb-atlas-authentication-authorization-tutorial\/","title":{"rendered":"MongoDB: The Complete MongoDB Atlas Authentication &amp; Authorization Tutorial"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">MongoDB Atlas security becomes simple once you stop treating \u201cAtlas access\u201d and \u201cdatabase access\u201d as one thing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They are <strong>two different systems<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas access        = Who can manage Atlas?\nDatabase access     = Who can connect to MongoDB and read\/write data?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB\u2019s own docs make this separation clear: <strong>Atlas users access the Atlas application<\/strong>, while <strong>database users access MongoDB databases<\/strong>. Atlas Admin API access also does <strong>not<\/strong> allow reading or writing cluster data; for that, a client must authenticate to the cluster as a database user with the right roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/api\/api-authentication\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. Big Picture: The Two Security Planes<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB Atlas has two major security planes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Control Plane: Atlas Management Access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is for managing Atlas itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Create organization\nCreate project\nCreate cluster\nCreate database users\nManage backups\nManage IP access list\nManage private endpoints\nManage alerts\nUse Atlas UI\nUse Atlas Administration API\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The identities here are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas users\nTeams\nService accounts\nLegacy API keys\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The permissions here are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Organization roles\nProject roles\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Data Plane: MongoDB Database Access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is for connecting to the actual database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Connect with mongosh\nConnect from application code\nUse MongoDB Compass\nRun find \/ insert \/ update \/ delete\nRead collections\nWrite documents\nCreate indexes\nRun aggregation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The identities here are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Database users\nApplication identities\nWorkload identities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The permissions here are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MongoDB database roles\nBuilt-in roles\nCustom database roles\nSpecific privileges\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. The Most Important Diagram<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;Human or Machine] --&gt; B{What are they trying to access?}\n\n    B --&gt;|Manage Atlas| C&#91;Atlas Control Plane]\n    B --&gt;|Read or write documents| D&#91;MongoDB Data Plane]\n\n    C --&gt; C1&#91;Atlas User]\n    C --&gt; C2&#91;Team]\n    C --&gt; C3&#91;Service Account]\n    C --&gt; C4&#91;Legacy API Key]\n\n    C1 --&gt; C5&#91;Organization Role]\n    C2 --&gt; C5\n    C3 --&gt; C5\n    C4 --&gt; C5\n\n    C5 --&gt; C6&#91;Project Role]\n    C6 --&gt; C7&#91;Can manage projects, clusters, users, backup, network, alerts]\n\n    D --&gt; D1&#91;Network Access Check]\n    D1 --&gt; D2&#91;Database Authentication]\n    D2 --&gt; D3&#91;Database Authorization]\n    D3 --&gt; D4&#91;Can read\/write database resources]\n\n    D2 --&gt; D5&#91;Database User]\n    D3 --&gt; D6&#91;MongoDB Role: read, readWrite, custom role, etc.]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Translation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas role decides what you can do in Atlas.\nDatabase role decides what you can do inside MongoDB.\nNetwork access decides whether you can reach the cluster at all.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tiny but deadly important.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Authentication vs Authorization<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Authentication<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Authentication answers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Who are you?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas UI login with username\/password, SSO, MFA\nService account OAuth token for Atlas Admin API\nDatabase username\/password using SCRAM\nAWS IAM database authentication\nX.509 database authentication\nOIDC database authentication\nLDAP database authentication\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas supports several authentication mechanisms across UI, API, and database access, including service accounts for API access and database authentication options such as SCRAM, X.509, AWS IAM, LDAP, and OIDC\/OAuth-based approaches depending on the access type and setup. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/auth\/authentication\/?utm_source=chatgpt.com\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Authorization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Authorization answers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>What are you allowed to do?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Can this user create a project?\nCan this user pause a cluster?\nCan this user create database users?\nCan this app read orders?\nCan this app write payments?\nCan this analyst read only reporting data?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas uses RBAC for management authorization, and MongoDB uses role-based authorization for database-level privileges. MongoDB roles grant actions on resources, and those resources can be scoped as tightly as database or collection level. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/auth\/authorization\/?utm_source=chatgpt.com\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. Atlas Resource Hierarchy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas resources are usually organized like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    ORG&#91;Organization] --&gt; TEAM&#91;Teams]\n    ORG --&gt; USER&#91;Atlas Users]\n    ORG --&gt; SA&#91;Service Accounts \/ API Keys]\n    ORG --&gt; PROJECT&#91;Project]\n\n    PROJECT --&gt; CLUSTER&#91;Cluster]\n    PROJECT --&gt; NET&#91;Network Access]\n    PROJECT --&gt; DBACCESS&#91;Database Access]\n    PROJECT --&gt; BACKUP&#91;Backups]\n    PROJECT --&gt; ALERTS&#91;Alerts]\n    PROJECT --&gt; LOGS&#91;Logs]\n    PROJECT --&gt; CUSTOMROLES&#91;Custom Database Roles]\n\n    CLUSTER --&gt; DB1&#91;Database: app_db]\n    CLUSTER --&gt; DB2&#91;Database: reporting_db]\n    DB1 --&gt; C1&#91;Collection: users]\n    DB1 --&gt; C2&#91;Collection: orders]\n    DB2 --&gt; C3&#91;Collection: daily_sales]\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Organization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>organization<\/strong> is the top-level administrative boundary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It contains:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Projects\nAtlas users\nTeams\nBilling settings\nOrganization-level service accounts \/ API keys\nOrganization roles\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Typical organization-level roles include:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Role<\/th><th>Meaning<\/th><\/tr><\/thead><tbody><tr><td>Organization Owner<\/td><td>Root-level organization access<\/td><\/tr><tr><td>Organization Project Creator<\/td><td>Can create projects<\/td><\/tr><tr><td>Organization Billing Admin<\/td><td>Can manage billing<\/td><\/tr><tr><td>Organization Billing Viewer<\/td><td>Can view billing<\/td><\/tr><tr><td>Organization Read Only<\/td><td>Can view organization settings, users, and projects<\/td><\/tr><tr><td>Organization Member<\/td><td>Can view organization settings\/users and only projects they belong to<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">An Organization Owner gets broad root-level organization access, including Project Owner access to all projects, organization administration, user\/database-user management, and the combined privileges of other organization roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>project<\/strong> is one of the most important security boundaries in Atlas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A project contains:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Clusters\nDatabase users\nCustom database roles\nIP access list\nPrivate endpoint configuration\nBackups\nAlerts\nProject-level Atlas users \/ teams \/ service accounts\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Most teams use projects to separate environments:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dev project\nqa project\nstaging project\nprod project\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That gives you clean boundaries:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Developers can have broad access in dev.\nDevelopers can have limited access in staging.\nDevelopers can have read-only or no data access in prod.\nProduction apps get production-only database users.\nCI\/CD gets specific project-level service account roles.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Atlas Users<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">An <strong>Atlas user<\/strong> is a human account that logs in to Atlas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>rajesh@example.com logs in to cloud.mongodb.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An Atlas user can be granted:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Organization roles\nProject roles\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That user may be able to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>View projects\nCreate clusters\nManage database users\nView metrics\nUse Data Explorer\nManage IP access list\nManage backups\nInvite users\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But remember:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas user \u2260 MongoDB database user\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An Atlas user may manage a database user, but that does not automatically mean the same human can connect to the database using that Atlas login.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Teams<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>team<\/strong> is a group of Atlas users inside an organization.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You use teams to avoid assigning project roles user-by-user.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Team: Backend Developers\nMembers:\n  - Alice\n  - Bob\n  - Rajesh\n\nProject: dev\nRole:\n  - Project Data Access Read\/Write\n\nProject: prod\nRole:\n  - Project Read Only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Teams are very useful for real companies because people join, move teams, or leave. Instead of changing every project manually, you update the team membership.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    U1&#91;Alice] --&gt; T&#91;Backend Team]\n    U2&#91;Bob] --&gt; T\n    U3&#91;Rajesh] --&gt; T\n\n    T --&gt; P1&#91;dev project: Data Access Read\/Write]\n    T --&gt; P2&#91;staging project: Read Only]\n    T --&gt; P3&#91;prod project: Read Only]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>Project Access Manager<\/strong> role can add or remove teams and manage team roles within a project. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Atlas Project Roles<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Project roles control what someone can do <strong>inside a project<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common project roles:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Project role<\/th><th>What it is for<\/th><\/tr><\/thead><tbody><tr><td>Project Owner<\/td><td>Full project administration<\/td><\/tr><tr><td>Project Cluster Manager<\/td><td>Edit, pause, and resume clusters<\/td><\/tr><tr><td>Project Cluster Creator<\/td><td>Create clusters<\/td><\/tr><tr><td>Project Access Manager<\/td><td>Manage project users, teams, API keys, service accounts<\/td><\/tr><tr><td>Project Database Access Admin<\/td><td>Manage database users and custom database roles<\/td><\/tr><tr><td>Project Network Access Manager<\/td><td>Manage access lists, VPC peering, PrivateLink\/private endpoint settings<\/td><\/tr><tr><td>Project Data Access Admin<\/td><td>Use Atlas UI Data Explorer with broad data permissions<\/td><\/tr><tr><td>Project Data Access Read\/Write<\/td><td>Use Atlas UI Data Explorer to view\/modify documents<\/td><\/tr><tr><td>Project Data Access Read Only<\/td><td>Use Atlas UI Data Explorer to view documents<\/td><\/tr><tr><td>Project Read Only<\/td><td>View project metadata, metrics, activity, users, roles<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A very important nuance: <strong>Project Data Access roles are for Atlas UI data access, especially Data Explorer. They do not allow reading or writing data through the Atlas Administration API.<\/strong> MongoDB states this explicitly for Data Access Admin and Data Access Read\/Write roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Project Data Access Read\/Write\n  \u2705 Can modify documents through Atlas UI Data Explorer\n  \u274c Cannot use Atlas Admin API to query documents\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8. Atlas Admin API Access<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas Admin API access is for automation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use it for:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Terraform\nCI\/CD\nPlatform engineering\nCluster provisioning\nDatabase user management\nNetwork access automation\nBackup automation\nAlert automation\nCompliance reporting\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Modern Atlas Admin API authentication supports:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Service accounts with OAuth 2.0 access tokens\nLegacy API keys using HTTP Digest authentication\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB recommends <strong>service accounts instead of API keys<\/strong> for the Atlas Administration API, and marks API keys as a legacy authentication method. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/api\/api-authentication\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Service Accounts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A service account is a machine identity for the Atlas Admin API.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It has:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Client ID\nClient secret\nRoles\nOptional access list restrictions\nShort-lived access tokens\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Service accounts use OAuth 2.0 client credentials. They can be assigned roles like users, but they cannot log in to the Atlas UI and cannot access cluster data. Service account tokens are valid for one hour according to MongoDB\u2019s docs. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/api\/api-authentication\/\">MongoDB<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sequenceDiagram\n    participant CI as CI\/CD Pipeline\n    participant OAuth as Atlas OAuth Token Endpoint\n    participant API as Atlas Admin API\n    participant Atlas as Atlas Project\n\n    CI-&gt;&gt;OAuth: Send client ID + secret\n    OAuth--&gt;&gt;CI: Return short-lived access token\n    CI-&gt;&gt;API: Call API with Bearer token\n    API-&gt;&gt;API: Check service account role\n    API-&gt;&gt;Atlas: Create\/update Atlas resource\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">What Atlas API Can Do<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Create clusters\nPause or resume clusters\nCreate database users\nUpdate IP access list\nConfigure backups\nRead project metadata\nManage alerts\nManage service accounts\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">What Atlas API Cannot Do<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Read documents\nInsert documents\nUpdate documents\nDelete documents\nRun aggregation queries\nDump collection data\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That last part matters a lot. Atlas Admin API can create a database user, but it does not magically become that database user. MongoDB explicitly says the Atlas Administration API does not provide access to data stored in clusters. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/api\/api-authentication\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9. Database Access: The Data Plane<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">To access data in MongoDB Atlas, a client needs three things:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Network path to the cluster\n2. Valid database authentication\n3. Database authorization role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Think of it as three locked doors:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    APP&#91;Application \/ Compass \/ mongosh] --&gt; N{Network allowed?}\n    N --&gt;|No| DENY1&#91;Connection blocked]\n    N --&gt;|Yes| A{Database authentication valid?}\n    A --&gt;|No| DENY2&#91;Authentication failed]\n    A --&gt;|Yes| Z{Role allows operation?}\n    Z --&gt;|No| DENY3&#91;Unauthorized]\n    Z --&gt;|Yes| OK&#91;Operation succeeds]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A correct username\/password is not enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A correct database role is not enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You need all three.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10. Network Access<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before MongoDB even checks your database username\/password, Atlas checks whether your client can reach the cluster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common network controls:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IP access list\nTemporary IP access list entries\nVPC\/VNet peering\nPrivate endpoints \/ PrivateLink \/ Private Service Connect\nTLS\nFirewall rules\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas network security starts restrictive: database connections are blocked unless you explicitly allow inbound access through a public IP access list entry, peering\/private IPs, or private endpoints. Atlas also enforces mandatory TLS for database connections. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/network-security\/?utm_source=chatgpt.com\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">IP Access List<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An IP access list says:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only these IP addresses or CIDR ranges can connect to this project\u2019s clusters.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>203.0.113.10\/32        office IP\n10.20.0.0\/16           private network CIDR\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas project IP access list entries apply to all clusters in the project, and MongoDB documents that Atlas also supports temporary entries that expire within a configurable period. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/security\/ip-access-list\/?interface-default-atlas-cli=atlas-cli\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Private Endpoint<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A private endpoint lets your application connect to Atlas without sending traffic over the public internet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Recommended production pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Application VPC\/VNet\n  -&gt; Private endpoint\n  -&gt; Atlas cluster\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB recommends private endpoints for staging and production projects because they reduce the network trust boundary and are usually easier than managing large IP allowlists at scale. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/network-security\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Control Plane vs Data Plane IP Lists<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There are two different IP-list concepts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas API\/service account IP access list\n  Controls where Atlas API calls can come from.\n\nProject cluster IP access list\n  Controls where database connections can come from.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB explicitly distinguishes API\/programmatic access IP access lists from project data-plane IP access lists for cluster connections. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/network-security\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11. Database Users<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>database user<\/strong> is the identity used to connect to the MongoDB cluster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example connection string shape:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mongodb+srv:\/\/app_user:&lt;password&gt;@cluster-name.mongodb.net\/app_db\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The database user is usually created under:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas UI -&gt; Project -&gt; Database &amp; Network Access -&gt; Database Users\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Or by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas CLI\nAtlas Administration API\nTerraform\nAtlas Kubernetes Operator\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB says Atlas database users must be managed through Atlas-supported tools such as the Atlas UI, Atlas CLI, Atlas Administration API, or supported integrations; otherwise Atlas may roll back manual user modifications. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/security-add-mongodb-users\/?auth-method=password&amp;interface-default-atlas-cli=atlas-ui&amp;utm_source=chatgpt.com\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">12. Database User Authentication Methods<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas supports multiple database user authentication methods.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Method<\/th><th>Best for<\/th><\/tr><\/thead><tbody><tr><td>Password \/ SCRAM<\/td><td>Simple development and test setups<\/td><\/tr><tr><td>AWS IAM<\/td><td>Apps running in AWS, secret reduction<\/td><\/tr><tr><td>X.509<\/td><td>Certificate-based authentication \/ mTLS style access<\/td><\/tr><tr><td>LDAP<\/td><td>Enterprise directory integration<\/td><\/tr><tr><td>OIDC \/ OAuth 2.0<\/td><td>Modern identity federation for workforce\/workload access<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB currently recommends service accounts for Atlas API access, while database authentication can use mechanisms such as SCRAM, AWS IAM, X.509, LDAP, and OIDC depending on your cluster and identity setup. MongoDB\u2019s architecture guidance also says SCRAM is supported but recommends it primarily for development and test environments; for stronger production posture, prefer identity-based or certificate-based methods where appropriate. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/architecture\/current\/auth\/authentication\/?utm_source=chatgpt.com\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">13. Database Authorization: Roles<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Database authorization is role-based.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A database user gets one or more roles.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A role says:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>On this database or collection,\nallow these actions.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB roles grant privileges to perform actions on resources. A role can apply to a database and can grant access down to collection-level granularity. (<a href=\"https:\/\/www.mongodb.com\/docs\/manual\/reference\/built-in-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common Database Roles<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Role<\/th><th>Scope<\/th><th>Meaning<\/th><\/tr><\/thead><tbody><tr><td><code>read<\/code><\/td><td>One database<\/td><td>Can read data<\/td><\/tr><tr><td><code>readWrite<\/code><\/td><td>One database<\/td><td>Can read and write data<\/td><\/tr><tr><td><code>dbAdmin<\/code><\/td><td>One database<\/td><td>Can perform database administration tasks<\/td><\/tr><tr><td><code>readAnyDatabase<\/code><\/td><td>All databases<\/td><td>Can read across databases<\/td><\/tr><tr><td><code>readWriteAnyDatabase<\/code><\/td><td>All databases<\/td><td>Can read\/write across databases<\/td><\/tr><tr><td><code>atlasAdmin<\/code><\/td><td>Broad Atlas database admin role<\/td><td>Powerful admin role; avoid for apps<\/td><\/tr><tr><td>Custom role<\/td><td>Database\/collection\/action-specific<\/td><td>Fine-grained least privilege<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For applications, avoid broad roles unless absolutely necessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bad app user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>role: atlasAdmin\ndatabase: admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good app user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>role: readWrite\ndatabase: app_db\ncluster scope: app-prod-cluster\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Even better if the app only needs a subset of operations:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>custom role:\n  db: app_db\n  collection: orders\n  actions:\n    - find\n    - insert\n    - update\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">14. Built-In Roles vs Custom Roles<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Built-In Roles<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Built-in roles are convenient and cover common cases:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>read@app_db\nreadWrite@app_db\nreadAnyDatabase\nreadWriteAnyDatabase\nclusterMonitor\nbackup\natlasAdmin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas CLI role syntax uses this shape:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>roleName@databaseName.collectionName\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>readWrite@app_db\nread@reporting_db\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Atlas CLI docs describe the <code>--role<\/code> format as <code>roleName[@dbName[.collection]]<\/code>, where the role can be built-in or custom, and database\/collection are required for built-in roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/cli\/current\/command\/atlas-dbusers-create\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Custom Roles<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Custom roles are for least privilege.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use them when built-in roles are too broad.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example use cases:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Analyst can read only reporting_db.daily_sales\nApplication can insert orders but not delete them\nSupport user can read limited customer metadata\nETL job can read source collection and write target collection\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas custom roles can be created when built-in roles do not match the desired privileges. Atlas applies custom roles together with built-in roles and specific privileges assigned to the database user. A single database user can have multiple custom roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/security-add-mongodb-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Important behavior: if multiple assigned roles grant different permissions for the same object, Atlas honors the highest permissions granted by any role. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/security-add-mongodb-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That means there is no useful \u201cdeny role\u201d pattern like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grant readWrite\nthen deny delete\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, create a smaller custom role that only grants what you need.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">15. Project-Wide Database Users vs Cluster-Scoped Database Users<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This is one of the biggest \u201coops\u201d areas in Atlas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By default, when you create a database user with Atlas built-in roles, Atlas adds that user to all clusters in the project. To narrow that, use <strong>Restrict Access to Specific Clusters<\/strong> or define more specific privileges\/custom roles. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/security-add-mongodb-users\/?auth-method=password&amp;interface-default-atlas-cli=atlas-ui\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Risky Design<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Project: production\nClusters:\n  - prod-app-cluster\n  - prod-analytics-cluster\n  - prod-archive-cluster\n\nDatabase user:\n  app_user with readWrite@app_db\n\nProblem:\n  app_user may exist across all project clusters unless scoped.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Better Design<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Project: production\n\nDatabase user:\n  prod_app_user\n  role: readWrite@app_db\n  scope: prod-app-cluster only\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Best Design for Many Teams<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use separate projects for different environments:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dev project\nstaging project\nprod project\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then also scope users carefully inside each project.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">16. Atlas UI Data Explorer vs Database Connection<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas UI Data Explorer is a feature inside Atlas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It lets authorized Atlas users view or manipulate data through the Atlas UI.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is different from connecting with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mongosh\nMongoDB Compass\nPython driver\nNode.js driver\nJava driver\nGo driver\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A developer has:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas role:\n  Project Data Access Read Only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That means:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u2705 They may view documents in Atlas UI Data Explorer.\n\u274c They cannot use that Atlas login as a MongoDB database username.\n\u274c They cannot query documents through Atlas Admin API.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For actual database connection, they need:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Database user:\n  dev_reader\nRole:\n  read@app_db\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">17. Access Flow: Atlas UI Login<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>sequenceDiagram\n    participant User as Human User\n    participant AtlasLogin as Atlas Login \/ IdP\n    participant Atlas as Atlas UI\n    participant RBAC as Atlas RBAC\n    participant Project as Atlas Project\n\n    User-&gt;&gt;AtlasLogin: Sign in\n    AtlasLogin--&gt;&gt;Atlas: Authenticated identity\n    Atlas-&gt;&gt;RBAC: Check org\/project roles\n    RBAC--&gt;&gt;Atlas: Allowed actions\n    Atlas-&gt;&gt;Project: Show\/manage permitted resources\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Rajesh logs in to Atlas.\nAtlas authenticates Rajesh.\nAtlas checks his organization and project roles.\nAtlas shows only what his roles allow.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If Rajesh has <code>Project Read Only<\/code>, he can view project metadata but cannot access Data Explorer or retrieve process\/audit logs. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">18. Access Flow: Atlas Admin API<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>sequenceDiagram\n    participant Pipeline as CI\/CD Pipeline\n    participant Token as OAuth Token Service\n    participant API as Atlas Admin API\n    participant RBAC as Atlas Project RBAC\n    participant Atlas as Atlas Resource\n\n    Pipeline-&gt;&gt;Token: Request access token using service account\n    Token--&gt;&gt;Pipeline: Access token\n    Pipeline-&gt;&gt;API: API call with token\n    API-&gt;&gt;RBAC: Check service account role\n    RBAC--&gt;&gt;API: Allow or deny\n    API-&gt;&gt;Atlas: Change Atlas configuration\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CI\/CD service account wants to create a database user.\nIt must have a project role that allows managing database access.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good role:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Project Database Access Admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Too broad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Project Owner\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Project Database Access Admin role can manage database access and custom database roles, but it does not create clusters, access Data Explorer, or retrieve process\/audit logs. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">19. Access Flow: Application Connecting to MongoDB<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>sequenceDiagram\n    participant App as Application\n    participant Net as Atlas Network Rules\n    participant Cluster as Atlas Cluster\n    participant Auth as Database Authentication\n    participant Authz as MongoDB Authorization\n    participant Data as Database \/ Collection\n\n    App-&gt;&gt;Net: Connect from source IP\/private endpoint\n    Net--&gt;&gt;App: Allowed or blocked\n\n    App-&gt;&gt;Cluster: Start TLS connection\n    Cluster-&gt;&gt;Auth: Validate database user credentials\n    Auth--&gt;&gt;Cluster: Authenticated\n\n    App-&gt;&gt;Authz: Request operation: insert into app_db.orders\n    Authz--&gt;&gt;Cluster: Role allows insert?\n    Cluster-&gt;&gt;Data: Execute operation if allowed\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app_user connects from Kubernetes.\nAtlas checks whether the Kubernetes egress IP or private endpoint is allowed.\nMongoDB checks app_user credentials.\nMongoDB checks whether app_user has insert permission on app_db.orders.\nOnly then does the insert succeed.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">20. Hands-On Tutorial: Build a Secure Atlas Access Model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s design a realistic setup.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Scenario<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Company: ExampleCorp\nEnvironment: dev, staging, prod\nApplication: ecommerce-api\nDatabase: ecommerce\nCollections:\n  - users\n  - orders\n  - payments\n  - products\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Teams:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Platform Team\nBackend Developers\nData Analysts\nAuditors\nCI\/CD Automation\nProduction Application\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Create Organization and Projects<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Recommended project layout:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Organization: ExampleCorp\n\nProjects:\n  ecommerce-dev\n  ecommerce-staging\n  ecommerce-prod\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why separate projects?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Cleaner access control\nSeparate database users\nSeparate IP access lists\nSeparate backup settings\nSeparate alerts\nSafer production boundary\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Mermaid:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    ORG&#91;ExampleCorp Organization]\n    ORG --&gt; DEV&#91;ecommerce-dev Project]\n    ORG --&gt; STG&#91;ecommerce-staging Project]\n    ORG --&gt; PROD&#91;ecommerce-prod Project]\n\n    DEV --&gt; DEVCLUSTER&#91;dev cluster]\n    STG --&gt; STGCLUSTER&#91;staging cluster]\n    PROD --&gt; PRODCLUSTER&#91;prod cluster]\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Create Atlas Teams<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suggested teams:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Team<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>atlas-org-admins<\/code><\/td><td>Very small admin group<\/td><\/tr><tr><td><code>platform-engineers<\/code><\/td><td>Cluster\/network\/backup operations<\/td><\/tr><tr><td><code>backend-developers<\/code><\/td><td>Development team<\/td><\/tr><tr><td><code>data-analysts<\/code><\/td><td>Reporting and analytics<\/td><\/tr><tr><td><code>security-auditors<\/code><\/td><td>Read-only audit access<\/td><\/tr><tr><td><code>support-readonly<\/code><\/td><td>Limited support access<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Assign Atlas Roles<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suggested access matrix:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Team<\/th><th>dev<\/th><th>staging<\/th><th>prod<\/th><\/tr><\/thead><tbody><tr><td>atlas-org-admins<\/td><td>Project Owner<\/td><td>Project Owner<\/td><td>Project Owner<\/td><\/tr><tr><td>platform-engineers<\/td><td>Project Owner or Cluster Manager<\/td><td>Cluster Manager<\/td><td>Cluster Manager + Network Access Manager<\/td><\/tr><tr><td>backend-developers<\/td><td>Data Access Read\/Write<\/td><td>Data Access Read Only<\/td><td>Project Read Only<\/td><\/tr><tr><td>data-analysts<\/td><td>Data Access Read Only<\/td><td>Data Access Read Only<\/td><td>Data Access Read Only, preferably limited<\/td><\/tr><tr><td>security-auditors<\/td><td>Project Read Only<\/td><td>Project Read Only<\/td><td>Project Read Only<\/td><\/tr><tr><td>support-readonly<\/td><td>Project Read Only<\/td><td>Project Read Only<\/td><td>Project Read Only<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Production hot take: do not give developers broad prod write access by default. That is how \u201cI was just checking something\u201d becomes a postmortem title.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Configure Network Access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For dev:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Temporary IP access entries may be acceptable.\nDeveloper office\/VPN IPs may be allowed.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For staging:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Prefer private network access.\nAllow CI\/CD and staging app network only.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For prod:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Use private endpoints where possible.\nAvoid 0.0.0.0\/0.\nAllow only production app network.\nAllow only production CI\/CD network for automation.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Bad prod setting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0.0.0.0\/0\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Better prod setting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Private endpoint from production VPC\/VNet\nCI\/CD static egress IP only if needed\nNo developer laptop IPs\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Create Database Users<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use different database users for different purposes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bad pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>one_user_to_rule_them_all\nrole: atlasAdmin\nused by app, developers, BI tools, cron jobs\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dev_app_user\nstaging_app_user\nprod_app_user\nprod_reporting_reader\nprod_migration_user\nprod_breakglass_admin\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example Users<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>User<\/th><th>Role<\/th><th>Scope<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>dev_app_user<\/code><\/td><td><code>readWrite@ecommerce<\/code><\/td><td>dev cluster<\/td><td>Dev app<\/td><\/tr><tr><td><code>staging_app_user<\/code><\/td><td><code>readWrite@ecommerce<\/code><\/td><td>staging cluster<\/td><td>Staging app<\/td><\/tr><tr><td><code>prod_app_user<\/code><\/td><td><code>readWrite@ecommerce<\/code><\/td><td>prod app cluster only<\/td><td>Production app<\/td><\/tr><tr><td><code>prod_reporting_reader<\/code><\/td><td><code>read@reporting<\/code><\/td><td>prod analytics cluster only<\/td><td>Reports<\/td><\/tr><tr><td><code>prod_migration_user<\/code><\/td><td>Custom migration role<\/td><td>prod cluster, temporary<\/td><td>Migrations<\/td><\/tr><tr><td><code>prod_breakglass_admin<\/code><\/td><td>Powerful admin role<\/td><td>prod, highly controlled<\/td><td>Emergency only<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">21. Atlas CLI Examples<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Database User with Built-In Role<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>atlas dbusers create \\\n  --username prod_app_user \\\n  --password '&lt;use-a-secret-manager-generated-password&gt;' \\\n  --role readWrite@ecommerce \\\n  --scope prod-cluster \\\n  --projectId '&lt;PROJECT_ID&gt;'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Atlas CLI supports <code>atlas dbusers create<\/code>, accepts <code>--username<\/code>, <code>--password<\/code>, <code>--role<\/code>, <code>--scope<\/code>, and <code>--projectId<\/code>, and uses <code>--scope<\/code> to define the clusters the user can access. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/cli\/current\/command\/atlas-dbusers-create\/\">MongoDB<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Read-Only Reporting User<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>atlas dbusers create \\\n  --username prod_reporting_reader \\\n  --password '&lt;use-a-secret-manager-generated-password&gt;' \\\n  --role read@reporting \\\n  --scope prod-analytics-cluster \\\n  --projectId '&lt;PROJECT_ID&gt;'\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Temporary Migration User<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>atlas dbusers create \\\n  --username prod_migration_user \\\n  --password '&lt;temporary-secret&gt;' \\\n  --role readWrite@ecommerce \\\n  --scope prod-cluster \\\n  --deleteAfter '2026-06-16T00:00:00Z' \\\n  --projectId '&lt;PROJECT_ID&gt;'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Atlas CLI supports <code>--deleteAfter<\/code> for a timestamp after which Atlas deletes the database user. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/cli\/current\/command\/atlas-dbusers-create\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">22. Custom Role Example<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose an analytics job should only read:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>reporting.daily_sales\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It should not read:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>reporting.customer_pii\nreporting.payments_raw\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create a custom role conceptually like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Role: dailySalesReader\nResource:\n  db: reporting\n  collection: daily_sales\nActions:\n  find\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then assign:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User: analytics_job_user\nRole: dailySalesReader\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Flow:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    Job&#91;Analytics Job] --&gt; User&#91;analytics_job_user]\n    User --&gt; Role&#91;dailySalesReader]\n    Role --&gt; Resource&#91;reporting.daily_sales]\n    Role --&gt; Action&#91;find only]\n\n    User -. denied .-&gt; PII&#91;reporting.customer_pii]\n    User -. denied .-&gt; Payments&#91;reporting.payments_raw]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Custom roles are ideal when built-in roles like <code>read@reporting<\/code> are too broad, because <code>read@reporting<\/code> would read the whole database, not just one collection.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">23. Complete Access Design Example<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Human Admin Access<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Identity:\n  Alice, Platform Engineer\n\nAtlas access:\n  Team: platform-engineers\n  Project role: Project Cluster Manager\n  Project role: Project Network Access Manager\n\nDatabase access:\n  No default database user\n  Temporary admin database user only when needed\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Alice can manage infrastructure.\nAlice cannot casually browse production data.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Developer Access<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Identity:\n  Backend developer\n\nAtlas access:\n  dev: Project Data Access Read\/Write\n  staging: Project Data Access Read Only\n  prod: Project Read Only\n\nDatabase access:\n  dev database user only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Developers can move fast in dev.\nProduction data remains protected.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Production App Access<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Identity:\n  ecommerce-api\n\nAtlas access:\n  None\n\nDatabase access:\n  prod_app_user\n  role: readWrite@ecommerce\n  scope: prod-cluster\n  network: private endpoint only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>The app does not need Atlas UI or Atlas Admin API access.\nIt only needs database access.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">CI\/CD Access<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Identity:\n  ci-cd-service-account\n\nAtlas access:\n  Service account\n  Project Database Access Admin, if it manages DB users\n  Project Cluster Manager, if it updates clusters\n  Project Network Access Manager, if it updates access lists\n\nDatabase access:\n  Usually none\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CI\/CD manages Atlas configuration.\nIt should not read customer data unless specifically required.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Analyst Access<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Identity:\n  Data analyst\n\nAtlas access:\n  Possibly Project Data Access Read Only\n\nDatabase access:\n  reporting_reader\n  role: read@reporting\n  or custom collection-level role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Analysts read curated reporting data.\nThey should not read operational or sensitive collections by default.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">24. Authorization Decision Tree<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use this when someone asks: \u201cWhat access should I give?\u201d<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    START&#91;User or app needs access] --&gt; Q1{Need to manage Atlas resources?}\n\n    Q1 --&gt;|Yes| ATLAS&#91;Grant Atlas org\/project role]\n    Q1 --&gt;|No| Q2{Need to read\/write database data?}\n\n    ATLAS --&gt; Q1A{Human or machine?}\n    Q1A --&gt;|Human| USER&#91;Atlas user or team]\n    Q1A --&gt;|Machine| SA&#91;Service account preferred]\n\n    USER --&gt; ROLE1&#91;Assign least-privilege project\/org role]\n    SA --&gt; ROLE2&#91;Assign least-privilege service account role]\n\n    Q2 --&gt;|Yes| DBUSER&#91;Create database user]\n    Q2 --&gt;|No| NOACCESS&#91;No access needed]\n\n    DBUSER --&gt; Q3{What data scope?}\n    Q3 --&gt;|Whole database read| READ&#91;read@db]\n    Q3 --&gt;|Whole database read\/write| RW&#91;readWrite@db]\n    Q3 --&gt;|One collection\/actions only| CUSTOM&#91;Custom DB role]\n    Q3 --&gt;|Admin tasks| ADMIN&#91;Specific admin role, avoid broad admin]\n\n    READ --&gt; NET&#91;Configure network access]\n    RW --&gt; NET\n    CUSTOM --&gt; NET\n    ADMIN --&gt; NET\n\n    NET --&gt; TEST&#91;Test with actual operation]\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">25. Common Mistakes<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 1: Confusing Atlas User with Database User<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wrong assumption:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u201cI can log in to Atlas, so I can connect with mongosh.\u201d\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Reality:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas login is for Atlas UI.\nDatabase connection needs database credentials.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 2: Giving Apps Atlas Admin API Access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most apps do not need this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas service account\nProject Owner\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Most apps need this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Database user\nreadWrite@app_db\nNetwork access from app environment\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 3: Using One Database User Everywhere<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>same username\/password in dev, staging, prod\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dev_app_user\nstaging_app_user\nprod_app_user\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 4: Leaving Database User Unscoped<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User exists across all clusters in the project\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Restrict Access to Specific Clusters\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 5: Using <code>atlasAdmin<\/code> for Applications<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Application role: atlasAdmin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Application role: readWrite@app_db\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Custom role with only required actions\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 6: Allowing Public Internet Too Broadly<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0.0.0.0\/0\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Private endpoint\nStatic egress IP\nVPN CIDR\nTemporary IP access entry for short-lived work\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 7: Assuming Project Read Only Means Data Read Only<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>Project Read Only<\/code> is mostly Atlas control-plane visibility. It does not grant Data Explorer access. MongoDB\u2019s docs say Project Read Only grants view-only access to project control plane metadata but not Data Explorer access. (<a href=\"https:\/\/www.mongodb.com\/docs\/atlas\/reference\/user-roles\/\">MongoDB<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">26. Troubleshooting Guide<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Error: \u201cAuthentication failed\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Likely causes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Wrong username\nWrong password\nWrong authSource\nUser deleted or expired\nWrong authentication mechanism\nSCRAM vs AWS IAM vs X.509 mismatch\nPassword contains special characters not URL-encoded\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Is the database user present in Atlas?\nIs the password correct?\nIs the connection string correct?\nIs authSource correct?\nFor AWS IAM, is authMechanism=MONGODB-AWS?\nFor X.509, does certificate subject match expected user?\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Error: \u201cnot authorized on db to execute command\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Likely causes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User authenticated successfully\nBut role does not allow the attempted operation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User has read@app_db\nOperation is insert into app_db.orders\nResult: unauthorized\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Fix:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Grant readWrite@app_db\nor create a custom role with insert on app_db.orders\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Error: \u201cconnection timed out\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Likely causes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IP not allowed\nPrivate endpoint not configured correctly\nFirewall issue\nDNS issue\nWrong connection string\nCluster paused\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Project IP access list\nPrivate endpoint status\nVPC\/VNet routing\nSecurity groups \/ firewall rules\nCluster status\nDNS resolution\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Error: \u201cuser works in dev but not prod\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Likely causes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Different project\nDifferent database user\nDifferent network access\nDifferent cluster scope\nDifferent password\nDifferent role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Fix:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Compare dev and prod:\n  project role\n  database user role\n  cluster scope\n  network access\n  connection string\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">27. Recommended Production Security Model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use this as your production baseline.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Atlas Organization<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Very few Organization Owners\nSSO \/ federated authentication enabled\nMFA enforced\nSeparate teams for admins, developers, auditors\nNo shared human accounts\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Atlas Projects<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Separate dev, staging, prod projects\nSeparate database users per environment\nSeparate network rules per environment\nSeparate service accounts per automation pipeline\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Atlas API<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Use service accounts instead of legacy API keys\nGrant least-privilege project roles\nRestrict API access to trusted CI\/CD IPs\nRotate secrets\nStore client secrets in a secret manager\nDo not use API access for app data queries\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Database Users<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>One database user per app\/service\/job\nNo shared superuser\nNo atlasAdmin for app runtime\nUse readWrite only on required database\nUse custom roles for sensitive collections\nUse temporary users for short-lived migration\/admin work\nRestrict users to specific clusters\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Network<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Use private endpoints for staging\/prod\nAvoid 0.0.0.0\/0\nUse temporary IP entries for emergency work\nKeep app egress IPs stable\nSeparate control-plane API IP lists from data-plane cluster access lists\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Operations<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Review users and roles regularly\nRemove unused database users\nRotate app secrets\nMonitor Activity Feed\nAudit database access where required\nUse break-glass access with approval and expiry\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">28. The Best Mental Model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Remember this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas user\/team\/service account\/API key\n  -&gt; controls Atlas management actions\n\nDatabase user\n  -&gt; controls MongoDB data actions\n\nNetwork access\n  -&gt; controls who can reach the cluster\n\nDatabase roles\n  -&gt; control what authenticated clients can do inside MongoDB\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">One more diagram to tattoo on the inside of your eyelids:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;Need Access] --&gt; B{Atlas Management or Database Data?}\n\n    B --&gt;|Atlas Management| C&#91;Atlas Identity]\n    C --&gt; C1&#91;Human: Atlas User \/ Team]\n    C --&gt; C2&#91;Machine: Service Account]\n    C1 --&gt; C3&#91;Org Role \/ Project Role]\n    C2 --&gt; C3\n    C3 --&gt; C4&#91;Manage Atlas Resources]\n\n    B --&gt;|Database Data| D&#91;Database Identity]\n    D --&gt; D1&#91;Database User]\n    D1 --&gt; D2&#91;Authentication Method]\n    D2 --&gt; D3&#91;SCRAM \/ AWS IAM \/ X.509 \/ LDAP \/ OIDC]\n    D3 --&gt; D4&#91;Database Roles]\n    D4 --&gt; D5&#91;read \/ readWrite \/ custom privileges]\n    D5 --&gt; D6&#91;Read or Write Documents]\n\n    D --&gt; E&#91;Network Access]\n    E --&gt; E1&#91;IP Access List \/ Private Endpoint \/ Peering]\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">29. Final Cheat Sheet<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Need<\/th><th>Use this identity<\/th><th>Use this permission<\/th><\/tr><\/thead><tbody><tr><td>Log in to Atlas UI<\/td><td>Atlas user<\/td><td>Org\/project role<\/td><\/tr><tr><td>Assign users to projects<\/td><td>Atlas user or team<\/td><td>Project Access Manager \/ Project Owner<\/td><\/tr><tr><td>Automate cluster creation<\/td><td>Service account<\/td><td>Project Cluster Creator \/ Project Owner as needed<\/td><\/tr><tr><td>Automate DB user creation<\/td><td>Service account<\/td><td>Project Database Access Admin<\/td><\/tr><tr><td>Connect app to MongoDB<\/td><td>Database user<\/td><td><code>readWrite@app_db<\/code> or custom role<\/td><\/tr><tr><td>Read reports only<\/td><td>Database user<\/td><td><code>read@reporting<\/code> or custom role<\/td><\/tr><tr><td>View documents in Atlas UI<\/td><td>Atlas user\/team<\/td><td>Project Data Access Read Only<\/td><\/tr><tr><td>Modify documents in Atlas UI<\/td><td>Atlas user\/team<\/td><td>Project Data Access Read\/Write<\/td><\/tr><tr><td>Query documents from app\/API\/driver<\/td><td>Database user<\/td><td>MongoDB database role<\/td><\/tr><tr><td>Restrict source network<\/td><td>Network access<\/td><td>IP list\/private endpoint\/VPC peering<\/td><\/tr><tr><td>Emergency admin<\/td><td>Temporary database user<\/td><td>Short-lived admin role, audited<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">30. One-Sentence Summary<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">MongoDB Atlas authentication and authorization is best understood as <strong>three gates<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Atlas RBAC controls who manages Atlas.\nNetwork access controls who can reach the cluster.\nDatabase RBAC controls who can read\/write MongoDB data.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Keep those gates separate, grant the smallest useful permission at each gate, and your Atlas security model becomes clean, scalable, and production-grade.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>MongoDB Atlas security becomes simple once you stop treating \u201cAtlas access\u201d and \u201cdatabase access\u201d as one thing. They are two different systems: MongoDB\u2019s own docs make this&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1025","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1025","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1025"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1025\/revisions"}],"predecessor-version":[{"id":1026,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1025\/revisions\/1026"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}