Run RabbitMQ as a non-root user

By default, the provided Fedora / RHEL RabbitMQ RPM creates a local user account called ‘rabbitmq’. However, the app needs to be started by the root user, which starts the service as the rabbitmq user. As far as I can tell, this is required because lock and pid files are created in root owned directories. However, since RabbitMQ, by default, does not run on a privledged port, we can customize the installation process of RabbitMQ and set it up to start, stop, and run as any user we wish. My approach was to create my own RPM package from RabbitMQ binary tar.gz.

Create custom RabbitMQ RPM Package


In order to create our own RabbitMQ RPM package, the following packages need to exist on the system:

  • rpm-build
  • redhat-rpm-config

Typically, in an rpmbuild scenario, we would also require a complier like gcc and make, but in this example, we will not be compling code since we’re going to make an RPM out of a binary distribution of files provided to us in a tar.gz.

Prepare rpmbuild environment

The first order of business is to prepare the rpmbuild directory structure. There are two ways to do this:

First

This is as easy as creating a few subdirectories along with a .rpmmacros file to contain directives not typically found in a .spec file.

DEV mquser@rabbitmq01 ~ $ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros  
DEV mquser@rabbitmq01 ~ $ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

Alternatively, install the rpmdevtools package and as a non-root user (in this example the mquser), run the command rpmdev-setuptree.

Second

Alternatively, one may wish to implement customizations from the src RPM, whereby upon installation of the src RPM, the rpmbuild directory structure is created for you along with the source files and spec file used to create the RPM. In order to do this, first create the .rpmmacros file as in the First option above, then download the src RabbitMQ RPM and install it from the home dir of the non-root user being used to build the custom RPM.

DEV mquser@rabbitmq01 ~ $ cd $HOME  
DEV mquser@rabbitmq01 ~ $ wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.3.3/rabbitmq-server-3.3.3-1.src.rpm
DEV mquser@rabbitmq01 ~ $
DEV mquser@rabbitmq01 ~ $ rpm -ivh rabbitmq-server-3.3.3-1.src.rpm</div>

If the second option is exercised, the rpmbuild and subsequent directories are put into place. Navigate around and check them out. For our purposes, we do not require everything the src RPM provides us, therefore, delete everything from the SOURCES directory except for rabbitmq-server.init

Download RabbitMQ generic unix tar ball

Now that the rpmbuild directory structure is in place, it’s time to download the binary.

DEV mquser@rabbitmq01 ~ $ cd  /export/home/mquser/rpmbuild/SOURCES  
DEV mquser@rabbitmq01 ~ $ wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.3.3/rabbitmq-server-generic-unix-3.3.3.tar.gz

Extract the contents, rename the extracted directory, and re-tar. This is necessary in order to keep the name schema consistent with how we will define our directives within the spec file.

DEV mquser@rabbitmq01 ~ $ tar zxvf rabbitmq-server-generic-unix-3.3.3.tar.gz  
DEV mquser@rabbitmq01 ~ $ mv rabbitmq_server-3.3.3 rabbitmq-3.3.3
DEV mquser@rabbitmq01 ~ $ tar cvf - ./rabbitmq-3.3.3 | gzip > rabbitmq-3.3.3.tar.gz
DEV mquser@rabbitmq01 ~ $ rm –rf ./rabbitmq-3.3.3

Create / modify the spec file

The spec file is kept in the ~/rpmbuild/SPECS directory and is what allows the custom definitions we’re after in allowing the start / stop of the RabbitMQ application as a non-root user. It is usually a good idea to model the spec file from the src RPM spec file. This can be obtained by installing the src RPM as a non-root user as described in the Second option above, and modifying the resulting spec file from the ~/rpmbuild/SPECS directory. Otherwise, a spec file can be created manually as shown here.

Name:		rabbitmq
Version: 3.3.3
Release: 1%{?dist}
Summary: RabbitMQ custom RPM build for mquser

Group: Development/Libraries
License: MPLv1.1 and MIT and ASL 2.0 and BSD
URL: http://www.rabbitmq.com/
Source0: %{name}-%{version}.tar.gz
Source1: rabbitmq-server.init
BuildArch: noarch
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)

BuildRequires: erlang >= R13B-03
Requires: erlang >= R13B-03, logrotate
Requires(post): chkconfig initscripts
Requires(pre): chkconfig initscripts

%description
RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
scalable implementation of an AMQP broker.

# Install RabbitMQ to /opt
%define _prefix /opt/

%prep
%setup -q

%build

%install
rm -rf %{buildroot}
mkdir -m 0755 -p %{buildroot}%{_prefix}%{name}
mkdir -m 0755 -p %{buildroot}%{_prefix}%{name}%{_localstatedir}
mkdir -m 0755 -p %{buildroot}%{_prefix}%{name}%{_localstatedir}/lock/subsys
cp -R * %{buildroot}%{_prefix}%{name}

