Skip to content

Commit

Permalink
Fix ClusterSecretStore; add creds to deployment; fix image tag - see PR
Browse files Browse the repository at this point in the history
#1 for more

* change TLDR to Usage because there's not much read :P

* add secret and escape existing {{}} in cluster-secret-stores

* add some env vars and readiness probes to our deployment

* base64 encode the credentials

* allow for setting the secrets keys in an existing secret for credentials

* fix existingSecret conditional

* bump helm chart verison

* install ESO dependency for ci testing

* fix trailing spaces for linter

* adding @cloudymax's fix for the bitwarden secret keys instead of item IDs

* Add example secret

Co-authored-by: @cloudymax <emax@cloudydev.net>

* add @cloudymax's example to the README

Co-authored-by: @cloudymax <emax@cloudydev.net>

* move example into an examples directory and link it in the readme

* Update example-secret.yaml

* Update README.md

* fix example secret comments

* change helm connection test endpoint to `/status`

* make renovateBot notice the appVersion as a docker tag to keep up to date

* switch to config.js for renovatebot

* adding more linter style updates

* image tag was wrong 🙃: Added the missing `v` in the version tag

* clean up Dockerfile and docker ci, and start using an actual bot account for bitwarden

* we're now passing in github token for helm version (to pull latest `helm` release)

* change test connection script to just be a mounted configMap and not use busybox (we use `curlimages/curl` now)

---------

Co-authored-by: @cloudymax <emax@cloudydev.net>
Co-authored-by: Max! <admin@cloudydev.net>
  • Loading branch information
3 people authored Aug 8, 2023
1 parent a7c42d0 commit a227e95
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 35 deletions.
41 changes: 41 additions & 0 deletions .github/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module.exports = {
branchPrefix: 'test-renovate/',
username: 'renovate-release',
gitAuthor: 'Renovate Bot <bot@renovateapp.com>',
platform: 'github',
includeForks: true,
dryRun: 'full',
repositories: ['jessebot/bitwarden-eso-provider'],
extends: ['config:base'],
allowPostUpgradeCommandTemplating: true,
allowedPostUpgradeCommands: ['^.*'],
regexManagers: [
{
fileMatch: ['(^|/)Chart\\.yaml$'],
matchStrings: [
'#\\s?renovate: image=(?<depName>.*?)\\s?appVersion:\\s?\\"?(?<currentValue>[\\w+\\.\\-]*)',
],
datasourceTemplate: 'docker',
},
],
packageRules: [
{
matchManagers: ['helm-requirements', 'helm-values', 'regex'],
postUpgradeTasks: {
commands: [
`version=$(grep '^version:' {{{parentDir}}}/Chart.yaml | awk '{print $2}')
major=$(echo $version | cut -d. -f1)
minor=$(echo $version | cut -d. -f2)
patch=$(echo $version | cut -d. -f3)
minor=$(expr $minor + 1)
echo "Replacing $version with $major.$minor.$patch"
sed -i "s/^version:.*/version: $\{major\}.$\{minor\}.$\{patch\}/g" {{{parentDir}}}/Chart.yaml
cat {{{parentDir}}}/Chart.yaml
`,
],
},
fileFilters: ['**/Chart.yaml'],
executionMode: 'branch',
},
],
};
5 changes: 0 additions & 5 deletions .github/renovate.json

This file was deleted.

4 changes: 3 additions & 1 deletion .github/workflows/ci-helm-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:

