Securing a meteor app
In this article, I show how to deploy a meteor app (Rocketchat) with tls/ssl encryption using self-signed certificates:
- https between client and the app server
- tls/ssl between the app server and mongodb
My setup:
- docker
- the server running docker is a debian server
- the app server and mongodb can be running either on a single or different machines
- the containers are in a virtual network running on a single machine
- the certificates are self-signed
- stud is used for https, other solutions can be used.
The steps are applicable to any framework and app using mongodb as a database.
The commands below are available in the git securingMeteorWithSSL.
Steps:
- Install docker
- Generate certificates
- Create the docker images
- Setup Mongodb
- Setup the app server (RocketChat)
Install docker
My server runs Debian Jessie, so I install docker from the jessie repo:
export DEBIAN_FRONTEND=noninteractive ; \
apt-get update -y ;\
apt-get install -y -q apt-transport-https ;\
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D ;\
echo "deb https://apt.dockerproject.org/repo debian-jessie main" > /etc/apt/sources.list.d/docker.list ;\
apt-get update -y -q;\
apt-get upgrade -y -q;\
apt-get install -y -q docker-engine
docker network create --subnet=172.18.0.0/16 intranet
The private virtual network is intranet 172.18.0.0/16.
Generate certificates
3 certificates are needed for this setup:
- a Certificate Authority (CA) to sign the certificates
- a certificate for the app server (https)
- a certificate for mongodb
Creating a Certificate Authority (CA)
# create a private key file
openssl genrsa -out exampleCA.key 2048
# create the CA certificate
openssl req -x509 -sha256 -new -key exampleCA.key -out exampleCA.crt -days 1460 -subj /CN="Example Inc. CA"
Creating a certificate for the app server (https)
# create a private key
openssl genrsa -out app.key 2048
# create the CSR
openssl req -new -out app.req -key app.key -subj /CN=www2.mysite.com
# use the CSR to create the certificate
openssl x509 -req -sha256 -in app.req -out app.crt -CAkey exampleCA.key -CA exampleCA.crt -days 730 -CAcreateserial -CAserial serial
# create pem file
cat app.key app.crt > app.pem
The CN in the CSR can be any address in a private network.
Creating a certificate for mongodb
Same steps as before with 127.0.0.1 as CN (in my setup mongodb doesnt take the hostname I provide neither with docker nor with my dns server):
# create a private key
openssl genrsa -out mongodb.key 2048
# create the CSR
openssl req -new -out mongodb.req -key mongodb.key -subj /CN=127.0.0.1
# use the CSR to create the certificate
openssl x509 -req -sha256 -in mongodb.req -out mongodb.crt -CAkey exampleCA.key -CA exampleCA.crt -days 730 -CAcreateserial -CAserial serial
# create pem file
cat mongodb.key mongodb.crt > mongodb.pem
Create the docker images
- Mongodb image
Copy CA and mongodb certificate to new mongodb image, the CA is then added to the truststore:
FROM mongo
COPY exampleCA.crt /
COPY mongodb.pem /
RUN export DEBIAN_FRONTEND=noninteractive ;\
apt-get purge -y ca-certificates ;\
apt-get update -y ;\
mkdir -p /usr/share/ca-certificates/ ;\
cp exampleCA.crt /usr/share/ca-certificates/exampleCA.crt ;\
apt-get install -y ca-certificates
- Rockerchat image
Add stud and run as root to connect to port 443:
FROM rocketchat/rocket.chat
# use root for stud to be able to connect to port 443
USER root
COPY nodeStart.sh /opt/
# --- stud SETUP ---
RUN mkdir -p /opt/stud ;\
mkdir -p /opt/certs ;\
useradd stud || : ;\
mkdir -p /usr/local/share/man/man8 ;\
apt-get update -y ;\
apt-get -y install libev4 libev-dev libssl-dev
COPY stud /usr/local/bin/
COPY stud.8 /usr/local/share/man/man8/
COPY stud.conf /opt/stud/
COPY app.pem /opt/certs/ssl.pem
EXPOSE 443
#EXPOSE 3000
CMD ["bash","/opt/nodeStart.sh"]
Build the images with:
docker build -t example/mongo .
docker build -t example/rocketchat .
Setup Mongodb
mkdir -p mongochatdb
docker container run -v mongochatdb:/data/db -d --net intranet --ip 172.18.0.2 --name mongochat --restart=always example/mongo --smallfiles --auth --sslMode requireSSL --sslPEMKeyFile /mongodb.pem --sslCAFile /exampleCA.crt --sslAllowConnectionsWithoutCertificates
Create mongo admin and chatdb user with mongoCreateAdmin.js and mongoChatAccess.js (NOTE: change the passwords):
mongoCreateAdmin.js
m = new Mongo();
db = m.getDB('admin');
db.createUser(
{
user: "admin",
pwd: "qwerty",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
);
mongoChatAccess.js
m = new Mongo();
db = m.getDB('admin');
db.auth('admin', 'qwerty');
db = m.getDB('chatdb');
db.dropUser('chat');
db.createUser(
{
user: 'chat',
pwd: 'qwerty',
roles: [ { role: 'dbOwner', db: 'chatdb' } ]
}
);
Add the users in mongodb:
docker cp mongoCreateAdmin.js mongochat:/
docker cp mongoChatAccess.js mongochat:/
docker exec mongochat mongo --ssl admin /mongoCreateAdmin.js
docker exec mongochat mongo --ssl -u "admin" -p "qwerty" --authenticationDatabase "admin" /mongoChatAccess.js
Setup the app server (RocketChat)
By default, the chat container exposes the port 443 but I already have a server running at this port, so I change the port to 3443.
The ROOT_URL is: https://127.0.0.1:3443
On the MONGO_URL, we need to give the mongodb user and password for the chatdb database and ssl is enabled with ?ssl=true
The rocketchat container runs in the same network as the mongodb container: --net intranet --ip 172.18.0.3
docker container run -p 3443:443 -e ROOT_URL=https://127.0.0.1:3443 -e MONGO_URL=mongodb://chat:qwerty@172.18.0.2/chatdb?ssl=true --net intranet --ip 172.18.0.3 -d --name chat --restart=always example/rocketchat
- Add the exampleCA.crt CA to your browser truststore:
FIREFOX
preferences
advanced
certificates
view certificates
authorities
import
CHROME
settings
show advanced settings...
HTTPS/SSL
manage certificates
authorities
import
Rocketchat is available at:
https://127.0.0.1:3443