RE:NODE

MongoDB-ის მომხმარებლები და როლები: createUser და მინიმალური უფლებები

ავტორი RE:NODE-ის გუნდი
16 წუთის საკითხავი


MongoDB-ის მომხმარებელი არის სახელი და ბაზა, რომელშიც ის შეიქმნა, და ის აკეთებს ზუსტად იმას, რასაც მისი როლები უშვებს, სხვას არაფერს. მას ქმნი db.createUser()-ით, აძლევ ერთ ან რამდენიმე როლს - თითოეული როლი ერთ ბაზაზეა მიბმული - და შემდეგ მომხმარებელი ავტორიზაციას გადის იმ ბაზაში, სადაც შეიქმნა. აპლიკაციისთვის თითქმის ყოველთვის სწორი პასუხია ცალკე მომხმარებელი, რომელსაც აქვს readWrite მხოლოდ ამ აპლიკაციის ბაზაზე და მეტი არაფერი. დაშბორდისთვის - read. backup-ის სამუშაოსთვის - backup. სუპერმომხმარებელი root-ით password manager-ში რჩება და მას ადამიანი იყენებს, იშვიათად.

ეს არის მთელი მოდელი. ამ გაიდის დანარჩენი ნაწილი ის დეტალებია, რაც მას მუშაობს: რომელი ჩაშენებული როლი რას აკეთებს (იმ ორის ჩათვლით, რომლებიც სახელზე გაცილებით ძლიერია), სად ინახება მომხმარებლები სინამდვილეში, როგორ ნახო სია, შეცვალო პაროლი და დაარეგულირო როლები და როგორ დაწერო საკუთარი როლი, როცა არც ერთი ჩაშენებული საკმარისად ვიწრო არ არის. აქ ყველაფერი mongosh-ით კეთდება და MongoDB 5.0-სა და უფრო ახალ ვერსიებზე მუშაობს; უმეტესობა 4.x-შიც იგივეა.

სად ცხოვრობენ მომხმარებლები: ავტორიზაციის ბაზა#

ყოველი მომხმარებელი რომელიღაც ბაზაში იქმნება და ეს ბაზა მისი იდენტობის ნაწილია. shopapp, შექმნილი shop-ში, და shopapp, შექმნილი admin-ში, ორი სხვადასხვა მომხმარებელია, განსხვავებული პაროლებითა და როლებით. ბაზას, სადაც მომხმარებელი შეიქმნა, ავტორიზაციის ბაზა ჰქვია და სწორედ მას ასახელებს connection string-ის authSource პარამეტრი. MongoDB connection string-ები განმარტავს, როგორ მუშავდება ეს პარამეტრი და რატომ იძლევა არასწორი მნიშვნელობა Authentication failed-ს სწორი პაროლის მიუხედავად.

ფიზიკურად ყველა მომხმარებელი ერთ კოლექციაშია, მიუხედავად იმისა, სად შეიქმნა: admin.system.users. თითოეული დოკუმენტის db ველი ინახავს ავტორიზაციის ბაზას. ამიტომ ხანდახან მომხმარებლებს shopapp@shop სახით წერენ - სახელი, შემდეგ ავტორიზაციის ბაზა.

ავტორიზაციის ბაზა და ბაზები, სადაც მომხმარებელს მუშაობა შეუძლია, ერთმანეთისგან დამოუკიდებელია. admin-ში შექმნილ მომხმარებელს შეიძლება ჰქონდეს readWrite shop-ზე და არაფერი თავად admin-ზე, ხოლო shop-ში შექმნილს შეიძლება analytics-ზეც მიეცეს როლები. იმას, თუ სად ცხოვრობს მომხმარებელი, მხოლოდ ის წყვეტს, სად შედის; იმას, რას შეეხება, როლები წყვეტს.

ორივე კონვენცია მუშაობს:

  • ყველა მომხმარებელი `admin`-ში. ერთი ადგილი სანახავად, ერთი authSource=admin ყველა connection string-ში და როლები თითო ბაზაზე. ეს უფრო გავრცელებული სქემაა ერთ სერვერზე.
  • თითოეული აპლიკაციის მომხმარებელი თავის ბაზაში. shopapp ცხოვრობს shop-ში, blogapp - blog-ში, და show users თითოეულ ბაზაში ზუსტად იმ ანგარიშებს აჩვენებს, რომლებიც მას ეკუთვნის. connection string იყენებს authSource=shop-ს.

