Working with Rocket Chat and OpenID Connect (RH-SSO)

Oren Oichman
Nerd For Tech
Published in
7 min readApr 2, 2021

Why Rocket Chat ?

Well… for many reasons.
I have been working for a long time in the disconnected environment and I have not found a web application for community/communities communication as good as Rocket Chat.
In Rocket Chat I can create a channel for each group and gave permission (as admin) to anyone I wanted to.
More so I notice that the communication within the organization is better and intermediate communication between different teams have increased significantly.

What’s in the Tutorial ?

In this tutorial I will do a walk through about how to run a small deployment of Rocket chat in our OpenShift environment and how to configure it to work with our organization OpenID Connect provider (In our case it will be Red Hat SSO)

Where to start ?

First we are going to deploy a very minimal deployment of rocket chat (if you want an enterprise grade deployment there is a great tutorial here) then we are going to connected Rocket Chat to RH SSO.

NOTE!
this document already assumes you are running the RH SSO (or Keycloak) application. In case you have not done that yet you can follow my story about how to configure the RH SSO (keycloak) application here

Deployment

As always , let’s first of all create the project :

# oc new-project rocketchat

Deploy MongoDB

Rocket Chat’s database is MongoDB configured with a replica set. In our case we are going to start only one POD but we still need to make sure it comes up with a replica set. for this we will use statefulset with args option.

Our mongodb will need a persistent storage so first we will create a PVC for it and then the POD it self.

For the persistent storage :

# cat > mongodb-pvc.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
EOF

And apply if :

# oc apply -f mongodb-pvc.yaml

Next we will create the statefulset :

# cat > mongodb-sfs.yaml << EOF
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: mongo
labels:
k8s-app: mongo
spec:
serviceName: mongo
replicas: 1
selector:
matchLabels:
k8s-app: mongo
template:
metadata:
labels:
k8s-app: mongo
name: mongo
spec:
terminationGracePeriodSeconds: 10
volumes:
- name: mongo
persistentVolumeClaim:
claimName: mongodb-pvc
containers:
- image: registry.example.com/mongo:4.2
name: mongo
volumeMounts:
- mountPath: /data/db
name: mongo
ports:
- name: mongo
containerPort: 27017
args:
- --replSet=rs01
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "512Mi"
EOF

And apply it :

# oc apply -f mongodb-sfs.yaml

Next we would like to create a small cron job that will initiate the replica set in case of a failure.

# cat > mongodb-cronjob.yaml << EOF
apiVersion: batch/v1
kind: Job
metadata:
name: mongo-0-init
spec:
backoffLimit: 4
template:
spec:
containers:
- name: mongo-0-init
image: mongo:4.2
command: ["sh", "-c", "sleep 15; mongo mongo-0.mongo/rocketchat --eval \"rs.initiate({_id: 'rs01',members: [ { _id: 0, host: 'mongo-0.mongo:27017' } ]})\""]
restartPolicy: OnFailure
EOF

and apply it :

# oc create -f mongodb-cronjob.yaml

Now we will want to access our mongodb so let’s go ahead and create a service for it :

# cat > mongodb-svc.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: mongo
labels:
k8s-app: mongo
name: mongo
spec:
ports:
- port: 27017
targetPort: 27017
selector:
k8s-app: mongo
EOF

Once it is created we are good to move forward to the application part :

# oc apply -f mongodb-svc.yaml

Rocket Chat Deployment

Rocket Chat stores data in files out of the database , for the porpase it will need a PVC of it’s own :

# cat > rocketchat-data-pvc.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rocketchat-data-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
EOF

And let’s apply it :

# oc apply -f rocketchat-data-pvc.yaml

Add custom CA certificates

working with OpenID Connect depends on the application passing the TLS verification process. In order to do that we need to add our custom CA certificates to the rocket chat image.

To achieve that there are 2 ways :

  1. add the CA to the Image
  2. create a ConfigMap with the CA certificate file.

In our example we will add the CA to our image for a couple of reasons.
Sense we are working in a disconnected environment we are directing our image to an internal registry (in our case registry.example.com) so changing the digest of the image has next to none effects. Secondly I believe it is a good practice to know more then one way to achieve what you want and if in some case we would want to create an Operator (Hint for the future) and deploy the application with the Operator then we would not be able to add a ConfigMap to it (unless it is part of the Operator).
To update the image all we basically need to do is to COPY the CA certificate to the IMAGE and tell node.js (Rocket Chat’s middle ware) about our added certificate with an environment variable.

