Jan. 3, 2021
So as my girlfriend Emma and I setup the logistics of our new apartment in Boston, we quickly figured out that we had many accounts that would really be joint, but only filed under one person's name. Some of the bills were in my name, such as internet, while others were under her name like gas and electric, yet I felt that we both should have access to the accounts in case we needed to get a bill paid quickly.
Also, being two security minded people, Emma and I both use Bitwarden to create new passwords on the sites we visit so we have strong, unique passwords to our accounts. This makes it so that if one company has a data breach, not all of your accounts are leaked. However, Bitwarden only offers password sharing between organizations, which is a premium feature for the hosted service. However, since Bitwarden is open-source, you can self host the premium version on your own hardware if you would like and unlock all of the features. Since I was already paying for the kubernetes cluster that is hosting this blog, I figured I would throw a bitwarden server behind my traefik instance and utilize the nodes a little more efficiently. Two birds with one stone.
So initially, while looking up bitwarden self hosted options, I first landed on the official Bitwarden Github Page. It looks like it could be run with Docker, which means that the image is hosted somewhere, which is perfect for what I needed!
However, as I started to do more testing locally with the docker image, the official image seemed to be very resource heavy... Ok, not that resource heavy, but certainly more than I wanted since it required an instanced of sql server to be running. So, I started to look for other open source projects around the web and stumbled upon bitwarden_rs. It is the Bitwarden API written in rust and it's rocket server. This was exactly what I was looking for. A lightweight, simple Bitwarden server that could write to small sqlite3 instanced inside the container in the /data directory.
I also really loved that Bitwarden unofficially supports bitwarden_rs and actually files issues in their github if problems arise. On the flip side, bitwarden_rs actively encourages their users to contribute to upstream development, whether it be through financial contributions or fixing bugs. So if you are following along with this blog, please consider donating to this wonderful service.
The first thing I did before deciding on bitwarden_rs was read over their entire wiki which you can find here. If I miss anything in this blog article, I guarantee you it will be in their wiki, and I encourage my readers to also read the wiki before following along. It will help you understand my implementation further, and maybe even find things I have missed.
Next, I dove into creating the kubernetes manifests. Since bitwarden_rs maintains a public docker image, it was pretty easy to get the Kubernetes deployment going. You can find the code below, with short explanations after each snippet:
--- apiVersion: v1 kind: ConfigMap metadata: name: bitwarden labels: app: bitwarden data: SMTP_HOST: "smtp.domain.tld" SMTP_FROM: "email@example.com" SMTP_PORT: "587" SMTP_SSL: "true" # nginx-ingress-controller has built in support for Websockets # Project: https://github.com/kubernetes/ingress-nginx WEBSOCKET_ENABLED: "true" DATA_FOLDER: "/data" DOMAIN: "https://bitwarden.domain.tld" ROCKET_WORKERS: "5" SHOW_PASSWORD_HINT: "false" WEB_VAULT_ENABLED: "true" ROCKET_PORT: "8080" # Bitwarden RS settings SIGNUPS_ALLOWED: "false" LOG_FILE: "/data/bitwarden.log"
After reading over the wiki, it became apparent that bitwarden_rs uses environment variables for most of their user config. So, I collected all the variables I wanted to change from their defaults and stuck them in the above configmap. As you can see, I disable sign-ups and disable showing password hints to harden our server a little bit more, while also lowering the rocket worker number since I want the server to be super lightweight.
apiVersion: v1 kind: Secret metadata: name: bitwarden-admin-token labels: app: bitwarden type: Opaque data: # openssl rand -base64 48 token: ""
Next, the wiki recommended creating an admin token using openssl in order to be able to access the bitwarden admin page and create new organizations and such. However, in our case, we want to be able to store this secret in Kubernetes and attach it to our bitwarden service account (more on that next). So above is the yaml to create that secret in kubernetes and give it a name. I left a comment in there just so I don't forget how to create the token at a later date :)
--- apiVersion: v1 kind: ServiceAccount metadata: name: bitwarden labels: app: bitwarden --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: bitwarden rules: - apiGroups: - "" resources: - configmaps resourceNames: - "bitwarden" verbs: - get - apiGroups: - "" resources: - secrets resourceNames: - "bitwarden-admin-token" verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: bitwarden roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: bitwarden subjects: - kind: ServiceAccount name: bitwarden
Next, I created a Kubernetes service account, role, and role binding to make sure that our bitwarden account that will be running our bitwarden container cannot perform CRUD operations arbitrarily on other resources in Kubernetes. Here, we specify in our role that our bitwarden service account can only access our secret we made above and the configmap that contains other non-secure configuration settings, and then bind it to the account.
apiVersion: apps/v1 kind: Deployment metadata: name: bitwarden labels: name: bitwarden spec: selector: matchLabels: pod: bitwarden replicas: 1 template: metadata: labels: pod: bitwarden spec: serviceAccountName: bitwarden containers: - name: bitwarden image: bitwardenrs/server:latest imagePullPolicy: IfNotPresent env: - name: ADMIN_TOKEN valueFrom: secretKeyRef: name: bitwarden-admin-token key: token envFrom: - configMapRef: name: bitwarden ports: - containerPort: 8080 name: http protocol: TCP - containerPort: 3012 name: websocket protocol: TCP resources: limits: cpu: 200m memory: 512Mi requests: cpu: 50m memory: 256Mi volumeMounts: - mountPath: /data name: bitwarden-data volumeClaimTemplates: - metadata: name: bitwarden-data spec: accessModes: - "ReadWriteOnce" resources: requests: storage: "5Gi" storageClassName: default
Ok, so there is a lot more going on here, so let's go over each part of this deployment. It is actually pretty straight forward if you are familiar with Kubernetes, but for completeness sake and when I inevitably forget this later, I will still review the important parts from the top of the document to the bottom:
apiVersion: v1 kind: Service metadata: name: bitwarden spec: selector: pod: bitwarden type: ClusterIP ports: - name: http port: 80 protocol: TCP targetPort: 8080 - name: websocket protocol: TCP port: 3012 targetPort: 3012
And then finally, we create a service that allows our bitwarden ports to be accessed by other pods in our cluster. Please note that I don't use the loadbalancer type for this service, as I am running Traefik in front of this server with Let's Encrypt, as suggested by the wiki.
Overall, this kubernetes deployment has been working well for me for about a week now. I have no problems accessing the server over the web when I am out of the house, and Emma and I have been sharing passwords across our house organization flawlessly for utility bills and other financials. It has really allowed us to be transparent about expenses as we move across the country to our new apartment in Boston!
As always, if you have an improvement to my blog, please feel free to leave a comment below! I am always trying to learn and grow.
Aug. 29, 2023
Hello, i think that i saw you visited my web site so i came to “return the favor”.I'm trying to find things to improve my web site!I suppose its ok to use some of your ideas!!
Sept. 7, 2023
Thanks for sharing your thoughts. I really appreciate your efforts and I am waiting for your next post thank you once again.
เครดิตฟรี ไม่ต้องฝาก ไม่ต้องแชร์
Sept. 15, 2023
Hi! Do you use Twitter? I'd like to follow you if that would be okay. I'm absolutely enjoying your blog and look forward to new posts.
เครดิตฟรี 50 ไม่ต้องฝากไม่ต้องแชร์
Sept. 16, 2023
Excellent weblog here! Additionally your site rather a lot up fast! What web host are you the usage of? Can I am getting your associate link for your host? I desire my site loaded up as fast as yours lol
Sept. 18, 2023
Wow, amazing blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your website is great, let alone the content!
Sept. 19, 2023
My programmer is trying to persuade me to move to .net from PHP. I have always disliked the idea because of the costs. But he's tryiong none the less. I've been using WordPress on several websites for about a year and am anxious about switching to another platform. I have heard very good things about blogengine.net. Is there a way I can transfer all my wordpress posts into it? Any kind of help would be greatly appreciated!
Sept. 20, 2023
Wow, this piece of writing is good, my younger sister is analyzing these things, so I am going to inform her.
เครดิตฟรี 50 ไม่ต้องฝากไม่ต้องแชร์
Sept. 22, 2023
This design is incredible! You most certainly know how to keep a reader entertained. Between your wit and your videos, I was almost moved to start my own blog (well, almost...HaHa!) Excellent job. I really enjoyed what you had to say, and more than that, how you presented it. Too cool!
Sept. 22, 2023
Very rapidly this web page will be famous among all blog visitors, due to it's good articles or reviews
เครดิตฟรี 300 ถอนได้
Sept. 25, 2023
Every weekend i used to go to see this web page, as i wish for enjoyment, since this this web site conations genuinely good funny stuff too.
Sept. 28, 2023
Good way of telling, and good paragraph to take information regarding my presentation subject matter, which i am going to present in university.