აირჩიე ერთი და მისი მიყევი. შერეული მდგომარეობა - ზოგი მომხმარებელი admin-ში, ზოგი სხვაგან და არავინ იცის, რომელი სად არის - დროის წამღები ჩავარდნების წყაროა.

მომხმარებლის შექმნა db.createUser-ით#

ჯერ ავტორიზაცია უნდა ჩაირთოს - security.authorization: enabled mongod.conf-ში. მის გარეშე როლები არ მოქმედებს და ნებისმიერ კავშირს ყველაფერი შეუძლია. ჰოსტინგის ბაზაზე ეს უკვე ჩართულია და პირველ მონაცემებს ისე იღებ. საკუთარ ინსტალაციაზე localhost exception საშუალებას აძლევს თავად სერვერიდან მოსულ კავშირს, შექმნას პირველი მომხმარებელი admin-ში, სანამ მომხმარებლები არ არსებობს; ის ამ მომხმარებლის შექმნისთანავე იკეტება.

დაუკავშირდი მომხმარებლით, რომელსაც მომხმარებლების მართვა შეუძლია, გადადი არჩეულ ავტორიზაციის ბაზაში და შექმენი მომხმარებელი:

javascript
use admindb.createUser({  user: "shopapp",  pwd: passwordPrompt(),  roles: [ { role: "readWrite", db: "shop" } ]})

ველები:

FieldRequiredWhat it holds
userკისახელი, უნიკალური ამ ბაზაში
pwdკიპაროლი; passwordPrompt() მას გეკითხება
rolesკიმასივი, რომელიც შეიძლება ცარიელი იყოს []
customDataარანებისმიერი დოკუმენტი შენი შენიშვნებისთვის
authenticationRestrictionsარადაშვებული კლიენტისა და სერვერის მისამართები
mechanismsარაSCRAM-SHA-1, SCRAM-SHA-256 ან ორივე

passwordPrompt() უფრო მნიშვნელოვანია, ვიდრე ჩანს. პაროლი, რომელიც პირდაპირ აკრიფე, pwd: "hunter2", რჩება terminal-ის ისტორიაში, ეკრანის გაზიარებაში და ნებისმიერ ჩანაწერში თუ სკრიპტში, სადაც ჩასვი. mongosh ცნობილ credential-ის ბრძანებებს თავისი ისტორიის ფაილში ისედაც არ ინახავს, მაგრამ მოთხოვნის შემთხვევაში კითხვა საერთოდ არ დგება.

როლი ორნაირად შეიძლება დაიწეროს. { role: "readWrite", db: "shop" } ცხადია და ყოველთვის სწორია. უბრალო სტრიქონი, "readWrite", ნიშნავს ამ როლს იმ ბაზაზე, რომელშიც ახლა ხარ - ანუ იგივე ბრძანება admin-ში readWrite-ს admin-ზე მისცემს, რაც თითქმის არასოდეს გინდა. ყოველთვის დოკუმენტის ფორმა გამოიყენე და კითხვა აღარ გაჩნდება.

customData თავისუფალი ფორმისაა და იმსახურებს გამოყენებას იმ ერთი ფაქტისთვის, რომელიც მოგვიანებით დაგჭირდება: customData: { owner: "checkout-api", created: "2026-10-15" }. ის სიის ნახვისას ჩანს, ანუ მაშინ, როცა ცდილობ გაიგო, რისთვის არის ძველი ანგარიში.

სად შეუძლია მომხმარებელს დაკავშირება

authenticationRestrictions მომხმარებელს კონკრეტული კლიენტის მისამართებით ზღუდავს, რაც firewall-ის უკან იაფი მეორე ფენაა:

javascript
use admindb.createUser({  user: "reporting",  pwd: passwordPrompt(),  roles: [ { role: "read", db: "shop" } ],  authenticationRestrictions: [ { clientSource: ["10.0.0.0/24"] } ]})

