Add users to a Kubernetes deployment of MySQL with secrets

3/4/2021

My overall goal is to create MySQL users (despite root) automatically after the deployment in Kubernetes.

I found the following resources:
https://stackoverflow.com/questions/64946194/how-to-create-mysql-users-and-database-during-deployment-of-mysql-in-kubernetes
https://stackoverflow.com/questions/50373869/add-another-user-to-mysql-in-kubernetes

People suggested that .sql scripts can be mounted to docker-entrypoint-initdb.d with a ConfigMap to create these users. In order to do that, I have to put the password of these users in this script in plain text. This is a potential security issue. Thus, I want to store MySQL usernames and passwords as Kubernetes Secrets.

This is my ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  labels:
    app: mysql-image-db
data:
  initdb.sql: |-
    CREATE USER <user>@'%' IDENTIFIED BY <password>;

How can I access the associated Kubernetes secrets within this ConfigMap?

-- Marcel Gohsen
docker
kubernetes
mysql

1 Answer

3/16/2021

I am finally able to provide a solution to my own question. Since PjoterS made me aware that you can mount Secrets into a Pod as a volume, I came up with following solution.

This is the ConfigMap for the user creation scipt:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-init-script
  labels:
    app: mysql-image-db
data:
  init-user.sh: |-
    #!/bin/bash
    sleep 30s

    mysql -u root -p"$(cat /etc/mysql/credentials/root_password)" -e \
      "CREATE USER '$(cat /etc/mysql/credentials/user_1)'@'%' IDENTIFIED BY '$(cat /etc/mysql/credentials/password_1)';"

To made this work, I needed to mount the ConfigMap and the Secret as Volumes of my Deployment and added a postStart lifecycle hook to execute the user creation script.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-image-db
spec:
  selector:
    matchLabels:
      app: mysql-image-db
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql-image-db
    spec:
      containers:
        - image: mysql:8.0
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: root_password
                  name: mysql-user-credentials
          ports:
            - containerPort: 3306
              name: mysql
          volumeMounts:
            - name: mysql-persistent-volume
              mountPath: /var/lib/mysql
            - name: mysql-config-volume
              mountPath: /etc/mysql/conf.d
            - name: mysql-init-script-volume
              mountPath: /etc/mysql/init
            - name: mysql-credentials-volume
              mountPath: /etc/mysql/credentials
          lifecycle:
            postStart:
              exec:
                command: ["/bin/bash", "-c", "/etc/mysql/init/init-user.sh"]
      volumes:
        - name: mysql-persistent-volume
          persistentVolumeClaim:
            claimName: mysql-volume-claim
        - name: mysql-config-volume
          configMap:
            name: mysql-config
        - name: mysql-init-script-volume
          configMap:
            name: mysql-init-script
            defaultMode: 0777
        - name: mysql-credentials-volume
          secret:
            secretName: mysql-user-credentials
-- Marcel Gohsen
Source: StackOverflow