Skip to content

Commit

Permalink
Added initial support for MySQL as a database backend
Browse files Browse the repository at this point in the history
Since it was added as subchart (from bitnami), the following steps are
needed before deployment.

```
cd build/helm
helm dependency update keylime
```

In addition to it, tweaked a little bit the messages in NOTES.txt

This uses randomly generated password which persist accross upgrades

Here we also have a new Makefile, providing options to deploy/undeploy/update/debug

Signed-off-by: Marcio Silva <marcio.a.silva@ibm.com>
  • Loading branch information
Marcio Silva authored and maugustosilva committed Aug 23, 2023
1 parent 9ac2418 commit 39db82f
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 24 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
values.yaml
/build/artifacts/**
!/build/artifacts/.keepme
/build/helm/**.tgz
/build/helm/values.yaml
/build/helm/*/*.lock
/build/helm/*/charts/mysql*
57 changes: 55 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ VERSION ?= latest

# helm chart version must be semver 2 compliant
HELM_CHART_KEYLIME_VERSION ?= 0.1.0
HELM_CHART_RELEASE_NAME ?= hhkl
HELM_CHART_NAMESPACE ?= keylime
HELM_CHART_CUSTOM_VALUES ?= values.yaml
HELM_CHART_DEBUG_FILE ?= /tmp/keylime.helm.debug
HELM_CHART_KEYLIME_DIR := $(BUILD_DIR)/helm/keylime
HELM_CHART_KEYLIME_FILES := $(shell find $(HELM_CHART_KEYLIME_DIR) -type f)
HELM_CHART_REPO ?= ghcr.io/keylime/helm-charts
Expand All @@ -40,21 +44,70 @@ all: helm

##@ Build

helm: helm-keylime ## Builds all helm charts
helm: helm-build ## Builds all helm charts

.PHONY: helm-clean
helm-clean: helm-keylime-clean ## Cleans all packaged helm charts

helm-keylime: $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz ## Builds the keylime helm chart
.PHONY: helm-undeploy
helm-undeploy: helm-keylime-undeploy

.PHONY: helm-deploy
helm-deploy: helm-keylime-deploy

.PHONY: helm-update
helm-deploy: helm-keylime-update

.PHONY: helm-debug
helm-debug: helm-keylime-debug

helm-build: $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz ## Builds the keylime helm chart

$(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz: $(HELM_CHART_KEYLIME_FILES)
helm lint $(HELM_CHART_KEYLIME_DIR)
helm dependency update $(HELM_CHART_KEYLIME_DIR)
helm package $(HELM_CHART_KEYLIME_DIR) --version $(HELM_CHART_KEYLIME_VERSION) --app-version $(VERSION) -d $(BUILD_ARTIFACTS_DIR)

.PHONY: helm-keylime-clean
helm-keylime-clean: ## Cleans the packaged keylime helm chart
rm -v $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz 2>/dev/null || true

.PHONY: helm-keylime-undeploy
helm-keylime-undeploy: ## Undeploy the keylime helm chart
{ \
helm list --namespace $(HELM_CHART_NAMESPACE) | grep -q $(HELM_CHART_RELEASE_NAME);\
if [[ $$? -eq 0 ]]; then helm uninstall $(HELM_CHART_RELEASE_NAME) --namespace $(HELM_CHART_NAMESPACE); fi;\
kubectl get persistentvolumeclaim/data-$(HELM_CHART_RELEASE_NAME)-mysql-0 --namespace $(HELM_CHART_NAMESPACE) > /dev/null 2>&1;\
if [[ $$? -eq 0 ]]; then kubectl delete persistentvolumeclaim/data-$(HELM_CHART_RELEASE_NAME)-mysql-0 --namespace $(HELM_CHART_NAMESPACE); fi;\
kubectl get secret/$(HELM_CHART_RELEASE_NAME)-keylime-ca-password --namespace $(HELM_CHART_NAMESPACE) > /dev/null 2>&1;\
if [[ $$? -eq 0 ]]; then kubectl delete secret/$(HELM_CHART_RELEASE_NAME)-keylime-ca-password --namespace $(HELM_CHART_NAMESPACE); fi;\
kubectl get secret/$(HELM_CHART_RELEASE_NAME)-keylime-mysql-password --namespace $(HELM_CHART_NAMESPACE) > /dev/null 2>&1;\
if [[ $$? -eq 0 ]]; then kubectl delete secret/$(HELM_CHART_RELEASE_NAME)-keylime-mysql-password --namespace $(HELM_CHART_NAMESPACE); fi;\
kubectl get secret/$(HELM_CHART_RELEASE_NAME)-keylime-certs --namespace $(HELM_CHART_NAMESPACE) > /dev/null 2>&1;\
if [[ $$? -eq 0 ]]; then kubectl delete secret/$(HELM_CHART_RELEASE_NAME)-keylime-certs --namespace $(HELM_CHART_NAMESPACE); fi;\
}

.PHONY: helm-keylime-deploy
helm-keylime-deploy: ## Deploy the keylime helm chart
{ \
touch $(HELM_CHART_CUSTOM_VALUES);\
helm install $(HELM_CHART_RELEASE_NAME) $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz --namespace $(HELM_CHART_NAMESPACE) --create-namespace -f $(HELM_CHART_CUSTOM_VALUES);\
}

.PHONY: helm-keylime-update
helm-keylime-update: ## Update the deployed keylime helm chart
{ \
touch $(HELM_CHART_CUSTOM_VALUES);\
helm upgrade $(HELM_CHART_RELEASE_NAME) $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz --namespace $(HELM_CHART_NAMESPACE) --create-namespace -f $(HELM_CHART_CUSTOM_VALUES);\
}

.PHONY: helm-keylime-debug
helm-keylime-debug: ## Attempt to debug the keylime helm chart, without deploying it
{ \
touch $(HELM_CHART_CUSTOM_VALUES);\
helm install $(HELM_CHART_RELEASE_NAME) $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz --namespace $(HELM_CHART_NAMESPACE) --create-namespace --debug --dry-run -f $(HELM_CHART_CUSTOM_VALUES)>$(HELM_CHART_DEBUG_FILE);\
}

.PHONY: helm-keylime-push
helm-keylime-push: helm ## Builds AND pushes the keylime helm chart
helm push $(BUILD_ARTIFACTS_DIR)/keylime-$(HELM_CHART_KEYLIME_VERSION).tgz oci://$(HELM_CHART_REPO)
9 changes: 9 additions & 0 deletions build/helm/keylime/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,35 @@ sources:
# all dependencies and subcharts of this helm chart
dependencies:
- name: keylime-agent
version: "0.1.0"
tags:
- agent
import-values:
- child: service
parent: agent.service
- name: keylime-init
version: "0.1.0"
tags:
- init
- name: keylime-registrar
version: "0.1.0"
tags:
- registrar
import-values:
- child: service
parent: registrar.service
- name: keylime-tenant
version: "0.1.0"
tags:
- tenant
- name: keylime-verifier
version: "0.1.0"
tags:
- verifier
import-values:
- child: service
parent: verifier.service
- name: mysql
version: "9.3.4"
repository: https://charts.bitnami.com/bitnami
condition: global.database.mysql.enable
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ Expand to the secret name for the certificate volume to be used
*/}}
{{- define "agent.cvca.secret" -}}
{{- if .Values.global.ca.generate }}
{{- include "keylime.ca.secret" . }}
{{- include "keylime.ca.secret.certs" . }}
{{- else }}
{{- default (include "keylime.ca.secret" .) .Values.global.ca.agentName }}
{{- default (include "keylime.ca.secret.certs" .) .Values.global.ca.agentName }}
{{- end }}
{{- end }}
48 changes: 36 additions & 12 deletions build/helm/keylime/charts/keylime-init/templates/ca-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,69 @@ spec:
fieldRef:
fieldPath: metadata.namespace
- name: KEYLIME_SECRETS_NAME
value: "{{ include "keylime.ca.secret" . }}"
value: "{{ include "keylime.ca.secret.certs" . }}"
- name: KEYLIME_CA_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "keylime.ca.secret.password" . }}
key: KEYLIME_CA_PASSWORD
- name: KEYLIME_SECRETS_CA_PW_NAME
value: "{{ include "keylime.ca.secret.password" . }}"
command:
- /bin/bash
- -c
- |
ls /usr/local/bin/kubectl
if [ $? -ne 0 ]
if [[ $? -ne 0 ]]
then
pushd /usr/local/bin
curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl
chmod +x /usr/local/bin/kubectl
popd
fi
if [[ -z $KEYLIME_CA_PASSWORD ]]
then
echo "ERROR: unable to find created secret"
exit 1
fi
# check if the secrets exist already in which case we'll just respect them
kubectl get secret $KEYLIME_SECRETS_NAME $KEYLIME_SECRETS_CA_PW_NAME
if [ $? -eq 0 ] ; then
echo "NOTE: secrets already exist, we will *NOT* recreate them!"
kubectl get secret $KEYLIME_SECRETS_NAME --namespace ${KEYLIME_NAMESPACE}
if [[ $? -eq 0 ]]
then
echo "NOTE: secret containing TLS certificates already exist, we will *NOT* recreate it!"
exit 0
fi
# now fail if any of the commands fail
set -e
# create a directory where we'll generate the certs to
mkdir -p /tmp/certs
cd /tmp
# this generates a password for the CA which is required
export KEYLIME_CA_PASSWORD=$(openssl rand -base64 32)
# now generate the CV CA
keylime_ca -d /tmp/certs --command init
keylime_ca -d /tmp/certs --command create --name server
keylime_ca -d /tmp/certs --command create --name client
keylime_ca -d /tmp/certs --command init && keylime_ca -d /tmp/certs --command create --name server && keylime_ca -d /tmp/certs --command create --name client
if [[ $? -ne 0 ]]
then
echo "ERROR: unable to generete certificates"
exit 1
fi
# create Kubernetes secrets from this - we'll create a separate secret for the CA password
kubectl create secret generic $KEYLIME_SECRETS_NAME --namespace ${KEYLIME_NAMESPACE} --from-file=/tmp/certs
kubectl create secret generic $KEYLIME_SECRETS_CA_PW_NAME --namespace ${KEYLIME_NAMESPACE} --from-literal=KEYLIME_CA_PASSWORD=$KEYLIME_CA_PASSWORD
if [[ $? -ne 0 ]]
then
echo "ERROR: unable to create secret with certificates"
exit 1
fi
kubectl get secret $KEYLIME_SECRETS_NAME --namespace ${KEYLIME_NAMESPACE}
if [[ $? -ne 0 ]]
then
echo "ERROR: unable to check if secret with certificates was indeed created"
exit 1
fi
exit 0
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
Expand Down
14 changes: 14 additions & 0 deletions build/helm/keylime/charts/keylime-init/templates/capw-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{- if .Values.global.ca.generate -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "keylime.ca.secret.password" . }}
labels:
{{- include "init.labels" . | nindent 4 }}
annotations:
"helm.sh/resource-policy": "keep"
"helm.sh/hook": pre-install
type: Opaque
data:
KEYLIME_CA_PASSWORD: {{ printf "%s" (include "keylime.ca.secret.passwordcontents" .) }}
{{- end -}}
15 changes: 15 additions & 0 deletions build/helm/keylime/charts/keylime-init/templates/mysql-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- if .Values.global.database.mysql.enable }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "keylime.mysql.secret.password" . }}
labels:
{{- include "init.labels" . | nindent 4 }}
annotations:
"helm.sh/resource-policy": "keep"
"helm.sh/hook": pre-install
type: Opaque
data:
mysql-root-password: {{ printf "%s" (include "keylime.mysql.secret.passwordcontents" .) }}
mysql-password: {{ printf "%s" (include "keylime.mysql.secret.passwordcontents" .) }}
{{- end -}}
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ Expand to the secret name for the certificate volume to be used
*/}}
{{- define "registrar.ca.secret" -}}
{{- if .Values.global.ca.generate }}
{{- include "keylime.ca.secret" . }}
{{- include "keylime.ca.secret.certs" . }}
{{- else }}
{{- default (include "keylime.ca.secret" .) .Values.global.ca.registrarName }}
{{- default (include "keylime.ca.secret.certs" .) .Values.global.ca.registrarName }}
{{- end }}
{{- end }}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ Expand to the secret name for the certificate volume to be used
*/}}
{{- define "tenant.ca.secret" -}}
{{- if .Values.global.ca.generate }}
{{- include "keylime.ca.secret" . }}
{{- include "keylime.ca.secret.certs" . }}
{{- else }}
{{- default (include "keylime.ca.secret" .) .Values.global.ca.tenantName }}
{{- default (include "keylime.ca.secret.certs" .) .Values.global.ca.tenantName }}
{{- end }}
{{- end }}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ Expand to the secret name for the certificate volume to be used
*/}}
{{- define "verifier.ca.secret" -}}
{{- if .Values.global.ca.generate }}
{{- include "keylime.ca.secret" . }}
{{- include "keylime.ca.secret.certs" . }}
{{- else }}
{{- default (include "keylime.ca.secret" .) .Values.global.ca.verifierName }}
{{- default (include "keylime.ca.secret.certs" .) .Values.global.ca.verifierName }}
{{- end }}
{{- end }}

