Syncing Secrets
The operator uses DopplerSecret
custom resources to determine which secrets should be synced from Doppler to Kubernetes. Each of these resources contain the details for a single Doppler config sync including:
- the Doppler access token that's used to perform the secret fetch
- the Doppler project and config the secrets are being fetched from
- the Kubernetes secret they're being synced to
The Kubernetes secret that's being synced to will be created if it doesn't exist. The operator will then continuously monitor all DopplerSecret
custom resources and ensure that any upstream changes in Doppler will be reflected in the Kubernetes secret (by default, it checks for changes every 60 seconds).
Permissions
The Doppler Kubernetes Operator will always install into the doppler-operator-system
kubernetes namespace (which is automatically created when you install the helm chart). This namespace is considered privileged, which means DopplerSecret
CRDs created in this namespace are able to do some things they can't do if they exist in other namespaces. Notably they can:
- manage kubernetes secrets in other namespaces
- reference kubernetes secrets in other namespaces (e.g., doppler token secrets)
If a DopplerSecret
CRD is created in any other namespace, it's restricted to managing and referencing kubernetes secrets in that namespace. If one attempts to reference any outside of its namespace, the DopplerSecret
will not get processed by the operator.
This permission setup is designed to allow an orchestration or management team to create secrets for other teams if needed by creating them in the operator namespace, while also allowing self-service by letting other teams create their own CRDs that impact their own namespaces.
Doppler Access Token
Every DopplerSecret
CRD requires a tokenSecret
to be specified that tells the operator where to find a Doppler access token to use to sync that CRD. In a production environment, you would likely use a Service Account token, but when testing locally it's easiest to just use your local CLI access token:
kubectl create secret generic doppler-token-secret \
--namespace doppler-operator-system \
--from-literal=serviceToken=$(doppler configure get token --plain)
Keep in mind that your local CLI access token is tied to your user and has all the permissions your user account does. We recommend against using these in production. Instead, consider using one or more Service Account tokens.
DopplerSecret Custom Resource
A DopplerSecret
custom resource definition (CRD) looks like this:
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
project: k8s-demo
config: dev
managedSecret:
name: dopplersecret-test
namespace: default
type: Opaque
To create the DopplerSecret
CRD, you apply it using kubectl
as you would any other CRD:
kubectl apply -f examples/doppler-secret.yml
Kubernetes Secret Type
Kubernetes has many different secret types. By default, the operator creates secrets using kubernetes' Opaque
type. In some situations, you may want to sync to another secret type though. This can be done by specifying the type
of the managedSecret
. Supported types are as follows:
Opaque
kubernetes.io/tls
kubernetes.io/service-account-token
kubernetes.io/dockercfg
kubernetes.io/dockerconfigjson
kubernetes.io/basic-auth
kubernetes.io/ssh-auth
bootstrap.kubernetes.io/token
These types have additional expectations in terms of the secret keys that are added. For example, the kubernetes.io/tls
type expects a tls.key
and tls.crt
key and no other entries. To comply with this, the usual DOPPLER_*
secrets are not synced for these secret types and you need to use processors to rename the secrets:
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
managedSecret:
name: doppler-test-secret
namespace: default
type: kubernetes.io/tls
project: k8s-demo
config: dev
processors:
TLS_CRT:
type: plain
asName: tls.crt
TLS_KEY:
type: plain
asName: tls.key
In the above example, the TLS_CRT
and TLS_KEY
secrets are renamed to tls.crt
and tls.key
to comply with the expectations of the kubernetes.io/tls
secret type.
Adjusting Sync Interval
You can control the polling interval that the operator uses when syncing by specifying resyncSeconds
. We recommend leaving this at the default (60 seconds), but there are scenarios where adjusting this may be necessary or desired.
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
managedSecret:
name: dopplersecret-test
namespace: default
type: Opaque
project: k8s-demo
config: dev
resyncSeconds: 120
Name Transformers
Name transformers allow secret names to be transformed from Doppler's UPPER_SNAKE_CASE
format into any of the following environment variable compatible formats:
Type | Default | Transform |
---|---|---|
camel | API_KEY | apiKey |
upper-camel | API_KEY | ApiKey |
lower-snake | API_KEY | api_key |
tf-var | API_KEY | TF_VAR_api_key |
dotnet-env | SMTP__USER_NAME | Smtp__UserName |
lower-kebab | API_KEY | api-key |
To use a transformer, add the nameTransformer
field with any of the above types:
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
managedSecret:
name: dopplersecret-test
namespace: default
type: Opaque
project: k8s-demo
config: dev
nameTransformer: dotnet-env
Processors
Type
Type
By default, the Operator base64 encodes Doppler secret values when creating the managed Opaque Kubernetes secret as Key / Value pairs. However, instances may arise where you do not wish this base64 encoding to occur, such as when a binary .p12
key file has already been base64 encoded in Doppler and double base64 encoding it would prevent Kubernetes from mounting it in its original binary format.
Secret processors allow you to customize the default encoding behavior.
To override the default plain
processor, add a processors:
map which specifies the secret name and the processor to apply which in this case, is base64
:
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
managedSecret:
name: doppler-test-secret
namespace: default
type: Opaque
project: k8s-demo
config: dev
processors:
TLS_CRT:
type: plain
asName: tls.crt
TLS_KEY:
type: plain
asName: tls.key
At present, only plain
and base64
processors exist. Reach out to [email protected] if there is another processor you'd like us to support.
asName
asName
You can also override the default name that's used when creating the secret in Kubernetes. By default, it will use the same uppercase secret name found in Doppler. This is useful when using the kubernetes.io/tls
type that expects a tls.crt
and tls.key
secret entry. To accomplish this, add the asName
parameter to the processor:
processors:
TLS_CRT:
type: plain
asName: tls.crt
TLS_KEY:
type: plain
asName: tls.key
Note that using the plain
type combined with the asName
parameter will let you rename any secret during the sync without affecting the value being synced.
For a complete example, check out our tutorial on using the Doppler Kubernetes Operator for Managing PKCS12 Certificates and the README in GitHub.
Secret Subsets
You can specify a subset of secrets from a config that you'd like to sync by using the secrets
field. Note that the DOPPLER_*
secrets will still appear in addition to any secrets you specify here.
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dopplersecret-test
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-secret
namespace: doppler-operator-system
managedSecret:
name: doppler-test-secret
namespace: default
type: Opaque
project: k8s-demo
config: dev
secrets:
- TLS_CRT
- TLS_KEY
Download Format
Instead of the standard Key / Value pairs, you can download secrets as a single file in the following formats:
- json
- dotnet-json
- env
- yaml
- docker
When format
is specified, a single DOPPLER_SECRETS_FILE
key is set in the created secret with the string contents of the downloaded file.
To use this feature, add the format
field:
apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
name: dotnet-webapp-appsettings
namespace: doppler-operator-system
spec:
tokenSecret:
name: doppler-token-dotnet-webapp
namespace: doppler-operator-system
managedSecret:
name: dotnet-webapp-appsettings
namespace: default
format: dotnet-json
You can then configure your deployment spec to mount the file at the desired path:
---
spec:
containers:
- name: dotnet-webapp
volumeMounts:
- name: doppler
mountPath: /usr/src/app/secrets
readOnly: true
volumes:
- name: doppler
secret:
secretName: dotnet-webapp-appsettings # Managed secret name
optional: false
items:
- key: DOPPLER_SECRETS_FILE # Hard-coded by Operator when format specified
path: appsettings.json # Name or path to file name appended to container mountPath
Updated 2 days ago