How to add initial users when starting a RabbitMQ Docker container?

68,473

Solution 1

You can create a simple Dockerfile that extends the functionality of the basic image and creates a default user. The Docker file you need is the following:

FROM rabbitmq

# Define environment variables.
ENV RABBITMQ_USER user
ENV RABBITMQ_PASSWORD user
ENV RABBITMQ_PID_FILE /var/lib/rabbitmq/mnesia/rabbitmq

ADD init.sh /init.sh
RUN chmod +x /init.sh
EXPOSE 15672

# Define default command
CMD ["/init.sh"]

And the init.sh:

#!/bin/sh

# Create Rabbitmq user
( rabbitmqctl wait --timeout 60 $RABBITMQ_PID_FILE ; \
rabbitmqctl add_user $RABBITMQ_USER $RABBITMQ_PASSWORD 2>/dev/null ; \
rabbitmqctl set_user_tags $RABBITMQ_USER administrator ; \
rabbitmqctl set_permissions -p / $RABBITMQ_USER  ".*" ".*" ".*" ; \
echo "*** User '$RABBITMQ_USER' with password '$RABBITMQ_PASSWORD' completed. ***" ; \
echo "*** Log in the WebUI at port 15672 (example: http:/localhost:15672) ***") &

# $@ is used to pass arguments to the rabbitmq-server command.
# For example if you use it like this: docker run -d rabbitmq arg1 arg2,
# it will be as you run in the container rabbitmq-server arg1 arg2
rabbitmq-server $@

This script also initialize and expose the RabbitMQ webadmin at port 15672.

Solution 2

Came up with a solution that suits my needs, leaving it here in case anybody else needs it.

Summary

The idea is to take a standard rabbitmq container with management plugin enabled and use it to create the required configuration, then export and use it to start new containers. The below solution creates a derived docker image but it also works to just mount the two files at runtime (e.g. using docker compose).

References

Components

  • official rabbitmq image, management plugin version (rabbitmq:management)

  • custom image based on the original one, with this Dockerfile (using version 3.6.6):

     FROM rabbitmq:3.6.6-management
     ADD rabbitmq.config /etc/rabbitmq/
     ADD definitions.json /etc/rabbitmq/
     RUN chown rabbitmq:rabbitmq /etc/rabbitmq/rabbitmq.config /etc/rabbitmq/definitions.json
     CMD ["rabbitmq-server"]
    
  • rabbitmq.config just tells rabbitmq to load definitions from the json file

  • definitions.json contains the users, vhosts, etc. and can be generated by the export function of the management web interface

rabbitmq.config example:

[
  {rabbit, [
    {loopback_users, []}
  ]},
  {rabbitmq_management, [
    {load_definitions, "/etc/rabbitmq/definitions.json"}
  ]}
].

definitions.json example:

{
 "rabbit_version": "3.6.6",
 "users": [
  {
   "name": "user1",
   "password_hash": "pass1",
   "hashing_algorithm": "rabbit_password_hashing_sha256",
   "tags": ""
  },
  {
   "name": "adminuser",
   "password_hash": "adminpass",
   "hashing_algorithm": "rabbit_password_hashing_sha256",
   "tags": "administrator"
  }
 ],
 "vhosts": [
  {
   "name": "\/vhost1"
  },
  {
   "name": "\/vhost2"
  }
 ],
 "permissions": [
  {
   "user": "user1",
   "vhost": "\/vhost1",
   "configure": ".*",
   "write": ".*",
   "read": ".*"
  }
 ],
 "parameters": [],
 "policies": [],
 "queues": [],
 "exchanges": [],
 "bindings": []
}

Alternave version

Deriving a new docker image is just one solution and works best when portability is key, since it avoids including host-based file management in the picture.

In some situations using the official image and providing configuration files from storage local to the host might be preferred.

The rabbitmq.config and definitions.json files are produced the same way, then mounted at runtime.

Notes:

  • I'm assuming they have been placed in /etc/so/ for the sake of these examples
  • files need to either be world readable or owned by the rabbitmq user or group (numerical id inside the docker container is 999), this needs to be handled by the host's sysadmin

docker run example:

    docker run --rm -it \
        -v /etc/so/rabbitmq.config:/etc/rabbitmq/rabbitmq.config:ro \
        -v /etc/so/definitions.json:/etc/rabbitmq/definitions.json:ro \
        rabbitmq:3.6-management

