Kubernetes Passbolt Operator
This repository contains the Kubernetes Operator for Passbolt. Passbolt is an open source password manager for teams. It is a self-hosted solution that allows you to manage your passwords securely and share them with your team. The Passbolt Operator is a Kubernetes Operator that allows you to synchronize your Passbolt credentials with Kubernetes Secrets. It is based on Kubebuilder framework.
Getting Started
Synchronize credentials with Kubernetes Secrets
The Passbolt Operator allows you to synchronize your Passbolt credentials with Kubernetes Secrets. To do so, you need to create a PassboltSecret
resource. The PassboltSecret
resource is a Kubernetes Custom Resource Definition (CRD) that allows you to define the Passbolt credentials that you want to synchronize with Kubernetes Secrets. The Passbolt Operator will then synchronize the Passbolt credentials with Kubernetes Secrets.
apiVersion: passbolt.tagesspiegel.de/v1alpha3
kind: PassboltSecret
metadata:
name: passboltsecret-sample
spec:
leaveOnDelete: false
secretType: Opaque
passboltSecrets:
s3_access_key:
name: EXAMPLE_APP
field: username
dsn:
name: EXAMPLE_APP
value: postgres://{{ .Username }}@{{ .URI }}/mydb?sslmode=disable&password={{ .Password }}
plainTextFields:
key: value
foo: bar
The PassboltSecret
resource contains the following fields:
Field |
Type |
Default |
Required |
Condition |
Description |
leaveOnDelete |
bool |
false |
false |
- |
A boolean that indicates if the Passbolt Operator should leave the Kubernetes Secret on deletion of the PassboltSecret resource. |
secretType |
string |
Opaque |
false |
- |
The type of the Kubernetes Secret. Can be either Opaque or kubernetes.io/dockerconfigjson . If the secretType is kubernetes.io/dockerconfigjson , the passboltSecretName field is required. If the secretType is Opaque , the secrets field is required. |
passboltSecretID |
string |
- |
false |
secretType is kubernetes.io/dockerconfigjson |
The ID of the Passbolt credential that contains the Docker configuration (URI, Username, Password). |
passboltSecrets |
map[string]PassboltSecrets |
- |
false |
secretType is Opaque |
A mapping of Passbolt credentials that you want to synchronize with Kubernetes Secrets. The key represents the name of the key in the Kubernetes secret to be added. |
passboltSecrets[*].id |
string |
- |
true |
- |
The ID of the Passbolt credential that you want to synchronize with Kubernetes Secrets. |
passboltSecrets[*].field |
string |
- |
false |
- |
The field of the Passbolt credential that you want to synchronize with Kubernetes Secrets. Can be one of: username , password , uri |
passboltSecrets[*].value |
string |
- |
false |
- |
A Go template value of the Passbolt credential that you want to synchronize with Kubernetes Secrets. Supported variables are: Username , Password , URI . The secrets[*].passboltSecret.value field is mutually exclusive with the passboltSecrets[*].field field. |
plainTextFields |
map[string]string |
- |
false |
- |
Assignment of plain text fields that you want to synchronize with Kubernetes Secrets. The key represents the name of the key in the Kubernetes secret to be added and the corresponding value. It is not recommended to store "secret" values such as passwords in it. |
The Passbolt Operator will then synchronize the Passbolt credentials with Kubernetes Secrets. The Passbolt Operator will create a Kubernetes Secret with the name passbolt-secret-name
in the namespace default
. The resulting Kubernetes Secret is defined as follows:
apiVersion: v1
kind: Secret
metadata:
name: passbolt-secret-sample
namespace: default
type: Opaque
data:
username: example
pg_dsn: postgres://example@db.example.com:5432/mydb?sslmode=disable&password=example
Under the hood, the Passbolt Operator does the following during the reconciliation loop:
- Retrieve the Passbolt CRD from Kubernetes.
- Retrieve the
secrets[*].passboltSecret.name
credentials from Passbolt.
- Create a Kubernetes secret with the name
passbolt-secret-name
in the namespace default
with the secrets[*].kubernetesSecretKey
key and the secrets[*].passboltSecret.name
value.
If an error occurs during the reconciliation loop, the Passbolt Operator will update the .status.syncStatus
field to Error
and adds the error message to the .status.syncErrors
field of the PassboltSecret
resource. If the reconciliation loop is successful, the Passbolt Operator will update the .status.syncStatus
field of the PassboltSecret
resource with the message Success
.
Installation
For both installation methods, you need to create a Kubernetes Secret with the Passbolt credentials. To do so, you need to run the following command:
kubectl create secret generic controller-passbolt-secret \
--from-file=gpg_key='/path/to/my/gpg.key' \
--from-literal=password='<my-user-password>' \
--from-literal=url='<my-passbolt-url>' \
--namespace system
Prerequisites
In order to install the Passbolt Operator, you need to have the following prerequisites installed on your K8s cluster:
Kustomize
ATTENTION: This installation method is not recommended for production environments. If you want to install the Passbolt Operator in a production environment, please refer to the Helm installation method.
To install the Passbolt Operator with Kustomize, for example in a local Kind cluster, we expect that you have a working Kubernetes cluster with the controller-passbolt-secret
secret created. To install the Passbolt Operator, you need to run the following commands:
-
Load the controller-manager image into the Kind cluster. See Kind Load
make deploy
Helm
For the installation instructions regarding Helm, please refer to the Helm-Chart repository.
Configuration
The Passbolt Operator can be configured with the following environement variables:
PASSBOLT_URL
: The URL of the Passbolt instance.
PASSBOLT_GPG
: The GPG key to identify the user.
PASSBOLT_PASSWORD
: The password of the Passbolt user.
Development
Prerequisites
- Go >= v1.19
- Docker >= 20.10
- Kubebuilder >= v3.7
- Kubectl >= v1.25
- Kind >= v0.17
- mysql-client >= 15.1 (
mysql --version
=> mysql Ver 15.1 Distrib 10.6.11-MariaDB
)
Setup the development environment
To setup the development environment, you need to run the following commands:
docker-compose up -d
Restore the database
mysql \
--host=127.0.0.1 \
--port=13306 \
--database=passbolt \
--user=passbolt \
--password=P4ssb0lt < _data/passbolt_db.sql
Create another API (Version)
Kubebuilder allows you to bootstrap a new API Version. To do so, you need to run the following command:
kubebuilder create api --group passbolt --version v1alpha1 --kind PassboltSecret
Create validation and defaulting webhooks
Kubebuilder allows you to bootstrap a new webhook. To do so, you need to run the following command:
kubebuilder create webhook --group passbolt --version v1alpha1 --kind PassboltSecret --defaulting --programmatic-validation
Start the Operator
Since the Operator requires a running instance of Passbolt, we will use the Passbolt Docker image to start a Passbolt instance. To start the Passbolt instance, you need to run the following command:
docker-compose up -d
When the Passbolt instance is up and running, the second step would be to expose the Passbolt instance credentials to the Operator. To do so, you need to run the following command:
./_data/credentials.sh
The last step would be to start the Operator. To do so, you need to run the following command:
make run
Create a User in Passbolt
To create a user in Passbolt, you need to run the following command:
docker exec -ti passbolt /usr/share/php/passbolt/bin/cake \
passbolt register_user \
-u user.example@mydomain.local \
-f user \
-l example \
-r admin
We already created a user with the above command. You can retrieve the password and the GPG key from the _data/credentials.sh file.
Test the Operator
In order to run the end-to-end and unit tests, we need to start passbolt locally. To do so, you need to run the following command:
docker-compose up -d
When the Passbolt instance is up and running, the second step would be to execute the end-to-end and unit tests. To do so, you need to run the following command:
make test
Note:
When we bootstraped passbolt, we created two secrets:
ID |
Name |
184734ea-8be3-4f5a-ba6c-5f4b3c0603e8 |
APP_EXAMPLE |
cec328ec-cb1f-48f6-be1e-1ca35fc3c62d |
APP2_EXAMPLE |
In Cluster Testing (Kind)
In order to run the end-to-end tests in a Kubernetes cluster, we need to load the Passbolt Operator image into the Kind cluster. To do so, you need to run the following command:
kind load docker-image <image-name> --name <cluster-name> --nodes <node-names-separated-by-a-comma>
When the Passbolt Operator image is loaded into the Kind cluster, the second step would be to deploy the Passbolt Operator in the Kind cluster. To do so, you need to run the following command:
IMG="my-img-name:latest" make deploy
Continuous Integration (CI)
During the continuous integration, we automatically run the end-to-end and unit tests. To do so, we use the GitHub Actions platform. The GitHub Actions configuration is defined in the .github/workflows directory.
During the end-to-end and unit tests, we restore the the mysql Passbolt database from the _data/passbolt_db.sql
file. The '_data/passbolt_db.sql' file was generated with the following command:
mysqldump \
--host=127.0.0.1 \
--port=13306 \
--databases passbolt \
--user=passbolt \
--password=P4ssb0lt > _data/passbolt_db.sql
Contributing
Code of Conduct
This project and everyone participating in it is governed by the Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [leon.steinhaeuser@tagesspiegel.de].
Contributing Guide
If you want to contribute to this project, please read the Contributing Guide.
License
This project is licensed under the MIT License.
Security
If you discover a security vulnerability within this project, please use issue form Report a security vulnerability. All security vulnerabilities will be promptly addressed. Please see Security Policy for more information.
Support
If you need help with Passbolt, please contact Passbolt Support.