ნებისმიერი სხვა მისამართიდან შესვლა ავტორიზაციას ვერ გაივლის, სწორი პაროლითაც კი. ის იმდენად სასარგებლოა, რამდენადაც სტაბილურია შენი მისამართები: აპლიკაცია პლატფორმაზე, სადაც გამავალი მისამართი ფიქსირებული არ არის, ამას ვერ გამოიყენებს. ის არც binding-ს და firewall-ს ანაცვლებს - მიუწვდომელი port კვლავ უკეთესი კონტროლია, როგორც მონაცემთა ბაზის უსაფრთხოების checklist დაწვრილებით ამტკიცებს.

ჩაშენებული როლები და რას უშვებს ისინი სინამდვილეში#

MongoDB-ს მოყვება როლების ნაკრები, რომელიც უმეტეს საჭიროებას ფარავს. ბაზაზე მიბმული როლები ერთდროულად ერთ ბაზაზე გაიცემა:

RoleAllowsTypical holder
readყველა არასისტემური კოლექციის წაკითხვადაშბორდები, რეპორტინგი, ადამიანები
readWriteread plus insert, update, deleteაპლიკაცია
dbAdminინდექსები, სტატისტიკა, profiling, ვალიდაციაიშვიათად ვინმე მარტო
userAdminმომხმარებლებისა და როლების შექმნა და შეცვლარუტინულად არავინ
dbOwnerreadWrite, dbAdmin და userAdminერთი ბაზის სანდო ადმინისტრატორი

როლები, რომლებიც მხოლოდ admin ბაზაზე არსებობს და მთელ სერვერზე მოქმედებს:

RoleAllowsTypical holder
readAnyDatabaseread ყველა ბაზაზესერვერის მასშტაბის რეპორტინგი
readWriteAnyDatabasereadWrite ყველა ბაზაზემიგრაციის ხელსაწყოები, ხანმოკლედ
dbAdminAnyDatabasedbAdmin ყველა ბაზაზეოპერაციების ხელსაწყოები
userAdminAnyDatabaseuserAdmin ყველა ბაზაზეფაქტობრივად სუპერმომხმარებელი
clusterMonitorსერვერისა და რეპლიკაციის სტატისტიკა, მხოლოდ წასაკითხადმონიტორინგის აგენტები
backupყველაფერი, რაც mongodump-ს სჭირდებაbackup-ის სამუშაოები
restoreყველაფერი, რაც mongorestore-ს სჭირდებააღდგენის სამუშაოები, ხანმოკლედ
rootყველა ზემოთქმულის ერთადსაგანგებო ანგარიში

ამათგან სამს გულწრფელი შენიშვნა სჭირდება, რადგან სახელები მათ ნაკლებად აფასებს.

`readWrite`-ს შეუძლია კოლექციების წაშლა. insert-ის, update-ისა და delete-ის გარდა, ის შეიცავს createCollection-ს, createIndex-ს, dropIndex-ს და dropCollection-ს. ბაზას ვერ წაშლის, მაგრამ აპლიკაციას readWrite-ით და ცუდი მიგრაციის სკრიპტით მაინც შეუძლია ბაზა კოლექცია-კოლექცია დააცარიელოს. თუ შენი აპლიკაცია runtime-ზე კოლექციებს არ ქმნის და არ შლის, საკუთარ როლს (ქვემოთ) ამის მოხსნა შეუძლია.

`dbAdmin` წაკითხვის უფლება არ არის - მაგრამ წაშლა შეუძლია. ის მოიცავს ინდექსებს, სტატისტიკას, profiler-ს, collMod-ს და ვალიდაციას და არ გაძლევს ჩვეულებრივ კოლექციებში დოკუმენტების find-ის უფლებას. მაგრამ მასში შედის dropCollection და dropDatabase. ანუ მომხმარებელს მხოლოდ dbAdmin-ით არ შეუძლია შენი მონაცემების წაკითხვა და შეუძლია ყველას განადგურება. ეს უცნაური კომბინაციაა ვინმესთვის გასაცემად, ამიტომ ის იშვიათად ჩანს მარტო.