docker compose example:

    version: '2.1'
    services:
        rabbitmq:
            image: "rabbitmq:3.6-management"
            ports:
                - 5672:5672
                - 15672:15672
            volumes:
                - /etc/so/rabbitmq.config:/etc/rabbitmq/rabbitmq.config:ro
                - /etc/so/definitions.json:/etc/rabbitmq/definitions.json:ro

Solution 3

The newest version of the RabbitMQ image on Dockerhub has in-built functionality for changing the default username / password from "guest" / "guest" to something else.

Simply set the environment variables "RABBITMQ_DEFAULT_USER" and "RABBITMQ_DEFAULT_PASS" when starting the image.

As a docker command, you would run the image like this:

docker run \
-e RABBITMQ_DEFAULT_USER=test-user \
-e RABBITMQ_DEFAULT_PASS=test-user \
-p 5672:5672 \
rabbitmq

Solution 4

I would like to add that sudo's response helped me a lot. But that it still missed a command to be added to the Dockerfile.

The rabbitmq.config and definitions.json file should be owned by the rabbitmq user & group. So after adding the files run chown.

The full Dockerfile in my case was the following:

FROM rabbitmq:3-management-alpine
ADD definitions.json /etc/rabbitmq/
ADD rabbitmq.config /etc/rabbitmq/
RUN chown rabbitmq:rabbitmq /etc/rabbitmq/rabbitmq.config /etc/rabbitmq/definitions.json

EXPOSE 4369 5671 5672 15671 15672 25672

CMD ["rabbitmq-server"]

The rabbitmq.config file has the following content being a merge from the default image's config and the added definitions loading:

[
    { rabbit, [
        {loopback_users, []},
        { tcp_listeners, [ 5672 ]},
        { ssl_listeners, [ ]},
        { hipe_compile, false } 
    ]},
    { rabbitmq_management, [
        { load_definitions, "/etc/rabbitmq/definitions.json"},
        { listeners, [
            { port, 15672 },
            { ssl, false } 

        ]}
    ]}
].

The definitions file can be exported from the management interface in the overview tab.

So you would first create a normal 'empty' rabbitmq container. Define whatever users, exchanges and queues you like. Then enter the management interface, export the definitions and create your own image using the file as described above.