Expand Down
2 changes: 1 addition & 1 deletion build/helm/keylime/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ To control and manage your keylime installation, you probably want to use the `k

You can achieve this by "execing" into a keylime-tenant pod that got deployed with this installation by running the following command:
{{ $klt := index .Subcharts "keylime-tenant" }}
kubectl exec -ti $(kubectl get pods -l app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/name={{ include "tenant.name" $klt }} -o name | head -n 1) -c {{ $klt.Chart.Name }} -- /bin/bash
kubectl exec -ti -n {{ .Release.Namespace }} $(kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/name={{ include "tenant.name" $klt }} -o name | head -n 1) -c {{ $klt.Chart.Name }} -- /bin/bash

From within the pod you can interact with keylime with the common `keylime_tenant` commands. The pod comes preconfigured with all registrar and verifier URLs. As it is a Kubernetes pod, it will also have direct access to the agent pods. Therefore the keylime-tenant pod is in a perfect position to run all `keylime_tenant` commands.
{{- else }}
Expand Down
47 changes: 46 additions & 1 deletion build/helm/keylime/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Expand to the name of the keylime config map
{{/*
Always expands to the name of the secret used for certificates when the init job runs.
*/}}
{{- define "keylime.ca.secret" -}}
{{- define "keylime.ca.secret.certs" -}}
{{- printf "%s-%s" .Release.Name "keylime-certs" | trunc 63 | trimSuffix "-" }}
{{- end }}

Expand All @@ -82,6 +82,51 @@ Always expands to the name of the secret used for the CA certificate when the in
{{- printf "%s-%s" .Release.Name "keylime-ca-password" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "generate_static_password" -}}
{{- if not (index .Release "tmp_vars") -}}
{{- $_ := set .Release "tmp_vars" dict -}}
{{- end }}
{{- $key := printf "%s_%s" .Release.Name "password" -}}
{{- if not (index .Release.tmp_vars $key) -}}
{{- $_ := set .Release.tmp_vars $key (randAlphaNum 32) -}}
{{- end -}}
{{- /* Retrieve previously generated value. */ -}}
{{- index .Release.tmp_vars $key -}}
{{- end -}}

{{/*
Generate a random password if one is not defined
*/}}
{{- define "keylime.ca.secret.passwordcontents" -}}
{{- $capwsecretname := printf "%s" (include "keylime.ca.secret.password" .) }}
{{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace "$capwsecretname") }}
{{- if $existingSecret -}}
{{- index $existingSecret.data "KEYLIME_CA_PASSWORD" -}}
{{- else -}}
{{- default (include "generate_static_password" .) .Values.global.ca.password | b64enc | quote -}}
{{- end -}}
{{- end -}}

{{/*
Need to find a way to override .Values.mysql.auth.existingSecret to include Release.Name
*/}}
{{- define "keylime.mysql.secret.password" -}}
{{- printf "%s-%s" .Release.Name "keylime-mysql-password" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Generate a random password if one is not defined
*/}}
{{- define "keylime.mysql.secret.passwordcontents" -}}
{{- $mysqlpwsecretname := printf "%s" (include "keylime.mysql.secret.password" .) -}}
{{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace "$mysqlpwsecretname") -}}
{{- if $existingSecret -}}
{{- index $existingSecret.data "mysql-root-password" -}}
{{- else -}}
{{- default (include "generate_static_password" .) .Values.global.database.mysql.password | b64enc | quote -}}
{{- end -}}
{{- end -}}

{{/*
Always expands to the name of the secret used for the TPM cert store when the init job runs.
*/}}
Expand Down
7 changes: 7 additions & 0 deletions build/helm/keylime/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ metadata:
labels:
{{- include "keylime.labels" . | nindent 4 }}
data:

{{- if .Values.global.database.mysql.enable }}
{{- $mysqlPassword := printf "%s" (include "keylime.mysql.secret.passwordcontents" .) | replace "\"" "" | b64dec }}
KEYLIME_REGISTRAR_DATABASE_URL: "mysql+pymysql://root:{{ $mysqlPassword }}@{{ template "mysql.primary.fullname" ( index .Subcharts "mysql" ) }}.{{ .Release.Namespace }}.svc.cluster.local:3306/{{ .Values.mysql.auth.database }}?charset=utf8"
KEYLIME_VERIFIER_DATABASE_URL: "mysql+pymysql://root:{{ $mysqlPassword }}@{{ template "mysql.primary.fullname" ( index .Subcharts "mysql" ) }}.{{ .Release.Namespace }}.svc.cluster.local:3306/{{ .Values.mysql.auth.database }}?charset=utf8"
{{- end }}

{{- if .Values.tags.agent }}
KEYLIME_AGENT_UUID: "hash_ek"
KEYLIME_AGENT_IP: "0.0.0.0"
Expand Down
13 changes: 13 additions & 0 deletions build/helm/keylime/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ global:
registrarName: ""
# verifierName is the name of the secret to be used for the "cv_ca" folder for the registrar if generate is not true
verifierName: ""
# leave it empty, and new password, maintained accross multiple upgrades, will be generated
password: ""
# tpmCertStore manages the TPM cert store which is used for verifying the EK of the TPMs
tpmCertStore:
# create means that an init job will run which will create a Kubernetes secret with the "well known" CAs for EKs.
Expand Down Expand Up @@ -111,3 +113,14 @@ global:
# This will pull in a PostgreSQL helm chart for deployment.
# TODO: implement
enable: false
# mysql enables a MySQL database backend
mysql:
# enable activates the PostgreSQL database backend
# This will pull in a MySQL helm chart for deployment.
enable: false
# leave it empty, and a new password, maintained accross multiple upgrades, will be generated
password: ""
mysql:
auth:
existingSecret: "{{ .Release.Name }}-keylime-mysql-password"
database: "keylimedb"

0 comments on commit 39db82f

Please sign in to comment.