Skip to content
Open
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
389 changes: 389 additions & 0 deletions helm/README.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions helm/chart/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: v2
name: openrelik
version: 1.0.0
description: A Helm chart for Openrelik Kubernetes deployments.
keywords:
- openrelik
- dfir
- analysis
- forensics
home: "https://openrelik.org/"
maintainers:
- name: Open Source DFIR
url: https://github.com/openrelik/openrelik-deploy
sources:
- https://github.com/openrelik
- https://github.com/google/osdfir-infrastructure
icon: https://openrelik.org/favicon.ico
appVersion: "latest"
annotations:
category: Security
licenses: Apache-2.0
136 changes: 136 additions & 0 deletions helm/chart/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/bin/bash

# Copyright 2025 Google LLC
#
# 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
#
# https://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 -x

cat << "EOF"

____ _____ _ _ _
/ __ \ | __ \ | (_) |
| | | |_ __ ___ _ __ | |__) |___| |_| | __
| | | | '_ \ / _ \ '_ \| _ // _ \ | | |/ /
| |__| | |_) | __/ | | | | \ \ __/ | | <
\____/| .__/ \___|_| |_|_| \_\___|_|_|_|\_\
| |
|_|

EOF

OPENRELIK_API_URL="http://localhost:8710"
OPENRELIK_URL="http://localhost:8711"

if [[ "$1" == "cloud" ]]; then
OPENRELIK_API_HOSTNAME="openrelik.${OPENRELIK_HOSTNAME}"
OPENRELIK_API_URL="https:\/\/${OPENRELIK_API_HOSTNAME}"
OPENRELIK_URL="https:\/\/${OPENRELIK_HOSTNAME}"
echo "CERTIFICATE_NAME: ${CERTIFICATE_NAME}"
echo "OPENRELIK_HOSTNAME: ${OPENRELIK_HOSTNAME}"
echo "PROJECT: ${PROJECT}"
echo "REDIS_ADDRESS: ${REDIS_ADDRESS}"
echo "ZONE: ${ZONE}"
elif [[ "$1" == "local" ]]; then
ENABLE_GCP=false
OPENRELIK_DB="openrelik"
OPENRELIK_DB_ADDRESS="svc-postgres"
OPENRELIK_DB_USER="openrelik"
PROJECT="none"
ZONE="none"
else
echo "usage: config.sh [cloud|local]"
exit
fi

# Generates a random string of a specified length using characters from a defined set.
function generate_random_string() {
local charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
local length=32
openssl rand -base64 32 | tr -dc "$charset" | fold -w "$length" | head -n 1
}

# This function replaces all occurrences of a search pattern within a specified file
# with a given replacement value. It ensures compatibility with both GNU and BSD
# versions of the 'sed' command.
replace_in_file() {
local search_pattern="$1"
local replacement_value="$2"
local filename="$3"
# Portable sed usage: handle both GNU and BSD sed
if sed --version 2>&1 | grep -q GNU; then
sed -i "s#${search_pattern}#${replacement_value}#g" "${filename}"
else
sed -i "" "s#${search_pattern}#${replacement_value}#g" "${filename}"
fi
}

# Setup variables
echo -e "\033[1;34m[1/8] Setting up variables...\033[0m\c"
STORAGE_PATH="\/usr\/share\/openrelik\/data\/artifacts"
POSTGRES_PASSWORD="$(generate_random_string)"
RANDOM_JWT_STRING="$(generate_random_string)"
RANDOM_SESSION_STRING="$(generate_random_string)"
echo -e "\r\033[1;32m[1/8] Setting up variables... Done\033[0m"

echo "ENABLE_GCP: ${ENABLE_GCP}"
echo "OPENRELIK_API_HOSTNAME: ${OPENRELIK_API_HOSTNAME}"
echo "OPENRELIK_API_URL: ${OPENRELIK_API_URL}"
echo "OPENRELIK_DB: ${OPENRELIK_DB}"
echo "OPENRELIK_DB_ADDRESS: ${OPENRELIK_DB_ADDRESS}"
echo "OPENRELIK_DB_USER: ${OPENRELIK_DB_USER}"
echo "OPENRELIK_URL: ${OPENRELIK_URL}"
echo "RANDOM_JWT_STRING: ${RANDOM_JWT_STRING}"
echo "RANDOM_SESSION_STRING: ${RANDOM_SESSION_STRING}"
echo "STORAGE_PATH: ${STORAGE_PATH}"

