The Doppler Kubernetes Operator continuously syncs secrets to Kubernetes and can auto-reload deployments when secrets change.
Install the Operator using Helm:
helm repo add doppler https://helm.doppler.com helm install --generate-name doppler/doppler-kubernetes-operator
Or kubectl:
1kubectl apply -f https://github.com/DopplerHQ/kubernetes-operator/releases/latest/download/recommended.yaml
Installing the Kubernetes Operator creates the following resources:
Visit the Kubernetes Operator GitHub repository to learn more.
As the PKCS12 certificate is in binary format, it must be base64 encoded before importing to Doppler.
If you haven't yet created a Doppler project, you can use the CLI:
1doppler projects create pkcs12
Select the appropriate environment to import the secret to:
1doppler setup --project pkcs12 --config prd
Then create the base64 encoded PKCS12 certificate secret:
1doppler secrets set PKCS12_CERT="$(base64 -i doppler.p12)"
If your PKCS12 certificate is password-protected, you'll need to add that too:
1doppler secrets set PKCS12_PASS="changeit"
A Doppler Service Token is required to give the Operator access to the secrets for a specific project and config. It will be stored in a Kubernetes secret that the Operator will then access.
Create the Service Token and inject it as a Kubernetes secret in the doppler-operator-system namespace:
1kubectl create secret generic doppler-project-pkcs12-token \
2 --namespace doppler-operator-system \
3 --from-literal=serviceToken=$(doppler configs tokens create kubernetes-operator --plain)
Next, we'll create a custom DopplerSecret which contains data the Operator uses to manage the Kubernetes secret containing the synced secrets.
Kubernetes secrets are base64 encoded, not for security, but to store binary values such as PKCS12 certificates. But as the PKCS12 certificate is already base64 encoded in Doppler, we'll use the optional processors: map, which tells the Operator to skip base64 encoding the PKCS12_CERT value.
Save the file contents as doppler-secret-pkcs12.yaml:
1apiVersion: secrets.doppler.com/v1alpha1
2kind: DopplerSecret
3metadata:
4 name: doppler-secret-pkcs12 # Name of custom resource
5 namespace: doppler-operator-system
6spec:
7 tokenSecret:
8 name: doppler-project-pkcs12-token # Name of Kubernetes service token secret from previous step
9 managedSecret:
10 name: doppler-pkcs12 # Name of Kubernetes secret Operator will sync secrets to
11 namespace: default # Namespace of the deployment that will use the secret
12 processors:
13 PKCS12_CERT:
14 type: base64 # Instructs the Operator to not base64 encode the secret value again
Then create the DopplerSecret in Kubernetes:
1kubectl apply -f pkcs12-secret.yaml
You can check the Operator created the Kubernetes synced secret by querying for secrets with the Operator's custom label:
1kubectl describe secrets --selector=secrets.doppler.com/subtype=dopplerSecret
The output should be similar to:
1Name: doppler-pkcs12
2Namespace: default
3Labels: secrets.doppler.com/subtype=dopplerSecret
4Annotations: secrets.doppler.com/dashboard-link: https://dashboard.doppler.com/workplace/projects/pkcs12/configs/prd
5 secrets.doppler.com/processor-version: 07647691b375a71fda056fa16a8adb90a1caa0aea8e8adc3bc6ee7a5b69405a4
6 secrets.doppler.com/version: W/"d249692722e5022e9a08b911e4b4f53de7e69d0c6c98df6ddde8c679347a4b47"
7
8Type: Opaque
9
10Data
11====
12PKCS12_PASS: 8 bytes
13DOPPLER_CONFIG: 3 bytes
14DOPPLER_ENVIRONMENT: 3 bytes
15DOPPLER_PROJECT: 6 bytes
16PKCS12_CERT: 3975 bytes
The final step is mounting the certificate inside a container.
The below deployment uses the doppler-pkcs12 managed secret created by the Operator to mount the certificate using a secrets volume and supply the certificate password using the PKCS12_PASS environment variable.
The command and args combine to verify the certificate by extracting its metadata for testing purposes.
Save the file contents as pkcs12-deployment.yaml:
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: doppler-pkcs12
5 annotations:
6 secrets.doppler.com/reload: 'true'
7spec:
8 replicas: 1
9 selector:
10 matchLabels:
11 app: doppler-pkcs12
12 template:
13 metadata:
14 labels:
15 app: doppler-pkcs12
16 spec:
17 containers:
18 - name: doppler-pkcs12
19 image: alpine
20 workingDir: /usr/src/app
21 command:
22 - '/bin/sh'
23 args: # Install OpenSSL and verify certificate for testing purposes
24 - '-c'
25 - 'apk add openssl > /dev/null &&
26 openssl pkcs12 -in ./secrets/doppler.p12 -nodes -passin pass:"$PKCS12_PASS" | openssl x509 -noout -text &&
27 tail -f /dev/null'
28 env: # Set PKCS12_PASS environment variable needed to decrypt certificate
29 - name: PKCS12_PASS
30 valueFrom:
31 secretKeyRef:
32 name: doppler-pkcs12 # Operator managed secret
33 key: PKCS12_PASS
34 volumeMounts:
35 - name: doppler-pkcs12-volume
36 readOnly: true
37 mountPath: /usr/src/app/secrets
38 resources:
39 limits:
40 memory: '256Mi'
41 cpu: '250m'
42 volumes:
43 - name: doppler-pkcs12-volume
44 secret:
45 secretName: doppler-pkcs12 # Operator managed secret
46 items:
47 - key: PKCS12_CERT # Only select the PKCS12_CERT for mounting
48 path: doppler.p12 # Certificate name at mount path
Create the deployment in Kubernetes:
1kubectl apply -f pkcs12-deployment.yaml
Then confirm the certificate was verified by viewing the container logs:
1kubectl logs --selector app=doppler-pkcs12 --tail=70
Awesome work!
Now you know how to store and automatically sync PKCS12 certificates from Doppler to Kubernetes using the Doppler Kubernetes Operator.
Check out the Kubernetes Operator documentation and head to the Doppler Community Forum if you need help or have any questions.
Stay up to date with new platform releases and get to know the team of experts behind them.
Trusted by the world’s best DevOps and security teams. Doppler is the secrets manager developers love.