Browse Source

Add bitwarden example (#2139)

* Add bitwarden example

Signed-off-by: Thibault Cohen <47721+titilambert@users.noreply.github.com>

* Fix bitwarden docs

Signed-off-by: Thibault Cohen <47721+titilambert@users.noreply.github.com>

* fix: punctuation, newline for bullet list

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>

---------

Signed-off-by: Thibault Cohen <47721+titilambert@users.noreply.github.com>
Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Co-authored-by: Moritz Johner <beller.moritz@googlemail.com>
Thibault Cohen 3 years ago
parent
commit
6c070bb538

+ 99 - 0
docs/examples/bitwarden.md

@@ -0,0 +1,99 @@
+# Bitwarden support using webhook provider
+
+Bitwarden is an integrated open source password management solution for individuals, teams, and business organizations.
+
+## How is it working ?
+
+To make external-secret compatible with BitWarden, we need:
+
+* External-Secret >= 0.8.0
+* To use the Webhook Provider
+* 2 (Cluster)SecretStores
+* BitWarden CLI image running `bw serve`
+
+When you create a new external-secret object,
+External-Secret Webhook provider will do a query to the Bitwarden CLI pod,
+which is synced with the BitWarden server.
+
+## Requirements
+
+* Bitwarden account (it works also with VaultWarden)
+* A Kubernetes secret which contains your BitWarden Credentials
+* You need a Docker image with BitWarden CLI installed.
+  You could use `registry.gitlab.com/ttblt-oss/docker-bw:2023.1.0` or build your own.
+
+Here an example of Dockerfile use to build this image:
+```dockerfile
+FROM debian:sid
+
+ENV BW_CLI_VERSION=2023.1.0
+
+RUN apt update && \
+    apt install -y wget unzip && \
+    wget https://github.com/bitwarden/clients/releases/download/cli-v${BW_CLI_VERSION}/bw-linux-${BW_CLI_VERSION}.zip && \
+    unzip bw-linux-${BW_CLI_VERSION}.zip && \
+    chmod +x bw && \
+    mv bw /usr/local/bin/bw && \
+    rm -rfv *.zip
+
+COPY entrypoint.sh /
+
+CMD ["/entrypoint.sh"]
+```
+
+And the content of `entrypoint.sh`
+```bash
+#!/bin/bash
+
+set -e
+
+bw config server ${BW_HOST}
+
+export BW_SESSION=$(bw login ${BW_USER} --passwordenv BW_PASSWORD --raw)
+
+bw unlock --check
+
+echo 'Running `bw server` on port 8087'
+bw serve --hostname 0.0.0.0 #--disable-origin-protection
+```
+
+
+## Deploy Bitwarden Credentials
+
+```yaml
+{% include 'bitwarden-cli-secrets.yaml' %}
+```
+
+## Deploy Bitwarden CLI container
+
+```yaml
+{% include 'bitwarden-cli-deployment.yaml' %}
+```
+
+> NOTE: Deploying a network policy is recommended since, there is no authentication to query the BitWarden CLI, which means that your secrets are exposed.
+
+> NOTE: In this example the Liveness probe is quering /sync to ensure that the BitWarden CLI is able to connect to the server and also to sync secrets. (The secret sync is only every 2 minutes in this example)
+
+## Deploy ClusterSecretStore (Or SecretStore)
+
+Here the two ClusterSecretStore to deploy
+
+```yaml
+{% include 'bitwarden-secret-store.yaml' %}
+```
+
+
+## How to use it ?
+
+* If you need the `username` or the `password` of a secret, you have to use `bitwarden-login`
+* If you need a custom field of a secret, you have to use `bitwarden-fields`
+* The `key` is the ID of a secret, which can be find in the URL with the `itemId` value:
+  `https://myvault.com/#/vault?itemId=........-....-....-....-............`
+* The `property` is the name of the field:
+  * `username` for the username of a secret (`bitwarden-login` SecretStore)
+  * `password` for the password of a secret (`bitwarden-login` SecretStore)
+  * `name_of_the_custom_field` for any custom field (`bitwarden-fields` SecretStore)
+
+```yaml
+{% include 'bitwarden-secret.yaml' %}
+```

+ 110 - 0
docs/snippets/bitwarden-cli-deployment.yaml

@@ -0,0 +1,110 @@
+{% raw %}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: bitwarden-cli
+  namespace: bitwarden
+  labels:
+    app.kubernetes.io/instance: bitwarden-cli
+    app.kubernetes.io/name: bitwarden-cli
+spec:
+  replicas: 1
+  strategy:
+    type: Recreate
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: bitwarden-cli
+      app.kubernetes.io/instance: bitwarden-cli
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: bitwarden-cli
+        app.kubernetes.io/instance: bitwarden-cli
+    spec:
+      containers:
+        - name: bitwarden-cli
+          image: YOUR_BITWARDEN_CLI_IMAGE
+          imagePullPolicy: IfNotPresent
+          env:
+            - name: BW_HOST
+              valueFrom:
+                secretKeyRef:
+                  name: bitwarden-cli
+                  key: BW_HOST
+            - name: BW_USER
+              valueFrom:
+                secretKeyRef:
+                  name: bitwarden-cli
+                  key: BW_USERNAME
+            - name: BW_PASSWORD
+              valueFrom:
+                secretKeyRef:
+                  name: bitwarden-cli
+                  key: BW_PASSWORD
+          ports:
+            - name: http
+              containerPort: 8087
+              protocol: TCP
+          livenessProbe:
+            exec:
+              command:
+                - wget
+                - -q
+                - http://127.0.0.1:8087/sync
+                - --post-data=''
+            initialDelaySeconds: 20
+            failureThreshold: 3
+            timeoutSeconds: 1
+            periodSeconds: 120
+          readinessProbe:
+            tcpSocket:
+              port: 8087
+            initialDelaySeconds: 20
+            failureThreshold: 3
+            timeoutSeconds: 1
+            periodSeconds: 10
+          startupProbe:
+            tcpSocket:
+              port: 8087
+            initialDelaySeconds: 10
+            failureThreshold: 30
+            timeoutSeconds: 1
+            periodSeconds: 5
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: bitwarden-cli
+  namespace: bitwarden
+  labels:
+    app.kubernetes.io/instance: bitwarden-cli
+    app.kubernetes.io/name: bitwarden-cli
+  annotations:
+spec:
+  type: ClusterIP
+  ports:
+  - port: 8087
+    targetPort: http
+    protocol: TCP
+    name: http
+  selector:
+    app.kubernetes.io/name: bitwarden-cli
+    app.kubernetes.io/instance: bitwarden-cli
+---
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  namespace: bitwarden
+  name: external-secret-2-bw-cli
+spec:
+  podSelector:
+    matchLabels:
+      app.kubernetes.io/instance: bitwarden-cli
+      app.kubernetes.io/name: bitwarden-cli
+  ingress:
+  - from:
+      - podSelector:
+          matchLabels:
+            app.kubernetes.io/instance: external-secrets
+            app.kubernetes.io/name: external-secrets
+{% endraw %}

+ 12 - 0
docs/snippets/bitwarden-cli-secrets.yaml

@@ -0,0 +1,12 @@
+{% raw %}
+apiVersion: v1
+data:
+  BW_HOST: ...
+  BW_USERNAME: ...
+  BW_PASSWORD: ....
+kind: Secret
+metadata:
+  name: bitwarden-cli
+  namespace: bitwarden
+type: Opaque
+{% endraw %}

+ 26 - 0
docs/snippets/bitwarden-secret-store.yaml

@@ -0,0 +1,26 @@
+{% raw %}
+---
+apiVersion: external-secrets.io/v1beta1
+kind: ClusterSecretStore
+metadata:
+  name: bitwarden-login
+spec:
+  provider:
+    webhook:
+      url: "http://bitwarden-cli:8087/object/item/{{ .remoteRef.key }}"
+      headers:
+        Content-Type: application/json
+      result:
+        jsonPath: "$.data.login.{{ .remoteRef.property }}"
+---
+apiVersion: external-secrets.io/v1beta1
+kind: ClusterSecretStore
+metadata:
+  name: bitwarden-fields
+spec:
+  provider:
+    webhook:
+      url: "http://bitwarden-cli:8087/object/item/{{ .remoteRef.key }}"
+      result:
+        jsonPath: "$.data.fields[?@.name==\"{{ .remoteRef.property }}\"].value"
+{% endraw %}

+ 57 - 0
docs/snippets/bitwarden-secret.yaml

@@ -0,0 +1,57 @@
+{% raw %}
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: my-db-secrets
+  namespace: default
+spec:
+  target:
+    name: my-db-secrets
+    deletionPolicy: Delete
+    template:
+      type: Opaque
+      data:
+        username: |-
+          {{ .username }}
+        password: |-
+          {{ .password }}
+        postgres-password: |-
+          {{ .postgres_password }}
+        postgres-replication-password: |-
+          {{ .postgres_replication_password }}
+        db_url: |-
+          postgresql://{{ .username }}:{{ .password }}@my-postgresql:5432/mydb
+  data:
+    - secretKey: username
+      sourceRef:
+        storeRef:
+          name: bitwarden-login
+          kind: ClusterSecretStore  # or SecretStore
+      remoteRef:
+        key: aaaabbbb-cccc-dddd-eeee-000011112222
+        property: username
+    - secretKey: password
+      sourceRef:
+        storeRef:
+          name: bitwarden-login
+          kind: ClusterSecretStore  # or SecretStore
+      remoteRef:
+        key: aaaabbbb-cccc-dddd-eeee-000011112222
+        property: password
+    - secretKey: postgres_password
+      sourceRef:
+        storeRef:
+          name: bitwarden-fields
+          kind: ClusterSecretStore  # or SecretStore
+      remoteRef:
+        key: aaaabbbb-cccc-dddd-eeee-000011112222
+        property: admin-password
+    - secretKey: postgres_replication_password
+      sourceRef:
+        storeRef:
+          name: bitwarden-fields
+          kind: ClusterSecretStore  # or SecretStore
+      remoteRef:
+        key: aaaabbbb-cccc-dddd-eeee-000011112222
+        property: postgres-replication-password
+{% endraw %}

+ 1 - 0
hack/api-docs/mkdocs.yml

@@ -103,6 +103,7 @@ nav:
     - FluxCD: examples/gitops-using-fluxcd.md
     - Anchore Engine: examples/anchore-engine-credentials.md
     - Jenkins: examples/jenkins-kubernetes-credentials.md
+    - BitWarden: examples/bitwarden.md
   - Community:
     - Contributing:
       - Developer guide: contributing/devguide.md