# Fetch installation files
echo -e "\033[1;34m[2/8] Copying settings file...\033[0m\c"
cp settings_template.toml settings.toml
echo -e "\r\033[1;32m[2/8] Copying settings file... Done\033[0m"

# Replace placeholder values in settings.toml
echo -e "\033[1;34m[3/8] Configuring settings...\033[0m\c"
replace_in_file "<REPLACE_WITH_ALLOWED_ORIGIN>" "${OPENRELIK_URL}" "settings.toml"
replace_in_file "<REPLACE_WITH_API_SERVER_URL>" "${OPENRELIK_API_URL}" "settings.toml"
replace_in_file "<REPLACE_WITH_ENABLE_GCP>" "${ENABLE_GCP}" "settings.toml"
replace_in_file "<REPLACE_WITH_POSTGRES_DATABASE_NAME>" "${OPENRELIK_DB}" "settings.toml"
replace_in_file "<REPLACE_WITH_POSTGRES_USER>" "${OPENRELIK_DB_USER}" "settings.toml"
replace_in_file "<REPLACE_WITH_POSTGRES_SERVER>" "${OPENRELIK_DB_ADDRESS}" "settings.toml"
replace_in_file "<REPLACE_WITH_PROJECT_ID>" "${PROJECT}" "settings.toml"
replace_in_file "<REPLACE_WITH_RANDOM_SESSION_STRING>" "${RANDOM_SESSION_STRING}" "settings.toml"
replace_in_file "<REPLACE_WITH_RANDOM_JWT_STRING>" "${RANDOM_JWT_STRING}" "settings.toml"
replace_in_file "<REPLACE_WITH_STORAGE_PATH>" "${STORAGE_PATH}" "settings.toml"
replace_in_file "<REPLACE_WITH_UI_SERVER_URL>" "${OPENRELIK_URL}" "settings.toml"
replace_in_file "<REPLACE_WITH_ZONE>" "${ZONE}" "settings.toml"

if [[ "$1" == "cloud" ]]; then
# Replace placeholders in values-gcp.yaml
replace_in_file "<REPLACE_WITH_API_SERVER_HOSTNAME>" "${OPENRELIK_API_HOSTNAME}" "values-gcp.yaml"
replace_in_file "<REPLACE_WITH_API_SERVER_URL>" "${OPENRELIK_API_URL}" "values-gcp.yaml"
replace_in_file "<REPLACE_WITH_CERTIFICATE_NAME>" "${CERTIFICATE_NAME}" "values-gcp.yaml"
replace_in_file "<REPLACE_WITH_PROJECT_ID>" "${PROJECT}" "values-gcp.yaml"
replace_in_file "<REPLACE_WITH_REDIS_URL>" "redis:\/\/${REDIS_ADDRESS}:6379" "values-gcp.yaml"
replace_in_file "<REPLACE_WITH_UI_SERVER_HOSTNAME>" "${OPENRELIK_HOSTNAME}" "values-gcp.yaml"
fi

if [[ "$1" == "local" ]]; then
# Replace placeholders in values.yaml
replace_in_file "<REPLACE_WITH_POSTGRES_PASSWORD>" "${POSTGRES_PASSWORD}" "settings.toml"
replace_in_file "<REPLACE_WITH_API_SERVER_URL>" "${OPENRELIK_API_URL}" "values.yaml"
replace_in_file "<REPLACE_WITH_POSTGRES_PASSWORD>" "${POSTGRES_PASSWORD}" "values.yaml"
replace_in_file "<REPLACE_WITH_POSTGRES_USER>" "${OPENRELIK_DB_USER}" "values.yaml"
fi
echo -e "\r\033[1;32m[3/8] Configuration settings... Done\033[0m"