`userAdmin` შენიღბული root-ია. მომხმარებელს, რომელსაც შეუძლია მომხმარებლების შექმნა და როლების გაცემა, შეუძლია ამ ბაზაზე ნებისმიერი როლი ნებისმიერს მისცეს, საკუთარ თავსაც. ერთ ბაზაზე ეს userAdmin-ს dbOwner-ის ტოლფასს ხდის. admin-ზე userAdmin-ს ან userAdminAnyDatabase-ს root-ის გაცემა შეუძლია. MongoDB-ის საკუთარი დოკუმენტაციაც ამასვე ამბობს. ნებისმიერი ანგარიში, რომელსაც ეს ორიდან რომელიმე აქვს, სუპერმომხმარებლად ჩათვალე, ისე დაიცავი და არასოდეს ჩასვა აპლიკაციის connection string-ში.

dbOwner და ყველაფერი, რაც AnyDatabase-ით მთავრდება, აპლიკაციების შემთხვევაში იმავე კატეგორიაშია: არასოდეს. თუ აპლიკაციის მომხმარებელს ყველა ბაზაზე წვდომა აქვს, SQL-injection-ის მსგავსი query-ის შეცდომა ან გაჟონილი .env ფაილი ყველას გამოაჩენს.

მინიმალური უფლებები: ერთი მომხმარებელი ერთ საქმეზე#

მომხმარებლებზე ფიქრის სასარგებლო გზა სამუშაოს მიხედვითაა და არა ადამიანის ან სისტემის. ყველაფერს, რაც უკავშირდება, თავისი მომხმარებელი აქვს ყველაზე ვიწრო როლით, რომელიც მუშაობის საშუალებას აძლევს. ტიპური მცირე სქემა ასე გამოიყურება:

javascript
use admin// The running application: read and write its own database only.db.createUser({  user: "shop_app", pwd: passwordPrompt(),  roles: [ { role: "readWrite", db: "shop" } ],  customData: { owner: "checkout-api" }})// Dashboards and people poking about: read only.db.createUser({  user: "shop_ro", pwd: passwordPrompt(),  roles: [ { role: "read", db: "shop" } ]})// Nightly dump: the backup role, nothing else.db.createUser({  user: "backup_job", pwd: passwordPrompt(),  roles: [ { role: "backup", db: "admin" } ]})// The monitoring check: server stats, no data.db.createUser({  user: "monitor", pwd: passwordPrompt(),  roles: [ { role: "clusterMonitor", db: "admin" } ]})

ცალკე მომხმარებლები სამნაირად ამართლებს. გაჟონილი credential ერთი სამუშაოს უფლებებს ამჟღავნებს და არა ყველაფერს. ერთი პაროლის შეცვლა ერთ მომხმარებელს ეხება და არა ყველა სერვისს ერთდროულად. და სერვერის log და db.currentOp() ყოველ ოპერაციაზე მომხმარებელს აჩვენებს, ამიტომ როცა ცხრაწამიანი query გამოჩნდება, იცი რომელმა სერვისმა გამოგზავნა, სანამ გამოცნობას დაიწყებ. თუ ამას ყოველ connection string-ში appName-ს დაამატებ, კითხვა „ვინ აკეთებს ამას“ თავისით გაიცემა პასუხს.

backup-ის მომხმარებლისთვის, რომელიც მხოლოდ ერთ ბაზას აკეთებს dump-ს, ამ ბაზაზე read საკმარისია, რომ mongodump-მა მისი კოლექციები გამოიტანოს. backup როლი მთელი სერვერის dump-ისთვისაა, მომხმარებლებისა და როლების ჩათვლით, --dumpDbUsersAndRoles-ით. ორივეს მექანიკა mongodump-სა და mongorestore-ში წერია. restore მომხმარებელს მხოლოდ აღდგენის დროს მიეცი; ის ნებისმიერ ბაზაში წერს.

readWrite on shopread on shopbackupclusterMonitorაპლიკაციაshop_appდაშბორდიshop_roBackup jobbackup_jobმონიტორინგიmonitormongodauth admin-ითshop ბაზა
თითოეული მომხმარებელი თავისი user-ით უკავშირდება

იგივე იდეა სხვა ძრავებში სხვა სინტაქსით და იგივე ლოგიკით მუშაობს: MySQL-ის მომხმარებლები და privilege-ები და PostgreSQL-ის როლები და უფლებები მათ აღწერს, თუ ერთზე მეტს იყენებ.

მომხმარებლების სია და მათი უფლებების შემოწმება#

ოთხი ბრძანება თითქმის ყველა კითხვას პასუხობს იმაზე, ვინ არსებობს და რა შეუძლია:

