From c7c273b2440515f42d47ac4b9097a736c8bbac4d Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 00:41:43 +0100 Subject: [PATCH 1/6] feat(devel): enable vault persistence in dev mode Switch Vault to server mode with file backend to persist data across restarts while maintaining auto-unseal and dev token convenience. Fixes #2574 Signed-off-by: Miguel Martinez --- devel/compose.common.yml | 14 ++++++---- devel/vault-config.hcl | 26 +++++++++++++++++ devel/vault-init.sh | 60 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 devel/vault-config.hcl create mode 100755 devel/vault-init.sh diff --git a/devel/compose.common.yml b/devel/compose.common.yml index ae9ba0887..90801a6e4 100644 --- a/devel/compose.common.yml +++ b/devel/compose.common.yml @@ -17,21 +17,25 @@ services: interval: 2s retries: 10 - # in memory-only vault for development - # note that secrets will get removed when the container is restarted + # Vault with persistence for development vault: image: docker.io/vault:1.12.3 cap_add: - IPC_LOCK ports: - 8200:8200 - environment: - - VAULT_DEV_ROOT_TOKEN_ID=notasecret + volumes: + - ./vault-config.hcl:/vault/config/local.hcl + - ./vault-init.sh:/vault-init.sh + - vault_data:/vault/file + command: "/vault-init.sh" healthcheck: test: [ "CMD", "wget", "--spider", "http://127.0.0.1:8200/v1/sys/health" ] interval: 10s timeout: 3s retries: 10 start_period: 5s + volumes: - postgresql_data: \ No newline at end of file + postgresql_data: + vault_data: \ No newline at end of file diff --git a/devel/vault-config.hcl b/devel/vault-config.hcl new file mode 100644 index 000000000..1ffe7a892 --- /dev/null +++ b/devel/vault-config.hcl @@ -0,0 +1,26 @@ +# +# Copyright 2025 The Chainloop Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +storage "file" { + path = "/vault/file" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 +} + +disable_mlock = true +ui = true diff --git a/devel/vault-init.sh b/devel/vault-init.sh new file mode 100755 index 000000000..55f351370 --- /dev/null +++ b/devel/vault-init.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# +# Copyright 2025 The Chainloop Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +# Start Vault in background +vault server -config=/vault/config/local.hcl & +VAULT_PID=$! + +# Wait for Vault to start +sleep 2 + +export VAULT_ADDR='http://127.0.0.1:8200' + +# Check if Vault is initialized +if ! vault status | grep -q "Initialized.*true"; then + echo "Initializing Vault..." + vault operator init -key-shares=1 -key-threshold=1 > /vault/file/init.txt +fi + +# Unseal Vault +echo "Unsealing Vault..." +UNSEAL_KEY=$(grep "Unseal Key 1:" /vault/file/init.txt | awk '{print $4}') +vault operator unseal $UNSEAL_KEY + +# Login with root token to create the dev token +ROOT_TOKEN=$(grep "Initial Root Token:" /vault/file/init.txt | awk '{print $4}') +export VAULT_TOKEN=$ROOT_TOKEN + +# Create the 'notasecret' token if it doesn't exist +echo "Ensuring 'notasecret' token exists..." +if ! vault token lookup notasecret > /dev/null 2>&1; then + echo "Token 'notasecret' not found (or lookup failed), creating it..." + vault token create -id="notasecret" -policy="root" +else + echo "Token 'notasecret' already exists." +fi + +# Enable kv secrets engine at secret/ if not enabled +if ! vault secrets list | grep -q "^secret/"; then + echo "Enabling kv secrets engine at secret/..." + vault secrets enable -path=secret kv +fi + + +# Keep container running +wait $VAULT_PID From a8000d80de0381cfa290b0902bba520a9db65769 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 01:34:09 +0100 Subject: [PATCH 2/6] feat(devel): enable vault persistence in dev mode Switch Vault to server mode with file backend to persist data across restarts while maintaining auto-unseal and dev token convenience. Fixes #2574 Signed-off-by: Miguel Martinez --- deployment/chainloop/templates/_helpers.tpl | 2 +- deployment/chainloop/values.yaml | 115 ++++++++++++++++++-- 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/deployment/chainloop/templates/_helpers.tpl b/deployment/chainloop/templates/_helpers.tpl index e1fee827a..16ab48e64 100644 --- a/deployment/chainloop/templates/_helpers.tpl +++ b/deployment/chainloop/templates/_helpers.tpl @@ -77,7 +77,7 @@ vault: {{- if $tokenEnvVar }} token: {{ $tokenEnvVar | quote }} {{- else }} - {{- required "VAULT_DEV_ROOT_TOKEN_ID environment variable is required when development mode is enabled" (index $.Values.vault.server.extraEnvVars "VAULT_DEV_ROOT_TOKEN_ID") }} + token: "notasecret" {{- end }} {{- else if (required "vault backend selected but configuration not provided" .vault ) }} address: {{ required "vault address required" .vault.address | quote }} diff --git a/deployment/chainloop/values.yaml b/deployment/chainloop/values.yaml index e23e42315..265a3ddc0 100644 --- a/deployment/chainloop/values.yaml +++ b/deployment/chainloop/values.yaml @@ -1690,14 +1690,109 @@ postgresql: ## @param vault.server.extraEnvVars[1].name Address to listen on development mode ## @param vault.server.extraEnvVars[1].value The address to listen on. Default: [::]:8200 vault: + extraDeploy: + - | + apiVersion: v1 + kind: ConfigMap + metadata: + name: {{ include "vault.server.fullname" . }}-init + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/part-of: vault + app.kubernetes.io/component: server + data: + vault-init.sh: | + #!/bin/sh + # + # Copyright 2025 The Chainloop Authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + set -e + + # Start Vault in background + vault server -config /bitnami/vault/config/config.hcl & + PID=$! + + # Wait for Vault to start + echo "Waiting for Vault to start..." + until vault status > /dev/null 2>&1; STATUS=$?; [ $STATUS -eq 0 ] || [ $STATUS -eq 2 ]; do + sleep 1 + done + + export VAULT_ADDR='http://127.0.0.1:8200' + + # Initialize if not already initialized or if init.txt is invalid + if [ ! -f /bitnami/vault/data/init.txt ] || ! grep -q "Unseal Key 1:" /bitnami/vault/data/init.txt; then + echo "Initializing Vault..." + vault operator init -key-shares=1 -key-threshold=1 > /bitnami/vault/data/init.txt + echo "Vault initialized successfully" + else + echo "Vault already initialized, using existing keys" + fi + + # Unseal + echo "Reading unseal key..." + UNSEAL_KEY=$(grep 'Unseal Key 1:' /bitnami/vault/data/init.txt | awk '{print $NF}') + if [ -z "$UNSEAL_KEY" ]; then + echo "ERROR: Failed to read unseal key from init.txt" + echo "Contents of init.txt:" + cat /bitnami/vault/data/init.txt || echo "Cannot read init.txt" + exit 1 + fi + echo "Unsealing Vault..." + vault operator unseal "$UNSEAL_KEY" + + # Login + ROOT_TOKEN=$(grep 'Initial Root Token:' /bitnami/vault/data/init.txt | awk '{print $NF}') + export VAULT_TOKEN=$ROOT_TOKEN + + # Create 'notasecret' token if it doesn't exist + if ! vault token lookup notasecret > /dev/null 2>&1; then + echo "Creating 'notasecret' token..." + vault token create -id="notasecret" -policy="root" + fi + + # Enable KV v2 secrets engine (required by controlplane) + if ! vault secrets list | grep -q "^secret/"; then + echo "Enabling KV v2 secrets engine at secret/..." + vault secrets enable -path=secret kv-v2 + else + echo "Secrets engine already exists at secret/" + fi + + # Keep container running + wait $PID server: - args: [ - "server", - "-dev" - ] - extraEnvVars: - - name: VAULT_DEV_ROOT_TOKEN_ID - value: "notasecret" - - name: VAULT_DEV_LISTEN_ADDRESS - value: "[::]:8200" - config: "storage \"inmem\" {}\ndisable_mlock = true\nui = true\nservice_registration \"kubernetes\" {}" + command: ["/vault-init.sh"] + args: [""] + config: | + disable_mlock = true + ui = true + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + } + storage "file" { + path = "/bitnami/vault/data" + } + extraVolumes: + - name: vault-init + configMap: + name: '{{ include "vault.server.fullname" . }}-init' + defaultMode: 0755 + extraVolumeMounts: + - name: vault-init + mountPath: /vault-init.sh + subPath: vault-init.sh From 723918c0ef31ed352eab042744adf2ded9ed22eb Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 09:46:19 +0100 Subject: [PATCH 3/6] fix local initialization Signed-off-by: Miguel Martinez --- deployment/chainloop/Chart.yaml | 1 + devel/vault-init.sh | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/deployment/chainloop/Chart.yaml b/deployment/chainloop/Chart.yaml index f0cee5cff..46f7c292c 100644 --- a/deployment/chainloop/Chart.yaml +++ b/deployment/chainloop/Chart.yaml @@ -21,6 +21,7 @@ dependencies: name: postgresql repository: file://charts/postgresql version: 15.x.x + # vault is run in development mode only in development - condition: development name: vault repository: file://charts/vault diff --git a/devel/vault-init.sh b/devel/vault-init.sh index 55f351370..1b7df4af2 100755 --- a/devel/vault-init.sh +++ b/devel/vault-init.sh @@ -49,10 +49,12 @@ else echo "Token 'notasecret' already exists." fi -# Enable kv secrets engine at secret/ if not enabled +# Enable KV v2 secrets engine at secret/ if not enabled if ! vault secrets list | grep -q "^secret/"; then - echo "Enabling kv secrets engine at secret/..." - vault secrets enable -path=secret kv + echo "Enabling KV v2 secrets engine at secret/..." + vault secrets enable -path=secret kv-v2 +else + echo "Secrets engine already exists at secret/" fi From c88b2a10493667f3521c2571c91817ced99b30bf Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 09:56:26 +0100 Subject: [PATCH 4/6] fix local initialization Signed-off-by: Miguel Martinez --- deployment/chainloop/values.yaml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/deployment/chainloop/values.yaml b/deployment/chainloop/values.yaml index 265a3ddc0..7bb29beb8 100644 --- a/deployment/chainloop/values.yaml +++ b/deployment/chainloop/values.yaml @@ -1703,21 +1703,6 @@ vault: data: vault-init.sh: | #!/bin/sh - # - # Copyright 2025 The Chainloop Authors. - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - set -e # Start Vault in background @@ -1778,7 +1763,7 @@ vault: args: [""] config: | disable_mlock = true - ui = true + ui = false listener "tcp" { tls_disable = 1 address = "[::]:8200" From 146bb7d43f744c79cb7545d2988874924eb6e35c Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 10:48:04 +0100 Subject: [PATCH 5/6] feat: improve help Signed-off-by: Miguel Martinez --- deployment/chainloop/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/chainloop/Chart.yaml b/deployment/chainloop/Chart.yaml index 46f7c292c..e79972d70 100644 --- a/deployment/chainloop/Chart.yaml +++ b/deployment/chainloop/Chart.yaml @@ -7,7 +7,7 @@ description: Chainloop is an open source software supply chain control plane, a type: application # Bump the patch (not minor, not major) version on each change in the Chart Source code -version: 1.307.0 +version: 1.307.1 # Do not update appVersion, this is handled automatically by the release process appVersion: v1.60.0 From 972714c63e34dad1c966eeaff47ff2f042788a8b Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 21 Nov 2025 12:21:20 +0100 Subject: [PATCH 6/6] refactor: simplify vault token default in helm template Signed-off-by: Miguel Martinez --- deployment/chainloop/templates/_helpers.tpl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/deployment/chainloop/templates/_helpers.tpl b/deployment/chainloop/templates/_helpers.tpl index 16ab48e64..57ba24c3e 100644 --- a/deployment/chainloop/templates/_helpers.tpl +++ b/deployment/chainloop/templates/_helpers.tpl @@ -74,11 +74,7 @@ secretPrefix: {{ required "secret prefix required" .secretPrefix | quote }} vault: {{- if and $.Values.development (or (not .vault) not .vault.address) }} address: {{ printf "http://%s-server:8200" (include "chainloop.vault.fullname" $) | quote }} - {{- if $tokenEnvVar }} - token: {{ $tokenEnvVar | quote }} - {{- else }} - token: "notasecret" - {{- end }} + token: {{ default "notasecret" $tokenEnvVar | quote }} {{- else if (required "vault backend selected but configuration not provided" .vault ) }} address: {{ required "vault address required" .vault.address | quote }} token: {{ required "vault token required" .vault.token | quote }}