如何通过 Docker 在 MongoDB 上启用身份验证?

我想为 mongodb:latest启动一个 docker,但是只允许某些用户访问某些 db (即启用 --auth)。任何人都不应该进入蒙哥达!作为码头入会仪式的一部分,我该怎么做?

顺便说一下,data directory在起始阶段通过使用以下命令坐在主机上: -v /my/own/datadir:/data/db

207619 次浏览

The Dockerfile for the official mongo image is here. The default command is mongod but you can override to add the --auth switch assuming user's are already configured.

docker run -d .... mongodb:latest mongod --auth

If the user has to be created then you need to volume mount a startup script into /entrypoint.sh to replace the default startup script and then have that script create users and start mongo with the auth switch.

docker run -d .... -v $PWD/my_custom_script.sh:/entrypoint.sh mongodb:latest

If you take a look at:

you will notice that there are two variables used in the docker-entrypoint.sh:

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

You can use them to setup root user. For example you can use following docker-compose.yml file:

mongo-container:
image: mongo:3.4.2
environment:
# provide your credentials here
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=rootPassXXX
ports:
- "27017:27017"
volumes:
# if you wish to setup additional user accounts specific per DB or with different roles you can use following entry point
- "$PWD/mongo-entrypoint/:/docker-entrypoint-initdb.d/"
# no --auth is needed here as presence of username and password add this option automatically
command: mongod

Now when starting the container by docker-compose up you should notice following entries:

...
I CONTROL  [initandlisten] options: { net: { bindIp: "127.0.0.1" }, processManagement: { fork: true }, security: { authorization: "enabled" }, systemLog: { destination: "file", path: "/proc/1/fd/1" } }
...
I ACCESS   [conn1] note: no users configured in admin.system.users, allowing localhost access
...
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}

To add custom users apart of root use the entrypoint exectuable script (placed under $PWD/mongo-entrypoint dir as it is mounted in docker-compose to entrypoint):

#!/usr/bin/env bash
echo "Creating mongo users..."
mongo admin --host localhost -u USER_PREVIOUSLY_DEFINED -p PASS_YOU_PREVIOUSLY_DEFINED --eval "db.createUser({user: 'ANOTHER_USER', pwd: 'PASS', roles: [{role: 'readWrite', db: 'xxx'}]}); db.createUser({user: 'admin', pwd: 'PASS', roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]});"
echo "Mongo users created."

Entrypoint script will be executed and additional users will be created.

@jbochniak: Thanks, although at first read I thought I've already discovered all of this, it turned out that your example (esp. the version of the Mongo Docker image) helped me out!

That version (v3.4.2) and the v3.4 (currently corresponding to v3.4.3) still support 'MONGO_INITDB_ROOT' specified through those variables, as of v3.5 (at least tags '3' and 'latest') DON'T work as described in your answer and in the docs.

I quickly had a look at the code on GitHub, but saw similar usage of these variables and couldn't find the bug immediately, should do so before filing this as a bug...

use this images to fix:

With docker-compose.yml

services:
db:
image: aashreys/mongo-auth:latest
environment:
- AUTH=yes
- MONGODB_ADMIN_USER=admin
- MONGODB_ADMIN_PASS=admin123
- MONGODB_APPLICATION_DATABASE=sample
- MONGODB_APPLICATION_USER=aashrey
- MONGODB_APPLICATION_PASS=admin123
ports:
- "27017:27017"
// more configuration

Better solutions for furthering:
https://blog.madisonhub.org/setting-up-a-mongodb-server-with-auth-on-docker/ https://docs.mongodb.com/v2.6/tutorial/add-user-administrator/