javascript
use adminshow users                                   // users in the current databasedb.getUsers()                                // the same, as documentsdb.getUser("shop_app", { showPrivileges: true })db.adminCommand({ usersInfo: { forAllDBs: true } })   // every user on the server

show users და db.getUsers() მხოლოდ იმ მომხმარებლებს აჩვენებს, რომელთა ავტორიზაციის ბაზა ის არის, სადაც ახლა ხარ. თუ მომხმარებლებს რამდენიმე ბაზაში ქმნი, სრული სია მხოლოდ forAllDBs ფორმაა და მას მომხმარებელი სჭირდება, რომელსაც სერვერის მასშტაბით მომხმარებლების ნახვის უფლება აქვს.

showPrivileges: true მომხმარებლის როლებს რეალურ მოქმედებებად შლის, სხვა როლებიდან მემკვიდრეობით მიღებულის ჩათვლით, inheritedPrivileges-ში. ის გრძელია, მაგრამ ეს არის პასუხი კითხვაზე „შეუძლია თუ არა ამ მომხმარებელს ამ კოლექციის წაშლა“ production-ში ტესტირების გარეშე.

იმ მომხმარებლის შესამოწმებლად, რომლითაც ახლა ხარ დაკავშირებული:

javascript
db.runCommand({ connectionStatus: 1, showPrivileges: true })

authInfo.authenticatedUsers აჩვენებს, ვინ ხარ და სად გაიარე ავტორიზაცია; authenticatedUserRoles - მოქმედ როლებს. როცა აპლიკაცია იღებს not authorized on shop to execute command-ს, ამის გაშვება აპლიკაციის credential-ებით mongosh-ში ზუსტად გეტყვის, რა აქვს მას, რაც იმ კოდის კითხვაზე სწრაფია, რომელმაც ის შექმნა.

პაროლების, როლების შეცვლა და მომხმარებლების წაშლა#

მომხმარებლები დროთა განმავლობაში იცვლებიან და ყოველ ცვლილებას თავისი helper აქვს:

javascript
use admindb.changeUserPassword("shop_app", passwordPrompt())db.grantRolesToUser("shop_ro", [ { role: "read", db: "analytics" } ])db.revokeRolesFromUser("shop_ro", [ { role: "read", db: "analytics" } ])db.updateUser("shop_app", { customData: { owner: "checkout-api-v2" } })db.dropUser("old_worker")

გაუშვი ისინი მომხმარებლის ავტორიზაციის ბაზაში - changeUserPassword shop-ში იმ მომხმარებლისთვის, რომელიც admin-შია, ვარდება User shop_app@shop not found-ით, რაც იგივე შეცდომაა, რაც არასწორი authSource, ოღონდ მეორე მხრიდან დანახული.

db.updateUser() roles ველით მთელ მასივს ანაცვლებს და არ ამატებს. ერთი როლის გადაცემა მის „დასამატებლად“ ჩუმად შლის მომხმარებლის ყველა დანარჩენ როლს. ნაბიჯ-ნაბიჯ ცვლილებისთვის გამოიყენე grantRolesToUser და revokeRolesFromUser, ხოლო updateUser დატოვე customData-სთვის, authenticationRestrictions-სთვის და სრული გადაწერისთვის, რომელიც შეგნებულად გინდა.

როლების ცვლილებები დამოუკიდებელ mongod-ზე დაუყოვნებლივ მოქმედებს, უკვე გახსნილი კავშირებისთვისაც. shard-ირებულ cluster-ში mongos მომხმარებლის ინფორმაციას cache-ში ინახავს და ანახლებს userCacheInvalidationIntervalSecs-ის მიხედვით, ნაგულისხმევად 30 წამში.

აპლიკაციის პაროლის შეცვლა downtime-ის გარეშე

