Deploying on Kubernetes #6: Application Secrets

Assumptions

To read this it’s expected that you’re familiar with Docker, and have perhaps played with building docker containers. Additionally, some experience with docker-compose is perhaps useful, though not immediately related.

Necessary Background

So far we’ve been able:

  1. Create the helm chart to manage the resources
  2. Add the MySQL and Redis dependencies
  3. Create a functional unit of software … sortof.
  4. Configure some of the software

Secrets

There is some information that is inherently sensitive. When managing authentication applications must be able to uniquely prove that they’re authorised to access a given resource (username/password), or otherwise prove their identity (PKI). Should that information be compromised, the guarantees inherent in providing identity to a limited set of users are lost.

  • The information is encoded in base64, so odd secret types (for example, pgp keys) can be embedded easily
  • It is possible to encrypt them such that only applications with the required identity can read them.

The secrets we need

In the previous post, we added a large amount of configuration to the fleet binary. However, we deliberately omitted secret information:

# templates/configmap.yaml:14-1814     mysql:
address: {{ default "kolide-fleet-mysql:3306" .Values.fleet.mysql.address }}
username: {{ default "kolide" .Values.fleet.mysql.username }}
# Handled as a secret in an environment variable
# password: kolide
mysql.password
redis.password
auth.jwt_key

Reusing existing secrets

Both MySQL and Redis already have provision for managing secrets. Indeed, they automatically generate secrets when the applications are loaded. Unfortunately, it is a little difficult to reach those secrets. Additionally, there are problems with those secrets as time goes on — with each release, they are regenerated. This might be fine if something takes care of updating those secrets, but in doing preliminary testing this does not appear to be the case.

Stubbing Configuration

First, we need to stub the values for these secrets. Earlier, we added redis and mysql as dependencies to this chart. We are able to influence the configuration in those charts in our chart, simply by adding the variables to our charts values.yml and prefixing it with the appropriate package name:

# values.yml:6-12mysql:
# This is a required value.
mysqlPassword: ""
redis:
# This is a required value.
redisPassword: ""
# templates/secret.yml:1-11---
apiVersion: "v1"
kind: "Secret"
metadata:
labels:
app: {{ template "fleet.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
heritage: "{{ .Release.Service }}"
release: "{{ .Release.Name }}"
name: {{ template "fleet.fullname" . }}
data:
# templates/secret.yml:11-14data:
fleet.mysql.username: {{ required "A valid MySQL Username is required" .Values.mysql.mysqlUser | b64enc }}
fleet.mysql.password: {{ required "A valid MySQL Password is required" .Values.mysql.mysqlPassword | b64enc }}
fleet.auth.jwt_key: {{ required "A valid JWT key is required" .Values.fleet.auth.jwt_key | b64enc }}
  1. All secrets are base64 encoded, as denoted by the specification
$ cat <<EOF > values.secret.yaml
---
mysql:
mysqlUser: "kolide"
mysqlPassword: $(pwgen 32 1)
redis:
redisPassword: $(pwgen 32 1)
fleet:
auth:
jwt_key: $(pwgen 32 1)
EOF
$ helm upgrade --install kolide-fleet --values values.yaml --values values.secret.yaml .

Consuming Configuration

Kolide/Fleet allows specifying configuration via environment variables. We’ll take advantage of that to inject our secret information.

# templates/deployment.yml:50-68      containers:
- name: fleet
env:
- name: "KOLIDE_AUTH_JWT_KEY"
valueFrom:
secretKeyRef:
name: {{ template "fleet.fullname" . }}
key: "fleet.auth.jwt_key"
- name: "KOLIDE_MYSQL_USERNAME"
valueFrom:
secretKeyRef:
name: {{ template "fleet.fullname" . }}
key: "fleet.mysql.username"
- name: "KOLIDE_MYSQL_PASSWORD"
valueFrom:
secretKeyRef:
name: {{ template "fleet.fullname" . }}
key: "fleet.mysql.password"
image: {{ .Values.pod.fleet.image | quote }}

In summary

That’s it! If we check the fleet logs, we can see it’s successfully able to connect to MySQL:

$ kubectl logs kolide-fleet-fleet-7c5f4999d7-9j6bt
Using config file: /etc/fleet/config.yml
################################################################################
# ERROR:
# Your Fleet database is not initialized. Fleet cannot start up.
#
# Run `fleet prepare db` to initialize the database.
################################################################################

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store