'Combining multiple k8s secrets into an env variable
My k8s namespace contains a Secret
which is created at deployment time (by svcat
), so the values are not known in advance.
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-database-credentials
data:
hostname: ...
port: ...
database: ...
username: ...
password: ...
A Deployment
needs to inject these values in a slightly different format:
...
containers:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: my-database-credentials
key: jdbc:postgresql:<hostname>:<port>/<database> // ??
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: my-database-credentials
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: my-database-credentials
key: password
The DATABASE_URL
needs to be composed out of the hostname
, port
, 'database` from the previously defined secret.
Is there any way to do this composition?
Solution 1:[1]
Kubernetes allows you to use previously defined environment variables as part of subsequent environment variables elsewhere in the configuration. From the Kubernetes API reference docs:
Variable references $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables.
This $(...)
syntax defines interdependent environment variables for the container.
So, you can first extract the required secret values into environment variables, and then compose the DATABASE_URL
with those variables.
...
containers:
env:
- name: DB_URL_HOSTNAME // part 1
valueFrom:
secretKeyRef:
name: my-database-credentials
key: hostname
- name: DB_URL_PORT // part 2
valueFrom:
secretKeyRef:
name: my-database-credentials
key: port
- name: DB_URL_DBNAME // part 3
valueFrom:
secretKeyRef:
name: my-database-credentials
key: database
- name: DATABASE_URL // combine
value: jdbc:postgresql:$(DB_URL_HOSTNAME):$(DB_URL_PORT)/$(DB_URL_DBNAME)
...
Solution 2:[2]
If all the pre-variables are defined as env variables:
- { name: DATABASE_URL, value: '{{ printf "jdbc:postgresql:$(DATABASE_HOST):$(DATABASE_PORT)/$(DB_URL_DBNAME)" }}'}
With this statement you may also bring in vlaues from the values.yaml file as well:
For Example:
If you may have defined DB_URL_DBNAME in the values file:
- { name: DATABASE_URL, value: '{{ printf "jdbc:postgresql:$(DATABASE_HOST):$(DATABASE_PORT)/%s" .Values.database.DB_URL_DBNAME }}'}
Solution 3:[3]
You can do a couple of things I can think of:
Use a secrets volume and make a startup script that reads the secrets from the volume and then starts your application with the
DATABASE_URL
environment variable.apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: your_db_container command: [ "yourscript.sh" ] volumeMounts: - name: mycreds mountPath: "/etc/credentials" volumes: - name: mycreds secret: secretName: my-database-credentials defaultMode: 256
Pass the env variable in the
command
key of your container spec:apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: your_db_container command: [ "/bin/sh", "-c", "DATABASE_URL=jdbc:postgresql:<hostname>:<port>/<database>/$(DATABASE_USERNAME):$(DATABASE_PASSWORD) /start/yourdb" ] env: - name: DATABASE_USERNAME valueFrom: secretKeyRef: name: my-database-credentials key: username - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: my-database-credentials key: password
Solution 4:[4]
There are several ways to go (in increasing complexity order):
Mangle the parameter before putting it into the Secret (extend whatever you use to insert the info there).
Add a script into your Pod/Container to mangle the incoming parameters (environmental variables or command arguments) into what is needed. If you cannot or don't want to have your own container image, you can add your extra script as a Volume to the container, and set the Container's
command
field to override the container image start command.Add a facility to your Kubernetes to do an automatic mangling "behind the scenes": you can add a Dynamic Admission Controller to do your mangling, or you can create a Kubernetes Operator and add a Custom Resource Definition (the operator would be told by the CRD which Secrets to watch for changes, and the operator would read the values and generate whatever other entries you want).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | suresh Palemoni |
Solution 3 | Rico |
Solution 4 | Laszlo Valko |