To add the CA create the following Dockerfile :
(for our example our ca certificate file is named ca.crt and it located in the same directory with the Dockerfile file.

# cat > Dockerfile << EOF
FROM registry.example.com/rocket.chat:latest
MAINTAINER You Rock
USER root
RUN mkdir /etc/certs
COPY ca.crt /etc/certs/keycloak.crt
USER rocketchat
EOF

We are using buildah to update the image and then push it back to our registry.

# buildah bud -f Dockerfile -t registry.example.com/rocket.chat
# buildah push registry.example.com/rocket.chat:latest

Now that the Image has been updated we need to add the ‘NODE_EXTRA_CA_CERTS’ environment variable to our rocket chat deployment and point rocket chat to our mongodb.

The deployment file should look like this :

# cat > rocketchat-deployment.yaml << EOF
kind: Deployment
apiVersion: apps/v1
metadata:
name: rocketchat
labels:
k8s-app: rocketchat
spec:
replicas: 1
selector:
matchLabels:
k8s-app: rocketchat
template:
metadata:
labels:
k8s-app: rocketchat
name: rocketchat
spec:
volumes:
- name: rocketchat
persistentVolumeClaim:
claimName: rocketchat-data-pvc
containers:
- image: registry.example.com/rocket.chat:latest
imagePullPolicy: Always
name: rocketchat
env:
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MONGO_URL
value: "mongodb://mongo-0.mongo:27017/rocketchat?replicaSet=rs01"
- name: MONGO_OPLOG_URL
value: "mongodb://mongo-0.mongo:27017/local?replicaSet=rs01"
- name: ROOT_URL
value: "https://chat.example.com"
- name: PORT
value: "3000"
- name: NODE_EXTRA_CA_CERTS
value: /etc/certs/keycloak.crt
volumeMounts:
- mountPath: /app/uploads
name: rocketchat
ports:
- name: http
containerPort: 3000
EOF

In my example I am directing the application to the pod name but we can choose and use the mongodb service if we want to.

Next we would create a service and an ingress for rocket chat :

# cat > rocketchat-service.yaml << EOF
kind: Service
apiVersion: v1
metadata:
name: rocketchat
spec:
selector:
k8s-app: rocketchat
ports:
- protocol: TCP
port: 3000
name: http
EOF

Because we want to serve over TLS/SSL we need to create our certificate (a good how to can be found here) and create a secret which holds the certificate.

To create the secret run :

# oc create secret generic chat-tls \
--from-file=key.pem=`pwd`/chat.key \
--from-file=cert.pem=`pwd`/chat.crt \
-n rocketchat

And create a file for the ingress :

# cat > rocketchat-ingress.yaml << EOF
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: rocketchat-ingress
spec:
tls:
- hosts:
- chat.example.com
secretName: chat-tls
rules:
- host: "chat.example.com"
http:
paths:
- backend:
serviceName: rocketchat
servicePort: 3000
path: /
EOF

Now that we finished with the deployment we can move forward to the OpenID Connect configuration:

Go to chat.example.com (to the FQDN you gave the rocket chat ingress).
If this is your first time create a new admin user and then go to the administration page :

Then scroll down to “oauth” (or go to : https://{rocket_chat_URL}/admin/OAuth :

And now click on “Add custom oauth” (on the top right) :

Add a name (something like “RH-SSO”)

and then start filling the following values :

The URL paths provided in the below configurations can be also obtained by navigating to the Realm setting and clicking the endpoints link in the General Tab. While configuring the below settings replace the realm_name with the appropriate realm name. The default realm provided by Keycloak is master.

  1. Make sure you switch the bar to Enable
  2. URL: http://{rh-sso_URL:{port}/auth
  3. Token Path: /realms/{realm_name}/protocol/openid-connect/token
  4. Token sent via: Header
  5. Identity Token Sent Via: Same As “Token Sent Via”
  6. Identity Path /realms/{realm_name}/protocol/openid-connect/userinfo
  7. Authorize Path /realms/{realm_name}/protocol/openid-connect/auth
  8. Scope: openid
  9. Param Name for access token: access_token
  10. Id: This is the id of the Rocket.Chat client created in the keycloak rocket-chat-client
  11. Secret: Secret key provided in the credentials tab when creating the Rocket.Chat client
  12. Button Text: Login with Keycloak
  13. Click on “Save Chnages”

Now logout from the user (on the “user” icon) and now you will see the “OpenID Connect” link.

Click on it and Login with your Organization Username and Password. and you will be redirect to Rocket Chat.

If you have any question feel free to responed/ leave a comment.
You can find on linkedin at : https://www.linkedin.com/in/orenoichman
Or twitter at : https://twitter.com/ooichman

HAVE FUN !!!

--

--