Skip to content

Commit

Permalink
resourcegen: add volume-stateful-set deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
3u13r committed Sep 13, 2024
1 parent add78a6 commit 125a228
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 2 deletions.
5 changes: 5 additions & 0 deletions internal/kuberesource/mutators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestPatchNamespaces(t *testing.T) {
coordinator := CoordinatorBundle()
openssl := OpenSSL()
emojivoto := Emojivoto(ServiceMeshIngressEgress)
volumeStatefulSet := VolumeStatefulSet()

for _, tc := range []struct {
name string
Expand All @@ -34,6 +35,10 @@ func TestPatchNamespaces(t *testing.T) {
name: "emojivoto",
set: emojivoto,
},
{
name: "volume-stateful-set",
set: volumeStatefulSet,
},
} {
t.Run(tc.name, func(_ *testing.T) {
expectedNamespace := "right-namespace"
Expand Down
2 changes: 2 additions & 0 deletions internal/kuberesource/resourcegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func main() {
case "emojivoto-sm-ingress":
subResources = kuberesource.Emojivoto(kuberesource.ServiceMeshIngressEgress)
subResources = kuberesource.PatchRuntimeHandlers(subResources, "contrast-cc")
case "volume-stateful-set":
subResources = kuberesource.PatchRuntimeHandlers(kuberesource.VolumeStatefulSet(), "contrast-cc")
default:
log.Fatalf("Error: unknown set: %s\n", set)
}
Expand Down
126 changes: 126 additions & 0 deletions internal/kuberesource/sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/edgelesssys/contrast/internal/platforms"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/intstr"
applyappsv1 "k8s.io/client-go/applyconfigurations/apps/v1"
applycorev1 "k8s.io/client-go/applyconfigurations/core/v1"
Expand Down Expand Up @@ -496,3 +497,128 @@ func Emojivoto(smMode serviceMeshMode) []any {

return resources
}

// VolumeStatefulSet returns a stateful set for testing volume mounts and the
// mounting of encrypted luks volumes using the workload-secret.
func VolumeStatefulSet() []any {
initCommand := `#!/bin/bash
# cryptsetup complains if there is no /run directory.
mkdir /run
set -e
# device is the path to the block device to be encrypted.
device="/dev/csi0"
# workload_secret_path is the path to the Contrast workload secret.
workload_secret_path="/contrast/secrets/workload-secret-seed"
# tmp_key_path is the path to a temporary key file.
tmp_key_path="/dev/shm/key"
# disk_encryption_key_path is the path to the disk encryption key.
disk_encryption_key_path="/dev/shm/disk-key"
# If the device is not already a LUKS device, format it.
if ! cryptsetup isLuks "${device}"; then
# Generate a random key for the first initialization.
dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 | tr -d '\n' > "${tmp_key_path}"
cryptsetup luksFormat $device "${tmp_key_path}" </dev/null
# Now we can get the LUKS UUID and deterministically derive the disk encryption key from the workload secret.
uuid=$(blkid "${device}" -s UUID -o value)
openssl kdf -keylen 32 -kdfopt digest:SHA2-256 -kdfopt key:$(cat "${workload_secret_path}") \
-kdfopt info:${uuid} -binary HKDF | base64 | tr -d '\n' > "${disk_encryption_key_path}"
cryptsetup luksChangeKey "${device}" --key-file "${tmp_key_path}" "${disk_encryption_key_path}"
cryptsetup open "${device}" state -d "${disk_encryption_key_path}"
mkfs.ext4 /dev/mapper/state
cryptsetup close state
fi
# No matter if this is the first initialization derive the key (again) and open the device.
uuid=$(blkid "${device}" -s UUID -o value)
openssl kdf -keylen 32 -kdfopt digest:SHA2-256 -kdfopt key:$(cat "${workload_secret_path}") \
-kdfopt info:${uuid} -binary HKDF | base64 | tr -d '\n' > "${disk_encryption_key_path}"
cryptsetup luksUUID "${device}"
cryptsetup open "${device}" state -d "${disk_encryption_key_path}"
mkdir -p /srv/state
mount /dev/mapper/state /srv/state
sleep inf
`

vss := StatefulSet("volume-tester", "").
WithSpec(StatefulSetSpec().
WithReplicas(1).
WithSelector(LabelSelector().
WithMatchLabels(map[string]string{"app.kubernetes.io/name": "volume-tester"}),
).
WithServiceName("volume-tester").
WithTemplate(PodTemplateSpec().
WithLabels(map[string]string{"app.kubernetes.io/name": "volume-tester"}).
WithSpec(
PodSpec().
WithInitContainers(
Container().
WithName("volume-tester-init").
WithImage("ghcr.io/edgelesssys/contrast/cryptsetup:latest").
WithCommand("/bin/sh", "-c", initCommand).
WithVolumeDevices(
applycorev1.VolumeDevice().
WithName("state").
WithDevicePath("/dev/csi0"),
).
WithVolumeMounts(
VolumeMount().
WithName("share").
WithMountPath("/srv").
WithMountPropagation(corev1.MountPropagationBidirectional),
VolumeMount().
WithName("contrast-secrets").
WithMountPath("/contrast"),
).
WithSecurityContext(
applycorev1.SecurityContext().
WithPrivileged(true),
).
WithResources(ResourceRequirements().
WithMemoryLimitAndRequest(100),
).
WithReadinessProbe(
Probe().
WithInitialDelaySeconds(1).
WithPeriodSeconds(5).
WithExec(applycorev1.ExecAction().
WithCommand("/bin/sh", "-c", "ls /srv/state"),
),
).
WithRestartPolicy(
corev1.ContainerRestartPolicyAlways,
),
).
WithContainers(
Container().
WithName("volume-tester").
WithImage("ghcr.io/edgelesssys/contrast/cryptsetup:latest").
WithCommand("/bin/sh", "-c", "sleep inf").
WithVolumeMounts(
VolumeMount().
WithName("share").
WithMountPath("/srv").
WithMountPropagation(corev1.MountPropagationHostToContainer),
),
).
WithVolumes(
applycorev1.Volume().
WithName("share").
WithEmptyDir(applycorev1.EmptyDirVolumeSource()),
),
),
).
WithVolumeClaimTemplates(applycorev1.PersistentVolumeClaim("state", "").
WithSpec(applycorev1.PersistentVolumeClaimSpec().
WithVolumeMode(corev1.PersistentVolumeBlock).
WithAccessModes(corev1.ReadWriteOnce).
WithResources(applycorev1.VolumeResourceRequirements().
WithRequests(map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("1Gi")}),
),
),
),
)

return []any{vss}
}
10 changes: 8 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Undeploy, rebuild, deploy.
default target=default_deploy_target platform=default_platform cli=default_cli: soft-clean coordinator initializer openssl port-forwarder service-mesh-proxy (node-installer platform) (deploy target cli platform) set verify (wait-for-workload target)
default target=default_deploy_target platform=default_platform cli=default_cli: soft-clean coordinator initializer openssl cryptsetup port-forwarder service-mesh-proxy (node-installer platform) (deploy target cli platform) set verify (wait-for-workload target)

# Build and push a container image.
push target:
Expand All @@ -15,6 +15,9 @@ coordinator: (push "coordinator")
# Build the openssl container and push it.
openssl: (push "openssl")
# Build the cryptsetup container and push it.
cryptsetup: (push "cryptsetup")
# Build the port-forwarder container and push it.
port-forwarder: (push "port-forwarder")
Expand Down Expand Up @@ -122,7 +125,7 @@ apply target=default_deploy_target:
kubectl apply -f ./{{ workspace_dir }}/runtime
exit 0
;;
"openssl" | "emojivoto")
"openssl" | "emojivoto" | "volume-stateful-set")
:
;;
*)
Expand Down Expand Up @@ -230,6 +233,9 @@ wait-for-workload target=default_deploy_target:
nix run -L .#scripts.kubectl-wait-ready -- $ns voting-svc
nix run -L .#scripts.kubectl-wait-ready -- $ns web-svc
;;
"volume-stateful-set")
nix run .#scripts.kubectl-wait-ready -- $ns volume-tester
;;
*)
echo "Please register workloads of new targets in wait-for-workload"
exit 1
Expand Down

0 comments on commit 125a228

Please sign in to comment.