Downloading the definitions is the easiest way to get the right password hashes in the definitions file for your own passwords. If you do not wish to do that you should follow the instructions as noted here (https://www.rabbitmq.com/passwords.html) to generate the correct hashes.

Solution 5

With RabbitMQ 3.7, and the newer rabbitmq.conf (sysctl) configuration format, the following sets up RabbitMQ with a default user and queue in Docker, you can optionally add the following RUN commands in the dockerfile to create users...

RUN rabbitmqctl add_user {username} {password}
RUN rabbitmqctl set_user_tags {username} administrator
RUN rabbitmqctl set_permissions ...

rabbitmq.conf

# Default user
default_user = testuser
default_pass = testpassword

## The default "guest" user is only permitted to access the server
## via a loopback interface (e.g. localhost).
loopback_users.guest = true

# IPv4
listeners.tcp.default = 5672

## HTTP listener and embedded Web server settings.
management.tcp.port = 15672

# Load queue definitions
management.load_definitions = /etc/rabbitmq/definitions.json

#Ignore SSL
ssl_options.verify               = verify_peer
ssl_options.fail_if_no_peer_cert = true

definitions.json

{
  "rabbit_version": "3.7.11",
  "users": [
    {
      "name": "testuser",
      "password_hash": "txn+nsYVkAaIMvDsH8Fsyb3RWMCMWihRUVCk/wICL1NBKKvz",
      "hashing_algorithm": "rabbit_password_hashing_sha256",
      "tags": "administrator"
    }
  ],
  "vhosts": [ { "name": "test-vhost" } ],
  "permissions": [
    {
      "user": "testuser",
      "vhost": "test-vhost",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    }
  ],
  "topic_permissions": [],
  "parameters": [],
  "global_parameters": [
    {
      "name": "cluster_name",
      "value": "rabbit@test-rabbit"
    }
  ],
  "policies": [],
  "queues": [
    {
      "name": "testqueue",
      "vhost": "test-vhost",
      "durable": true,
      "auto_delete": false,
      "arguments": {}
    }
  ],
  "exchanges": [],
  "bindings": []
}

Dockerfile

FROM rabbitmq:3.7-management

COPY rabbitmq.conf /etc/rabbitmq
COPY definitions.json /etc/rabbitmq

RUN ls /etc/rabbitmq
RUN cat /etc/rabbitmq/rabbitmq.conf

Dockers commands to build and run the container...

docker build -t rabbitmq-with-queue .
docker run --rm -it --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq-with-queue
Share:
68,473
Marco
Author by

Marco

Happy coder, system architect, software geek, cloud believer, tech guy, open-source enthusiasts, wannabe cooking chef, likes to travel, meet new people, share knowledge, and watch movies/series.

Updated on January 12, 2022

Comments

  • Marco
    Marco over 2 years

    Currently i am starting RabbitMQ Docker container using the default RabbitMQ image from DockerHub. Using the following commands.

    docker run --restart=always \
    -d \
    -e RABBITMQ_NODENAME=rabbitmq \
    -v /opt/docker/rabbitmq/data:/var/lib/rabbitmq/mnesia/rabbitmq \
    -p 5672:5672 \
    -p 15672:15672 \
    --name rabbitmq rabbitmq:3-management
    

    I have a need where i want to provide defaults users / and virtual-hosts when the image is first started. For example to create a default 'test-user'.

    Currently i have to do that manually by using the management plugin and adding the users / virtual-hosts via the web ui. Is there a way i can provide default settings when starting the RabbitMQ image?

  • Marco
    Marco about 9 years
    Thanks for your suggestion, but somehow the users do not get persisted.
  • Marco
    Marco about 9 years
    Got it working, but i have maybe a stupid question.. what does the $@ at the rabbitmq-server do?
  • george.yord
    george.yord about 9 years
    $@ is used to pass arguments to the rabbitmq-server command. For example if you use it like this: docker run -d rabbitmq [arg1] [arg2], it will be as you run in the container rabbitmq-server [arg1] [arg2].
  • Joris Mans
    Joris Mans over 8 years
    cd /tmp ; \ wget http://localhost:15672/cli/rabbitmqadmin ; \ mv ./rabbitmqadmin /rabbitmqadmin ; \ chmod +x /rabbitmqadmin ; \ I think these lines can be removed, as the admin command is already available inside the container.
  • blueFast
    blueFast about 8 years
    @JorisMans: and wget is not available in the base rabbitmq image
  • Marco
    Marco over 7 years
    @JanuszSkonieczny Maybe something wrong with your line endings? I just tried the instructions again and it worked.
  • Janusz Skonieczny
    Janusz Skonieczny over 7 years
    @Marco, thx line ending where wrong. But I'm not sure why passing env RABBITMQ_DEFAULT_USER and RABBITMQ_DEFAULT_PASS settings don'g have any effect. You end up with guest admin user with guest password, which is not desirable ;)
  • Marco
    Marco over 7 years
    @JanuszSkonieczny The post was just an example on how stuff could be done. You can pull the RABBITMQ_DEFAULT_USER etc into the init.sh and create the correct user
  • george.yord
    george.yord over 7 years
    @JorisMans: Thanks, great suggestion, I edited the answer and removed the rabbitmqadmin installation.
  • cdimitroulas
    cdimitroulas over 7 years
    I get this error: /usr/local/bin/docker-entrypoint.sh: line 296: /init.sh: Permission denied. Did I miss something?
  • Derek
    Derek about 7 years
    Does this actually work? On 3.6.6 I can't add any users without first having the node/application running. It looks like you are adding them before running rabbitmq-server.
  • Mihail Petkov
    Mihail Petkov about 7 years
    Add RUN ["chmod", "+x", "/init.sh"], otherwise it doesn't work.
  • GhostCat
    GhostCat almost 7 years
    I think you have enough content to make this an answer. So rather delete all the sentences that prevent this from being an answer (like saying: should be a comment). And that comment-needs-50 rule exists for good reasons.
  • Tom P.
    Tom P. almost 7 years
    Sorry those reputation roles are a sore point. There's been many times I felt like wanting to contribute something in a comment, an upvote and for everything I would get the 'this requires x reputation' message. Makes it a really high boundary to start contributing. In any case, thanks for the comment, I've made those changes. :)
  • GhostCat
    GhostCat almost 7 years
    The problem is that a very high number of people get accounts here. Too many of them give zip nada niente about quality. It only takes 1,2 well received questions to get to "upvote", and 1,2 well received answers and you are up to "comment".
  • mbeacom
    mbeacom almost 7 years
    @MihailPetkov You should be setting the init.sh file to executable before COPYing the shell script and building the image. That'll eliminate the need for this step, as file attributes are preserved by default.
  • Kent Bull
    Kent Bull almost 7 years
    @TomP. That was great recommending the export from Rabbit. That really saved me time! And it is completely accurate. This should be combined with sudo's answer as the accepted answer.
  • Kent Bull
    Kent Bull almost 7 years
    This is a great solution. @Tom.P adds a little to this with the definitions export from Rabbit. Combine the two and that should be the accepted answer. This worked for me!
  • sudo
    sudo almost 7 years
    @KentJohnson the fact that "definitions.json [...] can be generated by the export function of the management web interface" is already one of my points, that's how I did it too (the provided examples are just to get an idea right away)
  • sudo
    sudo over 6 years
    Added chown command to make sure permissions are ok (thanks @Tom P.) and added an alternate solution that uses the official image + configuration files mounted at runtime
  • Darwayne
    Darwayne over 6 years
    for anyone trying to use this approach with docker-compose. I had to replace ; with && inside of the init.sh file and this will work like a charm.
  • Oleg Shleif
    Oleg Shleif about 6 years
    I tried and the user is not created. I set sleep 10 in init.sh file and user was created...
  • jmhostalet
    jmhostalet almost 6 years
    I've found this password hashing script which was pretty useful for me also gist.github.com/lukebakken/7b4da46ed9abb7ed14f7a60b49f9e52e
  • jmhostalet
    jmhostalet almost 6 years
    I've found this password hashing script which was pretty useful for me also gist.github.com/lukebakken/7b4da46ed9abb7ed14f7a60b49f9e52e
  • Kleyson Rios
    Kleyson Rios over 5 years
    Great solution. The main problem is to find documentation for the definitions.json. But you can do manually all the configuration and then export the definiton medium.com/@thomasdecaux/…
  • Nathan Julsrud
    Nathan Julsrud over 5 years
    You will need to account for rabbitmq startup time. It's running all user commands in the background. The reason this works is because of the sleep 5 statement. It's basically saying do these commands in the background, while starting rabbitmq. @Derek If you have a cluster with a lot of established queues/exchanges you will need to make sleep 5 a lot longer, OR write some type of loop that waits for rabbit to come back to life first. @MihailPetkov your suggestion can't work because of how Docker treats CMD
  • user3793803
    user3793803 over 5 years
    About the sleep 5, If you want a more reliable way to wait for rabbitmq to be initalized, I would suggest to use this instead : rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbitmq.pid. I'm using a docker-compose running a lot of containers and it worked for me.
  • Cocowalla
    Cocowalla over 4 years
    Unfortunately it doesn't seem possible to combine this with a definitions file :(
  • jeffaudio
    jeffaudio over 4 years
    Using rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbitmq.pid worked for me as well, but I had to manually set the environment variable RABBITMQ_PID_FILE to that location as well or the pid file would be generated with a random name.
  • george.yord
    george.yord over 4 years
    Thank you all for the valid comments. @user3793803 I incorporated your suggestion, very nice one! I also added a --timeout 60 param to override the default 10 seconds waiting time to stay on the safe side and wait even if ReabbitMQ takes a little bit longer to load.
  • xbmono
    xbmono almost 4 years
    Thanks. This worked for me, the env variable was the key
  • Vinicius Dantas
    Vinicius Dantas almost 4 years
    Perfect advice, thanks. I used this idea together with the kubernetes docs on configmap (didn't know about this feature) for increasing the heartbeat of my rabbitmq server by saving a file under /etc/rabbitmq/conf.d/. But I didn't need to use subPath. Thank you so much for your contribution
  • NicoE
    NicoE over 3 years
    Since RabbitMQ 3.8.2, it's possible to load definitions at node boot time load_definitions = /path/to/definitions/file.json in rabbitmq.conf . docs
  • lollerskates
    lollerskates about 3 years
    i have a clarifying question: do we add rabbitmq-server $@ at the end of the bash script because we override the default start command in the Dockerfiles with CMD ["/init.sh"]?
  • Iman
    Iman almost 3 years
    convert '/etc/rabbitmq/rabbitmq.config' to the newer sysctl format ('/etc/rabbitmq/rabbitmq.conf'); see https://www.rabbitmq.com/configure.html#config-file
  • jimnkey
    jimnkey over 2 years
    At first I thought this wasn't supported because of the comment of 'WARNING' -- but the actual variables the warning is for are NOT these. I added the other ports : -p 15672:15672 -p 15692:15692 -- but this answer is good for what I was looking for - something very simple, easy to pass on to team - thanks! It would have saved me a bit of time if I didn't read that warning comment!
  • michasaucer
    michasaucer over 2 years
    How to deal with output: `/init.sh: line 1: syntax error near unexpected token rabbitmqctl' 'init.sh: line 1: ( rabbitmqctl wait --timeout 60 $RABBITMQ_PID_FILE ; ` ?