მომხმარებლის პაროლის შეცვლა, რომელსაც გაშვებული აპლიკაცია იყენებს, ახალ კავშირებს იმავე წამს არღვევს. უკვე არსებული pooled კავშირები ავტორიზებული რჩება, ამიტომ ჩავარდნა მოგვიანებით ჩნდება და შემთხვევითად გამოიყურება. სუფთა გზა ორი მომხმარებელია:

  1. შექმენი shop_app_2 ზუსტად იმავე როლებით, რაც shop_app-ს აქვს.
  2. ჩასვი ახალი მომხმარებელი და პაროლი აპლიკაციის environment-ში და გადატვირთე ან თავიდან deploy-ე.
  3. უყურე db.currentOp()-ს ან სერვერის log-ს, სანამ shop_app-ით ავტორიზაცია აღარავინ გაივლის.
  4. db.dropUser("shop_app").

შემდეგ ცვლილებაზე საპირისპირო მიმართულებით იარე. ეს ერთ დამატებით მომხმარებელს ღირს რამდენიმე წუთით და ნახევრად გაფუჭებულ მდგომარეობას სრულად გვარიდებს. სად უნდა ინახებოდეს credential-ები ამ დროს, environment ცვლადებსა და secret-ებში წერია.

მომხმარებლებს საკუთარი პაროლის შეცვლის უფლება

userAdmin-ზე დაბალ არც ერთ ჩაშენებულ როლს არ შეიცავს საკუთარი პაროლის შეცვლა, ამიტომ მომხმარებელს მხოლოდ readWrite-ით არ შეუძლია საკუთარ თავზე changeUserPassword-ის გაშვება. თუ გინდა, ადამიანებმა თავად შეცვალონ credential-ები, მიეცი მცირე საკუთარი როლი changeOwnPassword action-ით, რომელიც შემდეგ თავშია ნაჩვენები.

საკუთარი როლები უფრო ვიწრო საჭიროებისთვის#

როცა არც ერთი ჩაშენებული როლი არ ერგება - worker, რომელსაც შეუძლია ერთ კოლექციაში ჩაწერა და მეორის წაკითხვა, ან რეპორტინგის მომხმარებელი, რომელმაც customers კოლექცია არ უნდა ნახოს - დაწერე როლი. როლი privilege-ების სიაა, თითოეული რესურსი plus action-ები, და არასავალდებულოდ სხვა როლები, რომლებსაც მემკვიდრეობით იღებს:

javascript
use shopdb.createRole({  role: "ordersWriter",  privileges: [    { resource: { db: "shop", collection: "orders" },      actions: [ "find", "insert", "update" ] },    { resource: { db: "shop", collection: "products" },      actions: [ "find" ] }  ],  roles: []})use admindb.grantRolesToUser("order_worker", [ { role: "ordersWriter", db: "shop" } ])

ამ worker-ს შეუძლია products-ის წაკითხვა, orders-ის წაკითხვა, დამატება და შეცვლა და სხვა არაფერი: არც remove, არც dropCollection, არც სხვა კოლექციაზე წვდომა.

რესურსის ფორმები, რომლებიც უნდა იცოდე:

ResourceMeans
{ db: "shop", collection: "orders" }ერთი კოლექცია
{ db: "shop", collection: "" }shop-ის ყველა არასისტემური კოლექცია
{ db: "", collection: "orders" }orders ნებისმიერ ბაზაში
{ cluster: true }სერვერის მასშტაბის action-ები, მაგალითად serverStatus

ორი წესი იმის შესახებ, სად ცხოვრობს როლი. ჩვეულებრივ ბაზაში შექმნილ როლს შეუძლია privilege-ები მხოლოდ ამ ბაზაზე მისცეს. admin-ში შექმნილ როლს შეუძლია privilege-ები ნებისმიერ ბაზაზე და cluster-ზე მისცეს, ამიტომ ბაზათაშორისი როლები admin-ში იქმნება. და როლი სახელით და ბაზით ერთად მოიხსენიება, ზუსტად როგორც მომხმარებელი - ordersWriter shop-ში არის { role: "ordersWriter", db: "shop" }.

რამდენიმე action საკუთარი როლების უმეტესობას ფარავს: find, insert, update, remove მონაცემებისთვის; createIndex, dropIndex, createCollection, dropCollection სტრუქტურისთვის; listCollections, listIndexes, collStats, dbStats ხელსაწყოებისთვის, რომლებიც ამოწმებენ; changeOwnPassword და changeOwnCustomData თვითმომსახურებისთვის. სრული სია MongoDB manual-ის privilege actions გვერდზეა და უმჯობესია იქ შეამოწმო, ვიდრე გამოიცნო, რადგან არასწორად დაწერილი action createRole-ის დროს უარყოფილია, ხოლო გამოტოვებული მხოლოდ მაშინ ჩანს, როცა აპლიკაცია მას შეეჯახება.

