Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial support for MySQL as a database backend #16

Merged
merged 1 commit into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"