Bitwarden Secrets Manager
Bitwarden Secrets Manager Provider
This section describes how to set up the Bitwarden Secrets Manager provider for External Secrets Operator (ESO).
Prerequisites
In order for the bitwarden provider to work, we need a second service. This service is the Bitwarden SDK Server. The Bitwarden SDK is Rust based and requires CGO enabled. In order to not restrict the capabilities of ESO, and the image size ( the bitwarden Rust SDK libraries are over 150MB in size ) it has been decided to create a soft wrapper around the SDK that runs as a separate service providing ESO with a light REST API to pull secrets through.
Bitwarden SDK server
The server itself can be installed together with ESO. The ESO Helm Chart packages this service as a dependency. The Bitwarden SDK Server's full name is hardcoded to bitwarden-sdk-server. This is so that the exposed service URL gets a determinable endpoint.
In order to install the service install ESO with the following helm directive:
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set bitwarden-sdk-server.enabled=true
Certificate
The Bitwarden SDK Server NEEDS to run as an HTTPS service. That means that any installation that wants to communicate with the Bitwarden provider will need to generate a certificate. The best approach for that is to use cert-manager. It's easy to set up and can generate a certificate that the store can use to connect with the server.
For a sample set up look at the bitwarden sdk server's test setup. It contains a self-signed certificate issuer for cert-manager.
External secret store
With that out of the way, let's take a look at how a secret store would look like.
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: bitwarden-secretsmanager
spec:
provider:
bitwardensecretsmanager:
apiURL: https://api.bitwarden.com
identityURL: https://identity.bitwarden.com
auth:
secretRef:
credentials:
key: token
name: bitwarden-access-token
bitwardenServerSDKURL: https://bitwarden-sdk-server.default.svc.cluster.local:9998
caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ5akNDQXQ2Z0F3SUJBZ0lRS08vM1J1dXR4YWdOeThCdUcyUTJYREFOQmdrcWhraUc5dzBCQVFzRkFEQkQKTVJ3d0dnWURWUVFLRXhObGVIUmxjbTVoYkMxelpXTnlaWFJ6TG1sdk1TTXdJUVlEVlFRREV4cGpaWEowTFcxaApibUZuWlhJdFltbDBkMkZ5WkdWdUxYUnNjekFlRncweU5EQTJNVGt4TXpJd01EUmFGdzB5TkRBNU1UY3hNekl3Ck1EUmFNRU14SERBYUJnTlZCQW9URTJWNGRHVnlibUZzTFhObFkzSmxkSE11YVc4eEl6QWhCZ05WQkFNVEdtTmwKY25RdGJXRnVZV2RsY2kxaWFYUjNZWEprWlc0dGRHeHpNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QQpNSUlCQ2dLQ0FRRUExdlFxaTNCL0NVU01FaUx1b3NkTVdZV25QcWJmQ20xbnZsMWhoUWxjOW1ocDFnSmxDbndjCmE0MmxuTkx0TjNTUmdrZWFNYXppV1RyaDQ5SGdUeTNVQ2xoNDh5RXFvTmJDRUlaL2xxOHNoVzRMd2g0RTdNT08KOVJJMDY2a3JCYllYakZuam1ETjdJV1NLOVVwZjIrOUpLTi9PM3ZWTktLMGZhOERxRkppL3h3VUsyOGRNc05tZAo2NnkreW52TzRFRU51Wm9IRUFieWdrOTQ2cm9yNnNmUkxHZ3ZVYXg5cmd4dEh5TkZqcGkrbjhCUDRlQkRZeGI4CkVsQy93Q0Rza2NBNFF3TXphU3NFbDBwL3gwQm9nTS9nbWJWelNVemhBL2NGdXpMRVJmV0tuanJrbmpoenNFWncKRWlzUmZ6K3MyVnUvcm5YK3pabTBoWTFvSDZYY29mVkhOUUlEQVFBQm80SGxNSUhpTUE0R0ExVWREd0VCL3dRRQpBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJTeUplK1lnUWZQbWFFOEZKSHowbzZ0CjQzeGh4VENCbndZRFZSMFJCSUdYTUlHVWdqOWxlSFJsY201aGJDMXpaV055WlhSekxXSnBkSGRoY21SbGJpMXoKWkdzdGMyVnlkbVZ5TG1SbFptRjFiSFF1YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDTG1KcGRIZGhjbVJsYmkxegpaR3N0YzJWeWRtVnlMbVJsWm1GMWJIUXVjM1pqTG1Oc2RYTjBaWEl1Ykc5allXeUNDV3h2WTJGc2FHOXpkSWNFCmZ3QUFBWWNRQUFBQUFBQUFBQUFBQUFBQUFBQUFBVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBdllYUW5ETEgKczc3N3NJN3cwN2NWMVIrTmZvbGRYblp5ejVtQVpDZkc4T2djZDRGdjRYV3lrRG94MzlkUWo0dTJnOWlVcUNwawp2QzJsbUR1UjNrS2kzbjgySTYyQ1BDN1JmZFd3M2hqaFJOV1NKbVBGeGF6NHkrbnMvMDZ3RFBlMmZwRXpPMXIzCmwxTFdZMHBySVlMME1EYTI1c3BUdlZPdWxyeWlnUnJRRGNEbS9hZ3krSEs4RHB3dWlTTEpsdFM0Q1JVa25mb3kKS00rL213VTd4RzNrSnN5ekR0T2dOZDhZeG1lRU44Q05WSk9JalltRk9OWTJrYU51S2ZnMU1aaXArcllPTEFqUgpJdUNxOFhSSTVST2gxOFJKdVlXcVZ6MUkwbXE4aVgwYlo2WG5WRjliZ0ViQ2d3bXZOWkZha3Z4RVhkWmR2N3VmCkYvRm9PTUFlNTY3L0RBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
organizationID: 7c0d21ec-10d9-4972-bdf8-ec52df99cc86
projectID: 9c713cd6-728c-437a-a783-252b0773a0bb
The api url and identity url are optional. The secret should contain the token for the Machine account for bitwarden.
Note
Make sure that the machine account has Read-Write access to the Project that the secrets are in.
Note
A secret store is organization/project dependent. Meaning a 1 store == 1 organization/project. This is so that we ensure that no other project's secrets can be modified accidentally or intentionally.
External Secrets
There are two ways to fetch secrets from the provider.
Find by UUID
In order to fetch a secret by using its UUID simply provide that as remote key in the external secrets like this:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: bitwarden
spec:
refreshInterval: 10s
secretStoreRef:
# This name must match the metadata.name in the `SecretStore`
name: bitwarden-secretsmanager
kind: SecretStore
data:
- secretKey: test
remoteRef:
key: "339062b8-a5a1-4303-bf1d-b1920146a622"
Find by Name
To find a secret using its name, we need a bit more information. Mainly, these are the rules to find a secret:
- if name is a UUID get the secret
- if name is NOT a UUID Property is mandatory that defines the projectID to look for
- if name + projectID + organizationID matches, we return that secret
- if more than one name exists for the same projectID within the same organization we error
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: bitwarden
spec:
refreshInterval: 10s
secretStoreRef:
# This name must match the metadata.name in the `SecretStore`
name: bitwarden-secretsmanager
kind: SecretStore
data:
- secretKey: test
remoteRef:
key: "secret-name"
Push Secret
Pushing a secret is also implemented. Pushing a secret requires even more restrictions because Bitwarden Secrets Manager allows creating the same secret with the same key multiple times. In order to avoid overwriting, or potentially, returning the wrong secret, we restrict push secret with the following rules:
- name, projectID, organizationID and value AND NOTE equal, we won't push it again.
- name, projectID, organizationID and ONLY the value does not equal ( INCLUDING THE NOTE ) we update
- any of the above isn't true, we create the secret ( this means that it will create a secret in a separate project )
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: pushsecret-bitwarden # Customisable
spec:
refreshInterval: 10s # Refresh interval for which push secret will reconcile
secretStoreRefs: # A list of secret stores to push secrets to
- name: bitwarden-secretsmanager
kind: SecretStore
selector:
secret:
name: my-secret # Source Kubernetes secret to be pushed
data:
- match:
secretKey: key # Source Kubernetes secret key to be pushed
remoteRef:
remoteKey: remote-key-name # Remote reference (where the secret is going to be pushed)
metadata:
note: "Note of the secret to add."