თვითმომსახურების პაროლის როლი, რომელიც ზემოთ ვახსენეთ:

javascript
use admindb.createRole({  role: "changeOwnPassword",  privileges: [    { resource: { db: "admin", collection: "" },      actions: [ "changeOwnPassword", "changeOwnCustomData" ] }  ],  roles: []})

რესურსი მომხმარებლის ავტორიზაციის ბაზაა. მიეცი ის მომხმარებლის რეალურ როლთან ერთად და მას შეეძლება საკუთარ თავზე db.changeUserPassword()-ის გაშვება და არავისზე სხვაზე.

როლების შესამოწმებლად და სამართავად გამოიყენე db.getRoles({ showPrivileges: true }), db.getRole("ordersWriter", { showPrivileges: true }), db.grantPrivilegesToRole(), db.revokePrivilegesFromRole() და db.dropRole(). როლის შეცვლა ყველა მომხმარებელს ერთდროულად ცვლის, ვისაც ის აქვს - ეს არის მისი აზრი, და ამავე დროს მიზეზი, რატომ უნდა დაარქვა როლებს სამუშაოს მიხედვით და არა ადამიანის.

შეცდომები, რომლებსაც შეხვდები#

`Authentication failed` (კოდი 18). ჩვეულებრივ სწორი პაროლია, შემოწმებული არასწორ ავტორიზაციის ბაზაში. admin-ით გაუშვი db.adminCommand({ usersInfo: { forAllDBs: true } }), ნახე მომხმარებლის db ველი და authSource მას მიუსადაგე.

`not authorized on shop to execute command { ... }` (კოდი 13). ავტორიზებულია, მაგრამ როლები action-ს არ შეიცავს. შეტყობინება ბრძანებას ასახელებს; connectionStatus showPrivileges-ით აჩვენებს, რა აქვს მომხმარებელს. მიეცი ყველაზე ვიწრო როლი, რომელიც მას დაამატებს და არა dbOwner.

`command createUser requires authentication`. ანონიმურად ხარ დაკავშირებული სერვერთან, სადაც ავტორიზაცია ჩართულია. თავიდან დაუკავშირდი credential-ებით.

User already exists ან user not found. ბრძანებამდე use-მა სხვა ბაზაში მოგათავსა, ვიდრე ფიქრობდი, ამიტომ MongoDB-მ shop_app@admin-ის ნაცვლად shop_app@shop მოძებნა. მომხმარებლის ბრძანებებამდე db.getName()-ის გაშვება ამას გვარიდებს.

`Could not find role: ordersWriter@admin`. საკუთარ როლს სახელით მიმართე ბაზაში, სადაც ის არ შეგიქმნია. მიეცი სრული { role, db } დოკუმენტი იმ ბაზით, სადაც ის ცხოვრობს. იგივე შეცდომა ჩნდება ჩაშენებულ როლზე არასწორი რეგისტრით: სახელებია readWrite, dbAdmin, userAdmin და clusterMonitor, და readwrite არ არსებობს.

ჰოსტინგის MongoDB-ზე#

სერვერზე, რომელსაც ქირაობ და არა თავად აყენებ, ავტორიზაცია უკვე ჩართულია და პირველ credential-ებს გაძლევენ - RE:NODE-ზე ისინი თითოეული სერვერისთვის გენერირდება და პანელში ჩანს host-თან და port-თან ერთად, ამიტომ შესაცვლელი საერთო ნაგულისხმევი არ არსებობს. ეს ანგარიში სუპერმომხმარებლად მიიჩნიე, რადაც ის არის: გამოიყენე ზემოთ აღწერილი თითო სამუშაოზე მომხმარებლების შესაქმნელად, შეინახე password manager-ში და ნუ ჩასვამ აპლიკაციის environment-ში.