- name: Install Helm
uses: azure/setup-helm@v3.5
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up chart-testing
uses: helm/chart-testing-action@v2.4.0
Expand All @@ -44,4 +46,4 @@ jobs:
- name: Run chart-testing (install)
id: install
if: steps.list-changed.outputs.changed == 'true'
run: ct install --target-branch ${{ github.event.repository.default_branch }}
run: ct install --target-branch ${{ github.event.repository.default_branch }} --helm-extra-set-args="--set=bitwarden_eso_provider.create_cluster_secret_store=false --set=bitwarden_eso_provider.auth.password=${BOT_PASSWORD} --set=bitwarden_eso_provider.auth.clientID=${BOT_CLIENT_ID} --set=bitwarden_eso_provider.auth.clientSecret=${BOT_CLIENT_SECRET}"
5 changes: 3 additions & 2 deletions .github/workflows/docker-push-daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ jobs:
platforms: |
linux/amd64
linux/arm64
tags: |
jessebot/argocd-appset-secret-plugin:latest
tags: |
jessebot/bweso:latest
${{ startsWith(github.ref, 'refs/tags') || format('{0}:{1}', jessebot/bweso, github.ref_name) || '' }}
2 changes: 1 addition & 1 deletion .github/workflows/renovatebot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
uses: renovatebot/github-action@v39.0.1
with:
token: ${{ secrets.RENOVATE_TOKEN }}
configurationFile: .github/renovate.json
configurationFile: .github/config.js
44 changes: 42 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,50 @@
# Bitwarden External Secrets Operator Provider
We followed the [example](https://external-secrets.io/v0.9.2/examples/bitwarden/) over at the ESO docs to create a simple helm chart to deploy the Bitwarden ESO provider without having to spend a bunch of time on it. This project is neither affiliated with the External Secrets Operator, nor the official Bitwarden project. Report bugs here :)
We, mostly @cloudymax, followed the [example](https://external-secrets.io/v0.9.2/examples/bitwarden/) over at the ESO docs to create a simple helm chart to deploy the Bitwarden ESO provider without having to spend a bunch of time on it. This allows you to use the [`ExternalSecrets` Custom Resource](https://external-secrets.io/latest/introduction/overview/#externalsecret) with Bitwarden.
This project is neither affiliated with the External Secrets Operator, nor the official Bitwarden project. Report bugs here :)

### TLDR
## Usage
For helm, see the [README](./charts/bitwarden-eso-provider/README.md) for full details of the allowed values in `values.yaml`, but this is the gist:

```bash
helm repo add bitwarden-eso-provider https://jessebot.github.io/bitwarden-eso-provider
helm install my-release bitwarden-eso-provider
```

# Example Secret
By default we will create two [`ClusterSecretStore`s](https://external-secrets.io/latest/introduction/overview/#clustersecretstore) for you that can then be accessed when you create a secret like [this](./examples/example-secret.yaml), but also printed below here:

```yaml
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
# this is the name of the ExternalSecret object
name: cool-secret-4-dogs
namespace: coolapp4dogs
spec:
target:
# This is the name of the secret in bitwarden
name: cool-secret
deletionPolicy: Delete
template:
type: Opaque
data:
# The kubernetes secret name
password: |-
{{ .password }}
data:
# the value to pass to the kubernetes secret.
- secretKey: password
sourceRef:
storeRef:
# Use the `bitwarden-login` store to get `username` and
# `password` values from a bitwarden secret that does not
# contain custom fields, Otherwise use `bitwarden-fields'
name: bitwarden-login
kind: ClusterSecretStore
remoteRef:
# This is the `name` of your bitwarden secret.
key: <your-secret-name>
# This is the property of the bitwarden secret that we want
property: <some-secret-property>
```
9 changes: 3 additions & 6 deletions charts/bitwarden-eso-provider/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.2.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.0.1"
# renovate: image=deserializeme/bweso
appVersion: "v0.0.1"

maintainers:
- name: "cloudymax"
Expand Down
11 changes: 10 additions & 1 deletion charts/bitwarden-eso-provider/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bitwarden-eso-provider

![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.0.1](https://img.shields.io/badge/AppVersion-0.0.1-informational?style=flat-square)
![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.0.1](https://img.shields.io/badge/AppVersion-v0.0.1-informational?style=flat-square)

A Helm chart for Kubernetes

Expand All @@ -20,6 +20,15 @@ A Helm chart for Kubernetes
| autoscaling.maxReplicas | int | `100` | |
| autoscaling.minReplicas | int | `1` | |
| autoscaling.targetCPUUtilizationPercentage | int | `80` | |
| bitwarden_eso_provider.auth.clientID | string | `""` | bitwarden client ID to use to grabs secrets in the pod, ignored if existingSecret is set |
| bitwarden_eso_provider.auth.clientSecret | string | `""` | bitwarden client Secret to use to grabs secrets in the pod, ignored if existingSecret is set |
| bitwarden_eso_provider.auth.existingSecret | string | `""` | use an existing secret for bitwarden credentials, ignores above credentials if this is set |
| bitwarden_eso_provider.auth.host | string | `"https://bitwarden.com"` | bitwarden hostname to use to grab secrets in the pod, ignored if existingSecret is set |
| bitwarden_eso_provider.auth.password | string | `""` | password for bitwarden |
| bitwarden_eso_provider.auth.secretKeys.clientID | string | `"BW_CLIENTID"` | secret key for bitwarden client ID to use to grabs secrets in the pod |
| bitwarden_eso_provider.auth.secretKeys.clientSecret | string | `"BW_CLIENTSECRET"` | secret key for bitwarden client Secret to use to grabs secrets in the pod |
| bitwarden_eso_provider.auth.secretKeys.host | string | `"BW_HOST"` | secret key for bitwarden hostname to use to grab secrets in the pod |
| bitwarden_eso_provider.auth.secretKeys.password | string | `"BW_PASSWORD"` | secret key for bitwarden password key |
| bitwarden_eso_provider.create_cluster_secret_store | bool | `true` | if set to True, we'll create a cluster-wide accessible Cluster Secret Store see: https://external-secrets.io/latest/introduction/overview/#clustersecretstore |
| fullnameOverride | string | `""` | |
| image.pullPolicy | string | `"IfNotPresent"` | Overrides the image pullPolicy. Hint: set to Always if using latest tag |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ metadata:
spec:
provider:
webhook:
url: "http://{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}/object/item/{{ .remoteRef.key }}"
url: "http://{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}/object/items"
headers:
Content-Type: application/json
result:
jsonPath: "$.data.login.{{ .remoteRef.property }}"
jsonPath: "$.data.data[?(@.name=={{`{{ .remoteRef.key }}`}})].login.{{`{{ .remoteRef.property }}`}}"
---
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
Expand All @@ -20,7 +20,7 @@ metadata:
spec:
provider:
webhook:
url: "http://{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}/object/item/{{ .remoteRef.key }}"
url: "http://{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}/object/item/"
result:
jsonPath: "$.data.fields[?@.name==\"{{ .remoteRef.property }}\"].value"
jsonPath: "$.data.data[?(@.name==\"{{`{{ .remoteRef.key }}`}}\"].fields[?@.name==\"{{`{{ .remoteRef.property }}`}}\"].value"
{{- end }}
12 changes: 12 additions & 0 deletions charts/bitwarden-eso-provider/templates/credentials.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{- if not .Values.bitwarden_eso_provider.auth.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}
type: Opaque
data:
BW_HOST: {{ .Values.bitwarden_eso_provider.auth.host | b64enc | quote }}
BW_PASSWORD: {{ .Values.bitwarden_eso_provider.auth.password | b64enc | quote}}
BW_CLIENTID: {{ .Values.bitwarden_eso_provider.auth.clientID | b64enc | quote}}
BW_CLIENTSECRET: {{ .Values.bitwarden_eso_provider.auth.clientSecret | b64enc | quote}}
{{- end }}
46 changes: 40 additions & 6 deletions charts/bitwarden-eso-provider/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,52 @@ spec:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: BW_HOST
valueFrom:
secretKeyRef:
name: "{{ .Values.bitwarden_eso_provider.auth.existingSecret | default .Release.Name }}"
key: {{ .Values.bitwarden_eso_provider.auth.secretKeys.host }}
- name: BW_CLIENTID
valueFrom:
secretKeyRef:
name: "{{ .Values.bitwarden_eso_provider.auth.existingSecret | default .Release.Name }}"
key: {{ .Values.bitwarden_eso_provider.auth.secretKeys.clientID }}
- name: BW_CLIENTSECRET
valueFrom:
secretKeyRef:
name: "{{ .Values.bitwarden_eso_provider.auth.existingSecret | default .Release.Name }}"
key: {{ .Values.bitwarden_eso_provider.auth.secretKeys.clientSecret }}
- name: BW_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Values.bitwarden_eso_provider.auth.existingSecret | default .Release.Name }}"
key: {{ .Values.bitwarden_eso_provider.auth.secretKeys.password }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
exec:
command:
- wget
- -q
- http://127.0.0.1:{{ .Values.service.targetPort }}/sync
- --post-data=''
readinessProbe:
httpGet:
path: /
port: http
tcpSocket:
port: {{ .Values.service.targetPort }}
initialDelaySeconds: 20
failureThreshold: 3
timeoutSeconds: 1
periodSeconds: 10
startupProbe:
tcpSocket:
port: {{ .Values.service.targetPort }}
initialDelaySeconds: 10
failureThreshold: 30
timeoutSeconds: 1
periodSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: test-connection
data:
curl_script.sh: |
curl http://{{ include "bitwarden-eso-provider.fullname" . }}:{{ .Values.service.port }}/status
19 changes: 15 additions & 4 deletions charts/bitwarden-eso-provider/templates/tests/test-connection.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@ metadata:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "bitwarden-eso-provider.fullname" . }}:{{ .Values.service.port }}']
- name: curl
image: curlimages/curl
command: ['/bin/sh']
args:
- "-c"
- "/testing/curl_script.sh"
volumeMounts:
- name: curl-script
mountPath: "/testing"
readOnly: false
volumes:
- name: curl-script
configMap:
name: test-connection
defaultMode: 0777
restartPolicy: Never
22 changes: 21 additions & 1 deletion charts/bitwarden-eso-provider/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,27 @@ fullnameOverride: ""
bitwarden_eso_provider:
# -- if set to True, we'll create a cluster-wide accessible Cluster Secret Store
# see: https://external-secrets.io/latest/introduction/overview/#clustersecretstore
create_cluster_secret_store: True
create_cluster_secret_store: true
auth:
# -- password for bitwarden
password: ""
# -- bitwarden client Secret to use to grabs secrets in the pod, ignored if existingSecret is set
clientSecret: ""
# -- bitwarden client ID to use to grabs secrets in the pod, ignored if existingSecret is set
clientID: ""
# -- bitwarden hostname to use to grab secrets in the pod, ignored if existingSecret is set
host: "https://bitwarden.com"
# -- use an existing secret for bitwarden credentials, ignores above credentials if this is set
existingSecret: ""
secretKeys:
# -- secret key for bitwarden password key
password: "BW_PASSWORD"
# -- secret key for bitwarden client Secret to use to grabs secrets in the pod
clientSecret: "BW_CLIENTSECRET"
# -- secret key for bitwarden client ID to use to grabs secrets in the pod
clientID: "BW_CLIENTID"
# -- secret key for bitwarden hostname to use to grab secrets in the pod
host: "BW_HOST"

serviceAccount:
# -- Specifies whether a service account should be created
Expand Down
9 changes: 7 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM debian:sid
FROM debian:bookworm-slim

ENV BW_CLI_VERSION=2023.1.0
ENV BW_CLI_VERSION=2023.7.0

RUN apt update && \
apt list --upgradeable | grep security | cut -f1 -d '/' | xargs apt-get install --no-install-recommends -y && \
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 && \
Expand All @@ -25,4 +26,8 @@ RUN useradd -ms /bin/bash $USER && \
USER $USER
WORKDIR /home/$USER/

RUN apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/*

CMD ["/bin/bash", "/usr/bin/entrypoint.sh"]
34 changes: 34 additions & 0 deletions examples/example-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
# this is the name of the ExternalSecret object
name: cool-secret-4-dogs
namespace: coolapp4dogs
spec:
target:
# This is the name of the secret in bitwarden
name: cool-secret
deletionPolicy: Delete
template:
type: Opaque
data:
# The kubernetes secret name
password: |-
{{ .password }}
data:
# the value to pass to the kubernetes secret.
- secretKey: password
sourceRef:
storeRef:
# Use the `bitwarden-login` store to get `username` and
# `password` values from a bitwarden secret that does not
# contain custom fields, Otherwise use `bitwarden-fields'
name: bitwarden-login
kind: ClusterSecretStore
remoteRef:
# This is the `name` of your bitwarden secret.
key: <your-secret-name>
# This is the property of the bitwarden secret that we want
property: <some-secret-property>

0 comments on commit a227e95

Please sign in to comment.