diff --git a/deployment/chainloop/Chart.yaml b/deployment/chainloop/Chart.yaml index f0cee5cff..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 @@ -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/deployment/chainloop/templates/_helpers.tpl b/deployment/chainloop/templates/_helpers.tpl index e1fee827a..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 }} - {{- 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") }} - {{- 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 }} diff --git a/deployment/chainloop/values.yaml b/deployment/chainloop/values.yaml index e23e42315..7bb29beb8 100644 --- a/deployment/chainloop/values.yaml +++ b/deployment/chainloop/values.yaml @@ -1690,14 +1690,94 @@ 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 + 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 = false + 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 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..1b7df4af2 --- /dev/null +++ b/devel/vault-init.sh @@ -0,0 +1,62 @@ +#!/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 v2 secrets engine at secret/ if not enabled +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 $VAULT_PID