diff --git a/charts/chronicle/Chart.lock b/charts/chronicle/Chart.lock index 7db551ef5..c5cf6ffc8 100644 --- a/charts/chronicle/Chart.lock +++ b/charts/chronicle/Chart.lock @@ -4,9 +4,9 @@ dependencies: version: 0.1.3 - name: node repository: https://paritytech.github.io/helm-charts/ - version: 5.6.1 + version: 5.7.1 - name: vault repository: https://helm.releases.hashicorp.com version: 0.27.0 -digest: sha256:19c6ade52b5c53daab6fd0a8a2c42a81e5371b99eb9de8a5f102b215930dce40 -generated: "2024-03-05T14:03:42.428673+03:00" +digest: sha256:6073af2c490fa86b821ac5188b14cd4f9bd9f2c8e61a778d2acbde9861470a0c +generated: "2024-05-01T20:31:33.345331+01:00" diff --git a/charts/chronicle/Chart.yaml b/charts/chronicle/Chart.yaml index 71e556676..96feb98c4 100644 --- a/charts/chronicle/Chart.yaml +++ b/charts/chronicle/Chart.yaml @@ -27,9 +27,4 @@ dependencies: - name: standard-defs version: ~0.1.0 repository: https://btp-charts-stable.s3.amazonaws.com/charts/ - - name: node - version: ~5.6.1 - repository: https://paritytech.github.io/helm-charts/ - - name: vault - version: ~0.27 - repository: https://helm.releases.hashicorp.com + diff --git a/charts/chronicle/charts/node-5.6.1.tgz b/charts/chronicle/charts/node-5.6.1.tgz deleted file mode 100644 index 67cc59a76..000000000 Binary files a/charts/chronicle/charts/node-5.6.1.tgz and /dev/null differ diff --git a/charts/chronicle/charts/standard-defs-0.1.3.tgz b/charts/chronicle/charts/standard-defs-0.1.3.tgz index 2f63806a9..d5ac17a14 100644 Binary files a/charts/chronicle/charts/standard-defs-0.1.3.tgz and b/charts/chronicle/charts/standard-defs-0.1.3.tgz differ diff --git a/charts/chronicle/templates/_chronicle.tpl b/charts/chronicle/templates/_chronicle.tpl index 0b6d04868..c1bda86c9 100644 --- a/charts/chronicle/templates/_chronicle.tpl +++ b/charts/chronicle/templates/_chronicle.tpl @@ -3,7 +3,7 @@ {{- end -}} {{- define "tp.replicas" -}} -{{ include "lib.call-nested" (list . "sawtooth" "sawtooth.replicas") | int }} +{{ include "lib.call-nested" (list . "node" "node.replicas") | int }} {{- end -}} {{- define "chronicle.service.name" -}} @@ -26,16 +26,12 @@ chronicle: {{ include "common.names.fullname" . }} {{ include "chronicle.labels.appLabels" . }} {{- end -}} -{{- define "chronicle.sawtooth.sawcomp" -}} -{{ include "lib.call-nested" (list . "sawtooth" "sawtooth.ports.sawcomp") | int }} +{{- define "chronicle.substrate.rpc" -}} +9982 {{- end -}} -{{- define "chronicle.sawtooth.rest" -}} -{{ include "lib.call-nested" (list . "sawtooth" "sawtooth.ports.rest") | int }} -{{- end -}} - -{{- define "chronicle.sawtooth.service" -}} -{{- $svc := include "lib.call-nested" (list . "sawtooth" "common.names.fullname") -}} +{{- define "chronicle.substrate.service" -}} +{{- $svc := include "lib.call-nested" (list . "node" "common.names.fullname") -}} {{- $ns := .Release.Namespace -}} {{- $domain := "svc.cluster.local" -}} {{ printf "%s.%s.%s" $svc $ns $domain }} diff --git a/charts/chronicle/templates/chronicle-config.yaml b/charts/chronicle/templates/chronicle-config.yaml index f0f114b48..640f5f71d 100644 --- a/charts/chronicle/templates/chronicle-config.yaml +++ b/charts/chronicle/templates/chronicle-config.yaml @@ -1,17 +1,10 @@ --- -{{$stlServiceName := include "lib.call-nested" (list . "sawtooth" "common.names.fullname")}} +{{$stlServiceName := include "lib.call-nested" (list . "node" "common.names.fullname")}} apiVersion: v1 kind: ConfigMap metadata: name: {{.Release.Name}}-chronicle-config data: config.toml: | - [secrets] - path = "/var/lib/chronicle/secrets/" - [store] - path = "/var/lib/chronicle/store/" - address = "postgresql://{{ .Values.postgres.user }}@{{ .Values.postgres.host }}:5432/{{ .Values.postgres.database }}" - [validator] - address = "tcp://{{ include "chronicle.sawtooth.service" . }}:{{ include "chronicle.sawtooth.sawcomp" . }}" [namespace_bindings] default = "fd717fd6-70f1-44c1-81de-287d5e101089" diff --git a/charts/chronicle/templates/chronicle-init.yaml b/charts/chronicle/templates/chronicle-init.yaml deleted file mode 100644 index 90fdd1581..000000000 --- a/charts/chronicle/templates/chronicle-init.yaml +++ /dev/null @@ -1,231 +0,0 @@ -{{$stlServiceName := include "lib.call-nested" (list . "sawtooth" "common.names.fullname")}} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ include "common.names.fullname" . }}-init - labels: {{ include "chronicle.labels" . | nindent 4 }} - component: chronicle -spec: - ttlSecondsAfterFinished: 100 - template: - metadata: - labels: {{ include "chronicle.labels" . | nindent 8 }} - component: chronicle - spec: - restartPolicy: Never - serviceAccountName: {{ include "lib.serviceAccountName" . }} - automountServiceAccountToken: true - volumes: {{- include "lib.volumes" .Values.opa.tp.extraVolumes | nindent 8 }} - - name: shared-data - emptyDir: {} - initContainers: - - name: get-secret - image: alpine/k8s:1.24.13 - command: [ "sh", "-ec" ] - args: - - | - if kubectl get secret {{ include "chronicle.root-key.secret" . }} -n {{.Release.Namespace}} >/dev/null 2>&1; then - echo "Secret found." - kubectl get secret {{ include "chronicle.root-key.secret" . }} -n {{.Release.Namespace}} -o jsonpath='{.data.*}' | base64 -d > /shared-data/root.pem - touch /shared-data/secret-found - else - echo "Secret not found." - fi - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: generate-secret - {{- include "lib.image" (dict "imageRoot" .Values.opa.opaInit.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - if [[ ! -f "/shared-data/root.pem" ]]; then - echo "Generating new root key." - opactl generate --output /shared-data/root.pem - else - echo "Root key already exists." - fi - env: {{ include "lib.safeToYaml" .Values.env | nindent 12 }} - - name: RUST_LOG - value: {{ .Values.logLevel }} - - name: RUST_BACKTRACE - value: {{ .Values.backtraceLevel }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: create-secret - image: alpine/k8s:1.24.13 - command: [ "sh", "-ec" ] - args: - - | - if [ -f "/shared-data/secret-found" ]; then - echo "Secret already exists." - else - echo "Creating k8s secret from key." - kubectl create secret generic {{ include "chronicle.root-key.secret" . }} \ - -n {{ .Release.Namespace }} \ - --from-file=/shared-data/root.pem - fi - volumeMounts: - - name: shared-data - mountPath: /shared-data - {{ if .Values.opa.enabled }} - - name: opa-bootstrap-root - {{- include "lib.image" (dict "imageRoot" .Values.opa.opaInit.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - wait-for-it $HOST:$PORT --timeout=0 - echo "Waiting to ensure Sawtooth validator is ready ..." - sleep 100 - - if [[ -f "/shared-data/secret-found" ]]; then - echo "Skipping root key bootstrap." - else - opactl \ - --sawtooth-address tcp://$HOST:$PORT \ - bootstrap \ - --root-key /shared-data/root.pem - fi - env: {{ include "lib.safeToYaml" .Values.env | nindent 12 }} - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.sawcomp" . }}" - - name: RUST_LOG - value: {{ .Values.logLevel }} - - name: RUST_BACKTRACE - value: {{ .Values.backtraceLevel }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - {{ if .Values.opa.policy.url }} - - name: wait-for-sawtooth-rest-api - {{- include "lib.image" (dict "imageRoot" .Values.opa.opaInit.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - wait-for-it $HOST:$PORT --timeout=0 - echo "Sawtooth rest API is ready." - env: - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.rest" . }}" - - name: RUST_LOG - value: {{ .Values.logLevel }} - - name: RUST_BACKTRACE - value: {{ .Values.backtraceLevel }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: opa-settings - {{- include "lib.image" (dict "imageRoot" .Values.sawset.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - if sawtooth settings list --url http://$HOST:$PORT | grep -q "chronicle.opa.policy_name"; then - echo "Skipping setting Sawtooth OPA settings." - exit 0 - else - echo "Creating Sawtooth settings batch." - sawset proposal create \ - -k /etc/sawtooth/keys/{{ $stlServiceName }}-0 \ - chronicle.opa.policy_name={{ required "opa.policy.id required!" .Values.opa.policy.id }} \ - chronicle.opa.entrypoint={{ required "opa.policy.entrypoint required!" .Values.opa.policy.entrypoint }} \ - -o /shared-data/opa-settings.batch - - echo "Submitting Sawtooth OPA settings batch." - sawtooth batch submit \ - -f /shared-data/opa-settings.batch \ - --url http://$HOST:$PORT \ - --wait 60 - fi - env: - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.rest" . }}" - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: validator-secret - mountPath: /etc/sawtooth/keys - readOnly: true - - name: get-policy - {{- include "lib.image" (dict "imageRoot" .Values.opa.opaInit.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - echo "Attempting to get policy." - opactl \ - --sawtooth-address tcp://$HOST:$PORT \ - get-policy \ - --id {{ .Values.opa.policy.id }} \ - --output /shared-data/policy.bin - - if [ -f "/shared-data/policy.bin" ]; then - echo "Policy already set." - touch /shared-data/policy-already-set - exit 0 - else - echo "Policy not found." - exit 0 - fi - env: {{ include "lib.safeToYaml" .Values.env | nindent 12 }} - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.sawcomp" . }}" - - name: RUST_LOG - value: {{ .Values.logLevel }} - - name: RUST_BACKTRACE - value: {{ .Values.backtraceLevel }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: set-policy - {{- include "lib.image" (dict "imageRoot" .Values.opa.opaInit.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-ec"] - args: - - | - if [[ -f "/shared-data/policy-already-set" ]]; then - echo "Skipping setting policy." - exit 0 - else - echo "Policy not found on chain. Setting policy." - opactl \ - --sawtooth-address tcp://$HOST:$PORT \ - set-policy \ - --id {{ .Values.opa.policy.id }} \ - -p {{ .Values.opa.policy.url }} \ - --root-key /shared-data/root.pem - fi - env: {{ include "lib.safeToYaml" .Values.env | nindent 12 }} - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.sawcomp" . }}" - - name: RUST_LOG - value: {{ .Values.logLevel }} - - name: RUST_BACKTRACE - value: {{ .Values.backtraceLevel }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - {{ end }} - {{ end }} - containers: - - name: chronicle-init - image: busybox:1.36 - command: [ "sh", "-c"] - args: - - | - echo "Chronicle bootstrap and OPA settings initialization complete." - volumes: - - name: shared-data - emptyDir: {} - - name: validator-secret - configMap: - name: validator-secret diff --git a/charts/chronicle/templates/statefulset.yaml b/charts/chronicle/templates/statefulset.yaml index 0f3116a8d..cff0e60a1 100644 --- a/charts/chronicle/templates/statefulset.yaml +++ b/charts/chronicle/templates/statefulset.yaml @@ -1,4 +1,4 @@ -{{$stlServiceName := include "lib.call-nested" (list . "sawtooth" "common.names.fullname")}} +{{$substrateServiceName := include "lib.call-nested" (list . "node" "common.names.fullname")}} --- apiVersion: apps/v1 kind: StatefulSet @@ -19,57 +19,6 @@ spec: spec: serviceAccountName: {{ include "lib.serviceAccountName" . }} affinity: {{ include "lib.safeToYaml" .Values.affinity | nindent 8 }} - initContainers: - - name: chronicle-permissions - image: busybox:1.36 - command: [ "sh", "-c"] - args: - - | - chown -R 999:999 /var/lib/chronicle || true - volumeMounts: - - name: chronicle-config - mountPath: /etc/chronicle/config/ - - name: chronicle-secrets - mountPath: /var/lib/chronicle/secrets/ - readOnly: false - - name: chronicle-keystore - {{- include "lib.image" (dict "imageRoot" .Values.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-c"] - args: - - | - /usr/local/bin/chronicle \ - -c /etc/chronicle/config/config.toml \ - verify-keystore - env: {{ include "lib.safeToYaml" .Values.env | nindent 12 }} - - name: RUST_LOG - value: {{ .Values.logLevel }} - volumeMounts: - - name: chronicle-config - mountPath: /etc/chronicle/config/ - - name: chronicle-secrets - mountPath: /var/lib/chronicle/secrets/ - readOnly: false - {{- if and .Values.opa.enabled .Values.opa.policy.url }} - - name: wait-for-opa-settings - {{- include "lib.image" (dict "imageRoot" .Values.sawset.image "global" .Values.global ) | nindent 10 }} - command: [ "bash", "-exc"] - args: - - | - keepTrying=true - while [ $keepTrying = "true" ]; do - if sawtooth settings list --url http://$HOST:$PORT | grep -q "chronicle.opa.policy_name"; then - break - else - echo "Waiting for OPA policy id." - sleep 10 - fi - done - env: - - name: HOST - value: {{ $stlServiceName }}.{{ .Release.Namespace }}.svc.cluster.local - - name: PORT - value: "{{ include "chronicle.sawtooth.rest" . }}" - {{- end }} containers: {{- if .Values.postgres.enabled }} - name: postgres @@ -113,7 +62,7 @@ spec: chronicle \ -c /etc/chronicle/config/config.toml \ --console-logging json \ - --sawtooth tcp://{{ include "chronicle.sawtooth.service" . }}:{{ include "chronicle.sawtooth.sawcomp" . }} \ + --substrate grpc://{{ include "chronicle.substrate.service" . }}:{{ include "chronicle.substrate.rpc" . }} \ --remote-database \ --database-name {{ .Values.postgres.database }} \ --database-username {{ .Values.postgres.user }} \ diff --git a/charts/chronicle/templates/tests/api-test.yaml b/charts/chronicle/templates/tests/api-test.yaml deleted file mode 100644 index 354a69d7f..000000000 --- a/charts/chronicle/templates/tests/api-test.yaml +++ /dev/null @@ -1,130 +0,0 @@ -{{- if .Values.test.api.enabled }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ include "common.names.fullname" . }}-api-test - labels: {{ include "chronicle.labels" . | nindent 4 }} - component: api-test - annotations: - "helm.sh/hook": test - "helm.sh/hook-delete-policy": hook-succeeded -spec: - backoffLimit: 0 - template: - spec: - restartPolicy: Never - serviceAccountName: {{ include "lib.serviceAccountName" . }} - automountServiceAccountToken: true - {{- if .Values.auth.required }} - {{ if not .Values.test.auth.token }} - {{ if not .Values.devIdProvider.enabled }} - {{ required "If 'auth.required' when using the api-test 'test.auth.token' must be provided or 'devIdProvider.enabled' must be set to 'true'!" .Values.devIdProvider.enabled }} - {{ end }} - initContainers: - - name: wait-for-id-provider - {{- include "lib.image" (dict "imageRoot" .Values.test.api.image "global" .Values.global ) | nindent 10 }} - command: [ "sh", "-c" ] - args: - - | - URL="{{ include "chronicle.id-provider.service.jwks.url" . }}" - - wait_for_url() { - local url=$1 - scheme=$(echo "$url" | cut -f 1 -d :) - hostAndPort=$(echo "$url" | cut -f 3 -d /) - HOST=$(echo "$hostAndPort" | cut -f 1 -d :) - port=$(echo "$hostAndPort" | awk -F: '{print $2}') - - case $scheme in - "http") - defaultPort=80 - ;; - "https") - defaultPort=443 - ;; - *) - defaultPort=80 - ;; - esac - - PORT=${port:-$defaultPort} - wait-for-it "$HOST:$PORT" --timeout=120 - } - - echo "Waiting for id-provider to be ready ..." - wait_for_url "$URL" - - if [ $? -eq 0 ]; then - echo "Id-provider is ready. Exiting." - exit 0 - else - echo "Timeout occurred. Please check if the correct URL has been provided." - exit 1 - fi - - name: token-loader - image: alpine/k8s:1.24.13 - command: [ "sh", "-ec" ] - args: - - | - echo "Waiting to ensure id-provider is ready ..." - sleep 20 - echo "Getting token from id-provider ..." - kubectl exec {{ include "chronicle.id-provider.service" . }}-0 -c id-provider -- oauth-token > /shared-data/jwks-token - echo "Token loaded. Exiting." - volumeMounts: - - name: shared-data - mountPath: /shared-data - {{ end }} - {{- end }} - containers: - - name: test - {{- include "lib.image" (dict "imageRoot" .Values.test.api.image "global" .Values.global ) | nindent 10 }} - command: [ "sh", "-ec" ] - args: - - | - {{ if not .Values.test.auth.token }} - {{ if or .Values.auth.jwks.url .Values.auth.userinfo.url }} - echo "Auth endpoints provided but no token provided." - echo "Please provide 'test.auth.token' in the values.yaml file." - exit 1 - {{ end }} - {{ end }} - - API={{ include "chronicle.api.service" . }} - export PORT={{ .Values.port }} - echo "Waiting for API to be ready ..." - wait-for-it $API:$PORT --timeout=0 - echo "Getting IP address for API ..." - getent hosts $API | cut -f 1 -d \ | head -n 1 > /shared-data/api-ip || exit 1 - - {{- if .Values.test.auth.token }} - echo "{{ .Values.test.auth.token }}" > /shared-data/jwks-token - {{- end }} - - if [ -f "/shared-data/jwks-token" ]; then - echo "Found token." - sleep 5 - export TOKEN=$(cat "/shared-data/jwks-token") - fi - - export HOST=$(cat /shared-data/api-ip) - echo "Testing API with subscribe-submit-test..." - subscribe-submit-test - exit_code=$? - if [ $exit_code -eq 0 ]; then - echo "Test complete." - exit $exit_code - else - echo "Test failed." - exit $exit_code - fi - env: - - name: REQUIRE_AUTH - value: {{ .Values.auth.required | quote }} - volumeMounts: - - name: shared-data - mountPath: /shared-data - volumes: {{- include "lib.volumes" .Values.opa.tp.extraVolumes | nindent 8 }} - - name: shared-data - emptyDir: {} -{{- end }} diff --git a/charts/chronicle/templates/tests/auth-endpoints-test.yaml b/charts/chronicle/templates/tests/auth-endpoints-test.yaml deleted file mode 100644 index 79f80f9e9..000000000 --- a/charts/chronicle/templates/tests/auth-endpoints-test.yaml +++ /dev/null @@ -1,160 +0,0 @@ -{{- if .Values.test.auth.enabled }} -{{ if not (or (.Values.devIdProvider.enabled) (or (.Values.auth.jwks.url) (.Values.auth.userinfo.url)))}} -{{ required "If 'test.auth.enabled' you need to provide 'auth.jwks.url', 'auth.userinfo.url', or enable the `devIdProvider`!" .Values.devIdProvider.enabled }} -{{ end }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ include "common.names.fullname" . }}-auth-endpoints-test - labels: {{ include "chronicle.labels" . | nindent 4 }} - component: auth-endpoints-test - annotations: - "helm.sh/hook": test - "helm.sh/hook-delete-policy": hook-succeeded -spec: - backoffLimit: 0 - template: - spec: - restartPolicy: Never - serviceAccountName: {{ include "lib.serviceAccountName" . }} - {{- if .Values.devIdProvider.enabled }} - automountServiceAccountToken: true - initContainers: - - name: wait - {{- include "lib.image" (dict "imageRoot" .Values.test.api.image "global" .Values.global ) | nindent 10 }} - command: [ "sh", "-c" ] - args: - - | - URL="{{ include "chronicle.id-provider.service.jwks.url" . }}" - - wait_for_url() { - local url=$1 - scheme=$(echo "$url" | cut -f 1 -d :) - hostAndPort=$(echo "$url" | cut -f 3 -d /) - HOST=$(echo "$hostAndPort" | cut -f 1 -d :) - port=$(echo "$hostAndPort" | awk -F: '{print $2}') - - case $scheme in - "http") - defaultPort=80 - ;; - "https") - defaultPort=443 - ;; - *) - defaultPort=80 - ;; - esac - - PORT=${port:-$defaultPort} - wait-for-it "$HOST:$PORT" --timeout=120 - } - - echo "Waiting for id-provider to be ready ..." - wait_for_url "$URL" - - if [ $? -eq 0 ]; then - echo "Id-provider is ready. Exiting." - exit 0 - else - echo "Timeout occurred. Please check if the correct URL has been provided." - exit 1 - fi - - name: tok - image: alpine/k8s:1.24.13 - command: [ "sh", "-ec" ] - args: - - | - echo "Waiting to ensure id-provider is ready ..." - sleep 20 - echo "Getting token from id-provider ..." - kubectl exec {{ include "chronicle.id-provider.service" . }}-0 -c id-provider -- oauth-token > /shared-data/jwks-token - echo "Token loaded. Exiting." - volumeMounts: - - name: shared-data - mountPath: /shared-data - {{- end }} - containers: - - name: jwks - image: alpine/k8s:1.24.13 - command: [ "sh", "-c"] - args: - - | - {{ if or (.Values.auth.jwks.url) (.Values.devIdProvider.enabled) }} - {{ if .Values.auth.jwks.url }} - echo "Checking provided JWKS endpoint: {{ .Values.auth.jwks.url }}." - endPoint="{{ .Values.auth.jwks.url }}" - {{ else if .Values.auth.userinfo.url }} - echo "JWKS endpoint not set but userinfo url is set - skipping JWKS check." - exit 0 - {{ else }} - echo "Checking JWKS endpoint from id-provider: {{ include "chronicle.id-provider.service.jwks.url" . }}." - endPoint="{{ include "chronicle.id-provider.service.jwks.url" . }}" - {{ end }} - - time curl -s -o /shared-data/jwks.json $endPoint - - cat /shared-data/jwks.json | jq . > /dev/null \ - || { echo "JWKS endpoint did not return a valid JSON object."; echo "DEBUG: $(cat /shared-data/jwks.json)"; exit 1; } - echo "JWKS endpoint returned a valid JSON object:" - cat /shared-data/jwks.json - echo - {{ else }} - echo "Skipping JWKS endpoint check." - {{ end }} - - echo -e "Exiting." - volumeMounts: - - name: shared-data - mountPath: /shared-data - - name: userinfo - image: alpine/k8s:1.24.13 - command: [ "sh", "-c"] - args: - - | - {{ if or (.Values.auth.userinfo.url) (.Values.devIdProvider.enabled) }} - {{ if .Values.auth.userinfo.url }} - {{ if not .Values.test.auth.token }} - {{ required "If providing 'auth.userinfo.url' you need to provide a 'test.auth.token'!" .Values.test.auth.token}} - {{ end }} - echo "Checking user-provided userinfo endpoint: $endPoint" - endPoint="{{ .Values.auth.userinfo.url }}" - {{ else if .Values.auth.jwks.url }} - echo "Userinfo endpoint not set but JWKS url is set - skipping userinfo check." - exit 0 - {{ else }} - echo "Checking id-provider userinfo endpoint: $endPoint" - endPoint="{{ include "chronicle.id-provider.service.userinfo.url" . }}" - {{ end }} - - {{ if .Values.test.auth.token }} - {{ if not .Values.auth.userinfo.url }} - {{ required "If providing 'test.auth.token' you need to provide a 'auth.userinfo.url'!" .Values.auth.userinfo.url }} - {{ end }} - echo "Using 'test.auth.token' to check userinfo endpoint." - time curl -s -H "Authorization: Bearer {{ .Values.test.auth.token }}" -o /shared-data/userinfo.json $endPoint - {{ else }} - echo "Using token from id-provider to check userinfo endpoint." - time curl -s -H "Authorization: Bearer $(cat /shared-data/jwks-token)" -o /shared-data/userinfo.json $endPoint - {{ end }} - - if jq -e 'has("error")' /shared-data/userinfo.json > /dev/null; then - echo "Userinfo endpoint returned an error:" - echo "DEBUG: $(cat /shared-data/userinfo.json)" - exit 1 - else - echo "Userinfo endpoint returned a valid JSON object: $(cat /shared-data/userinfo.json)" - echo - fi - {{ else }} - echo "Skipping userinfo endpoint check." - {{ end }} - - echo -e "Exiting." - volumeMounts: - - name: shared-data - mountPath: /shared-data - volumes: - - name: shared-data - emptyDir: {} -{{- end }} diff --git a/charts/chronicle/values.yaml b/charts/chronicle/values.yaml index 945a12087..470279e1d 100644 --- a/charts/chronicle/values.yaml +++ b/charts/chronicle/values.yaml @@ -36,8 +36,13 @@ devIdProvider: ## @md | `devIdProvider.image.tag` | the image tag | latest | tag: BTP2.1.0-0.7.4 -## @md | `endpoints` | which API endpoints to offer | data, graphql | +opa: + enabled: false + +## @md | `endpoints` | which API endpoints to offer | arrow, json-ld, graphql | endpoints: + arrow: + enabled: true data: enabled: true graphql: @@ -184,8 +189,19 @@ resources: volumes: {} -## @md | `sawtooth` | sawtooth options may be configured | see [Sawtooth](../sawtooth/README.md) | node: + vault: + keys: + - name: aura + type: aura + scheme: secp256k1 + vaultPath: kv/secret/chronicle-node # path at which the secret is located in Vault + vaultKey: aura # key under which the secret value is stored in Vault + extraDerivation: "//${HOSTNAME}//aura" # allows to have unique derived keys for each pod of the statefulset + nodeKey: + name: nodekey + vaultPath: kv/secret/chronicle-node + vaultKey: nodekey image: ## @md | `test.api.image.pullPolicy` | the image pull policy | IfNotPresent | pullPolicy: IfNotPresent @@ -196,3 +212,5 @@ node: node: chain: "chronicle" command: "node-chronicle" + + diff --git a/terraform/chronicle-substrate/.gitignore b/terraform/chronicle-substrate/.gitignore new file mode 100644 index 000000000..00b1cb0d8 --- /dev/null +++ b/terraform/chronicle-substrate/.gitignore @@ -0,0 +1,25 @@ +# Local .terraform directories +**/.terraform/* +.terraform.lock.hcl +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which might contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version control +# as they are data points which are potentially sensitive and subject to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# should not be checked into version control +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/terraform/chronicle-substrate/bootnode.tf b/terraform/chronicle-substrate/bootnode.tf new file mode 100644 index 000000000..3b1cf162d --- /dev/null +++ b/terraform/chronicle-substrate/bootnode.tf @@ -0,0 +1,25 @@ +#------------------------------------------------------------------------------ +# Bootnode deployment +#------------------------------------------------------------------------------ +resource "helm_release" "bootnode" { + name = var.helm_release_name + repository = "https://paritytech.github.io/helm-charts/" + chart = "node" + namespace = var.kubernetes_namespace + + values = [ + templatefile("templates/bootnode.tmpl", { + helm_release_name = var.helm_release_name + + kubernetes_namespace = var.kubernetes_namespace + kubernetes_image_pull_secrets = var.kubernetes_image_pull_secrets + + chronicle_node_repository = var.chronicle-node-repository + bootnode_key = var.bootnode-key + + node = { + command = "node-chronicle" + } + }) + ] +} diff --git a/terraform/chronicle-substrate/provider.tf b/terraform/chronicle-substrate/provider.tf new file mode 100644 index 000000000..d9112c608 --- /dev/null +++ b/terraform/chronicle-substrate/provider.tf @@ -0,0 +1,10 @@ +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } +} + diff --git a/terraform/chronicle-substrate/templates/bootnode.tmpl b/terraform/chronicle-substrate/templates/bootnode.tmpl new file mode 100644 index 000000000..948a4d096 --- /dev/null +++ b/terraform/chronicle-substrate/templates/bootnode.tmpl @@ -0,0 +1,110 @@ +fullnameOverride: bootnode +image: + repository: ${chronicle_node_repository} + tag: local + pullPolicy: IfNotPresent +node: + chain: local + customChainspec: true # see extraInitContainers, chainspec-generator + role: full + replicas: 1 + command: node-chronicle + chainData: + pruning: archive + storageClass: "" + chainKeystore: + mountInMemory: + enabled: true + perNodeServices: + relayP2pService: + enabled: true + vault: + enabled: false + keys: + - name: aura + type: aura + scheme: sr25519 + vaultPath: kv/chronicle_substrate/aura # path at which the secret is located in Vault + vaultKey: secretSeed # key under which the secret value is stored in Vault + extraDerivation: "//$${HOSTNAME}//aura" # allows to have unique derived keys for each pod of the statefulset + nodeKey: + name: nodekey + vaultPath: kv/chronicle-substrate/bootnode_key + vaultKey: key + + customNodeKey: ${bootnode_key} + flags: + - "--allow-private-ipv4" + - "--discover-local" + +ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: TODO + external-dns.alpha.kubernetes.io/target: TODO + cert-manager.io/cluster-issuer: TODO + rules: + - host: chronicle-bootnode.paravela.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bootnode + port: + number: 9944 + tls: + - secretName: chronicle-bootnode.paravela.io + hosts: + - chronicle-bootnode.paravela.io + +# Generate chainspec, and expose it as url +extraInitContainers: + - name: chainspec-generator + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + annotations: + vault.hashicorp.com/agent-inject: "true" + vault.hashicorp.com/role: 'bootnode' + vault.hashicorp.com/agent-inject-secret-bootnode_key: 'kv/chronicle_substrate/bootnode_key' + vault.hashicorp.com/agent-inject-secret-bootnode_peer: 'kv/chronicle_substrate/bootnode_peer' + vault.hashicorp.com/ca-cert: "/vault/tls/ca.crt" + securityContext: + runAsUser: 0 + command: [ "/bin/bash" ] + args: + - -c + - | + apt update && apt install -y jq + {{ .Values.node.command }} build-spec --chain {{ .Values.node.chain }} > base.json + if [ ! -s base.json ]; then + echo "base.json is empty or missing." + exit 1 + fi + echo '{"bootNodes":["/dns/bootnode-0/tcp/30333/p2p/12D3KooWRpzRTivvJ5ySvgbFnPeEE6rDhitQKL1fFJvvBGhnenSk"]}' > override1.json + jq -s '.[0] * .[1]' base.json override1.json | sed 's/1e+18/1000000000000000000/' > plain.json + if [ ! -s plain.json ]; then + echo "plain.json is empty or malformed after jq processing." + exit 1 + fi + cut -c -256 plain.json + {{ .Values.node.command }} build-spec --chain plain.json --raw > chainspec.json + if [ ! -s chainspec.json ]; then + echo "chainspec.json failed to generate." + exit 1 + fi + cp chainspec.json {{ .Values.node.customChainspecPath }} + volumeMounts: + - mountPath: /chain-data + name: chain-data +extraContainers: + - name: chainspec + image: nginxinc/nginx-unprivileged:stable + ports: + - containerPort: 8080 + name: web + volumeMounts: + - name: chain-data + subPath: chainspec.json + mountPath: /usr/share/nginx/html/chainspec.json + readOnly: true diff --git a/terraform/chronicle-substrate/variables.tf b/terraform/chronicle-substrate/variables.tf new file mode 100644 index 000000000..ec7c13fbc --- /dev/null +++ b/terraform/chronicle-substrate/variables.tf @@ -0,0 +1,60 @@ +variable "chronicle-node-repository" { + type = string + description = "The repository to pull the chronicle node image from" + default = "node-chronicle-arm64" +} + +variable "kubernetes_namespace" { + type = string + description = "The Kubernetes namespace to deploy Vault into" + default = "vault" +} + +variable "kubernetes_sa_name" { + type = string + description = "The Kubernetes Service Account that Vault will use" + default = "vault-sa" +} + +variable "kubernetes_image_pull_secrets" { + type = list(string) + description = "A list of Kubernetes secrets that hold any required image registry credentials" + default = null +} + +variable "kubernetes_extra_secret_environment_variables" { + type = list(map(string)) + description = "A list of maps referencing Kubernetes secrets and their environment variable to mount to the Vault pods" + default = null +} + + +variable "bootnode-key" { + type = string + description = "The bootnode key" + default = "80c30ac6ba927c6e5c0c9681aa9674f1d181d180853bcd3485cee9d18e931238" +} + +variable "helm_release_name" { + type = string + description = "The name of the Helm release" + default = "chronicle-substrate" +} + +variable "helm_chart_name" { + type = string + description = "The chart name in the Helm repository" + default = "node" +} + +variable "helm_repository" { + type = string + description = "The location of the Helm repository" + default = "hhttps://paritytech.github.io/helm-charts/" +} + +variable "vault_replicas" { + type = number + description = "The number of Vault replicas to deploy" + default = 3 +} diff --git a/terraform/chronicle/.gitignore b/terraform/chronicle/.gitignore new file mode 100644 index 000000000..00b1cb0d8 --- /dev/null +++ b/terraform/chronicle/.gitignore @@ -0,0 +1,25 @@ +# Local .terraform directories +**/.terraform/* +.terraform.lock.hcl +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which might contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version control +# as they are data points which are potentially sensitive and subject to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# should not be checked into version control +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/terraform/signoz/.gitignore b/terraform/signoz/.gitignore new file mode 100644 index 000000000..d9a804e87 --- /dev/null +++ b/terraform/signoz/.gitignore @@ -0,0 +1,26 @@ +# Local .terraform directories +**/.terraform/* +.terraform.lock.hcl + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which might contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version control +# as they are data points which are potentially sensitive and subject to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# should not be checked into version control +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/terraform/signoz/output.tf b/terraform/signoz/output.tf new file mode 100644 index 000000000..4bf1b4a3e --- /dev/null +++ b/terraform/signoz/output.tf @@ -0,0 +1,32 @@ +output "otel_collector_service_name" { + value = "${helm_release.signoz.name}-otel-collector" + description = "The service name of the OpenTelemetry collector deployed with SigNoz." +} + +output "otel_collector_service_url" { + value = "http://${helm_release.signoz.name}-otel-collector.${var.signoz_namespace}.svc.cluster.local" + description = "The URL to access the OpenTelemetry collector service." +} + +output "otel_collector_service_port" { + value = "4317" + description = "The default gRPC port for the OpenTelemetry collector service." +} + +output "signoz_frontend_service_name" { + value = "${helm_release.signoz.name}-frontend" + description = "The service name of the SigNoz frontend." +} + +output "signoz_frontend_service_url" { + value = "http://${helm_release.signoz.name}-frontend.${var.signoz_namespace}.svc.cluster.local" + description = "The URL to access the SigNoz frontend service." +} + +output "signoz_frontend_service_port" { + value = "3000" + description = "The default port for the SigNoz frontend service." +} + + + diff --git a/terraform/signoz/provider.tf b/terraform/signoz/provider.tf new file mode 100644 index 000000000..912fdd629 --- /dev/null +++ b/terraform/signoz/provider.tf @@ -0,0 +1,9 @@ +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } +} diff --git a/terraform/signoz/signoz.tf b/terraform/signoz/signoz.tf new file mode 100644 index 000000000..97cb64dd4 --- /dev/null +++ b/terraform/signoz/signoz.tf @@ -0,0 +1,22 @@ +resource "helm_release" "signoz" { + name = "signoz" + repository = var.signoz_helm_repository + chart = var.signoz_helm_chart_name + namespace = var.signoz_namespace + create_namespace = true + + set { + name = "frontend.replicaCount" + value = var.signoz_fe_replicas + } + + set { + name = "queryService.replicaCount" + value = var.signoz_query_replicas + } + + set { + name = "storage.size" + value = var.signoz_storage_size + } +} diff --git a/terraform/signoz/variables.tf b/terraform/signoz/variables.tf new file mode 100644 index 000000000..e7a2f9ebb --- /dev/null +++ b/terraform/signoz/variables.tf @@ -0,0 +1,37 @@ +variable "signoz_namespace" { + type = string + description = "The Kubernetes namespace to deploy SigNoz into" + default = "observabilty" +} + +variable "signoz_helm_chart_name" { + type = string + description = "The chart name in the Helm repository for SigNoz" + default = "signoz" +} + +variable "signoz_helm_repository" { + type = string + description = "The location of the Helm repository for SigNoz" + default = "https://charts.signoz.io/" +} + +variable "signoz_fe_replicas" { + type = number + description = "The number of SigNoz replicas to deploy" + default = 1 +} + + +variable "signoz_query_replicas" { + type = number + description = "The number of SigNoz replicas to deploy" + default = 1 +} + +variable "signoz_storage_size" { + type = string + description = "The size, in Gi, of the storage volume for SigNoz" + default = "20" +} + diff --git a/terraform/vault-configuration/.gitignore b/terraform/vault-configuration/.gitignore new file mode 100644 index 000000000..f8bc12791 --- /dev/null +++ b/terraform/vault-configuration/.gitignore @@ -0,0 +1,25 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which might contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version control +# as they are data points which are potentially sensitive and subject to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# should not be checked into version control +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/terraform/vault-configuration/BOOTNODE_KEY b/terraform/vault-configuration/BOOTNODE_KEY new file mode 100644 index 000000000..41ffceccc --- /dev/null +++ b/terraform/vault-configuration/BOOTNODE_KEY @@ -0,0 +1 @@ +4c0f9119a13ddc0d0382b7798fbbd08c639ca26f9fe344170ab93bad26b3c577 \ No newline at end of file diff --git a/terraform/vault-configuration/BOOTNODE_PEER_ID b/terraform/vault-configuration/BOOTNODE_PEER_ID new file mode 100644 index 000000000..41ffceccc --- /dev/null +++ b/terraform/vault-configuration/BOOTNODE_PEER_ID @@ -0,0 +1 @@ +4c0f9119a13ddc0d0382b7798fbbd08c639ca26f9fe344170ab93bad26b3c577 \ No newline at end of file diff --git a/terraform/vault-configuration/policies/admin.hcl b/terraform/vault-configuration/policies/admin.hcl new file mode 100644 index 000000000..02c929008 --- /dev/null +++ b/terraform/vault-configuration/policies/admin.hcl @@ -0,0 +1,58 @@ +# Manage auth methods broadly across Vault +path "auth/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# Create, update, and delete auth methods +path "sys/auth/*" +{ + capabilities = ["create", "update", "delete", "sudo"] +} + +# List auth methods +path "sys/auth" +{ + capabilities = ["read"] +} + +# List existing policies +path "sys/policies/acl" +{ + capabilities = ["list"] +} + +# Create and manage ACL policies +path "sys/policies/acl/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# List, create, update, and delete key/value secrets +path "secret/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# Manage secrets engines +path "sys/mounts/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# List existing secrets engines. +path "sys/mounts" +{ + capabilities = ["read"] +} + +# Read health checks +path "sys/health" +{ + capabilities = ["read", "sudo"] +} + +path "kv/*" +{ + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/terraform/vault-configuration/policies/bootnode.hcl b/terraform/vault-configuration/policies/bootnode.hcl new file mode 100644 index 000000000..13c870352 --- /dev/null +++ b/terraform/vault-configuration/policies/bootnode.hcl @@ -0,0 +1,4 @@ +path "kv/chronicle-substrate/*" +{ + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/terraform/vault-configuration/policies/chronicle.hcl b/terraform/vault-configuration/policies/chronicle.hcl new file mode 100644 index 000000000..0966630e5 --- /dev/null +++ b/terraform/vault-configuration/policies/chronicle.hcl @@ -0,0 +1,4 @@ +path "kv/chronicle/*" +{ + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/terraform/vault-configuration/provider.tf b/terraform/vault-configuration/provider.tf new file mode 100644 index 000000000..da874ddf3 --- /dev/null +++ b/terraform/vault-configuration/provider.tf @@ -0,0 +1,4 @@ +provider vault { + address = "https://localhost:8200" + ca_cert_file = var.vault_service_ca +} diff --git a/terraform/vault-configuration/variables.tf b/terraform/vault-configuration/variables.tf new file mode 100644 index 000000000..2ab862992 --- /dev/null +++ b/terraform/vault-configuration/variables.tf @@ -0,0 +1,48 @@ +variable "node_service_account" { + description = "The service account for the Chronicle Substrate node." + type = string + sensitive = false + default = "bootnode" +} + +variable "vault_token" { + description = "A vault access token with root permission" + type = string + sensitive = true + default = "s.VL1OYyHeeQ1Qxyg9FqSyKjBe" +} + +variable "bootnode_key" { + description = "The bootnode key for the Chronicle Substrate node." + type = string + sensitive = true +} + +variable "aura_key" { + description = "The bootnode key for the Chronicle Substrate node." + type = string + default = <