მართული cluster სერვისები ზოგჯერ მომხმარებლების მართვას shell-იდან სრულად იღებენ. მაგალითად, MongoDB Atlas მონაცემთა ბაზის მომხმარებლებს საკუთარი ინტერფეისითა და API-ით მართავს და არა db.createUser()-ით, თუმცა როლები იგივე იდეებია. დამოუკიდებელ სერვერზე, რომელსაც host-ითა და port-ით უკავშირდები, ამ გაიდის ყველაფერი ისე მუშაობს, როგორც წერია.

მომხმარებლები და როლები ბაზის შიგნით ინახება, ამიტომ ისინი იმის ნაწილია, რასაც სრულ backup-ს უნდა დაეჭიროს. მთელი სერვერის mongodump backup როლით, ან მონაცემთა დირექტორიის ფაილური დონის ასლი, შეიცავს admin.system.users-ს; ერთი ბაზის dump მომხმარებლებს არ შეიცავს, თუ ცალკე არ მოითხოვე. მონაცემთა ბაზის backup-ები და აღდგენა განმარტავს, რომელი სახეობა რომელ კატასტროფას შეესაბამება.

FAQ#

რომელ ბაზაში უნდა შევქმნა MongoDB-ის მომხმარებლები?

ან admin-ში, ან აპლიკაციის საკუთარ ბაზაში, ორივე მუშაობს და ორივეგან მყოფ მომხმარებელს შეუძლია სხვა ბაზებზე როლები ჰქონდეს. admin ყველა მომხმარებელს ერთ ადგილას ინახავს და ყველგან authSource=admin-ია; საკუთარ ბაზაში მყოფი მომხმარებელი თითოეული აპლიკაციის ანგარიშებს მის მონაცემებთან ახლოს ინახავს. აირჩიე ერთი კონვენცია და მისი მიყევი, რადგან authSource მას უნდა ემთხვეოდეს.

რით განსხვავდება readWrite dbOwner-ისგან?

readWrite მომხმარებელს აძლევს მონაცემების წაკითხვისა და შეცვლის, კოლექციებისა და ინდექსების მართვის საშუალებას. dbOwner ამატებს dbAdmin-ს და userAdmin-ს, რაც ნიშნავს, რომ მას შეუძლია ბაზის წაშლაც და მასზე ნებისმიერი როლით მომხმარებლების შექმნაც. აპლიკაციას პირველი სჭირდება და მეორე არასოდეს უნდა ჰქონდეს.

როგორ ვნახო სერვერზე MongoDB-ის ყველა მომხმარებელი?

გაუშვი db.adminCommand({ usersInfo: { forAllDBs: true } }) მომხმარებლით, რომელსაც მომხმარებლების ნახვის უფლება აქვს. show users მხოლოდ იმ მომხმარებლებს ჩამოთვლის, რომლებიც ახლანდელ ბაზაში შეიქმნა, ამიტომ არასრულად გამოიყურება, თუ მომხმარებლები ერთზე მეტ ადგილას გაქვს.

შემიძლია მომხმარებელს მხოლოდ ზოგიერთ კოლექციაზე მივცე წაკითხვის უფლება?

ჩაშენებული როლით არა - read ბაზის ყველა არასისტემურ კოლექციას ფარავს. შექმენი საკუთარი როლი find-ით თითოეულ კოლექციაზე, რომელიც ხილული უნდა იყოს, და ის მიეცი. არჩამოთვლილი კოლექციები ამ მომხმარებლის query-ებისთვის უხილავი რჩება.

როლის ცვლილებებს restart ან ხელახალი დაკავშირება სჭირდება?

არა. დამოუკიდებელ mongod-ზე როლის მიცემა ან ჩამორთმევა მაშინვე მოქმედებს, უკვე გახსნილ კავშირებზეც. shard-ირებულ cluster-ში mongos-ს შეიძლება userCacheInvalidationIntervalSecs-მდე დასჭირდეს - ნაგულისხმევად 30 წამი - შესამჩნევად.

საკმარისია ძლიერი პაროლი, თუ აპლიკაციის მომხმარებელს root აქვს?

არა. პაროლი გამოცნობისგან იცავს და არა იმისგან, რომ აპლიკაციას მოატყუებენ და ისეთ query-ს გაუშვებინებენ, რომელიც არ უნდა გაეშვა, ან მისი environment ფაილი გაჟონავს. როლის შეზღუდვა ორივე შემთხვევაში ზარალს ზღუდავს, რასაც პაროლი ვერ აკეთებს.