Here's what I did for the same problem, and it worked.

  1. Run the mongo docker instance on your server

    docker run -d -p 27017:27017 -v ~/dataMongo:/data/db mongo
    
  2. Open bash on the running docker instance.

    docker ps
    

    CONTAINER IDIMAGE COMMAND CREATED STATUS PORTS NAMES

    b07599e429fb mongo "docker-entrypoint..." 35 minutes ago Up 35 minutes 0.0.0.0:27017->27017/tcp musing_stallman

    docker exec -it b07599e429fb bash
    root@b07599e429fb:/#
    

    Reference- https://github.com/arunoda/meteor-up-legacy/wiki/Accessing-the-running-Mongodb-docker-container-from-command-line-on-EC2

  3. Enter the mongo shell by typing mongo.

    root@b07599e429fb:/# mongo
    
  4. For this example, I will set up a user named ian and give that user read & write access to the cool_db database.

    > use cool_db
    
    
    > db.createUser({
    user: 'ian',
    pwd: 'secretPassword',
    roles: [{ role: 'readWrite', db:'cool_db'}]
    })
    

    Reference: https://ianlondon.github.io/blog/mongodb-auth/ (First point only)

  5. Exit from mongod shell and bash.

  6. Stop the docker instance using the below command.

    docker stop mongo
    
  7. Now run the mongo docker with auth enabled.

    docker run -d -p 27017:27017 -v ~/dataMongo:/data/db mongo mongod --auth
    

    Reference: How to enable authentication on MongoDB through Docker? (Usman Ismail's answer to this question)

  8. I was able to connect to the instance running on a Google Cloud server from my local windows laptop using the below command.

    mongo <ip>:27017/cool_db -u ian -p secretPassword
    

    Reference: how can I connect to a remote mongo server from Mac OS terminal

Just dropping a .js file into the entry point init folder works for this

e.g. entrypoint.js

var db = connect("mongodb://localhost/admin");


db.createUser(
{
user: "yourAdminUserName",
pwd: "yourAdminPassword",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)

docker-compose.yml:

db:
image: mongo:3.2
volumes:
- /my/own/datadir:/data/db
- ../mongo-entrypoint:/docker-entrypoint-initdb.d

Doing the rest by hand or more of the same works.

If you want to you can also drop a .sh file into the init folder to clean up the files so they are not laying around: zz-cleanup.sh.

I want to comment but don't have enough reputation.

The user-adding executable script shown above has to be modified with --authenticationDatabase admin and NEWDATABASENAME.

mongo --authenticationDatabase admin --host localhost -u USER_PREVIOUSLY_DEFINED -p PASS_YOU_PREVIOUSLY_DEFINED NEWDATABASENAME --eval "db.createUser({user: 'NEWUSERNAME', pwd: 'PASSWORD', roles: [{role: 'readWrite', db: 'NEWDATABASENAME'}]});"

https://i.stack.imgur.com/MdyXo.png

a. You can use environment variables via terminal:

$ docker run -d --name container_name \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo

If you like to test if everything works:

// ssh into the running container
// Change container name if necessary
$ docker exec -it mongo /bin/bash


// Enter into mongo shell
$ mongo


// Caret will change when you enter successfully
// Switch to admin database
$> use admin
$> db.auth("admin", passwordPrompt())


// Show available databases
$> show dbs

If you like to instantiate a database on first run, check option b.

b. You can use environment variables in your docker stack deploy file or compose file for versions 3.4 through 4.1.

As it is explained on the quick reference section of the official mongo image set MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD in your yaml file:

mongo:
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password

docker-entrypoint.sh file in mongo image checks for the existence of these two variables and sets --auth flag accordingly.

c. You can also use docker secrets.

MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD is set indirectly by docker-entrypoint.sh from MONGO_INITDB_ROOT_USERNAME_FILE and MONGO_INITDB_ROOT_PASSWORD_FILE variables:

mongo:
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME_FILE=/run/secrets/db_root_username
- MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/db_root_password
secrets:
- db_root_username
- db_root_password

docker-entrypoint.sh converts MONGO_INITDB_ROOT_USERNAME_FILE and MONGO_INITDB_ROOT_PASSWORD_FILE to MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD.

You can use MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD in your .sh or .js scripts in docker-entrypoint-initdb.d folder while initializing database instance.

When a container is started for the first time it will execute files with extensions .sh and .js that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. .js files will be executed by mongo using the database specified by the MONGO_INITDB_DATABASE variable, if it is present, or test otherwise. You may also switch databases within the .js script.

This last method is not in the reference docs, so it may not survive an update.

I have hard time when trying to

  • Create other db than admin
  • Add new users and enable authentication to the db above

So I made 2021 answer here

My directory looks like this

├── docker-compose.yml
└── mongo-entrypoint
└── entrypoint.js

My docker-compose.yml looks like this

version: '3.4'
services:
mongo-container:
# If you need to connect to your db from outside this container
network_mode: host
image: mongo:4.2
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=pass
ports:
- "27017:27017"
volumes:
- "$PWD/mongo-entrypoint/:/docker-entrypoint-initdb.d/"
command: mongod

Please change admin and pass with your need.

Inside mongo-entrypoint, I have entrypoint.js file with this content:

var db = connect("mongodb://admin:pass@localhost:27017/admin");


db = db.getSiblingDB('new_db'); // we can not use "use" statement here to switch db


db.createUser(
{
user: "user",
pwd: "pass",
roles: [ { role: "readWrite", db: "new_db"} ],
passwordDigestor: "server",
}
)

Here again you need to change admin:pass to your root mongo credentials in your docker-compose.yml that you stated before. In additional you need to change new_db, user, pass to your new database name and credentials that you need.

Now you can:

docker-compose up -d

And connect to this db from localhost, please note that I already have mongo cli, you can install it or you can exec to the container above to use mongo command:

mongo new_db -u user -p pass

Or you can connect from other computer

mongo host:27017/new_db -u user -p pass

My git repository: https://github.com/sexydevops/docker-compose-mongo

Hope it can help someone, I lost my afternoon for this ;)

you can use env variables to setup username and password for mongo

MONGO_INITDB_ROOT_USERNAME
MONGO_INITDB_ROOT_PASSWORD

using simple docker command

docker run -e MONGO_INITDB_ROOT_USERNAME=my-user MONGO_INITDB_ROOT_PASSWORD=my-password mongo

using docker-compose

version: '3.1'


services:


mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: my-user
MONGO_INITDB_ROOT_PASSWORD: my-password

and the last option is to manually access the container and set the user and password inside the mongo docker container

docker exec -it mongo-container bash

now you can use mongo shell command to configure everything that you want

It works for me.

Create container with DB name

docker run -d \
--name mongodb \
-e MONGO_INITDB_DATABASE=trackdb \
-p 27017:27017 \
mongo

Go to in container and create user

docker exec -it mongodb bash
mongo
use trackdb
db.createUser({user: "user", pwd: "secretPassword",roles: [{ role: 'readWrite', db:'trackdb'}]})
exit
exit

Stop container:

docker stop mongodb

Check your container ID via:

docker ps -a

Change docker configuration (with your favorite editor)

sudo nano /var/lib/docker/containers/<YOUR_CONTAINER_ID>/config.v2.json

Find 2 places and add second argument:

"Args":["mongod"], --> "Args":["mongod","--auth"],

"Cmd":["mongod"], --> "Cmd":["mongod","--auth"],

Should be enough just restart the docker service, but I did sudo reboot now.

After the reboot you can verify your changes: docker inspect mongodb and find 2nd argument in 2 places. Start container and check authentication.

Enjoy!

Pretend you have two containers one for mongodb and one for api service, for mongo container to have user when initiating in addition to username & password you must add MONGO_INITDB_DATABASE too.

version: '3.4'


services:


mymongo:
container_name: mymongo
environment:
- MONGO_INITDB_DATABASE=admin // This is important
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=YOURPASSWORD
restart: unless-stopped
ports:
- "27017:27017"
volumes:
- mongo-database:/data/db
    

post.api:
container_name: post.api
environment:
- ASPNETCORE_ENVIRONMENT=Development
- DatabaseSettings__ConnectionString=mongodb://root:YOURPASSWORD@mymongodb:27017
ports:
- "5010:80"


volumes:
mongo-database:
external: false

And in your api service(here is post.api) in ApplicationContext.cs would be like this :

public ApplicationContext(IDatabaseSettings settings)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));


MongoClient client = new(settings.ConnectionString);
IMongoDatabase database = client.GetDatabase(settings.DatabaseName);
}