
Free & Secure Local Development: Bitwarden Secrets Manager with K3d + Walkthrough
- Haggai Philip Zagury (hagzag)
- Dev ops , Security
- January 17, 2024
Table of Contents
Originally posted on the Israeli Tech Radar on medium.
Free & Secure Local Development: Bitwarden Secrets Manager with K3d + Walkthrough
We all deal with secrets, and managing them effectively is crucial for security, especially when working with local development environments. I’ve personally relied on Bitwarden’s free tier for secure password management for years. I moved from a bunch of tools which I needed to be synchronized and kept in sync with my local machine, not because others are bad, but because Bitwarden has a CLI, Desktop, Chrome extension & web which seemly integrated with my workflows.
Now, I’m taking my security practices a step further by leveraging its CLI and Kubernetes controller to retrieve secrets in a secure and efficient manner, directly into my local K3d cluster.
As a consultant, I juggle multiple clients, each with their own set of services, APIs, and cloud environments. Bitwarden’s CLI, desktop app, and web interface allow me to seamlessly switch between these environments without compromising security or constantly looking up credentials. The ability to organize secrets by project/client within Bitwarden is a lifesaver. I regularly need to connect to databases, cloud storage, and various APIs, and Bitwarden ensures I can do so securely and efficiently.
It is very similar to using AWS / Google / Azure or Vault secret managers, but without the cost, in the past I wrote a short how to use Vault with K3d, but this time I’m using Bitwarden.
Before we start, I’m not affiliated with Bitwarden, just a happy user who appreciates a free and powerful solution which has all the required interfaces one needs to manage their secrets.
Let’s delve into why secret management is a must, how you can achieve it without spending a dime using Bitwarden Secrets Manager, and how to integrate it with your local Kubernetes development using K3d.
The walkthrough will be after the why section.
Why Secret Management Matters (Even Locally!) 🔑
You might be thinking, “Why bother with all this security overhead for my local machine?”
Well, here’s why it’s vital, even when developing locally:
(1) Prevent Accidental Commits: Hardcoding secrets in your code, Dockerfiles, or Kubernetes manifests is a recipe for disaster. They can easily be committed to version control, exposing sensitive information, potentially leading to security breaches, data loss, and reputational damage. Always use .gitignore and .dockerignore to prevent sensitive files from being committed.
(2) Consistent Environments: Managing secrets centrally allows you to easily switch between different environments (dev, staging, production) without having to manually edit configuration files or environmental variables. This promotes reproducible builds, deployments, and reduces errors.
(3) Good Habits: Developing secure habits in a local environment encourages consistency and helps ensure that you follow the same standards when deploying to larger and more critical environments. Good security practices should be part of your workflow, not an afterthought.
(4)Environment Parity: Once set up, this approach makes secret management simpler than any manual approach and more secure than using plain text configurations. The initial setup might seem complex, but the long-term benefits are worth it. It’s very similar to your staging and production environments.
Bitwarden: A Free-tier Secret Vault 🔐
Very similar to the external-secrets-operator, I described in this post which can work with AWS / Goolge / Azure & Vault secret managers.
Bitwarden is well-known for its secure password management tools, but it also offers a dedicated Secrets Manager product. When combined with its command-line interface (CLI) and a Kubernetes operator, it provides a powerful and free secrets management solution. The core components that we are leveraging are:
Bitwarden Secrets Manager CLI (bws): This command-line tool allows you to manage Bitwarden secrets. Bitwarden provides a free organization for 2 users and a limited number of projects which means you can try it before you buy it…
Bitwarden Secrets Manager Operator: This Kubernetes operator acts as a bridge between your cluster and your Bitwarden vault. It allows your pods and deployments to retrieve secrets from Bitwarden and mount them as Kubernetes secrets or environment variables, automating the process and making them available to your applications.
Not related but don’t confuse this with bw-cli with the bitwarden-secrets or bws
which is the cli used to manage your personal bitwarden vault Bitwarden CLI (bw) is a command-line tool allows you to interact with your Bitwarden vault (primarily for passwords) directly from your terminal, it quite handy for scripts - out of scope for this post.
sm-operator - The Kubernetes operator for Bitwarden Secrets Manager
The Kubernetes operator pattern is a great way to manage secrets securely and efficiently. We’ll start from the CLI with bws to create the secret and then consume it in our local development environment using a BitwardenSecret CRD, as described in the following diagram:
using 1 token to access the secret vault — similar to how you’d do with any cloud provider
This creates a secure workflow where:
Secrets are never stored in code
Access is controlled through Bitwarden’s authentication
Applications can access secrets without direct Bitwarden credentials
The process is automated through the operator
So, lets get our hand dirty with Bitwarden Secrets Manager & K3d🧑💻
Setting Up Bitwarden Secrets Management with K3d 🚀 — The Walkthrough
For sake of this post a simple k3d create cluster will suffice, once you have kubectl pointing to your cluster, you can proceed with the following steps.
- k3d cluster list should yield something like this:
NAME SERVERS AGENTS LOADBALANCER
k3s-default 1/1 0/0 true
Step 1: 👣 Install the Bitwarden Secrets Manager CLI (bws)
You can install the bws CLI using either cargo (if you have Rust installed) or a convenient installation script:
# If you have Rust and Cargo installed:
cargo install bws
# Alternatively, using the installation script:
curl -sSL https://bitwarden.com/secrets/install | sh
Official installation page can be found here
Step 2: 👣 Install the Bitwarden Secrets Manager Operator
We’ll use the official helm chart to install the Bitwarden Secrets Manager Operator.
helm repo add bitwarden https://charts.bitwarden.com
helm install sm-operator --namespace bitwarden --create-namespace bitwarden/sm-operator
The Bitwarden Secrets Manager Operator acts as a bridge between your Kubernetes cluster and your Bitwarden vault. It automates the process of retrieving secrets and making them available to your applications. In order to use it you will need ot provide a secret containing your Bitwarden access token.
Step 3: 👣 Create a Secret in Bitwarden Secrets Manager
Before you can use secrets in your Kubernetes cluster, you need to create them in your Bitwarden Secrets Manager account. You will need an access token to authenticate the bws CLI.
Generating an Access Token:
Log in to your Bitwarden Secrets Manager web vault.
Go to your organization and then to the Settings tab.
Click on Organization API Key, and generate a new API key.
Copy the displayed access token. Important: This token is only shown once, so store it securely.
Using the Access Token:
For the sake of this walkthrough, set the BWS_ACCESS_TOKEN environment variable like so:
export BWS_ACCESS_TOKEN="your_access_token"
Creating a Botwarden Project:
bws project create k3d-demo
Creating a Bitwarden Secret:
Let’s create a sample secret named a-secret-name with the value a-secret-value. We’ll also associate it with a project (you can create a project in the Bitwarden Secrets Manager UI).
Lest first fetch the bitwarde PROJECT_ID we created in the prvious step:
export PROJECT_ID=`bws project list | jq -r '.[] | select(.name == "k3d-demo") | .id'`
Now lets create the secret in the project:
bws secret create a-secret-name a-secret-value $PROJECT_ID
Step 4: 👣 Create a Kubernetes Manifest to retrieve a secret from Bitwarden
Bwfore we fetch the secret we need to provide the access token to the secret-manager in order to fetch secrets:
- Before applying the above manifest, you need to create a Kubernetes secret named bw-auth-token in the bitwarden namespace containing your
BWS_ACCESS_TOKEN
:
kubectl create secret generic bw-auth-token -n bitwarden --from-literal=token="$BWS_ACCESS_TOKEN"
Now, let’s create a BitwardenSecret resource that fetches your credentials from Bitwarden. Let’s create a file named bitwarden-secret.yaml with the following contents Please make sure to replace the placeholders with your actual values:
apiVersion: k8s.bitwarden.com/v1
kind: BitwardenSecret
metadata:
name: credentials
# Replace with the namespace where you installed the operator
namespace: bitwarden
spec:
# Replace with your Bitwarden organization ID
organizationId: "YOUR_ORGANIZATION_ID"
# The name of the Kubernetes secret to be created
secretName: credentials-from-bw
map:
# Get this from `bws secret list`
- bwSecretId: "YOUR_a-secret-name_SECRET_ID"
secretKeyName: a-secret-name
authToken:
# The secret containing your BWS_ACCESS_TOKEN
secretName: bw-auth-token
secretKey: token
Now, apply the Manifest:
kubectl apply -f bitwarden-secret.yaml
This will create a Kubernetes secret named credentials in the bitwarden namespace, containing the sample secret fetched from Bitwarden.
Under the hood we can examine the resources created by the controller, we can see this secret is managed by the Bitwarden Secrets Manager Operator and is automatically fetched from Bitwarden and mounted as a Kubernetes secret like so:
kubectl get bitwardensecrets.k8s.bitwarden.com
NAME AGE
credentials 17h
If we take a closer look at the secret, we can see that it has been populated with the secret value from Bitwarden and labaled with the secret id:
k get secrets --show-labels credentials
NAME TYPE DATA AGE LABELS
credentials-from-bw Opaque 1 17h k8s.bitwarden.com/bw-secret=204fe41a-5471-4666-a92d-ddedad477136
These are common kubernetes patterns followed by many operators, e.g external-secrets-operator
How would you use this in a common deployment ?
An example of how you cold use the Secret in a Deployment which uses the secret as part of it’s configuration manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-app
namespace: bitwarden
spec:
# ...
template:
# ...
spec:
containers:
- name: my-web-app-container
image: traefik/whoami:v1.10.1
env:
- name: USERNAME
value: admin
- name: PASSWORD
valueFrom:
secretKeyRef:
name: credentials-from-bw
key: 'a-secret-name'
To conclude
In this example, we’re injecting a secret from the credentials secret into the my-web-app container as environment variables.
Benefits of This Approach
Security: Your secrets are stored securely in your Bitwarden vault, not in your code or local files.
Efficiency: The Bitwarden operator automatically retrieves and updates your secrets, removing the manual step.
Free: No additional cost with the Bitwarden free tier for a limited number of 2 users and projects.
Consistency: Your secrets management is consistent across local development and other environments.
As always, I hope you found this post useful and if you have any questions or feedback, please feel free to reach out.
Yours sincerely, HP