mkdir -p templates/configmap
kubectl create configmap cm-settings --dry-run=client -o=yaml --from-file=settings.toml -n openrelik > templates/configmap/cm-settings.yaml
12 changes: 12 additions & 0 deletions helm/chart/filestore/pvc-filestore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-filestore
namespace: openrelik
spec:
accessModes:
- ReadWriteMany
storageClassName: sc-ms-512
resources:
requests:
storage: 512Gi
13 changes: 13 additions & 0 deletions helm/chart/filestore/sc-ms-512.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: sc-ms-512
namespace: openrelik
provisioner: filestore.csi.storage.gke.io
parameters:
tier: enterprise
multishare: "true"
max-volume-size: "512Gi"
network: gke-vpc
volumeBindingMode: Immediate
allowVolumeExpansion: true
68 changes: 68 additions & 0 deletions helm/chart/settings_template.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
[server]

# This should be set to the URL of your backend server.
api_server_url = "<REPLACE_WITH_API_SERVER_URL>"

# This should be set to the URL of your frontend server.
ui_server_url = "<REPLACE_WITH_UI_SERVER_URL>"

# This should be set to the URL of your frontend server.
allowed_origins = ["<REPLACE_WITH_ALLOWED_ORIGIN>"]

# Path to files
storage_path = "<REPLACE_WITH_STORAGE_PATH>"

[datastores.sqlalchemy]
# Postgresql: postgresql://user:password@postgresserver/db
database_url = "postgresql://<REPLACE_WITH_POSTGRES_USER>:<REPLACE_WITH_POSTGRES_PASSWORD>@<REPLACE_WITH_POSTGRES_SERVER>/<REPLACE_WITH_POSTGRES_DATABASE_NAME>"

[auth]
# Secret key for the Session middleware and JWT signing.
# IMPORTANT: Create a random string, e.g: openssl rand -base64 32
secret_session_key = "<REPLACE_WITH_RANDOM_SESSION_STRING>"
secret_jwt_key = "<REPLACE_WITH_RANDOM_JWT_STRING>"

# Algorithm to use for JWT.
jwt_algorithm = "HS256"

# UI token expiration in minutes.
jwt_cookie_refresh_expire_minutes = 1440 # 24 hours
jwt_cookie_access_expire_minutes = 720 # 12 hours

# API key token expiration in minutes, if not set by the user upon creation.
jwt_header_default_refresh_expire_minutes = 10080 # 7 days
jwt_header_default_access_expire_minutes = 5 # 5 minutes

[auth.google]
# Google OAuth authentication. You need to create credentials in a Google Cloud project:
# https://developers.google.com/workspace/guides/create-credentials#oauth-client-id
client_id = ""
client_secret = ""

# Restrict logins from a Google Workspace domain.
# Empty value = any domain, including gmail.com
workspace_domain = ""

# Allow only these users (email address) to access the server.
allowlist = ["<REPLACE_WITH_USERNAME>@gmail.com"]

# Allow anyone (who is authenitcated) to access the server.
# Note: If a workspace_domain is set then the public_access is limited to that domain.
# WARNING: This allows anyone to login to your server!
public_access = false

[ui]
# data_types that will be rendered using unescaped HTML in a sandboxed iframe in the
# frontend UI.
allowed_data_types_preview = [
"openrelik:hayabusa:html_report"
]

# Enable cloud features such as adding cloud disks.
# This requires your OpenRelik installation to run on cloud VMs.
[cloud.gcp]
name = "gcp"
display_name = "Google Cloud Platform"
project_name = "<REPLACE_WITH_PROJECT_ID>"
zone = "<REPLACE_WITH_ZONE>"
enabled = "<REPLACE_WITH_ENABLE_GCP>"
62 changes: 62 additions & 0 deletions helm/chart/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "openrelik.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "openrelik.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "openrelik.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "openrelik.labels" -}}
helm.sh/chart: {{ include "openrelik.chart" . }}
{{ include "openrelik.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "openrelik.selectorLabels" -}}
app.kubernetes.io/name: {{ include "openrelik.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "openrelik.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "openrelik.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Loading