#Copy all necessary start up, logrotate config files etc.
install -p -D -m 0755 %{S:1} %{buildroot}%{_initrddir}/rabbitmq-server

%clean
rm -rf %{buildroot}

%post
if [ $1 = 1 ]; then
#rpm -ivh issued for initial installation
echo "Enabling rabbitmq-management plugin"
su -c "%{_prefix}%{name}/sbin/rabbitmq-plugins enable rabbitmq_management > /dev/null 2>&1 ||:" mquser
su -c "%{_prefix}%{name}/sbin/rabbitmq-server -detached > /dev/null 2>&1 ||:" mquser

sleep 2

echo "Creating user accounts..."
su -c "%{_prefix}%{name}/sbin/rabbitmqctl add_user mqadmin password > /dev/null 2>&1 ||:" mquser
su -c "%{_prefix}%{name}/sbin/rabbitmqctl set_user_tags mqadmin administrator > /dev/null 2>&1 ||:" mquser
su -c "%{_prefix}%{name}/sbin/rabbitmqctl set_permissions -p / mqadmin \".*\" \".*\" \".*\" > /dev/null 2>&1 ||:" mquser

su -c "%{_prefix}%{name}/sbin/rabbitmqctl add_user mqreadonly password > /dev/null 2>&1 ||:" mquser
su -c "%{_prefix}%{name}/sbin/rabbitmqctl set_user_tags mqreadonly management > /dev/null 2>&1 ||:" mquser
su -c "%{_prefix}%{name}/sbin/rabbitmqctl set_permissions -p / mqreadonly \"\" \"\" \".*\" > /dev/null 2>&1 ||:" mquser

echo "Deleting guest user account"
su -c "%{_prefix}%{name}/sbin/rabbitmqctl delete_user guest > /dev/null 2>&1 ||:" mquser

echo "Shutting down server"
su -c "%{_prefix}%{name}/sbin/rabbitmqctl stop > /dev/null 2>&1 ||:" mquser
fi

chown -R mquser:root %{_prefix}%{name}/%{_localstatedir}*
echo "Please start RabbitMQ as mquser via '/etc/init.d/rabbitmq-server start'"

%preun
su -c "%{_prefix}%{name}/sbin/rabbitmqctl stop > /dev/null 2>&1 ||:" mquser

%postun
if [ $1 = 0 ]; then
#service is stopped in the preun section
#Complete uninstall
su -c "kill -9 `pidof epmd` > /dev/null 2>&1 ||:" mquser
su -c "rm -rf %{_prefix}%{name} > /dev/null 2>&1 ||:" mquser
fi

%files
%defattr(0755,mquser,root,-)
%{_prefix}%{name}/*
%{_initrddir}/rabbitmq-server

%dir %{_prefix}%{name}
%dir %{_prefix}%{name}/%{_localstatedir}

%doc

%changelog
* Mon Jun 18 2014 Kris Reese
- Initial creation

Description of Changes / Items of note

Line Item 1: Change Name to ‘rabbitmq’

Line Item 9: Change Source0 to what’s shown

Line Item 10: Change rabbitmq-server.init Source definition as Source1

get rid of all other Source definitions

Line Item 14: modify as shown

Litem Item 15: modify as shown

Line Item 25: Define prefix as /opt as this is where rabbitmq will be installed, and things like the lock and pid files will be kept.

Litem Items 34 thru 37: Define as shown. Some directories have to be made as part of the build as they’re not part of the binary tar.

%post section

  • Check if this is an initial installation – if [ $1 = 1 ] as we don’t want to run %post for an upgrade event
  • If initial, enable the rabbitmq-managment plugin as part of the installation process, create user accounts, and delete guest user
  • set permissions to the mquser

%preun and %postun

  • set steps for uninstall

Modify rabbitmq-server.init script

There are only a few lines that require modification from the rabbitmq-server.init script provided via the src RPM, and that is to add “/opt/rabbitmq” to the defined PATH, DAEMON, CONTROL, INIT_LOG_DIR, and PID_FILE variables. Also, add GROUP=users and change USER=mquser.

Build the RPM

DEV mquser@rabbitmq01 ~/rpmbuild/SPECS $ rpmbuild -bb rabitmq-server-3.3.3.spec

Once the command completes, the RPM will be written to the $HOME/rpmbuild/RPMS/noarch/rabbitmq-3.3.3-1.el6.noarch.rpm and can be installed onto any system. Things to note are:

  1. erlang is still a prerequisite to installing RabbitMQ. Please follow the instructions on RabbitMQ’s website for installing erlang.
  2. The custom RPM needs to be installed as the root user. The reason is because we’re creating directories in /opt which is owned by root, and we’re copying the rabbitmq-server init script to /etc/init.d. If these aren’t necessary for you, modify the spec file accordingly to the point where the RPM can be installed as mquser. To each their own, hence the flexibility being documented here in creating the RPM.

Once complete, RabbitMQ can be started using the ‘/etc/init.d/rabbitmq-server start’ script as the mquser. I hope this helped!

Share