yara mohamed
yara mohamed

Reputation: 451

Import data to config map from kubernetes secret

I'm using a kubernetes ConfigMap that contains database configurations for an app and there is a secret that has the database password. I need to use this secret in the ConfigMap so when I try to add environment variable in the ConfigMap and specify the value in the pod deployment from the secret I'm not able to connect to mysql with password as the values in the ConfigMap took the exact string of the variable.

apiVersion: v1
kind: ConfigMap
metadata:
  name: config
data:
  APP_CONFIG: |
    port: 8080
    databases:
      default:
        connector: mysql
        host: "mysql"
        port: "3306"
        user: "root"
        password: "$DB_PASSWORD"

and the deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app
  labels:
    app: backend
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: app
        image: simple-app-image
        ports:
          - name: "8080"
            containerPort: 8080
        env:
          - name: APP_CONFIG
            valueFrom:
              configMapKeyRef:
                name: config
                key: APP_CONFIG
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: "mysql-secret"
                key: "mysql-root-password"

Note: the secret exist and I'm able to get "mysql-root-password" value and use to login to the database

Upvotes: 37

Views: 42694

Answers (5)

Ali Bahramian
Ali Bahramian

Reputation: 31

There is an option to use external-secret operator and pull your configMap, inject passwords to it and create a secret out of it and finally mount it.

https://external-secrets.io/latest/guides/templating-v1/

Upvotes: 3

Abhinav Sureka
Abhinav Sureka

Reputation: 159

For me, something like this worked (sharing just the relevant example snippet for simplicity):

example-configmap

data:
  example.yaml: |
    user: ${USER}

example-secret

data:
  user: <some base64 encoded value>

example-deployment

containers:
  - name: example-container
    image: example-image
    env:
      - name: USER
        valueFrom:
          secretKeyRef:
            key: user
            name: example-secret
    volumeMounts:
      - mountPath: /some/path/in/container
        name: config
        readOnly: true
volumes:  
  - name: config
    configMap:
      name: example-configmap

Explanation: In the above example, say,
I need to substitute ${USER} in the configmap with the decoded value of the user: key from the secret.
Then, as done above, in the deployment/pod definition, I need to:

  • mount the configmap as a volume (volumes.configMap) under volumeMounts in the container, and
  • expose the secret value as an environment variable (env.valueFrom.secretKeyRef) in the container.

Result: The ${USER} in the configmap will have been substituted with the decoded value of the user: key from the secret.

Reason: This is because the configmap is now mounted as a file at the mountPath inside the container, and thus, can access any env variable exposed within the container.

Note: namespace for deployment/pod, configmap, and secret should be the same.

Upvotes: -1

Vishrant
Vishrant

Reputation: 16678

You could do something like this in HELM:

{{- define "getValueFromSecret" }}
{{- $len := (default 16 .Length) | int -}}
{{- $obj := (lookup "v1" "Secret" .Namespace .Name).data -}}
{{- if $obj }}
{{- index $obj .Key | b64dec -}}
{{- else -}}
{{- randAlphaNum $len -}}
{{- end -}}
{{- end }}

Then you could do something like this in configmap:

{{- include "getValueFromSecret" (dict "Namespace" .Release.Namespace "Name" "<secret_name>" "Length" 10 "Key" "<key>")  -}}

The secret should be already present while deploying; or you can control the order of deployment using https://github.com/vmware-tanzu/carvel-kapp-controller

Upvotes: 2

peedee
peedee

Reputation: 3739

I would transform the whole configMap into a secret and deploy the database password directly in there. Then you can mount the secret as a file to a volume and use it like a regular config file in the container.

Upvotes: -2

Ignacio Mill&#225;n
Ignacio Mill&#225;n

Reputation: 8066

Kubernetes can't make that substitution for you, you should do it with shell in the entrypoint of the container.

This is a working example. I modify the default entrypoint to create a new variable with that substitution. After this command you should add the desired entrypoint.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app
  labels:
    app: backend
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: app
        image: simple-app-image
        command:
          - /bin/bash
          - -c
        args:
          - "NEW_APP_CONFIG=$(echo $APP_CONFIG | envsubst) && echo $NEW_APP_CONFIG && <INSERT IMAGE ENTRYPOINT HERE>"
        ports:
          - name: "app"
            containerPort: 8080
        env:
          - name: APP_CONFIG
            valueFrom:
              configMapKeyRef:
                name: config
                key: APP_CONFIG
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: "mysql-secret"
                key: "mysql-root-password"

Upvotes: 21

Related Questions