├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── PULL_REQUEST_TEMPLATE.md ├── ct.yaml └── workflows │ ├── lint-test.yaml │ ├── markdown-linter.yml │ └── release.yml ├── .gitignore ├── .markdownlint.json ├── LICENSE ├── README.md ├── charts ├── osdfir-infrastructure │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── LICENSE │ ├── README.md │ ├── charts │ │ ├── grr │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── README.md │ │ │ ├── containers │ │ │ │ └── grr-client │ │ │ │ │ ├── Dockerfile │ │ │ │ │ ├── Dockerfile.kaniko │ │ │ │ │ ├── config │ │ │ │ │ ├── communicator.txt │ │ │ │ │ ├── config.textproto.tmpl │ │ │ │ │ ├── grr.yaml │ │ │ │ │ └── textservices │ │ │ │ │ │ └── grr.service │ │ │ │ │ └── grr-client-config.yaml │ │ │ ├── createSigningKeys.sh │ │ │ ├── templates │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── admin-deployment.yaml │ │ │ │ ├── admin-service.yaml │ │ │ │ ├── client │ │ │ │ │ ├── client-daemonset.yaml │ │ │ │ │ ├── client-namespace.yaml │ │ │ │ │ └── client-serviceaccount.yaml │ │ │ │ ├── database │ │ │ │ │ └── mysql.yaml │ │ │ │ ├── executable-keys-secret.yaml │ │ │ │ ├── fleetspeak │ │ │ │ │ ├── fleetspeak-admin-components-secret.yaml │ │ │ │ │ ├── fleetspeak-admin-deployment.yaml │ │ │ │ │ ├── fleetspeak-admin-service.yaml │ │ │ │ │ ├── fleetspeak-frontend-components-secret.yaml │ │ │ │ │ ├── fleetspeak-frontend-deployment.yaml │ │ │ │ │ ├── fleetspeak-frontend-service.yaml │ │ │ │ │ └── fleetspeak-services-configmap.yaml │ │ │ │ ├── frontend-deployment.yaml │ │ │ │ ├── frontend-service.yaml │ │ │ │ ├── job-build-grr-client.yaml │ │ │ │ ├── namespace.yaml │ │ │ │ ├── server-local-secret.yaml │ │ │ │ ├── serviceaccount.yaml │ │ │ │ └── worker-deployment.yaml │ │ │ └── values.yaml │ │ ├── hashr │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── data-manager.yaml │ │ │ │ ├── hashr-deb-cronjob.yaml │ │ │ │ ├── hashr-gcp-cronjob.yaml │ │ │ │ ├── hashr-iso9660-cronjob.yaml │ │ │ │ ├── hashr-rpm-cronjob.yaml │ │ │ │ ├── hashr-targz-cronjob.yaml │ │ │ │ ├── hashr-zip-cronjob.yaml │ │ │ │ ├── postgres │ │ │ │ │ ├── postgres-networkpolicy.yaml │ │ │ │ │ ├── postgres-service.yaml │ │ │ │ │ └── postgres-statefulset.yaml │ │ │ │ ├── pvc.yaml │ │ │ │ └── secret.yaml │ │ │ └── values.yaml │ │ ├── openrelik │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ │ ├── NOTES.txt │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── _initContainer.tpl │ │ │ │ ├── api-deployment.yaml │ │ │ │ ├── api-svc.yaml │ │ │ │ ├── configmap.yaml │ │ │ │ ├── frontend-deployment.yaml │ │ │ │ ├── frontend-svc.yaml │ │ │ │ ├── gcp │ │ │ │ │ ├── api-backendconfig.yaml │ │ │ │ │ └── frontend-backendconfig.yaml │ │ │ │ ├── init-oidc.yaml │ │ │ │ ├── mediator-deployment.yaml │ │ │ │ ├── metrics-deployment.yaml │ │ │ │ ├── metrics-svc.yaml │ │ │ │ ├── postgres │ │ │ │ │ ├── postgres-service.yaml │ │ │ │ │ └── postgres-statefulset.yaml │ │ │ │ ├── prometheus │ │ │ │ │ ├── prometheus-configmap.yaml │ │ │ │ │ ├── prometheus-deployment.yaml │ │ │ │ │ └── prometheus-svc.yaml │ │ │ │ ├── pvc.yaml │ │ │ │ ├── redis │ │ │ │ │ ├── redis-networkpolicy.yaml │ │ │ │ │ ├── redis-service.yaml │ │ │ │ │ └── redis-statefulset.yaml │ │ │ │ ├── secret-oidc-allowed-users.yaml │ │ │ │ ├── secret.yaml │ │ │ │ └── worker-deployment.yaml │ │ │ └── values.yaml │ │ ├── timesketch │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ │ ├── NOTES.txt │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── _initContainer.tpl │ │ │ │ ├── gcp │ │ │ │ │ └── backendconfig.yaml │ │ │ │ ├── init-configmap.yaml │ │ │ │ ├── nginx │ │ │ │ │ ├── nginx-configmap.yaml │ │ │ │ │ ├── nginx-deployment.yaml │ │ │ │ │ ├── nginx-networkpolicy.yaml │ │ │ │ │ └── nginx-service.yaml │ │ │ │ ├── opensearch │ │ │ │ │ ├── opensearch-service.yaml │ │ │ │ │ └── opensearch-statefulset.yaml │ │ │ │ ├── postgres │ │ │ │ │ ├── postgres-networkpolicy.yaml │ │ │ │ │ ├── postgres-service.yaml │ │ │ │ │ └── postgres-statefulset.yaml │ │ │ │ ├── pvc.yaml │ │ │ │ ├── redis │ │ │ │ │ ├── redis-networkpolicy.yaml │ │ │ │ │ ├── redis-service.yaml │ │ │ │ │ └── redis-statefulset.yaml │ │ │ │ ├── secret-oidc-allowed-users.yaml │ │ │ │ ├── secret.yaml │ │ │ │ ├── service.yaml │ │ │ │ ├── web-deployment.yaml │ │ │ │ └── worker-deployment.yaml │ │ │ ├── tools │ │ │ │ └── download-timesketch-configs.sh │ │ │ └── values.yaml │ │ └── yeti │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ ├── NOTES.txt │ │ │ ├── _env.tpl │ │ │ ├── _helpers.tpl │ │ │ ├── api-deployment.yaml │ │ │ ├── api-service.yaml │ │ │ ├── arangodb │ │ │ │ ├── arangodb-service.yaml │ │ │ │ └── arangodb-statefulset.yaml │ │ │ ├── gcp │ │ │ │ └── backendconfig.yaml │ │ │ ├── nginx │ │ │ │ ├── frontend-deployment.yaml │ │ │ │ ├── frontend-service.yaml │ │ │ │ └── nginx-configmap.yaml │ │ │ ├── redis │ │ │ │ ├── redis-networkpolicy.yaml │ │ │ │ ├── redis-service.yaml │ │ │ │ └── redis-statefulset.yaml │ │ │ ├── secret.yaml │ │ │ └── tasks-deployment.yaml │ │ │ └── values.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── certs │ │ │ ├── cert-manager-issuer.yaml │ │ │ └── tls-secrets.yaml │ │ ├── gcp │ │ │ ├── frontendconfig.yaml │ │ │ └── managedcertificate.yaml │ │ ├── ingress-ipv6.yaml │ │ └── ingress.yaml │ └── values.yaml └── standalone │ ├── dfdewey │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── LICENSE │ ├── README.md │ ├── templates │ │ └── _helpers.tpl │ ├── values-production.yaml │ └── values.yaml │ └── turbinia │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── LICENSE │ ├── README.md │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── _initContainer.tpl │ ├── api-deployment.yaml │ ├── certs │ │ ├── cert-manager-issuer.yaml │ │ └── tls-secrets.yaml │ ├── crds │ │ └── servicemonitor.yaml │ ├── gcp │ │ ├── backendconfig.yaml │ │ ├── frontendconfig.yaml │ │ └── managedcertificate.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── init-configmap.yaml │ ├── metrics │ │ ├── server-metrics-service.yaml │ │ └── worker-metrics-service.yaml │ ├── pvc.yaml │ ├── secret.yaml │ ├── server-deployment.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── worker-deployment.yaml │ └── values.yaml ├── contributing.md ├── docs ├── getting-started.md ├── images │ ├── cluster-info.png │ ├── dashboard-deployment-detail.png │ ├── dashboard-deployments.png │ ├── dashboard-overview.png │ ├── dashboard-pod-detail.png │ ├── dashboard-pods.png │ ├── dashboard-secrets.png │ ├── grr-fleetspeak-demo-architecture.png │ ├── notes-txt-secret.png │ └── notes-txt.png ├── installing-on-gke.md ├── maintainers.md ├── troubleshooting.md └── understanding-helm.md └── extras ├── gcp ├── shell │ └── init-gke.sh └── tf │ ├── README.md │ ├── main.tf │ ├── output.tf │ └── variables.tf └── tools ├── helper.sh └── run-integration-test.sh /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug 2 | description: Create a report to help us improve 3 | labels: ["bug", "triage", "process"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this bug report! 9 | 10 | Please fill in as much of the following form as you're able. 11 | - type: input 12 | attributes: 13 | label: Name and Version 14 | description: Name and version of the affected chart 15 | placeholder: charts/timesketch 0.1.0 16 | validations: 17 | required: true 18 | - type: dropdown 19 | attributes: 20 | label: What environment are you using? 21 | description: Choose the environment where the containers are executed 22 | options: 23 | - GKE 24 | - Minikube 25 | - type: textarea 26 | attributes: 27 | label: What steps will reproduce the bug? 28 | description: Enter details about your bug. 29 | placeholder: | 30 | 1. In this environment... 31 | 2. With this config... 32 | 3. Run '...' 33 | 4. See error... 34 | validations: 35 | required: true 36 | - type: textarea 37 | attributes: 38 | label: Are you using any custom parameters or values? 39 | description: Add any parameter used via `--set` or as a `values.yaml` customization. 40 | - type: textarea 41 | attributes: 42 | label: What is the expected behavior? 43 | description: If possible please provide textual output instead of screenshots. 44 | - type: textarea 45 | attributes: 46 | label: What do you see instead? 47 | description: If possible please provide textual output instead of screenshots. 48 | validations: 49 | required: true 50 | - type: textarea 51 | attributes: 52 | label: Additional information 53 | description: Tell us anything else you think we should know. 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: "Feature request" 2 | description: Suggest an idea for this project 3 | labels: ["enhancement", "triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for suggesting an idea to improve OSDFIR Helm charts. 9 | Please fill in as much of the following form as you're able. 10 | - type: input 11 | attributes: 12 | label: Name and Version 13 | description: Name and version of the affected chart 14 | placeholder: charts/turbinia 0.1.0 15 | validations: 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: What is the problem this feature will solve? 20 | validations: 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: What is the feature you are proposing to solve the problem? 25 | description: Describe the requests. If you already have something in mind... PRs are welcome! 26 | validations: 27 | required: true 28 | - type: textarea 29 | attributes: 30 | label: What alternatives have you considered? -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Description of the change 10 | 11 | 12 | 13 | ### Applicable issues 14 | 15 | 16 | - fixes # 17 | 18 | ### Additional information 19 | 20 | 21 | 22 | ### Checklist 23 | 24 | 25 | 26 | - [ ] Chart version bumped in `Chart.yaml` according to [semver](http://semver.org/). This is *not necessary* when the changes only affect README.md files. 27 | - [ ] Newly added variables are documented in the values.yaml 28 | - [ ] Title of the pull request is descriptive 29 | -------------------------------------------------------------------------------- /.github/ct.yaml: -------------------------------------------------------------------------------- 1 | remote: origin 2 | target-branch: main 3 | chart-repos: 4 | - bitnami=https://charts.bitnami.com/bitnami 5 | - opensearch=https://opensearch-project.github.io/helm-charts 6 | - osdfir-charts=https://google.github.io/osdfir-infrastructure/ 7 | chart-dirs: 8 | - charts 9 | check-version-increment: true 10 | validate-maintainers: false 11 | helm-extra-args: --timeout 800s -------------------------------------------------------------------------------- /.github/workflows/lint-test.yaml: -------------------------------------------------------------------------------- 1 | name: Lint and Test Charts 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | lint-test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 13 | 14 | - name: Set up Helm 15 | uses: azure/setup-helm@v3 16 | with: 17 | version: v3.12.1 18 | 19 | - uses: actions/setup-python@v4 20 | with: 21 | python-version: '3.9' 22 | check-latest: true 23 | 24 | - name: Set up chart-testing 25 | uses: helm/chart-testing-action@v2 26 | with: 27 | version: v3.8.0 28 | 29 | - name: Run chart-testing (list-changed) 30 | id: list-changed 31 | run: | 32 | changed=$(ct list-changed --config .github/ct.yaml) 33 | if [[ -n "$changed" ]]; then 34 | echo "changed=true" >> "$GITHUB_OUTPUT" 35 | fi 36 | 37 | - name: Run chart-testing (lint) 38 | if: steps.list-changed.outputs.changed == 'true' 39 | run: ct lint --config .github/ct.yaml 40 | 41 | - name: Create kind cluster 42 | if: steps.list-changed.outputs.changed == 'true' 43 | uses: helm/kind-action@v1.7.0 44 | 45 | - name: Run chart-testing (install) 46 | if: steps.list-changed.outputs.changed == 'true' 47 | run: ct install --config .github/ct.yaml -------------------------------------------------------------------------------- /.github/workflows/markdown-linter.yml: -------------------------------------------------------------------------------- 1 | name: 'Markdown Linter' 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | paths: 7 | - '**.md' 8 | permissions: {} 9 | 10 | jobs: 11 | markdown-linter: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: read 15 | steps: 16 | - name: Install markdownlint 17 | run: npm install -g markdownlint-cli@0.33.0 18 | 19 | - name: Checkout project 20 | uses: actions/checkout@v3 21 | 22 | - name: Execute markdownlint 23 | env: 24 | DIFF_URL: "${{github.event.pull_request.diff_url}}" 25 | TEMP_FILE: "${{runner.temp}}/pr-${{github.event.number}}.diff" 26 | run: | 27 | curl -Lkso $TEMP_FILE $DIFF_URL 28 | files_changed="$(sed -nr 's/[\-\+]{3} [ab]\/(.*)/\1/p' $TEMP_FILE | sort | uniq)" 29 | md_files="$(echo "$files_changed" | grep -o ".*\.md$" | sort | uniq || true)" 30 | exit_code=0 31 | markdownlint ${md_files[@]} || exit_code=$? 32 | if [[ $exit_code -ne 0 ]]; then 33 | echo "::error:: Please review linter messages" 34 | exit "$exit_code" 35 | fi -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | packages: write 10 | pages: write 11 | contents: write 12 | 13 | jobs: 14 | release: 15 | if: github.repository == 'google/osdfir-infrastructure' 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Configure Git 24 | run: | 25 | git config user.name "$GITHUB_ACTOR" 26 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 27 | 28 | - name: Install Helm 29 | uses: azure/setup-helm@v3 30 | 31 | - name: Add Helm Dependencies 32 | run: | 33 | helm repo add bitnami https://charts.bitnami.com/bitnami 34 | helm repo add opensearch https://opensearch-project.github.io/helm-charts/ 35 | helm repo add osdfir-charts https://google.github.io/osdfir-infrastructure/ 36 | helm repo add kube-prometheus https://prometheus-community.github.io/helm-charts 37 | 38 | - name: Run chart-releaser 39 | uses: helm/chart-releaser-action@v1.5.0 40 | env: 41 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 42 | CR_SKIP_EXISTING: true 43 | CR_GENERATE_RELEASE_NOTES: true 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore back-up files. 2 | *~ 3 | *.tgz 4 | 5 | # Exclude IDE files 6 | /.idea/* 7 | .vscode 8 | .DS_Store 9 | 10 | # Exclude config files 11 | charts/timesketch/configs 12 | turbinia.conf 13 | 14 | charts/osdfir-infrastructure/charts/grr/certs 15 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD001": false, 4 | "MD012": false, 5 | "MD013": false, 6 | "MD014": false, 7 | "MD033": false, 8 | "MD041": false 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OSDFIR Infrastructure 2 | 3 | OSDFIR Infrastructure simplifies the deployment and integration of Open Source 4 | Digital Forensics tools to Kubernetes clusters (local or cloud) using Helm. 5 | 6 | Currently, OSDFIR Infrastructure supports the deployment and integration of the 7 | following tools: 8 | 9 | * [Timesketch](https://github.com/google/timesketch) for collaborative forensic 10 | timeline analysis featuring analyzers to help identitify patterns in data, support 11 | for Plaso, JSONL, or CSV file imports, and built-in integrations to tools such as: 12 | * [DFIQ](https://dfiq.org/) for digital forensics investigative questions and 13 | the approaches to answering them 14 | * [Unfurl](https://github.com/obsidianforensics/unfurl) for graph analysis of URLs 15 | * [Yeti](https://github.com/yeti-platform/yeti) for DFIR and threat intelligence 16 | tracking, enabling responders to store and analyze CTI (observables, TTPs, campaigns, etc.) 17 | from internal and external systems and integrates with Timesketch. 18 | * [OpenRelik](https://openrelik.org/) is a platform that streamlines 19 | collaborative digital forensic investigations. It provides modular workflows, 20 | an intuitive interface, real-time collaboration, a centralized artifact repository, 21 | and can easily be extended to support new workers. 22 | * [GRR](https://github.com/google/grr) for incident response and remote live forensics. 23 | * [Hashr](https://github.com/google/hashr) to build your own hash sets based on 24 | your data sources. 25 | * [dfTimewolf](https://github.com/log2timeline/dftimewolf) for orchestrating 26 | forensic collection, processing and data export, helping pass data between tools 27 | using recipes (e.g. importing processed Plaso files Timesketch) 28 | 29 | ## Installing the Charts 30 | 31 | To get started, ensure you have [Helm](https://helm.sh) installed and are 32 | authenticated to your Kubernetes cluster. 33 | 34 | 35 | Once complete, add the repo containing the Helm charts as follows: 36 | 37 | ```console 38 | helm repo add osdfir-charts https://google.github.io/osdfir-infrastructure 39 | ``` 40 | 41 | If you had already added this repo earlier, run `helm repo update` to retrieve 42 | the latest versions of the packages. You can then run `helm search repo osdfir-charts` 43 | to see the available charts. 44 | 45 | To install the OSDFIR Infrastructure chart using a release name of `my-release`: 46 | 47 | ```console 48 | helm install my-release osdfir-charts/osdfir-infrastructure 49 | ``` 50 | 51 | > **Note**: The default configuration of the Helm chart installs it within your 52 | cluster for internal access. To enable external access, follow the instructions 53 | provided in the Helm chart's README. 54 | 55 | To uninstall the chart: 56 | 57 | ```console 58 | helm uninstall my-release 59 | ``` 60 | 61 | Please refer to the links below for more details on configuring OSDFIR Infrastructure, 62 | and accessing helpful guides. 63 | 64 | * [Getting Started with Minikube](docs/getting-started.md) 65 | * [OSDFIR Infrastructure Helm Chart](charts/osdfir-infrastructure/README.md) 66 | * [Troubleshooting Helm Charts](docs/troubleshooting.md) 67 | * [Understanding Helm Charts](docs/understanding-helm.md) 68 | 69 | --- 70 | 71 | ##### Obligatory Fine Print 72 | 73 | This is not an official Google product (experimental or otherwise), it is just 74 | code that happens to be owned by Google. 75 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: timesketch 3 | repository: file://charts/timesketch 4 | version: 2.1.3 5 | - name: yeti 6 | repository: file://charts/yeti 7 | version: 2.1.0 8 | - name: openrelik 9 | repository: file://charts/openrelik 10 | version: 2.1.2 11 | - name: grr 12 | repository: file://charts/grr 13 | version: 2.2.0 14 | - name: hashr 15 | repository: file://charts/hashr 16 | version: 2.0.0 17 | digest: sha256:d53ca2f2084ea1ed5b8fffd319499721a696228b4618c8300738085722f54521 18 | generated: "2025-05-12T20:38:33.883680087Z" 19 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: osdfir-infrastructure 3 | version: 2.2.9 4 | description: A Helm chart for Open Source Digital Forensics Kubernetes deployments. 5 | keywords: 6 | - timesketch 7 | - yeti 8 | - dfir 9 | - analysis 10 | - processing 11 | - security 12 | home: "https://github.com/google/osdfir-infrastructure" 13 | dependencies: 14 | - condition: global.timesketch.enabled 15 | name: timesketch 16 | repository: file://charts/timesketch 17 | version: 2.1.3 18 | - condition: global.yeti.enabled 19 | name: yeti 20 | repository: file://charts/yeti 21 | version: 2.1.0 22 | - condition: global.openrelik.enabled 23 | name: openrelik 24 | repository: file://charts/openrelik 25 | version: 2.1.2 26 | - condition: global.grr.enabled 27 | name: grr 28 | repository: file://charts/grr 29 | version: 2.2.0 30 | - condition: global.hashr.enabled 31 | name: hashr 32 | repository: file://charts/hashr 33 | version: 2.0.0 34 | maintainers: 35 | - name: Open Source DFIR 36 | email: osdfir-maintainers@googlegroups.com 37 | url: https://github.com/google/osdfir-infrastructure 38 | sources: 39 | - https://github.com/google/grr 40 | - https://github.com/google/osdfir-infrastructure 41 | - https://github.com/google/timesketch 42 | - https://github.com/yeti-platform/yeti 43 | - https://openrelik.org/ 44 | annotations: 45 | category: Security 46 | licenses: Apache-2.0 47 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: grr 3 | version: 2.2.0 4 | description: A Helm chart for GRR/Fleetspeak Kubernetes deployments. 5 | keywords: 6 | - grr 7 | - dfir 8 | - analysis 9 | - forensics 10 | home: "https://www.grr-response.com/" 11 | maintainers: 12 | - name: Open Source DFIR 13 | email: osdfir-maintainers@googlegroups.com 14 | url: https://github.com/google/osdfir-infrastructure 15 | sources: 16 | - https://github.com/google/grr 17 | - https://github.com/google/osdfir-infrastructure 18 | icon: https://www.grr-response.com/images/favicons/favicon.ico 19 | appVersion: "latest" 20 | annotations: 21 | category: Security 22 | licenses: Apache-2.0 23 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/README.md: -------------------------------------------------------------------------------- 1 | # GRR Helm Chart 2 | 3 | [GRR](https://github.com/google/grr) Rapid Response is an incident response framework focused on remote live forensics. 4 | 5 | [Overview of GRR](https://grr-doc.readthedocs.io/) 6 | 7 | Before we get started make sure you clone the repo onto your machine. 8 | 9 | ```console 10 | git clone https://github.com/google/osdfir-infrastructure.git 11 | cd osdfir-infrastructure 12 | export REPO=$(pwd) 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ghcr.io/google/grr:v3.4.9.1-release AS grr 15 | COPY config /config 16 | COPY grr-client-config.yaml /config/grr.client.yaml 17 | 18 | RUN mkdir /client_installers && \ 19 | grr_config_updater repack_clients \ 20 | --secondary_configs /config/grr.yaml \ 21 | --noupload 22 | 23 | FROM ubuntu:22.04 24 | WORKDIR / 25 | 26 | COPY --from=grr /config/communicator.txt /etc/fleetspeak-client/communicator.txt 27 | COPY --from=grr /config/config.textproto /etc/fleetspeak-client/client.config 28 | COPY --from=grr /config/grr.client.yaml /etc/fleetspeak-client/grr.client.yaml 29 | 30 | COPY --from=grr /client_installers/grr_*_amd64.deb . 31 | RUN dpkg -i grr_*_amd64.deb && rm grr_*_amd64.deb 32 | ENTRYPOINT ["fleetspeak-client", "-config" , "/etc/fleetspeak-client/client.config", "-alsologtostderr"] 33 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/Dockerfile.kaniko: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ghcr.io/google/grr:v3.4.9.1-release AS grr 15 | 16 | ARG FLEETSPEAK_FRONTEND 17 | ARG FLEETSPEAK_FRONTEND_PORT 18 | 19 | WORKDIR / 20 | 21 | COPY config /config 22 | COPY grr-client-config.yaml /config/grr.client.yaml 23 | 24 | RUN echo "FLEETSPEAK_FRONTEND: $FLEETSPEAK_FRONTEND, FLEETSPEAK_FRONTEND_PORT: $FLEETSPEAK_FRONTEND_PORT"; 25 | 26 | RUN export FLEETSPEAK_CERT=$(openssl s_client -showcerts -nocommands -connect $FLEETSPEAK_FRONTEND:$FLEETSPEAK_FRONTEND_PORT< /dev/null | openssl x509 -outform pem | sed ':a;N;$!ba;s/\n/\\\\n/g') && \ 27 | sed "s'FLEETSPEAK_FRONTEND_ADDRESS'$FLEETSPEAK_FRONTEND'g" /config/config.textproto.tmpl > /config/config.textproto && \ 28 | sed -i "s'FLEETSPEAK_FRONTEND_PORT'$FLEETSPEAK_FRONTEND_PORT'" /config/config.textproto && \ 29 | sed -i "s'FRONTEND_TRUSTED_CERTIFICATES'\"$FLEETSPEAK_CERT\"'g" /config/config.textproto && \ 30 | echo 'client_certificate_header: "client-certificate"' >> /config/config.textproto 31 | 32 | RUN PRI_KEY=$(cat /grr/exe/sign/keys/exe-sign-private-key.pem | sed ':a;N;$!ba;s/\n/\\\\n/g') && \ 33 | PUB_KEY=$(cat /grr/exe/sign/keys/exe-sign-public-key.pem | sed ':a;N;$!ba;s/\n/\\\\n/g') && \ 34 | sed -i "s'EXE_SIGN_PUBLIC_KEY'$PUB_KEY'g" /config/grr.client.yaml && \ 35 | sed -i "s'EXE_SIGN_PRIVATE_KEY'$PRI_KEY'g" /config/grr.server.yaml && \ 36 | sed -i "s'EXE_SIGN_PUBLIC_KEY'$PUB_KEY'g" /config/grr.server.yaml 37 | 38 | RUN mkdir /client_installers && \ 39 | grr_config_updater repack_clients \ 40 | --secondary_configs /config/grr.server.yaml 41 | 42 | FROM ubuntu:22.04 43 | WORKDIR / 44 | 45 | COPY --from=grr /config/communicator.txt /etc/fleetspeak-client/communicator.txt 46 | COPY --from=grr /config/config.textproto /etc/fleetspeak-client/client.config 47 | COPY --from=grr /config/grr.client.yaml /etc/fleetspeak-client/grr.client.yaml 48 | 49 | COPY --from=grr /client_installers/grr_*_amd64.deb . 50 | RUN dpkg -i grr_*_amd64.deb && rm grr_*_amd64.deb 51 | RUN cat /etc/fleetspeak-client/grr.client.yaml >> /usr/lib/grr/grr_3.4.9.1_amd64/grrd.yaml 52 | ENTRYPOINT ["fleetspeak-client", "-config" , "/etc/fleetspeak-client/client.config", "-alsologtostderr"] 53 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/config/communicator.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/charts/osdfir-infrastructure/charts/grr/containers/grr-client/config/communicator.txt -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/config/config.textproto.tmpl: -------------------------------------------------------------------------------- 1 | trusted_certs: FRONTEND_TRUSTED_CERTIFICATES 2 | server: "FLEETSPEAK_FRONTEND_ADDRESS:FLEETSPEAK_FRONTEND_PORT" 3 | client_label: "" 4 | filesystem_handler: < 5 | configuration_directory: "/etc/fleetspeak-client/" 6 | state_file: "/fleetspeak.state" 7 | > 8 | streaming: true 9 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/config/grr.yaml: -------------------------------------------------------------------------------- 1 | PrivateKeys.executable_signing_private_key: "EXE_SIGN_PRIVATE_KEY" 2 | Client.executable_signing_public_key: "EXE_SIGN_PUBLIC_KEY" 3 | # Configuration for repacking client templates: 4 | ClientBuilder.fleetspeak_bundled: true 5 | ClientBuilder.template_dir: /client_templates 6 | ClientBuilder.executables_dir: /client_installers 7 | 8 | Target:Linux: 9 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 10 | Target:Windows: 11 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 12 | Target:Darwin: 13 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 14 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/config/textservices/grr.service: -------------------------------------------------------------------------------- 1 | name: "GRR" 2 | factory: "Daemon" 3 | config { 4 | [type.googleapis.com/fleetspeak.daemonservice.Config] { 5 | argv: "/usr/sbin/grrd" 6 | argv: "--config" 7 | argv: "/etc/fleetspeak-client/grr.client.yaml" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/containers/grr-client/grr-client-config.yaml: -------------------------------------------------------------------------------- 1 | Client.allowed_commands: /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock images -o yaml, /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock info -o yaml, /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock pods -o yaml, /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock ps -o yaml, /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock stats -o yaml, /hostroot/usr/bin/crictl -r unix:///hostroot/run/containerd/containerd.sock statsp -o yaml 2 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/createSigningKeys.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script can be used to create the executable signing keys for the GRR clients. 3 | # Note: This is optional and just intended as an example for how keys could be created manually. 4 | set -e 5 | 6 | mkdir certs 7 | 8 | # Generate the GRR client executable signing private key 9 | openssl genrsa -out ./certs/exe-sign-private-key.pem 10 | 11 | # Generate the GRR client executable signing public key 12 | openssl rsa -in ./certs/exe-sign-private-key.pem -pubout -out ./certs/exe-sign-public-key.pem 13 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "grr.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "grr.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "grr.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "grr.labels" -}} 37 | helm.sh/chart: {{ include "grr.chart" . }} 38 | {{ include "grr.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "grr.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "grr.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "grr.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "grr.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/admin-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-grr-admin 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | labels: 9 | app: grr-admin 10 | spec: 11 | replicas: {{ .Values.grr.admin.replicas }} 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: grr-admin 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: grr-admin 19 | prometheus: grr-admin 20 | spec: 21 | serviceAccountName: {{ .Release.Name }}-grr-sa 22 | affinity: 23 | nodeAffinity: 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: nodepool 29 | operator: In 30 | values: 31 | - grr 32 | initContainers: 33 | - name: init-fleetspeak-health-check 34 | image: bitnami/git 35 | command: ["/bin/sh", "-c"] 36 | args: 37 | - | 38 | set -e 39 | until [ "$(curl -s -w '%{http_code}' -o /dev/null http://{{ .Release.Name }}-grr-fleetspeak-admin:{{ .Values.fleetspeak.admin.healthCheckPort }})" -eq 200 ] 40 | do 41 | echo "Waiting for Fleetspeak Admin to be ready"; 42 | sleep 5; 43 | done 44 | echo "Fleetspeak Admin health check is ready" 45 | - name: init-exe-sign 46 | image: bitnami/git 47 | command: ["/bin/sh", "-c"] 48 | args: 49 | - | 50 | set -e 51 | cp /sign/keys/*.pem /grr/exe/sign/keys/ 52 | if [ -e /sign/keys/exe-sign.crt ] 53 | then 54 | echo "Extracting public key from certificate..." 55 | openssl x509 -in /sign/keys/exe-sign.crt -pubkey -noout > /grr/exe/sign/keys/exe-sign-public-key.pem 56 | fi 57 | volumeMounts: 58 | - name: grr-exe-sign-keys-volume 59 | mountPath: /grr/exe/sign/keys 60 | - name: grr-exe-sign-keys-secret 61 | mountPath: /sign/keys 62 | containers: 63 | - name: grr-admin 64 | image: {{ .Values.grr.admin.image }} 65 | {{- if .Values.global.useResourceRequests }} 66 | resources: 67 | requests: 68 | memory: "2Gi" 69 | cpu: "1000m" 70 | {{- end }} 71 | ports: 72 | - containerPort: {{ .Values.grr.admin.listenPort }} 73 | name: admin 74 | - containerPort: {{ .Values.prometheus.metricsPort }} 75 | name: metrics 76 | args: ["-component", "admin_ui", "-config", "/usr/src/grr/grr/core/install_data/etc/server.local.yaml", "--logtostderr"] 77 | volumeMounts: 78 | - name: grr-admin-config 79 | mountPath: /usr/src/grr/grr/core/install_data/etc/server.local.yaml 80 | subPath: server.local.yaml 81 | - name: grr-exe-sign-keys-volume 82 | readOnly: true 83 | mountPath: "/grr/exe/sign/keys" 84 | volumes: 85 | - name: grr-admin-config 86 | secret: 87 | secretName: {{ .Release.Name }}-grr-server-local 88 | items: 89 | - key: server.local.yaml 90 | path: server.local.yaml 91 | - name: grr-exe-sign-keys-secret 92 | secret: 93 | secretName: {{ .Release.Name }}-grr-executable-signing-keys 94 | - name: grr-exe-sign-keys-volume 95 | emptyDir: 96 | sizeLimit: 5Mi 97 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/admin-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-grr-admin 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | spec: 9 | selector: 10 | app.kubernetes.io/name: grr-admin 11 | ports: 12 | - protocol: TCP 13 | name: admin 14 | port: {{ .Values.grr.admin.listenPort }} 15 | targetPort: {{ .Values.grr.admin.listenPort }} 16 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/client/client-daemonset.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.grr.daemon.image }} 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: {{ .Release.Name }}-grr-client 6 | {{- if .Values.grr.namespaceClient }} 7 | namespace: {{ .Values.grr.namespaceClient }} 8 | {{- end }} 9 | labels: 10 | app: grr 11 | spec: 12 | selector: 13 | matchLabels: 14 | app: grr 15 | template: 16 | metadata: 17 | labels: 18 | app: grr 19 | spec: 20 | # Only deploying GRR to nodes with the label 'grrclient=installed'. 21 | nodeSelector: 22 | grrclient: installed 23 | serviceAccountName: {{ .Release.Name }}-grr-client 24 | # Uses the host network rather than the container network. This way 25 | # the hostname that shows up in GRR will contain the cluster name too. 26 | hostNetwork: true 27 | # Allows us to list all processes on the host rather than just those 28 | # from the container. 29 | hostPID: true 30 | # Labeling volumes from the root file system so they can be exposed to 31 | # our container. 32 | volumes: 33 | - name: root 34 | hostPath: 35 | path: / 36 | dnsPolicy: ClusterFirstWithHostNet 37 | containers: 38 | - name: grr 39 | image: {{ .Values.grr.daemon.image }} 40 | {{- if .Values.global.useResourceRequests }} 41 | resources: 42 | requests: 43 | memory: "150Mi" 44 | cpu: "150m" 45 | {{- end }} 46 | imagePullPolicy: {{ .Values.grr.daemon.imagePullPolicy }} 47 | # Making it a privileged container. This way the processes within 48 | # the container get almost the same privileges as those outside the 49 | # container (e.g. manipulating the network stack or accessing devices). 50 | securityContext: 51 | privileged: true 52 | # Exposing the machine's file system to the container (read-only). 53 | volumeMounts: 54 | - mountPath: /hostroot 55 | name: root 56 | readOnly: true 57 | {{- end }} 58 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/client/client-namespace.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.grr.namespaceClient }} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ .Values.grr.namespaceClient }} 6 | labels: 7 | pod-security.kubernetes.io/enforce: privileged 8 | {{- end }} 9 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/client/client-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ .Release.Name }}-grr-client 5 | {{- if .Values.grr.namespaceClient }} 6 | namespace: {{ .Values.grr.namespaceClient }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/database/mysql.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.selfManagedMysql }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: mysql 6 | {{- if .Values.grr.namespace }} 7 | namespace: {{ .Values.grr.namespace }} 8 | {{- end }} 9 | spec: 10 | ports: 11 | - port: 3306 12 | selector: 13 | app: mysql 14 | clusterIP: None 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | name: sec-mysql 20 | {{- if .Values.grr.namespace }} 21 | namespace: {{ .Values.grr.namespace }} 22 | {{- end }} 23 | stringData: 24 | fleetspeak-password: fleetspeak-password 25 | grr-password: grr-password 26 | mysql-password: password 27 | --- 28 | apiVersion: v1 29 | kind: ConfigMap 30 | metadata: 31 | name: cfm-mysql-init 32 | {{- if .Values.grr.namespace }} 33 | namespace: {{ .Values.grr.namespace }} 34 | {{- end }} 35 | data: 36 | init.sh: | 37 | #!/bin/bash 38 | set -ex 39 | echo "** Creating default DB for GRR and fleetspeak" 40 | mariadb -u root -p"$MYSQL_ROOT_PASSWORD" --execute \ 41 | "CREATE USER'grr-user'@'%' IDENTIFIED BY '$GRR_PASSWORD'; 42 | CREATE DATABASE grr; 43 | GRANT ALL ON grr.* TO 'grr-user'@'%'; 44 | CREATE USER 'fleetspeak-user'@'%' IDENTIFIED BY '$FLEETSPEAK_PASSWORD'; 45 | CREATE DATABASE fleetspeak; 46 | GRANT ALL ON fleetspeak.* TO 'fleetspeak-user'@'%'; 47 | FLUSH PRIVILEGES;" 48 | echo "** Finished creating DBs and users" 49 | --- 50 | apiVersion: apps/v1 51 | kind: Deployment 52 | metadata: 53 | name: {{ .Release.Name }}-grr-mysql 54 | {{- if .Values.grr.namespace }} 55 | namespace: {{ .Values.grr.namespace }} 56 | {{- end }} 57 | spec: 58 | selector: 59 | matchLabels: 60 | app: mysql 61 | strategy: 62 | type: Recreate 63 | template: 64 | metadata: 65 | labels: 66 | app: mysql 67 | spec: 68 | containers: 69 | - image: mariadb:11.3.2 70 | name: mysql 71 | env: 72 | - name: MYSQL_ROOT_PASSWORD 73 | valueFrom: 74 | secretKeyRef: 75 | name: sec-mysql 76 | key: mysql-password 77 | - name: GRR_PASSWORD 78 | valueFrom: 79 | secretKeyRef: 80 | name: sec-mysql 81 | key: grr-password 82 | - name: FLEETSPEAK_PASSWORD 83 | valueFrom: 84 | secretKeyRef: 85 | name: sec-mysql 86 | key: fleetspeak-password 87 | args: ["--max_allowed_packet=40M", "--log_bin_trust_function_creators=ON"] 88 | ports: 89 | - containerPort: 3306 90 | name: mysql 91 | volumeMounts: 92 | - name: mysql-init 93 | mountPath: /docker-entrypoint-initdb.d/ 94 | volumes: 95 | - name: mysql-init 96 | configMap: 97 | name: cfm-mysql-init 98 | items: 99 | - key: init.sh 100 | path: init.sh 101 | {{- end }} 102 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/executable-keys-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- $cert := genSelfSignedCert "executable-signing" nil (list "executable-siging") 3650 }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ .Release.Name }}-grr-executable-signing-keys 6 | {{- if .Values.grr.namespace }} 7 | namespace: {{ .Values.grr.namespace }} 8 | {{- end }} 9 | labels: 10 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 11 | release: "{{ .Release.Name }}" 12 | heritage: "{{ .Release.Service }}" 13 | type: Opaque 14 | data: 15 | {{- if .Values.global.generateExeSignCert }} 16 | exe-sign-private-key.pem: {{ $cert.Key| b64enc }} 17 | exe-sign.crt: {{ $cert.Cert | b64enc }} 18 | {{- else }} 19 | exe-sign-private-key.pem: {{ .Files.Get "certs/exe-sign-private-key.pem" | b64enc }} 20 | exe-sign-public-key.pem: {{ .Files.Get "certs/exe-sign-public-key.pem" | b64enc }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-admin-components-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-admin-components 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | stringData: 9 | admin.components.textproto: | 10 | mysql_data_source_name: "{{ .Values.fleetspeak.mysqlDb.userName }}:{{ .Values.fleetspeak.mysqlDb.userPassword }}@tcp({{ .Values.fleetspeak.mysqlDb.address }}:{{ .Values.fleetspeak.mysqlDb.port }})/{{ .Values.fleetspeak.mysqlDb.name }}" 11 | admin_config: < 12 | listen_address: "0.0.0.0:{{ .Values.fleetspeak.admin.listenPort }}" 13 | > 14 | notification_use_http_notifier: true 15 | stats_config: < 16 | address: "0.0.0.0:{{ .Values.prometheus.metricsPort }}" 17 | > 18 | health_check_config: < 19 | listen_address: "0.0.0.0:{{ .Values.fleetspeak.admin.healthCheckPort }}" 20 | > 21 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-admin-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-admin 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | labels: 9 | app: fleetspeak-admin 10 | spec: 11 | replicas: {{ .Values.fleetspeak.admin.replicas }} 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: fleetspeak-admin 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: fleetspeak-admin 19 | prometheus: fleetspeak-admin 20 | spec: 21 | serviceAccountName: {{ .Release.Name }}-grr-sa 22 | affinity: 23 | nodeAffinity: 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: nodepool 29 | operator: In 30 | values: 31 | - grr 32 | containers: 33 | - name: fleetspeak-admin 34 | image: {{ .Values.fleetspeak.admin.image }} 35 | {{- if .Values.global.useResourceRequests }} 36 | resources: 37 | requests: 38 | memory: "2Gi" 39 | cpu: "1000m" 40 | {{- end }} 41 | ports: 42 | - containerPort: {{ .Values.fleetspeak.admin.listenPort }} 43 | name: admin 44 | - containerPort: {{ .Values.fleetspeak.admin.healthCheckPort }} 45 | name: healthz 46 | - containerPort: {{ .Values.prometheus.metricsPort }} 47 | name: metrics 48 | command: ["/fleetspeak/bin/server"] 49 | args: ["-alsologtostderr"] 50 | volumeMounts: 51 | - name: fleetspeak-admin-components 52 | mountPath: /etc/fleetspeak-server/server.components.config 53 | subPath: server.components.config 54 | - name: fleetspeak-services 55 | mountPath: /etc/fleetspeak-server/server.services.config 56 | subPath: server.services.config 57 | volumes: 58 | - name: fleetspeak-admin-components 59 | secret: 60 | secretName: {{ .Release.Name }}-grr-fleetspeak-admin-components 61 | items: 62 | - key: admin.components.textproto 63 | path: server.components.config 64 | - name: fleetspeak-services 65 | configMap: 66 | name: {{ .Release.Name }}-grr-fleetspeak-services 67 | items: 68 | - key: services.textproto 69 | path: server.services.config 70 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-admin-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-admin 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | spec: 9 | selector: 10 | app.kubernetes.io/name: fleetspeak-admin 11 | ports: 12 | - protocol: TCP 13 | name: admin 14 | port: {{ .Values.fleetspeak.admin.listenPort }} 15 | targetPort: {{ .Values.fleetspeak.admin.listenPort }} 16 | - protocol: TCP 17 | name: healthz 18 | port: {{ .Values.fleetspeak.admin.healthCheckPort }} 19 | targetPort: {{ .Values.fleetspeak.admin.healthCheckPort }} 20 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-frontend-components-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- /* Step 1: Perform lookup, store result */}} 2 | {{- $lookupResult := lookup "v1" "Node" "" "" | default dict -}} 3 | {{- $internalIP := "" -}} 4 | {{- /* Step 2: Get values, store result */}} 5 | {{- $nodeList := $lookupResult.items -}} 6 | {{- if $nodeList }} 7 | {{- /* Step 3: Get first node data, store result */}} 8 | {{- $nodeData := first $nodeList -}} 9 | {{- /* Step 4: Get the status */}} 10 | {{- $statusValue := $nodeData.status -}} 11 | {{- /* Step 5: Get the addresses */}} 12 | {{- $addressesList := $statusValue.addresses -}} 13 | {{- /* Step 6: Get the InternalIP address */}} 14 | {{- range $address := $addressesList -}} 15 | {{- if and (not $internalIP) (eq $address.type "InternalIP") -}} 16 | {{- $internalIP = $address.address -}} 17 | {{- end -}} 18 | {{- end -}} 19 | {{- end -}} 20 | {{- $cert := "" -}} 21 | {{- if or (eq .Values.fleetspeak.frontend.expose "internal") (eq .Values.fleetspeak.frontend.expose "external") -}} 22 | {{- $cert = genSelfSignedCert .Values.fleetspeak.subjectCommonName (list .Values.fleetspeak.frontend.address) (list "fleetspeak-frontend") 3650 }} 23 | {{- else }} 24 | {{- if not $internalIP -}} 25 | {{- /* Note: This should not ever happen but we set it to keep the linter happy. */}} 26 | {{- $cert = genSelfSignedCert .Values.fleetspeak.subjectCommonName (list "10.0.0.2") (list "fleetspeak-frontend") 3650 }} 27 | {{- else -}} 28 | {{- $cert = genSelfSignedCert .Values.fleetspeak.subjectCommonName (list $internalIP) (list "fleetspeak-frontend") 3650 }} 29 | {{- end -}} 30 | {{- end -}} 31 | apiVersion: v1 32 | kind: Secret 33 | metadata: 34 | name: {{ .Release.Name }}-grr-fleetspeak-frontend-components 35 | {{- if .Values.grr.namespace }} 36 | namespace: {{ .Values.grr.namespace }} 37 | {{- end }} 38 | stringData: 39 | frontend.components.textproto: | 40 | mysql_data_source_name: "{{ .Values.fleetspeak.mysqlDb.userName }}:{{ .Values.fleetspeak.mysqlDb.userPassword }}@tcp({{ .Values.fleetspeak.mysqlDb.address }}:{{ .Values.fleetspeak.mysqlDb.port }})/{{ .Values.fleetspeak.mysqlDb.name }}" 41 | https_config: < 42 | listen_address: "0.0.0.0:{{ .Values.fleetspeak.frontend.listenPort }}" 43 | {{- if .Values.fleetspeak.generateCert }} 44 | certificates: {{ $cert.Cert | quote }} 45 | key: {{ $cert.Key | quote }} 46 | {{- else }} 47 | certificates: {{ default (.Files.Get "../../certs/fleetspeak-frontend.crt") .Values.fleetspeak.frontend.cert | quote }} 48 | key: {{ default (.Files.Get "../../certs/fleetspeak-frontend.key") .Values.fleetspeak.frontend.key | quote }} 49 | {{- end }} 50 | {{- if .Values.fleetspeak.httpsHeaderChecksum }} 51 | frontend_config: < 52 | https_header_checksum_config: < 53 | client_certificate_header: "client-certificate" 54 | client_certificate_checksum_header: "X-Client-Cert-Hash" 55 | > 56 | > 57 | {{- end }} 58 | > 59 | health_check_config: < 60 | listen_address: "0.0.0.0:{{ .Values.fleetspeak.frontend.healthCheckPort }}" 61 | > 62 | notification_listen_address: "0.0.0.0:{{ .Values.fleetspeak.frontend.notificationPort }}" 63 | notification_public_address: "FLEETSPEAK_FRONTEND_IP:{{ .Values.fleetspeak.frontend.notificationPort }}" 64 | stats_config: < 65 | address: "0.0.0.0:{{ .Values.prometheus.metricsPort }}" 66 | > 67 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-frontend 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | labels: 9 | app: fleetspeak-frontend 10 | spec: 11 | replicas: {{ .Values.fleetspeak.frontend.replicas }} 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: fleetspeak-frontend 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: fleetspeak-frontend 19 | prometheus: fleetspeak-frontend 20 | spec: 21 | serviceAccountName: {{ .Release.Name }}-grr-sa 22 | affinity: 23 | nodeAffinity: 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: nodepool 29 | operator: In 30 | values: 31 | - grr 32 | initContainers: 33 | - name: init-fleetspeak-frontend 34 | env: 35 | - name: POD_IP 36 | valueFrom: 37 | fieldRef: 38 | fieldPath: status.podIP 39 | image: busybox:1.36 40 | command: ['sh', '-c', "cp /stage/fleetspeak-server/server.*.config /etc/fleetspeak-server/; sed -i \"s/FLEETSPEAK_FRONTEND_IP/$POD_IP/g\" /etc/fleetspeak-server/server.components.config"] 41 | volumeMounts: 42 | - name: fleetspeak-config-volume 43 | mountPath: /etc/fleetspeak-server 44 | - name: fleetspeak-frontend-components 45 | mountPath: /stage/fleetspeak-server/server.components.config 46 | subPath: server.components.config 47 | - name: fleetspeak-services 48 | mountPath: /stage/fleetspeak-server/server.services.config 49 | subPath: server.services.config 50 | containers: 51 | - name: fleetspeak-frontend 52 | image: {{ .Values.fleetspeak.frontend.image }} 53 | {{- if .Values.global.useResourceRequests }} 54 | resources: 55 | requests: 56 | memory: "2Gi" 57 | cpu: "1000m" 58 | {{- end }} 59 | ports: 60 | - containerPort: {{ .Values.fleetspeak.frontend.listenPort }} 61 | name: frontend 62 | - containerPort: {{ .Values.fleetspeak.frontend.healthCheckPort }} 63 | name: healthz 64 | - containerPort: {{ .Values.fleetspeak.frontend.notificationPort }} 65 | name: notification 66 | - containerPort: {{ .Values.prometheus.metricsPort }} 67 | name: metrics 68 | readinessProbe: 69 | httpGet: 70 | path: / 71 | port: {{ .Values.fleetspeak.frontend.healthCheckPort }} 72 | initialDelaySeconds: 5 73 | periodSeconds: 5 74 | command: ["/fleetspeak/bin/server"] 75 | args: ["-alsologtostderr"] 76 | volumeMounts: 77 | - name: fleetspeak-config-volume 78 | mountPath: /etc/fleetspeak-server 79 | volumes: 80 | - name: fleetspeak-config-volume 81 | emptyDir: 82 | sizeLimit: 5Mi 83 | - name: fleetspeak-frontend-components 84 | secret: 85 | secretName: {{ .Release.Name }}-grr-fleetspeak-frontend-components 86 | items: 87 | - key: frontend.components.textproto 88 | path: server.components.config 89 | - name: fleetspeak-services 90 | configMap: 91 | name: {{ .Release.Name }}-grr-fleetspeak-services 92 | items: 93 | - key: services.textproto 94 | path: server.services.config 95 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-frontend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-frontend 5 | {{- if .Values.grr.namespaceClient }} 6 | namespace: {{ .Values.grr.namespaceClient }} 7 | {{- end }} 8 | annotations: 9 | {{- if eq .Values.fleetspeak.frontend.expose "internal" }} 10 | networking.gke.io/load-balancer-type: "Internal" 11 | {{- else if eq .Values.fleetspeak.frontend.expose "external" }} 12 | cloud.google.com/l4-rbs: "enabled" 13 | {{- end }} 14 | spec: 15 | {{- if or (eq .Values.fleetspeak.frontend.expose "internal") (eq .Values.fleetspeak.frontend.expose "external") }} 16 | type: LoadBalancer 17 | loadBalancerIP: {{ .Values.fleetspeak.frontend.address }} 18 | {{- else }} 19 | type: NodePort 20 | {{- end }} 21 | selector: 22 | app.kubernetes.io/name: fleetspeak-frontend 23 | ports: 24 | - name: fleetspeak-frontend 25 | protocol: TCP 26 | port: {{ .Values.fleetspeak.frontend.listenPort }} 27 | targetPort: {{ .Values.fleetspeak.frontend.listenPort }} 28 | {{- if eq .Values.fleetspeak.frontend.expose "node" }} 29 | nodePort: {{ .Values.fleetspeak.frontend.listenPort }} 30 | {{- end }} 31 | - name: healthz 32 | port: {{ .Values.fleetspeak.frontend.healthCheckPort }} 33 | protocol: TCP 34 | targetPort: {{ .Values.fleetspeak.frontend.healthCheckPort }} 35 | --- 36 | kind: Service 37 | apiVersion: v1 38 | metadata: 39 | name: fleetspeak-frontend 40 | {{- if .Values.grr.namespaceClient }} 41 | namespace: {{ .Values.grr.namespaceClient }} 42 | {{- end }} 43 | spec: 44 | type: ExternalName 45 | {{- if .Values.grr.namespace }} 46 | externalName: {{ .Release.Name }}-fleetspeak-frontend.{{ .Values.grr.namespace }}.svc.cluster.local 47 | {{- else }} 48 | externalName: {{ .Release.Name }}-fleetspeak-frontend.default.svc.cluster.local 49 | {{- end }} 50 | ports: 51 | - port: {{ .Values.fleetspeak.frontend.listenPort }} 52 | name: frontend 53 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/fleetspeak/fleetspeak-services-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Release.Name }}-grr-fleetspeak-services 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | data: 9 | services.textproto: | 10 | services { 11 | name: "GRR" 12 | {{- if (and .Values.grr.pubsub .Values.grr.pubsub.topic) }} 13 | factory: "CPS" 14 | config { 15 | [type.googleapis.com/fleetspeak.cpsservice.Config] { 16 | project: "{{ .Values.grr.pubsub.project }}" 17 | topic: "{{ .Values.grr.pubsub.topic }}" 18 | } 19 | } 20 | {{- else}} 21 | factory: "GRPC" 22 | config { 23 | [type.googleapis.com/fleetspeak.grpcservice.Config] { 24 | target: "{{ .Release.Name }}-grr-frontend:{{ .Values.grr.frontend.listenPort }}" 25 | insecure: true 26 | } 27 | } 28 | {{- end }} 29 | } 30 | broadcast_poll_time { 31 | seconds: 1 32 | } 33 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-grr-frontend 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | labels: 9 | app: grr-frontend 10 | spec: 11 | replicas: {{ .Values.grr.frontend.replicas }} 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: grr-frontend 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: grr-frontend 19 | prometheus: grr-frontend 20 | spec: 21 | serviceAccountName: {{ .Release.Name }}-grr-sa 22 | affinity: 23 | nodeAffinity: 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: nodepool 29 | operator: In 30 | values: 31 | - grr 32 | initContainers: 33 | - name: init-fleetspeak-health-check 34 | image: bitnami/git 35 | command: ["/bin/sh", "-c"] 36 | args: 37 | - | 38 | set -e 39 | until [ "$(curl -s -w '%{http_code}' -o /dev/null http://{{ .Release.Name }}-grr-fleetspeak-admin:{{ .Values.fleetspeak.admin.healthCheckPort }})" -eq 200 ] 40 | do 41 | echo "Waiting for Fleetspeak Admin to be ready"; 42 | sleep 5; 43 | done 44 | echo "Fleetspeak Admin health check is ready" 45 | - name: init-exe-sign 46 | image: bitnami/git 47 | command: ["/bin/sh", "-c"] 48 | args: 49 | - | 50 | set -e 51 | cp /sign/keys/*.pem /grr/exe/sign/keys/ 52 | if [ -e /sign/keys/exe-sign.crt ] 53 | then 54 | echo "Extracting public key from certificate..." 55 | openssl x509 -in /sign/keys/exe-sign.crt -pubkey -noout > /grr/exe/sign/keys/exe-sign-public-key.pem 56 | fi 57 | volumeMounts: 58 | - name: grr-exe-sign-keys-volume 59 | mountPath: /grr/exe/sign/keys 60 | - name: grr-exe-sign-keys-secret 61 | mountPath: /sign/keys 62 | containers: 63 | - name: grr-frontend 64 | image: {{ .Values.grr.frontend.image }} 65 | {{- if .Values.global.useResourceRequests }} 66 | resources: 67 | requests: 68 | memory: "2Gi" 69 | cpu: "1000m" 70 | {{- end }} 71 | ports: 72 | - containerPort: {{ .Values.grr.frontend.listenPort }} 73 | name: frontend 74 | - containerPort: {{ .Values.prometheus.metricsPort }} 75 | name: metrics 76 | args: ["-component", "frontend", "-config", "/usr/src/grr/grr/core/install_data/etc/server.local.yaml", "--logtostderr"] 77 | volumeMounts: 78 | - name: grr-frontend-config 79 | mountPath: /usr/src/grr/grr/core/install_data/etc/server.local.yaml 80 | subPath: server.local.yaml 81 | - name: grr-exe-sign-keys-volume 82 | readOnly: true 83 | mountPath: "/grr/exe/sign/keys" 84 | volumes: 85 | - name: grr-frontend-config 86 | secret: 87 | secretName: {{ .Release.Name }}-grr-server-local 88 | items: 89 | - key: server.local.yaml 90 | path: server.local.yaml 91 | - name: grr-exe-sign-keys-secret 92 | secret: 93 | secretName: {{ .Release.Name }}-grr-executable-signing-keys 94 | - name: grr-exe-sign-keys-volume 95 | emptyDir: 96 | sizeLimit: 5Mi 97 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-grr-frontend 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | spec: 9 | selector: 10 | app.kubernetes.io/name: grr-frontend 11 | ports: 12 | - protocol: TCP 13 | name: frontend 14 | port: {{ .Values.grr.frontend.listenPort }} 15 | targetPort: {{ .Values.grr.frontend.listenPort }} 16 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.grr.namespace }} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ .Values.grr.namespace }} 6 | {{- end }} 7 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/server-local-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-grr-server-local 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | stringData: 9 | server.local.yaml: | 10 | Database.implementation: MysqlDB 11 | {{- if (and .Values.grr.blobstore .Values.grr.blobstore.bucket) }} 12 | Blobstore.implementation: GCSBlobStore 13 | Blobstore.gcs.project: {{ .Values.global.projectId }} 14 | Blobstore.gcs.bucket: {{ .Values.grr.blobstore.bucket }} 15 | {{- else }} 16 | Blobstore.implementation: DbBlobStore 17 | {{- end }} 18 | Mysql.host: {{ .Values.grr.mysqlDb.address }} 19 | Mysql.port: {{ .Values.grr.mysqlDb.port }} 20 | Mysql.database: {{ .Values.grr.mysqlDb.name }} 21 | Mysql.username: {{ .Values.grr.mysqlDb.userName }} 22 | Mysql.password: {{ .Values.grr.mysqlDb.userPassword }} 23 | Mysql.flow_processing_threads_max: 20 24 | AdminUI.csrf_secret_key: KPK,_0a_xY&DTeiaokEdsH1uXGobNIhfrr67BTSLlPPv64_UE0nyn8QsD6 25 | AdminUI.url: http://localhost:{{ .Values.grr.admin.listenPort }} 26 | AdminUI.bind: 0.0.0.0 27 | AdminUI.use_precompiled_js: true 28 | API.DefaultRouter: ApiCallRouterWithoutChecks 29 | 30 | Logging.domain: localhost 31 | Logging.verbose: true 32 | Logging.engines: file,stderr 33 | Logging.path: /grr 34 | Logging.filename: /grr/grr-server.log 35 | Monitoring.alert_email: grr-monitoring@localhost 36 | Monitoring.emergency_access_email: grr-emergency@localhost 37 | Monitoring.http_address: 0.0.0.0 38 | Monitoring.http_port: {{ .Values.prometheus.metricsPort }} 39 | 40 | Server.initialized: true 41 | Server.fleetspeak_server: {{ .Release.Name }}-grr-fleetspeak-admin:{{ .Values.fleetspeak.admin.listenPort }} 42 | Server.fleetspeak_message_listen_address: 0.0.0.0:{{ .Values.grr.frontend.listenPort }} 43 | {{- if (and .Values.grr.pubsub .Values.grr.pubsub.topic) }} 44 | Server.fleetspeak_cps_enabled: true 45 | Server.fleetspeak_cps_project: {{ .Values.grr.pubsub.project }} 46 | Server.fleetspeak_cps_subscription: {{ .Values.grr.pubsub.subscription }} 47 | Server.fleetspeak_cps_concurrency: 10 48 | {{- end }} 49 | 50 | # Configuration for repacking client templates: 51 | PrivateKeys.executable_signing_private_key: "%(/grr/exe/sign/keys/exe-sign-private-key.pem|file)" 52 | Client.executable_signing_public_key: "%(/grr/exe/sign/keys/exe-sign-public-key.pem|file)" 53 | 54 | ClientBuilder.fleetspeak_bundled: true 55 | ClientBuilder.template_dir: /client_templates 56 | ClientBuilder.executables_dir: /client_installers 57 | 58 | Target:Linux: 59 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 60 | Target:Windows: 61 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 62 | Target:Darwin: 63 | ClientBuilder.fleetspeak_client_config: /config/config.textproto 64 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ .Release.Name }}-grr-sa 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/grr/templates/worker-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-grr-worker 5 | {{- if .Values.grr.namespace }} 6 | namespace: {{ .Values.grr.namespace }} 7 | {{- end }} 8 | labels: 9 | app: grr-worker 10 | spec: 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: grr-worker 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: grr-worker 19 | prometheus: grr-worker 20 | spec: 21 | serviceAccountName: {{ .Release.Name }}-grr-sa 22 | affinity: 23 | nodeAffinity: 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: nodepool 29 | operator: In 30 | values: 31 | - grr 32 | initContainers: 33 | - name: init-fleetspeak-health-check 34 | image: bitnami/git 35 | command: ["/bin/sh", "-c"] 36 | args: 37 | - | 38 | set -e 39 | until [ "$(curl -s -w '%{http_code}' -o /dev/null http://{{ .Release.Name }}-grr-fleetspeak-admin:{{ .Values.fleetspeak.admin.healthCheckPort }})" -eq 200 ] 40 | do 41 | echo "Waiting for Fleetspeak Admin to be ready"; 42 | sleep 5; 43 | done 44 | echo "Fleetspeak Admin health check is ready" 45 | - name: init-exe-sign 46 | image: bitnami/git 47 | command: ["/bin/sh", "-c"] 48 | args: 49 | - | 50 | set -e 51 | cp /sign/keys/*.pem /grr/exe/sign/keys/ 52 | if [ -e /sign/keys/exe-sign.crt ] 53 | then 54 | echo "Extracting public key from certificate..." 55 | openssl x509 -in /sign/keys/exe-sign.crt -pubkey -noout > /grr/exe/sign/keys/exe-sign-public-key.pem 56 | fi 57 | volumeMounts: 58 | - name: grr-exe-sign-keys-volume 59 | mountPath: /grr/exe/sign/keys 60 | - name: grr-exe-sign-keys-secret 61 | mountPath: /sign/keys 62 | containers: 63 | - name: grr-worker 64 | image: {{ .Values.grr.worker.image }} 65 | {{- if .Values.global.useResourceRequests }} 66 | resources: 67 | requests: 68 | memory: "2Gi" 69 | cpu: "1000m" 70 | {{- end }} 71 | ports: 72 | - containerPort: {{ .Values.prometheus.metricsPort }} 73 | name: metrics 74 | args: ["-component", "worker", "-config", "/usr/src/grr/grr/core/install_data/etc/server.local.yaml", "--logtostderr"] 75 | volumeMounts: 76 | - name: grr-worker-config 77 | mountPath: /usr/src/grr/grr/core/install_data/etc/server.local.yaml 78 | subPath: server.local.yaml 79 | - name: grr-exe-sign-keys-volume 80 | readOnly: true 81 | mountPath: "/grr/exe/sign/keys" 82 | volumes: 83 | - name: grr-worker-config 84 | secret: 85 | secretName: {{ .Release.Name }}-grr-server-local 86 | items: 87 | - key: server.local.yaml 88 | path: server.local.yaml 89 | - name: grr-exe-sign-keys-secret 90 | secret: 91 | secretName: {{ .Release.Name }}-grr-executable-signing-keys 92 | - name: grr-exe-sign-keys-volume 93 | emptyDir: 94 | sizeLimit: 5Mi 95 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: hashr 3 | description: A Helm chart for HashR Kubernetes deployments. 4 | version: 2.0.0 5 | type: application 6 | keywords: 7 | - hashr 8 | - dfir 9 | - analysis 10 | - security 11 | home: "https://github.com/google/hashr" 12 | maintainers: 13 | - name: Open Source DFIR 14 | email: osdfir-maintainers@googlegroups.com 15 | url: https://github.com/google/osdfir-infrastructure 16 | sources: 17 | - https://github.com/google/hashr 18 | - https://github.com/google/osdfir-infrastructure 19 | appVersion: "latest" 20 | annotations: 21 | category: Security 22 | licenses: Apache-2.0 23 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "hashr.labels" -}} 5 | {{ include "hashr.selectorLabels" . }} 6 | helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }} 7 | app.kubernetes.io/managed-by: {{ .Release.Service }} 8 | date: "{{ now | htmlDate }}" 9 | {{- end }} 10 | 11 | {{/* 12 | Selector labels 13 | */}} 14 | {{- define "hashr.selectorLabels" -}} 15 | app.kubernetes.io/name: hashr 16 | app.kubernetes.io/instance: {{ .Release.Name }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/data-manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: {{ .Release.Name }}-hashr-data-manager 5 | spec: 6 | containers: 7 | - name: hashr-data-manager 8 | image: busybox:latest 9 | imagePullPolicy: IfNotPresent 10 | command: ["sh", "-c", "while true; do sleep 1800; done;"] 11 | volumeMounts: 12 | - name: hashrvolume 13 | mountPath: /mnt/hashrvolume/data 14 | restartPolicy: Always 15 | volumes: 16 | - name: hashrvolume 17 | persistentVolumeClaim: 18 | claimName: {{ .Release.Name }}-hashrvolume-claim 19 | readOnly: false 20 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-deb-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.deb.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-deb 6 | spec: 7 | schedule: {{ .Values.config.importers.deb.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-deb 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - deb 37 | - -deb_repo_path 38 | - /mnt/hashrvolume/data/deb/ 39 | env: 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: {{ .Release.Name }}-hashr-secret 44 | key: postgres-user 45 | volumeMounts: 46 | - name: hashrvolume 47 | mountPath: /mnt/hashrvolume/data 48 | restartPolicy: Never 49 | volumes: 50 | - name: hashrvolume 51 | persistentVolumeClaim: 52 | claimName: {{ .Release.Name }}-hashrvolume-claim 53 | readOnly: false 54 | {{- end }} 55 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-gcp-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.gcp.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-gcp 6 | spec: 7 | schedule: {{ .Values.config.importers.gcp.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-gcp 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - GCP 37 | - -gcp_projects 38 | - {{ .Values.config.importers.gcp.gcp_projects | quote }} 39 | - -hashr_gcp_project 40 | - {{ .Values.config.importers.gcp.hashr_gcp_project | quote }} 41 | - -hashr_gcs_bucket 42 | - {{ .Values.config.importers.gcp.hashr_gcs_bucket | quote }} 43 | env: 44 | - name: GOOGLE_APPLICATION_CREDENTIALS 45 | # Store your SA key in the hashrvolume/creds/ folder via "kubectl cp"! 46 | # chown 999:1000 hashr-sa-private-key.json to prevent permission issues 47 | value: {{ (include "hashr.dataPath" .) }}/creds/hashr-sa-private-key.json 48 | - name: POSTGRES_PASSWORD 49 | valueFrom: 50 | secretKeyRef: 51 | name: {{ include "postgresql.v1.secretName" .Subcharts.postgresql }} 52 | key: {{ include "postgresql.v1.adminPasswordKey" .Subcharts.postgresql }} 53 | volumeMounts: 54 | - name: hashrvolume 55 | mountPath: /mnt/hashrvolume/data 56 | restartPolicy: Never 57 | volumes: 58 | - name: hashrvolume 59 | persistentVolumeClaim: 60 | claimName: {{ include "hashr.pvc.name" . }} 61 | readOnly: false 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-iso9660-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.iso9660.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-iso9660 6 | spec: 7 | schedule: {{ .Values.config.importers.iso9660.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-iso9660 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - iso9660 37 | - -iso_repo_path 38 | - /mnt/hashrvolume/data/iso9660/ 39 | env: 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: {{ .Release.Name }}-hashr-secret 44 | key: postgres-user 45 | volumeMounts: 46 | - name: hashrvolume 47 | mountPath: /mnt/hashrvolume/data 48 | restartPolicy: Never 49 | volumes: 50 | - name: hashrvolume 51 | persistentVolumeClaim: 52 | claimName: {{ .Release.Name }}-hashrvolume-claim 53 | readOnly: false 54 | {{- end }} 55 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-rpm-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.rpm.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-rpm 6 | spec: 7 | schedule: {{ .Values.config.importers.rpm.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-rpm 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - rpm 37 | - -rpm_repo_path 38 | - /mnt/hashrvolume/data/rpm/ 39 | env: 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: {{ .Release.Name }}-hashr-secret 44 | key: postgres-user 45 | volumeMounts: 46 | - name: hashrvolume 47 | mountPath: /mnt/hashrvolume/data 48 | restartPolicy: Never 49 | volumes: 50 | - name: hashrvolume 51 | persistentVolumeClaim: 52 | claimName: {{ .Release.Name }}-hashrvolume-claim 53 | readOnly: false 54 | {{- end }} 55 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-targz-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.targz.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-targz 6 | spec: 7 | schedule: {{ .Values.config.importers.targz.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-targz 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - targz 37 | - -targz_repo_path 38 | - /mnt/hashrvolume/data/targz/ 39 | env: 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: {{ .Release.Name }}-hashr-secret 44 | key: postgres-user 45 | volumeMounts: 46 | - name: hashrvolume 47 | mountPath: /mnt/hashrvolume/data 48 | restartPolicy: Never 49 | volumes: 50 | - name: hashrvolume 51 | persistentVolumeClaim: 52 | claimName: {{ .Release.Name }}-hashrvolume-claim 53 | readOnly: false 54 | {{- end }} 55 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/hashr-zip-cronjob.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.config.importers.zip.enabled -}} 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: {{ .Release.Name }}-hashr-zip 6 | spec: 7 | schedule: {{ .Values.config.importers.zip.schedule | quote }} 8 | concurrencyPolicy: Forbid 9 | successfulJobsHistoryLimit: 2 10 | failedJobsHistoryLimit: 1 11 | jobTemplate: 12 | spec: 13 | template: 14 | spec: 15 | containers: 16 | - name: hashr-zip 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | args: 20 | - --logtostderr=1 21 | - -storage 22 | - postgres 23 | - -exporters 24 | - postgres 25 | - -postgres_host 26 | - {{ printf "%s-hashr-postgres" (.Release.Name) }} 27 | - -postgres_port 28 | - '5432' 29 | - -postgres_user 30 | - postgres 31 | - -postgres_password 32 | - "$(POSTGRES_PASSWORD)" 33 | - -postgres_db 34 | - hashr 35 | - -importers 36 | - zip 37 | - -zip_repo_path 38 | - /mnt/hashrvolume/data/zip/ 39 | env: 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: {{ .Release.Name }}-hashr-secret 44 | key: postgres-user 45 | volumeMounts: 46 | - name: hashrvolume 47 | mountPath: /mnt/hashrvolume/data 48 | restartPolicy: Never 49 | volumes: 50 | - name: hashrvolume 51 | persistentVolumeClaim: 52 | claimName: {{ .Release.Name }}-hashrvolume-claim 53 | readOnly: false 54 | {{- end }} 55 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/postgres/postgres-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-hashr-postgres-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: postgres 7 | {{- include "hashr.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 5432 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: postgres 18 | policyTypes: 19 | - Ingress 20 | - Egress 21 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/postgres/postgres-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-hashr-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "hashr.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 5432 13 | protocol: TCP 14 | targetPort: 5432 15 | selector: 16 | app.kubernetes.io/component: postgres 17 | {{- include "hashr.selectorLabels" . | nindent 4 }} 18 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/postgres/postgres-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-hashr-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: postgres 8 | {{- include "hashr.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: postgres 14 | {{- include "hashr.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: postgres 19 | {{- include "hashr.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | supplementalGroups: [] 25 | sysctls: [] 26 | hostNetwork: false 27 | hostIPC: false 28 | automountServiceAccountToken: false 29 | containers: 30 | - name: postgres 31 | securityContext: 32 | allowPrivilegeEscalation: false 33 | capabilities: 34 | drop: 35 | - ALL 36 | privileged: false 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}" 45 | imagePullPolicy: IfNotPresent 46 | env: 47 | - name: POSTGRES_DB 48 | value: hashr 49 | - name: POSTGRES_USER 50 | value: postgres 51 | - name: POSTGRES_PASSWORD 52 | valueFrom: 53 | secretKeyRef: 54 | name: {{ .Release.Name }}-hashr-secret 55 | key: postgres-user 56 | - name: PGDATA 57 | value: /mnt/postgres/data 58 | volumeMounts: 59 | - mountPath: /mnt/postgres/ 60 | name: data 61 | - mountPath: /var/run/postgresql 62 | name: emptydir 63 | - mountPath: /tmp 64 | name: emptydir 65 | ports: 66 | - containerPort: 5432 67 | resources: 68 | {{- toYaml .Values.postgresql.resources | nindent 12 }} 69 | {{- with .Values.postgresql.nodeSelector }} 70 | nodeSelector: 71 | {{- toYaml . | nindent 8 }} 72 | {{- end }} 73 | volumes: 74 | - name: emptydir 75 | emptyDir: {} 76 | volumeClaimTemplates: 77 | - metadata: 78 | name: data 79 | spec: 80 | accessModes: [ "ReadWriteOnce" ] 81 | resources: 82 | requests: 83 | storage: {{ .Values.postgresql.persistence.size }} 84 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: {{ .Release.Name }}-hashrvolume-claim 5 | namespace: {{ .Release.Namespace | quote }} 6 | spec: 7 | {{- if .Values.persistence.storageClass }} 8 | storageClassName: {{ .Values.persistence.storageClass }} 9 | {{- end }} 10 | accessModes: 11 | {{- range .Values.persistence.accessModes }} 12 | - {{ . | quote }} 13 | {{- end }} 14 | resources: 15 | requests: 16 | storage: {{ .Values.persistence.size | quote }} 17 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/hashr/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-hashr-secret 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "hashr.labels" . | nindent 4 }} 8 | data: 9 | {{- if .Release.IsUpgrade }} 10 | {{ $secretName := printf "%s-hashr-secret" (.Release.Name) }} 11 | postgres-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "postgres-user" }} 12 | {{- else }} 13 | postgres-user: {{ randAlphaNum 16 | b64enc | quote }} 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: openrelik 3 | version: 2.1.2 4 | description: A Helm chart for Openrelik Kubernetes deployments. 5 | keywords: 6 | - openrelik 7 | - dfir 8 | - analysis 9 | - forensics 10 | home: "https://openrelik.org/" 11 | maintainers: 12 | - name: Open Source DFIR 13 | email: osdfir-maintainers@googlegroups.com 14 | url: https://github.com/google/osdfir-infrastructure 15 | sources: 16 | - https://github.com/openrelik 17 | - https://github.com/google/osdfir-infrastructure 18 | icon: https://openrelik.org/favicon.ico 19 | appVersion: "latest" 20 | annotations: 21 | category: Security 22 | licenses: Apache-2.0 -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}:{{ .Chart.Version }} 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | $ helm status {{ .Release.Name }} 7 | $ helm get all {{ .Release.Name }} 8 | $ kubectl get pods 9 | 10 | To connect to the OpenRelik URL: 11 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-openrelik 8711:8711 12 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-openrelik-api 8710:8710 13 | $ echo "Visit http://localhost:8711 to access OpenRelik UI through port-forwarding" 14 | 15 | Login to OpenRelik with the User `openrelik`. To get your password run: 16 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-openrelik-secret -o jsonpath="{.data.openrelik-user}" | base64 -d 17 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "openrelik.labels" -}} 5 | {{ include "openrelik.selectorLabels" . }} 6 | helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }} 7 | app.kubernetes.io/managed-by: {{ .Release.Service }} 8 | date: "{{ now | htmlDate }}" 9 | {{- end }} 10 | 11 | {{/* 12 | Selector labels 13 | */}} 14 | {{- define "openrelik.selectorLabels" -}} 15 | app.kubernetes.io/name: openrelik 16 | app.kubernetes.io/instance: {{ .Release.Name }} 17 | {{- end }} 18 | 19 | {{- define "openrelik.oidc.authenticatedemails" -}} 20 | {{- if .Values.config.oidc.authenticatedEmailsFile.existingSecret -}} 21 | {{- .Values.config.oidc.authenticatedEmailsFile.existingSecret -}} 22 | {{- else -}} 23 | {{- printf "%s-openrelik-access-list" (.Release.Name) -}} 24 | {{- end -}} 25 | {{- end -}} 26 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/_initContainer.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Init Container for when a OpenRelik server starts. Required for setting up 3 | OIDC when enabled due to the changes having to be in settings.toml 4 | */}} 5 | {{- define "openrelik.initContainer" -}} 6 | - name: init-openrelik 7 | image: ubuntu 8 | command: ['sh', '-c', '/init/init-openrelik.sh'] 9 | {{- if and .Values.config.oidc.enabled .Values.config.oidc.existingSecret }} 10 | env: 11 | - name: OIDC_CLIENT_ID 12 | valueFrom: 13 | secretKeyRef: 14 | name: {{ .Values.config.oidc.existingSecret | quote }} 15 | key: "client-id" 16 | - name: OIDC_CLIENT_SECRET 17 | valueFrom: 18 | secretKeyRef: 19 | name: {{ .Values.config.oidc.existingSecret | quote }} 20 | key: "client-secret" 21 | {{- end }} 22 | volumeMounts: 23 | - mountPath: /tmp/openrelik/settings.toml 24 | subPath: settings.toml 25 | name: settings-config 26 | - mountPath: /init/ 27 | name: init-oidc 28 | - mountPath: /etc/openrelik 29 | name: openrelik-configs-dir 30 | {{- if .Values.config.oidc.authenticatedEmailsFile.enabled }} 31 | - name: authenticated-emails 32 | mountPath: /init/authenticated-emails 33 | readOnly: true 34 | {{- end }} 35 | {{- end }} 36 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/api-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-api 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | {{- if (eq .Values.global.ingress.className "gce") }} 9 | annotations: 10 | cloud.google.com/neg: '{"ingress": true}' 11 | cloud.google.com/backend-config: '{"ports": {"8710":"{{ .Release.Name }}-openrelik-api-backend-config"}}' 12 | {{- end }} 13 | spec: 14 | type: ClusterIP 15 | ports: 16 | - port: 8710 17 | protocol: TCP 18 | targetPort: 8710 19 | selector: 20 | app.kubernetes.io/component: api 21 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-configmap 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | data: 9 | settings.toml: | 10 | [server] 11 | 12 | # This should be set to the URL of your backend server. 13 | {{- if .Values.global.ingress.openRelikAPIHost }} 14 | api_server_url = "https://{{ .Values.global.ingress.openRelikAPIHost }}" 15 | {{- else }} 16 | api_server_url = "http://localhost:8710" 17 | {{- end }} 18 | 19 | # This should be set to the URL of your frontend server. 20 | {{- if .Values.global.ingress.openRelikFrontendHost }} 21 | ui_server_url = "https://{{ .Values.global.ingress.openRelikFrontendHost }}" 22 | {{- else }} 23 | ui_server_url = "http://localhost:8711" 24 | {{- end }} 25 | 26 | # This should be set to the URL of your frontend server. 27 | {{- if .Values.global.ingress.openRelikFrontendHost }} 28 | allowed_origins = ["https://{{ .Values.global.ingress.openRelikFrontendHost }}"] 29 | {{- else }} 30 | allowed_origins = ["http://localhost:8711"] 31 | {{- end }} 32 | 33 | # Path to files 34 | storage_path = "/mnt/openrelikvolume" 35 | 36 | [datastores.sqlalchemy] 37 | # Postgresql: postgresql://user:password@postgresserver/db 38 | database_url = "" 39 | 40 | [auth] 41 | # Secret key for the Session middleware and JWT signing. 42 | # IMPORTANT: Create a random string, e.g: openssl rand -base64 32 43 | secret_session_key = {{ randAlphaNum 32 | b64enc | quote }} 44 | secret_jwt_key = {{ randAlphaNum 32 | b64enc | quote }} 45 | 46 | # Algorithm to use for JWT. 47 | jwt_algorithm = "HS256" 48 | 49 | # UI token expiration in minutes. 50 | jwt_cookie_refresh_expire_minutes = 1440 # 24 hours 51 | jwt_cookie_access_expire_minutes = 720 # 12 hours 52 | 53 | # API key token expiration in minutes, if not set by the user upon creation. 54 | jwt_header_default_refresh_expire_minutes = 10080 # 7 days 55 | jwt_header_default_access_expire_minutes = 5 # 5 minutes 56 | 57 | [auth.google] 58 | # Google OAuth authentication. You need to create credentials in a Google Cloud project: 59 | # https://developers.google.com/workspace/guides/create-credentials#oauth-client-id 60 | client_id = "" 61 | client_secret = "" 62 | 63 | # Extra client_ids for apps that authenticate with OpenRelik using Google OAuth. 64 | extra_audiences = [] 65 | 66 | # Restrict logins from a Google Workspace domain. 67 | # Empty value = any domain, including gmail.com 68 | workspace_domain = "" 69 | 70 | # Allow only these users (email address) to access the server. 71 | allowlist = ["@gmail.com"] 72 | 73 | # Allow anyone (who is authenitcated) to access the server. 74 | # Note: If a workspace_domain is set then the public_access is limited to that domain. 75 | # WARNING: This allows anyone to login to your server! 76 | public_access = false 77 | 78 | [ui] 79 | # data_types that will be rendered using unescaped HTML in a sandboxed iframe in the 80 | # frontend UI. 81 | allowed_data_types_preview = [ 82 | "openrelik:hayabusa:html_report" 83 | ] 84 | 85 | # Enable cloud features such as adding cloud disks. 86 | # This requires your OpenRelik installation to run on cloud VMs. 87 | [cloud.gcp] 88 | name = "gcp" 89 | display_name = "Google Cloud Platform" 90 | project_name = "" 91 | zone = "" 92 | enabled = false -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-frontend 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: frontend 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: frontend 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: frontend 19 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 20 | spec: 21 | hostNetwork: false 22 | hostIPC: false 23 | automountServiceAccountToken: false 24 | containers: 25 | - name: frontend 26 | image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" 27 | imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} 28 | env: 29 | - name: OPENRELIK_SERVER_URL 30 | {{- if .Values.global.ingress.openRelikAPIHost }} 31 | value: https://{{ .Values.global.ingress.openRelikAPIHost }} 32 | {{- else }} 33 | value: http://localhost:8710 34 | {{- end }} 35 | - name: OPENRELIK_API_VERSION 36 | value: v1 37 | - name: OPENRELIK_AUTH_METHODS 38 | {{- if .Values.config.oidc.enabled }} 39 | value: local,google 40 | {{- else }} 41 | value: local 42 | {{- end }} 43 | volumeMounts: 44 | - mountPath: /mnt/openrelikvolume 45 | name: openrelikvolume 46 | ports: 47 | - containerPort: 8711 48 | resources: 49 | {{- toYaml .Values.frontend.resources | nindent 12 }} 50 | volumes: 51 | - name: openrelikvolume 52 | persistentVolumeClaim: 53 | {{- if .Values.persistence.existingPVC }} 54 | claimName: {{ .Values.persistence.existingPVC }} 55 | {{- else }} 56 | claimName: {{ .Release.Name }}-openrelikvolume-claim 57 | {{- end }} 58 | readOnly: false -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/frontend-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | {{- if (eq .Values.global.ingress.className "gce") }} 9 | annotations: 10 | cloud.google.com/neg: '{"ingress": true}' 11 | cloud.google.com/backend-config: '{"ports": {"8711":"{{ .Release.Name }}-openrelik-frontend-backend-config"}}' 12 | {{- end }} 13 | spec: 14 | type: ClusterIP 15 | ports: 16 | - port: 8711 17 | protocol: TCP 18 | targetPort: 8711 19 | selector: 20 | app.kubernetes.io/component: frontend 21 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/gcp/api-backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce")) }} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: {{ .Release.Name }}-openrelik-api-backend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | timeoutSec: 300 9 | healthCheck: 10 | checkIntervalSec: 300 11 | timeoutSec: 5 12 | healthyThreshold: 2 13 | unhealthyThreshold: 2 14 | type: HTTP 15 | requestPath: /openapi.json 16 | port: 8710 17 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/gcp/frontend-backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce")) }} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: {{ .Release.Name }}-openrelik-frontend-backend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | timeoutSec: 300 9 | healthCheck: 10 | checkIntervalSec: 300 11 | timeoutSec: 5 12 | healthyThreshold: 2 13 | unhealthyThreshold: 2 14 | type: HTTP 15 | requestPath: / 16 | port: 8711 17 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/init-oidc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-init-oidc 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | data: 9 | init-openrelik.sh: | 10 | #!/bin/sh 11 | set -e 12 | 13 | # Create openrelik config directory 14 | mkdir -p /etc/openrelik 15 | cd /etc/openrelik 16 | 17 | if [ $(ls /tmp/openrelik/ | wc -l) -gt 0 ]; then 18 | echo "Using existing configuration files provided." 19 | cp /tmp/openrelik/* /etc/openrelik/ 20 | fi 21 | 22 | # OIDC integration 23 | {{- if and .Values.config.oidc.enabled .Values.config.oidc.existingSecret }} 24 | sed -i 's#^client_id =.*#client_id = "'$OIDC_CLIENT_ID'"#' settings.toml 25 | sed -i 's#^client_secret =.*#client_secret = "'$OIDC_CLIENT_SECRET'"#' settings.toml 26 | 27 | {{- if .Values.config.oidc.authenticatedEmailsFile.enabled }} 28 | export EMAILS=$(awk '{printf "\"%s\", ", $0}' /init/authenticated-emails/authenticated-emails-list | sed 's/, $//; s/^/[/; s/$/]/') 29 | echo $EMAILS 30 | sed -i 's#^allowlist =.*#allowlist = '"$EMAILS"'#' settings.toml 31 | {{- end }} 32 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/mediator-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-mediator 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: mediator 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: mediator 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: mediator 19 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 20 | spec: 21 | hostNetwork: false 22 | hostIPC: false 23 | automountServiceAccountToken: false 24 | containers: 25 | - name: mediator 26 | image: "{{ .Values.mediator.image.repository }}:{{ .Values.mediator.image.tag }}" 27 | imagePullPolicy: {{ .Values.mediator.image.pullPolicy }} 28 | command: ["/bin/sh", "-c", "python mediator.py"] 29 | env: 30 | - name: PYTHONUNBUFFERED 31 | value: "1" 32 | - name: REDIS_URL 33 | valueFrom: 34 | secretKeyRef: 35 | name: {{ .Release.Name }}-openrelik-secret 36 | key: redis-url 37 | - name: SQLALCHEMY_DATABASE_URL 38 | valueFrom: 39 | secretKeyRef: 40 | name: {{ .Release.Name }}-openrelik-secret 41 | key: postgres-url 42 | - name: OPENRELIK_SERVER_SETTINGS 43 | value: /mediator/settings.toml 44 | volumeMounts: 45 | - mountPath: /mnt/openrelikvolume 46 | name: openrelikvolume 47 | - mountPath: /mediator/settings.toml 48 | subPath: settings.toml 49 | name: settings-config 50 | ports: 51 | - containerPort: 8710 52 | resources: 53 | {{- toYaml .Values.mediator.resources | nindent 12 }} 54 | volumes: 55 | - name: openrelikvolume 56 | persistentVolumeClaim: 57 | {{- if .Values.persistence.existingPVC }} 58 | claimName: {{ .Values.persistence.existingPVC }} 59 | {{- else }} 60 | claimName: {{ .Release.Name }}-openrelikvolume-claim 61 | {{- end }} 62 | readOnly: false 63 | - name: settings-config 64 | configMap: 65 | name: {{ .Release.Name }}-openrelik-configmap -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/metrics-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-metrics 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: metrics 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: metrics 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | annotations: 18 | prometheus.io/port: "8080" 19 | prometheus.io/scrape: "true" 20 | labels: 21 | app.kubernetes.io/component: metrics 22 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 23 | spec: 24 | hostNetwork: false 25 | hostIPC: false 26 | automountServiceAccountToken: false 27 | containers: 28 | - name: mediator 29 | image: "{{ .Values.metrics.image.repository }}:{{ .Values.metrics.image.tag }}" 30 | imagePullPolicy: {{ .Values.metrics.image.pullPolicy }} 31 | command: ["/bin/sh", "-c", "python exporter.py"] 32 | env: 33 | - name: REDIS_URL 34 | valueFrom: 35 | secretKeyRef: 36 | name: {{ .Release.Name }}-openrelik-secret 37 | key: redis-url 38 | ports: 39 | - containerPort: 8080 40 | resources: 41 | {{- toYaml .Values.metrics.resources | nindent 12 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/metrics-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-metrics 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | targetPort: 8080 14 | selector: 15 | app.kubernetes.io/component: metrics 16 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/postgres/postgres-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 5432 13 | protocol: TCP 14 | targetPort: 5432 15 | selector: 16 | app.kubernetes.io/component: postgres 17 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/postgres/postgres-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: postgres 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: postgres 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: postgres 19 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | supplementalGroups: [] 25 | sysctls: [] 26 | hostNetwork: false 27 | hostIPC: false 28 | automountServiceAccountToken: false 29 | containers: 30 | - name: postgres 31 | securityContext: 32 | allowPrivilegeEscalation: false 33 | capabilities: 34 | drop: 35 | - ALL 36 | privileged: false 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}" 45 | imagePullPolicy: IfNotPresent 46 | env: 47 | - name: POSTGRES_DB 48 | value: openrelik 49 | - name: POSTGRES_USER 50 | value: postgres 51 | - name: POSTGRES_PASSWORD 52 | valueFrom: 53 | secretKeyRef: 54 | name: {{ .Release.Name }}-openrelik-secret 55 | key: postgres-user 56 | - name: PGDATA 57 | value: /mnt/postgres/data 58 | volumeMounts: 59 | - mountPath: /mnt/postgres/ 60 | name: data 61 | - mountPath: /var/run/postgresql 62 | name: emptydir 63 | - mountPath: /tmp 64 | name: emptydir 65 | ports: 66 | - containerPort: 5432 67 | resources: 68 | {{- toYaml .Values.postgresql.resources | nindent 12 }} 69 | volumes: 70 | - name: emptydir 71 | emptyDir: {} 72 | volumeClaimTemplates: 73 | - metadata: 74 | name: data 75 | spec: 76 | accessModes: [ "ReadWriteOnce" ] 77 | resources: 78 | requests: 79 | storage: {{ .Values.postgresql.persistence.size }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/prometheus/prometheus-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-prometheus-configmap 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | data: 9 | prometheus.yml: | 10 | global: 11 | scrape_interval: 10s 12 | external_labels: 13 | monitor: "openrelik" 14 | scrape_configs: 15 | - job_name: "celery" 16 | static_configs: 17 | - targets: ["{{ .Release.Name }}-openrelik-metrics:8080"] 18 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/prometheus/prometheus-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-prometheus 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: prometheus 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: prometheus 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: prometheus 19 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 20 | spec: 21 | hostNetwork: false 22 | hostIPC: false 23 | automountServiceAccountToken: false 24 | containers: 25 | - name: prometheus 26 | image: "{{ .Values.prometheus.image.repository }}:{{ .Values.prometheus.image.tag }}" 27 | imagePullPolicy: Always 28 | ports: 29 | - containerPort: 9090 30 | volumeMounts: 31 | - mountPath: /etc/prometheus/prometheus.yml 32 | subPath: prometheus.yml 33 | name: prometheus-config 34 | resources: 35 | {{- toYaml .Values.prometheus.resources | nindent 12 }} 36 | volumes: 37 | - name: prometheus-config 38 | configMap: 39 | name: {{ .Release.Name }}-openrelik-prometheus-configmap 40 | defaultMode: 420 -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/prometheus/prometheus-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-prometheus 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 9090 13 | protocol: TCP 14 | targetPort: 9090 15 | selector: 16 | app.kubernetes.io/component: prometheus 17 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if not .Values.persistence.existingPVC }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ .Release.Name }}-openrelikvolume-claim 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | {{- if .Values.persistence.storageClass }} 9 | storageClassName: {{ .Values.persistence.storageClass }} 10 | {{- end }} 11 | accessModes: 12 | {{- range .Values.persistence.accessModes }} 13 | - {{ . | quote }} 14 | {{- end }} 15 | resources: 16 | requests: 17 | storage: {{ .Values.persistence.size | quote }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/redis/redis-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-redis-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: redis 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 6379 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: redis 18 | policyTypes: 19 | - Ingress 20 | - Egress -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/redis/redis-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 6379 13 | protocol: TCP 14 | targetPort: 6379 15 | selector: 16 | app.kubernetes.io/component: redis 17 | {{- include "openrelik.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/redis/redis-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: redis 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: redis 14 | {{- include "openrelik.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: redis 19 | {{- include "openrelik.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | hostNetwork: false 25 | hostIPC: false 26 | automountServiceAccountToken: false 27 | containers: 28 | - name: redis 29 | image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" 30 | imagePullPolicy: IfNotPresent 31 | command: ["redis-server" , "--appendonly yes"] 32 | securityContext: 33 | allowPrivilegeEscalation: false 34 | capabilities: 35 | drop: 36 | - ALL 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | env: 45 | - name: REDIS_PASSWORD 46 | valueFrom: 47 | secretKeyRef: 48 | name: {{ .Release.Name }}-openrelik-secret 49 | key: redis-user 50 | - name: REDIS_REPLICATION_MODE 51 | value: "master" 52 | - name: ALLOW_EMPTY_PASSWORD 53 | value: "no" 54 | volumeMounts: 55 | - mountPath: /data 56 | name: data 57 | ports: 58 | - containerPort: 6379 59 | resources: 60 | {{- toYaml .Values.redis.resources | nindent 12 }} 61 | volumeClaimTemplates: 62 | - metadata: 63 | name: data 64 | spec: 65 | accessModes: [ "ReadWriteOnce" ] 66 | resources: 67 | requests: 68 | storage: {{ .Values.redis.persistence.size }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/secret-oidc-allowed-users.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.config.oidc.authenticatedEmailsFile.enabled) (not .Values.config.oidc.authenticatedEmailsFile.existingSecret) }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ .Release.Name }}-openrelik-access-list 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "openrelik.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | authenticated-emails-list: {{ .Values.config.oidc.authenticatedEmailsFile.content | b64enc | quote }} 12 | {{- end -}} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-openrelik-secret 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "openrelik.labels" . | nindent 4 }} 8 | data: 9 | {{- if .Release.IsUpgrade }} 10 | {{ $secretName := printf "%s-openrelik-secret" (.Release.Name) }} 11 | openrelik-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "openrelik-user" }} 12 | postgres-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "postgres-user" }} 13 | postgres-url: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "postgres-url" }} 14 | redis-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "redis-user" }} 15 | redis-url: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "redis-url" }} 16 | {{- else }} 17 | {{ $postgresUser := randAlphaNum 16 }} 18 | {{ $redisUser := randAlphaNum 16 }} 19 | openrelik-user: {{ randAlphaNum 16 | b64enc | quote }} 20 | postgres-user: {{ $postgresUser | b64enc | quote }} 21 | postgres-url: {{ printf "postgresql://postgres:%s@%s-openrelik-postgres:5432/openrelik" $postgresUser .Release.Name | b64enc | quote }} 22 | redis-user: {{ $redisUser | b64enc | quote }} 23 | redis-url: {{ printf "redis://default:%s@%s-openrelik-redis:6379" $redisUser .Release.Name | b64enc | quote }} 24 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/openrelik/templates/worker-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- range .Values.workers }} 2 | --- 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: {{ $.Release.Name }}-{{ .name }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app.kubernetes.io/component: worker 12 | template: 13 | metadata: 14 | labels: 15 | app.kubernetes.io/component: worker 16 | spec: 17 | hostNetwork: false 18 | hostIPC: false 19 | automountServiceAccountToken: false 20 | containers: 21 | - name: worker 22 | image: {{ .image | quote }} 23 | imagePullPolicy: "IfNotPresent" 24 | command: ["/bin/sh", "-c", "{{ .command }}"] 25 | env: 26 | {{- if and (eq .name "openrelik-worker-timesketch") $.Values.global.timesketch.enabled }} 27 | - name: TIMESKETCH_SERVER_URL 28 | value: {{ printf "http://%s-timesketch:5000" $.Release.Name | quote }} 29 | - name: TIMESKETCH_USERNAME 30 | value: timesketch 31 | - name: TIMESKETCH_PASSWORD 32 | valueFrom: 33 | secretKeyRef: 34 | name: {{ printf "%s-timesketch-secret" $.Release.Name | quote }} 35 | key: timesketch-user 36 | {{- else if .env }} 37 | {{- toYaml .env | nindent 12 }} 38 | {{- end }} 39 | - name: REDIS_URL 40 | valueFrom: 41 | secretKeyRef: 42 | name: {{ $.Release.Name }}-openrelik-secret 43 | key: redis-url 44 | volumeMounts: 45 | - mountPath: /mnt/openrelikvolume 46 | name: openrelikvolume 47 | {{- if .resources }} 48 | resources: 49 | {{- toYaml .resources | nindent 12 }} 50 | {{- end }} 51 | volumes: 52 | - name: openrelikvolume 53 | persistentVolumeClaim: 54 | {{- if $.Values.persistence.existingPVC }} 55 | claimName: {{ $.Values.persistence.existingPVC }} 56 | {{- else }} 57 | claimName: {{ $.Release.Name }}-openrelikvolume-claim 58 | {{- end }} 59 | readOnly: false 60 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: timesketch 3 | version: 2.1.3 4 | description: A Helm chart for Timesketch Kubernetes deployments. 5 | keywords: 6 | - timesketch 7 | - dfir 8 | - analysis 9 | - security 10 | home: "https://timesketch.org/" 11 | maintainers: 12 | - name: Open Source DFIR 13 | email: osdfir-maintainers@googlegroups.com 14 | url: https://github.com/google/osdfir-infrastructure 15 | sources: 16 | - https://github.com/google/timesketch 17 | - https://github.com/google/osdfir-infrastructure 18 | icon: https://raw.githubusercontent.com/google/timesketch/master/timesketch/frontend-ng/dist/timesketch-color.png 19 | appVersion: "20240828" 20 | annotations: 21 | category: Security 22 | licenses: Apache-2.0 23 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}:{{ .Chart.Version }} 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | $ helm status {{ .Release.Name }} 7 | $ helm get all {{ .Release.Name }} 8 | $ kubectl get pods 9 | 10 | To connect to the Timesketch URL: 11 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-timesketch 5000:5000 12 | $ echo "Visit http://127.0.0.1:5000 to access Timesketch through port-forwarding" 13 | 14 | {{ if .Values.config.createUser -}} 15 | Login to Timesketch with the User `timesketch`. To get your password run: 16 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-timesketch-secret -o jsonpath="{.data.timesketch-user}" | base64 -d; echo "" 17 | {{- end }} 18 | 19 | Run the following commands on your workstation to orchestrate collection and processing of forensic data with dfTimewolf: 20 | $ git clone https://github.com/log2timeline/dftimewolf && cd dftimewolf 21 | $ pip3 install poetry 22 | $ poetry install && poetry shell 23 | $ dftimewolf -h 24 | $ To configure with Timesketch, use the credentials provided in this chart when prompted -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "timesketch.labels" -}} 5 | {{ include "timesketch.selectorLabels" . }} 6 | helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }} 7 | app.kubernetes.io/managed-by: {{ .Release.Service }} 8 | date: "{{ now | htmlDate }}" 9 | {{- end }} 10 | 11 | {{/* 12 | Selector labels 13 | */}} 14 | {{- define "timesketch.selectorLabels" -}} 15 | app.kubernetes.io/name: timesketch 16 | app.kubernetes.io/instance: {{ .Release.Name }} 17 | {{- end }} 18 | 19 | {{/* 20 | Redis connection url 21 | */}} 22 | {{- define "timesketch.redis.url" -}} 23 | {{- $name := printf "%s-timesketch-redis" (.Release.Name) -}} 24 | {{- printf "redis://default:'$REDIS_PASSWORD'@%s:6379" $name -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Postgresql connection url 29 | */}} 30 | {{- define "timesketch.postgresql.url" -}} 31 | {{- $name := printf "%s-timesketch-postgres" (.Release.Name) -}} 32 | {{- printf "postgresql://postgres:'$POSTGRES_PASSWORD'@%s:5432/timesketch" $name -}} 33 | {{- end -}} 34 | 35 | {{/* 36 | Opensearch host name 37 | */}} 38 | {{- define "timesketch.opensearch.host" -}} 39 | {{- printf "%s-opensearch-cluster" .Release.Name -}} 40 | {{- end -}} 41 | 42 | {{/* 43 | Opensearch endpoints 44 | */}} 45 | {{- define "timesketch.opensearch.endpoints" -}} 46 | {{- $replicas := int (toString (.Values.opensearch.replicas)) }} 47 | {{- $uname := printf "%s-opensearch-cluster" (.Release.Name) }} 48 | {{- range $i, $e := untilStep 0 $replicas 1 -}} 49 | {{ $uname }}-{{ $i }}, 50 | {{- end -}} 51 | {{- end -}} 52 | 53 | {{- define "timesketch.oidc.authenticatedemails" -}} 54 | {{- if .Values.config.oidc.authenticatedEmailsFile.existingSecret -}} 55 | {{- .Values.config.oidc.authenticatedEmailsFile.existingSecret -}} 56 | {{- else -}} 57 | {{- printf "%s-timesketch-access-list" (.Release.Name) -}} 58 | {{- end -}} 59 | {{- end -}} 60 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/_initContainer.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Init Container for when a Timesketch pod starts. To prevent duplicate code, 3 | this file has been created which then applies to both the Timesketch Web and 4 | Worker pod upon startup. 5 | */}} 6 | {{- define "timesketch.initContainer" -}} 7 | - name: init-timesketch 8 | image: alpine/git 9 | command: ['sh', '-c', '/init/init-timesketch.sh'] 10 | env: 11 | - name: TIMESKETCH_SECRET 12 | valueFrom: 13 | secretKeyRef: 14 | name: {{ .Release.Name }}-timesketch-secret 15 | key: timesketch-secret 16 | - name: REDIS_PASSWORD 17 | valueFrom: 18 | secretKeyRef: 19 | name: {{ .Release.Name }}-timesketch-secret 20 | key: redis-user 21 | - name: POSTGRES_PASSWORD 22 | valueFrom: 23 | secretKeyRef: 24 | name: {{ .Release.Name }}-timesketch-secret 25 | key: postgres-user 26 | {{- if .Values.global.yeti.enabled }} 27 | - name: YETI_API_KEY 28 | valueFrom: 29 | secretKeyRef: 30 | name: {{ printf "%s-yeti-secret" .Release.Name }} 31 | key: "yeti-api" 32 | {{- end }} 33 | {{- if .Values.global.hashr.enabled }} 34 | - name: HASHR_POSTGRES_KEY 35 | valueFrom: 36 | secretKeyRef: 37 | name: {{ printf "%s-hashr-secret" .Release.Name }} 38 | key: "postgres-user" 39 | {{- end }} 40 | {{- if and .Values.config.oidc.enabled .Values.config.oidc.existingSecret }} 41 | - name: OIDC_CLIENT_ID 42 | valueFrom: 43 | secretKeyRef: 44 | name: {{ .Values.config.oidc.existingSecret | quote }} 45 | key: "client-id" 46 | - name: OIDC_CLIENT_SECRET 47 | valueFrom: 48 | secretKeyRef: 49 | name: {{ .Values.config.oidc.existingSecret | quote }} 50 | key: "client-secret" 51 | - name: OIDC_CLIENT_ID_NATIVE 52 | valueFrom: 53 | secretKeyRef: 54 | name: {{ .Values.config.oidc.existingSecret | quote }} 55 | key: "client-id-native" 56 | optional: true 57 | {{- end }} 58 | volumeMounts: 59 | - mountPath: /init 60 | name: init-timesketch 61 | - mountPath: /etc/timesketch 62 | name: timesketch-configs 63 | {{- if .Values.config.existingConfigMap }} 64 | - mountPath: /tmp/timesketch 65 | name: uploaded-configs 66 | {{- end }} 67 | {{- if .Values.config.oidc.authenticatedEmailsFile.enabled }} 68 | - name: authenticated-emails 69 | mountPath: /init/authenticated-emails 70 | readOnly: true 71 | {{- end }} 72 | {{- end }} 73 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/gcp/backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce")) }} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: {{ .Release.Name }}-timesketch-backend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | timeoutSec: 300 9 | healthCheck: 10 | checkIntervalSec: 5 11 | timeoutSec: 5 12 | healthyThreshold: 2 13 | unhealthyThreshold: 2 14 | type: HTTP 15 | requestPath: /healthz/ 16 | port: 8080 17 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/nginx/nginx-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.ingress.enabled) -}} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ .Release.Name }}-timesketch-nginx-configmap 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | data: 10 | default.conf: | 11 | server { 12 | listen 8080; 13 | listen [::]:8080; 14 | client_max_body_size 0m; 15 | location / { 16 | proxy_buffer_size 128k; 17 | proxy_buffers 4 256k; 18 | proxy_busy_buffers_size 256k; 19 | proxy_pass http://{{ .Release.Name }}-timesketch:5000/; 20 | proxy_read_timeout 120s; 21 | proxy_set_header Host $host; 22 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 23 | proxy_set_header X-Forwarded-Proto $scheme; 24 | } 25 | location /healthz { 26 | return 200; 27 | } 28 | } 29 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/nginx/nginx-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.ingress.enabled) -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ .Release.Name }}-timesketch-nginx 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | app.kubernetes.io/component: nginx 9 | {{- include "timesketch.labels" . | nindent 4 }} 10 | spec: 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/component: nginx 15 | {{- include "timesketch.selectorLabels" . | nindent 6 }} 16 | template: 17 | metadata: 18 | labels: 19 | app.kubernetes.io/component: nginx 20 | {{- include "timesketch.selectorLabels" . | nindent 8 }} 21 | spec: 22 | securityContext: 23 | fsGroup: 101 24 | fsGroupChangePolicy: Always 25 | hostNetwork: false 26 | hostIPC: false 27 | automountServiceAccountToken: false 28 | containers: 29 | - name: nginx 30 | image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" 31 | imagePullPolicy: IfNotPresent 32 | securityContext: 33 | allowPrivilegeEscalation: false 34 | capabilities: 35 | drop: 36 | - ALL 37 | privileged: false 38 | readOnlyRootFilesystem: true 39 | runAsGroup: 101 40 | runAsNonRoot: true 41 | runAsUser: 101 42 | seLinuxOptions: {} 43 | seccompProfile: 44 | type: RuntimeDefault 45 | volumeMounts: 46 | - mountPath: /etc/nginx/conf.d/default.conf 47 | subPath: default.conf 48 | name: nginx-config 49 | readOnly: true 50 | - mountPath: /var/cache/nginx 51 | name: tmp 52 | - mountPath: /var/run/ 53 | name: tmp 54 | ports: 55 | - containerPort: 8080 56 | resources: 57 | {{- toYaml .Values.nginx.resources | nindent 12 }} 58 | volumes: 59 | - name: tmp 60 | emptyDir: {} 61 | - name: nginx-config 62 | configMap: 63 | name: {{ .Release.Name }}-timesketch-nginx-configmap 64 | {{- with .Values.nginx.nodeSelector }} 65 | nodeSelector: 66 | {{- toYaml . | nindent 8 }} 67 | {{- end }} 68 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/nginx/nginx-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-nginx-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: nginx 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 8080 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: nginx 18 | policyTypes: 19 | - Ingress 20 | - Egress -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/nginx/nginx-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.ingress.enabled) -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ .Release.Name }}-timesketch-nginx 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | {{- if (eq .Values.global.ingress.className "gce") }} 10 | annotations: 11 | cloud.google.com/neg: '{"ingress": true}' 12 | cloud.google.com/backend-config: '{"ports": {"8080":"{{ .Release.Name }}-timesketch-backend-config"}}' 13 | {{- end }} 14 | spec: 15 | type: ClusterIP 16 | ports: 17 | - port: 8080 18 | protocol: TCP 19 | targetPort: 8080 20 | selector: 21 | app.kubernetes.io/component: nginx 22 | {{- include "timesketch.selectorLabels" . | nindent 4 }} 23 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/opensearch/opensearch-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-opensearch-cluster 5 | annotations: 6 | service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" 7 | spec: 8 | type: ClusterIP 9 | clusterIP: None 10 | # Create endpoints also if the related pod isn't ready 11 | publishNotReadyAddresses: true 12 | ports: 13 | - name: http 14 | port: 9200 15 | targetPort: 9200 16 | - name: transport 17 | port: 9300 18 | targetPort: 9300 19 | - name: metrics 20 | port: 9600 21 | targetPort: 9600 22 | selector: 23 | app.kubernetes.io/component: opensearch -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/postgres/postgres-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-postgres-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: postgres 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 5432 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: postgres 18 | policyTypes: 19 | - Ingress 20 | - Egress -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/postgres/postgres-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 5432 13 | protocol: TCP 14 | targetPort: 5432 15 | selector: 16 | app.kubernetes.io/component: postgres 17 | {{- include "timesketch.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/postgres/postgres-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-postgres 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: postgres 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: postgres 14 | {{- include "timesketch.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: postgres 19 | {{- include "timesketch.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | supplementalGroups: [] 25 | sysctls: [] 26 | hostNetwork: false 27 | hostIPC: false 28 | automountServiceAccountToken: false 29 | containers: 30 | - name: postgres 31 | securityContext: 32 | allowPrivilegeEscalation: false 33 | capabilities: 34 | drop: 35 | - ALL 36 | privileged: false 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}" 45 | imagePullPolicy: IfNotPresent 46 | env: 47 | - name: POSTGRES_DB 48 | value: timesketch 49 | - name: POSTGRES_USER 50 | value: postgres 51 | - name: POSTGRES_PASSWORD 52 | valueFrom: 53 | secretKeyRef: 54 | name: {{ .Release.Name }}-timesketch-secret 55 | key: postgres-user 56 | - name: PGDATA 57 | value: /mnt/postgres/data 58 | volumeMounts: 59 | - mountPath: /mnt/postgres/ 60 | name: data 61 | - mountPath: /var/run/postgresql 62 | name: emptydir 63 | - mountPath: /tmp 64 | name: emptydir 65 | ports: 66 | - containerPort: 5432 67 | resources: 68 | {{- toYaml .Values.postgresql.resources | nindent 12 }} 69 | {{- with .Values.postgresql.nodeSelector }} 70 | nodeSelector: 71 | {{- toYaml . | nindent 8 }} 72 | {{- end }} 73 | volumes: 74 | - name: emptydir 75 | emptyDir: {} 76 | volumeClaimTemplates: 77 | - metadata: 78 | name: data 79 | spec: 80 | accessModes: [ "ReadWriteOnce" ] 81 | resources: 82 | requests: 83 | storage: {{ .Values.postgresql.persistence.size }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if not .Values.persistence.existingPVC }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ .Release.Name }}-timesketchvolume-claim 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | {{- if .Values.persistence.storageClass }} 9 | storageClassName: {{ .Values.persistence.storageClass }} 10 | {{- end }} 11 | accessModes: 12 | {{- range .Values.persistence.accessModes }} 13 | - {{ . | quote }} 14 | {{- end }} 15 | resources: 16 | requests: 17 | storage: {{ .Values.persistence.size | quote }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/redis/redis-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-redis-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: redis 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 6379 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: redis 18 | policyTypes: 19 | - Ingress 20 | - Egress -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/redis/redis-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 6379 13 | protocol: TCP 14 | targetPort: 6379 15 | selector: 16 | app.kubernetes.io/component: redis 17 | {{- include "timesketch.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/redis/redis-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: redis 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: redis 14 | {{- include "timesketch.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: redis 19 | {{- include "timesketch.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | hostNetwork: false 25 | hostIPC: false 26 | automountServiceAccountToken: false 27 | containers: 28 | - name: redis 29 | image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" 30 | imagePullPolicy: IfNotPresent 31 | command: ["redis-server" , "--appendonly yes"] 32 | securityContext: 33 | allowPrivilegeEscalation: false 34 | capabilities: 35 | drop: 36 | - ALL 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | env: 45 | - name: REDIS_PASSWORD 46 | valueFrom: 47 | secretKeyRef: 48 | name: {{ .Release.Name }}-timesketch-secret 49 | key: redis-user 50 | - name: REDIS_REPLICATION_MODE 51 | value: "master" 52 | - name: ALLOW_EMPTY_PASSWORD 53 | value: "no" 54 | volumeMounts: 55 | - mountPath: /data 56 | name: data 57 | ports: 58 | - containerPort: 6379 59 | resources: 60 | {{- toYaml .Values.redis.resources | nindent 12 }} 61 | {{- with .Values.redis.nodeSelector }} 62 | nodeSelector: 63 | {{- toYaml . | nindent 8 }} 64 | {{- end }} 65 | volumeClaimTemplates: 66 | - metadata: 67 | name: data 68 | spec: 69 | accessModes: [ "ReadWriteOnce" ] 70 | resources: 71 | requests: 72 | storage: {{ .Values.redis.persistence.size }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/secret-oidc-allowed-users.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.config.oidc.authenticatedEmailsFile.enabled) (not .Values.config.oidc.authenticatedEmailsFile.existingSecret) }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ .Release.Name }}-timesketch-access-list 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | authenticated-emails-list: {{ .Values.config.oidc.authenticatedEmailsFile.content | b64enc | quote }} 12 | {{- end -}} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-secret 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | data: 9 | {{- if .Release.IsUpgrade }} 10 | {{ $secretName := printf "%s-timesketch-secret" (.Release.Name) }} 11 | timesketch-secret: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "timesketch-secret" }} 12 | timesketch-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "timesketch-user" }} 13 | postgres-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "postgres-user" }} 14 | redis-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "redis-user" }} 15 | {{- else }} 16 | timesketch-secret: {{ randAlphaNum 32 | b64enc | quote }} 17 | timesketch-user: {{ randAlphaNum 16 | b64enc | quote }} 18 | postgres-user: {{ randAlphaNum 16 | b64enc | quote }} 19 | redis-user: {{ randAlphaNum 16 | b64enc | quote }} 20 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "timesketch.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 5000 12 | protocol: TCP 13 | targetPort: 5000 14 | selector: 15 | app.kubernetes.io/component: frontend 16 | {{- include "timesketch.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/templates/worker-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-timesketch-worker 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: worker 8 | {{- include "timesketch.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: worker 14 | {{- include "timesketch.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | annotations: 18 | # Restart pod if values.yaml parameters that affect the config were changed 19 | checksum/config: {{ include (print $.Template.BasePath "/init-configmap.yaml") . | sha256sum }} 20 | prometheus.io/port: "8080" 21 | prometheus.io/scrape: "true" 22 | labels: 23 | app.kubernetes.io/component: worker 24 | {{- include "timesketch.selectorLabels" . | nindent 8 }} 25 | spec: 26 | hostNetwork: false 27 | hostIPC: false 28 | automountServiceAccountToken: false 29 | initContainers: 30 | {{- include "timesketch.initContainer" . | nindent 8 }} 31 | containers: 32 | - name: worker 33 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 34 | imagePullPolicy: {{ .Values.image.pullPolicy }} 35 | command: ["sh", "-c", "celery -A timesketch.lib.tasks worker --loglevel=INFO"] 36 | {{- if .Values.securityContext.enabled }} 37 | securityContext: 38 | capabilities: 39 | drop: 40 | - ALL 41 | privileged: false 42 | readOnlyRootFilesystem: false 43 | seccompProfile: 44 | type: RuntimeDefault 45 | {{- end }} 46 | volumeMounts: 47 | - mountPath: /mnt/timesketchvolume 48 | name: timesketchvolume 49 | - mountPath: /etc/timesketch 50 | name: timesketch-configs 51 | ports: 52 | - containerPort: 8080 53 | - containerPort: 5000 54 | resources: 55 | {{- toYaml .Values.worker.resources | nindent 12 }} 56 | volumes: 57 | - name: timesketchvolume 58 | persistentVolumeClaim: 59 | {{- if .Values.persistence.existingPVC }} 60 | claimName: {{ .Values.persistence.existingPVC }} 61 | {{- else }} 62 | claimName: {{ .Release.Name }}-timesketchvolume-claim 63 | {{- end }} 64 | readOnly: false 65 | - name: init-timesketch 66 | configMap: 67 | name: {{ .Release.Name }}-timesketch-init-configmap 68 | defaultMode: 0744 69 | - name: timesketch-configs 70 | emptyDir: {} 71 | {{- if .Values.config.existingConfigMap }} 72 | - name: uploaded-configs 73 | configMap: 74 | name: {{ .Values.config.existingConfigMap }} 75 | {{- end }} 76 | {{- if .Values.config.oidc.authenticatedEmailsFile.enabled }} 77 | - name: authenticated-emails 78 | secret: 79 | items: 80 | - key: authenticated-emails-list 81 | path: authenticated-emails-list 82 | secretName: {{ include "timesketch.oidc.authenticatedemails" . }} 83 | {{- end }} 84 | {{- with .Values.worker.nodeSelector }} 85 | nodeSelector: 86 | {{- toYaml . | nindent 8 }} 87 | {{- end }} 88 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/timesketch/tools/download-timesketch-configs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script can be used to download all the necessary Timesketch configuration 3 | # files locally to this machine. Please run when you'd like to make some more 4 | # changes to the config file before deployment. 5 | # It accepts an optional --release argument to specify a branch/tag. 6 | set -o posix 7 | set -e 8 | 9 | # Default branch/tag 10 | release_branch="master" 11 | temp_dir="timesketch_temp" 12 | 13 | # --- Argument Parsing --- 14 | while [ $# -gt 0 ]; do 15 | case "$1" in 16 | --release) 17 | # Check if the argument value is provided and not empty and not another option 18 | if [ -n "$2" ] && [ "${2#--}" = "$2" ]; then 19 | release_branch="$2" 20 | shift 2 # Consume --release and its value 21 | else 22 | echo "Error: --release requires a branch/tag name argument." >&2 23 | echo "Usage: $0 [--release ]" >&2 24 | exit 1 25 | fi 26 | ;; 27 | *) 28 | echo "Error: Unknown option '$1'" >&2 29 | echo "Usage: $0 [--release ]" >&2 30 | exit 1 31 | ;; 32 | esac 33 | done 34 | 35 | # Create config directory 36 | mkdir -p timesketch-configs/ 37 | 38 | echo "* Fetching configuration files from branch/tag: ${release_branch}.." 39 | # Fetch default Timesketch config files from the specified branch/tag 40 | # Use a temporary directory name and shallow clone for efficiency 41 | rm -rf "${temp_dir}" # Clean up any previous temporary directory just in case 42 | git clone --depth 1 --branch "${release_branch}" https://github.com/google/timesketch.git "${temp_dir}" 43 | 44 | # Copy the data directory contents 45 | cp -r "${temp_dir}/data/"* timesketch-configs/ 46 | # Clean up the temporary cloned repository 47 | rm -rf "${temp_dir}" 48 | echo "OK" 49 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: yeti 3 | version: 2.1.0 4 | description: A Helm chart for Yeti Kubernetes deployments. 5 | keywords: 6 | - yeti 7 | - dfir 8 | - threatintel 9 | - threat-hunting 10 | - security 11 | home: "https://yeti-platform.io/" 12 | maintainers: 13 | - name: Open Source DFIR 14 | email: osdfir-maintainers@googlegroups.com 15 | url: https://github.com/google/osdfir-infrastructure 16 | sources: 17 | - https://github.com/yeti-platform/yeti 18 | - https://github.com/google/osdfir-infrastructure 19 | appVersion: "latest" 20 | annotations: 21 | category: Security 22 | licenses: Apache-2.0 23 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}:{{ .Chart.Version }} 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | $ helm status {{ .Release.Name }} 7 | $ helm get all {{ .Release.Name }} 8 | $ kubectl get pods 9 | 10 | To connect to the Yeti URL, run: 11 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-yeti 9000:9000 12 | $ echo "Visit http://127.0.0.1:9000 to access Yeti through port-forwarding" 13 | 14 | Login to Yeti with the User `yeti`. To get your password run: 15 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-yeti-secret -o jsonpath="{.data.yeti-user}" | base64 -d; echo "" -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/_env.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Init Container for when a Timesketch pod starts. To prevent duplicate code, 3 | this file has been created which then applies to both the Timesketch Web and 4 | Worker pod upon startup. 5 | */}} 6 | {{- define "yeti.envs" -}} 7 | - name: YETI_REDIS_HOST 8 | value: "{{ .Release.Name }}-yeti-redis" 9 | - name: YETI_REDIS_PORT 10 | value: "6379" 11 | - name: YETI_REDIS_DATABASE 12 | value: "0" 13 | - name: YETI_ARANGODB_HOST 14 | value: {{ .Release.Name }}-yeti-arangodb 15 | - name: YETI_ARANGODB_PORT 16 | value: "8529" 17 | - name: YETI_ARANGODB_DATABASE 18 | value: yeti 19 | - name: YETI_ARANGODB_USERNAME 20 | value: root 21 | - name: YETI_AUTH_SECRET_KEY 22 | value: {{ randAlphaNum 32 | quote }} 23 | - name: YETI_AUTH_ALGORITHM 24 | value: HS256 25 | - name: YETI_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES 26 | value: "10000" 27 | - name: YETI_AUTH_ENABLED 28 | value: "True" 29 | {{- if and .Values.config.oidc.enabled .Values.config.oidc.existingSecret }} 30 | - name: YETI_AUTH_MODULE 31 | value: "oidc" 32 | - name: YETI_AUTH_OIDC_DISCOVERY_URL 33 | value: "https://accounts.google.com/.well-known/openid-configuration" 34 | - name: YETI_AUTH_OIDC_CLIENT_ID 35 | valueFrom: 36 | secretKeyRef: 37 | name: {{ .Values.config.oidc.existingSecret | quote }} 38 | key: "client-id" 39 | - name: YETI_AUTH_OIDC_CLIENT_SECRET 40 | valueFrom: 41 | secretKeyRef: 42 | name: {{ .Values.config.oidc.existingSecret | quote }} 43 | key: "client-secret" 44 | {{- if .Values.global.ingress.enabled }} 45 | - name: YETI_SYSTEM_WEBROOT 46 | value: {{ printf "https://%s" .Values.global.ingress.yetiHost | quote }} 47 | {{- end }} 48 | {{- end }} 49 | - name: YETI_SYSTEM_PLUGINS_PATH 50 | value: "./plugins" 51 | - name: YETI_USER_PASSWORD 52 | valueFrom: 53 | secretKeyRef: 54 | name: {{ .Release.Name }}-yeti-secret 55 | key: yeti-user 56 | - name: YETI_ARANGODB_PASSWORD 57 | valueFrom: 58 | secretKeyRef: 59 | name: {{ .Release.Name }}-yeti-secret 60 | key: yeti-arangodb 61 | - name: YETI_API_KEY 62 | valueFrom: 63 | secretKeyRef: 64 | name: {{ .Release.Name }}-yeti-secret 65 | key: yeti-api 66 | {{- if .Values.global.timesketch.enabled }} 67 | - name: YETI_TIMESKETCH_ENDPOINT 68 | value: {{ printf "http://%s-timesketch:5000" .Release.Name | quote }} 69 | - name: YETI_TIMESKETCH_USERNAME 70 | value: timesketch 71 | - name: YETI_TIMESKETCH_PASSWORD 72 | valueFrom: 73 | secretKeyRef: 74 | name: {{ printf "%s-timesketch-secret" .Release.Name | quote }} 75 | key: timesketch-user 76 | {{- end }} 77 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "yeti.labels" -}} 5 | {{ include "yeti.selectorLabels" . }} 6 | helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }} 7 | app.kubernetes.io/managed-by: {{ .Release.Service }} 8 | date: "{{ now | htmlDate }}" 9 | {{- end }} 10 | 11 | {{/* 12 | Selector labels 13 | */}} 14 | {{- define "yeti.selectorLabels" -}} 15 | app.kubernetes.io/name: yeti 16 | app.kubernetes.io/instance: {{ .Release.Name }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/api-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-api 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: api 8 | {{- include "yeti.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: api 14 | {{- include "yeti.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: api 19 | {{- include "yeti.selectorLabels" . | nindent 8 }} 20 | spec: 21 | hostNetwork: false 22 | hostIPC: false 23 | automountServiceAccountToken: false 24 | containers: 25 | - name: api 26 | image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}" 27 | imagePullPolicy: {{ .Values.api.image.pullPolicy }} 28 | command: ["sh", "-c", "/docker-entrypoint.sh webserver"] 29 | {{- if not .Release.IsUpgrade }} 30 | lifecycle: 31 | postStart: 32 | exec: 33 | command: ["sh", "-c", "poetry run python yetictl/cli.py create-user yeti $YETI_USER_PASSWORD --api_key $YETI_API_KEY --admin"] 34 | {{- end }} 35 | securityContext: 36 | allowPrivilegeEscalation: false 37 | capabilities: 38 | drop: 39 | - ALL 40 | privileged: false 41 | seccompProfile: 42 | type: RuntimeDefault 43 | env: 44 | {{- include "yeti.envs" . | nindent 12 }} 45 | ports: 46 | - containerPort: 8000 47 | resources: 48 | {{- toYaml .Values.api.resources | nindent 12 }} 49 | {{- with .Values.api.nodeSelector }} 50 | nodeSelector: 51 | {{- toYaml . | nindent 8 }} 52 | {{- end }} 53 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/api-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-api 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 8000 12 | protocol: TCP 13 | targetPort: 8000 14 | selector: 15 | app.kubernetes.io/component: api 16 | {{- include "yeti.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/arangodb/arangodb-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-arangodb 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 8529 12 | protocol: TCP 13 | selector: 14 | app.kubernetes.io/component: arangodb 15 | {{- include "yeti.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/arangodb/arangodb-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-arangodb 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: arangodb 8 | {{- include "yeti.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: arangodb 14 | {{- include "yeti.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: arangodb 19 | {{- include "yeti.selectorLabels" . | nindent 8 }} 20 | spec: 21 | containers: 22 | - name: arangodb 23 | image: "{{ .Values.arangodb.image.repository }}:{{ .Values.arangodb.image.tag }}" 24 | imagePullPolicy: {{ .Values.arangodb.image.pullPolicy }} 25 | env: 26 | - name: ARANGO_ROOT_PASSWORD 27 | valueFrom: 28 | secretKeyRef: 29 | name: {{ .Release.Name }}-yeti-secret 30 | key: yeti-arangodb 31 | volumeMounts: 32 | - mountPath: /var/lib/arangodb3 33 | name: data 34 | ports: 35 | - containerPort: 8529 36 | resources: 37 | {{- toYaml .Values.arangodb.resources | nindent 12 }} 38 | {{- with .Values.arangodb.nodeSelector }} 39 | nodeSelector: 40 | {{- toYaml . | nindent 8 }} 41 | {{- end }} 42 | volumeClaimTemplates: 43 | - metadata: 44 | name: data 45 | spec: 46 | accessModes: [ "ReadWriteOnce" ] 47 | resources: 48 | requests: 49 | storage: {{ .Values.arangodb.persistence.size | quote }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/gcp/backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce")) }} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: {{ .Release.Name }}-yeti-backend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | timeoutSec: 300 9 | healthCheck: 10 | checkIntervalSec: 5 11 | timeoutSec: 5 12 | healthyThreshold: 2 13 | unhealthyThreshold: 2 14 | type: HTTP 15 | requestPath: /login/ 16 | port: 9000 17 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/nginx/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-yeti 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: frontend 8 | {{- include "yeti.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: frontend 14 | {{- include "yeti.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: frontend 19 | {{- include "yeti.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 101 23 | fsGroupChangePolicy: Always 24 | hostNetwork: false 25 | hostIPC: false 26 | automountServiceAccountToken: false 27 | containers: 28 | - name: frontend 29 | image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" 30 | imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} 31 | securityContext: 32 | allowPrivilegeEscalation: false 33 | capabilities: 34 | drop: 35 | - ALL 36 | privileged: false 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 101 39 | runAsNonRoot: true 40 | runAsUser: 101 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | volumeMounts: 45 | - mountPath: /etc/nginx/conf.d/default.conf 46 | subPath: default.conf 47 | name: nginx-config 48 | readOnly: true 49 | - mountPath: /var/cache/nginx 50 | name: tmp 51 | - mountPath: /var/run/ 52 | name: tmp 53 | ports: 54 | - containerPort: 9000 55 | resources: 56 | {{- toYaml .Values.frontend.resources | nindent 12 }} 57 | volumes: 58 | - name: nginx-config 59 | configMap: 60 | name: {{ .Release.Name }}-yeti-nginx-configmap 61 | - name: tmp 62 | emptyDir: {} 63 | {{- with .Values.frontend.nodeSelector }} 64 | nodeSelector: 65 | {{- toYaml . | nindent 8 }} 66 | {{- end }} 67 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/nginx/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-yeti 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | {{- if (eq .Values.global.ingress.className "gce") }} 9 | annotations: 10 | cloud.google.com/neg: '{"ingress": true}' 11 | cloud.google.com/backend-config: '{"ports": {"9000":"{{ .Release.Name }}-yeti-backend-config"}}' 12 | {{- end }} 13 | spec: 14 | type: ClusterIP 15 | ports: 16 | - port: 9000 17 | protocol: TCP 18 | targetPort: 9000 19 | selector: 20 | app.kubernetes.io/component: frontend 21 | {{- include "yeti.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/nginx/nginx-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-nginx-configmap 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | data: 9 | default.conf: | 10 | server { 11 | listen 9000; 12 | listen [::]:9000; 13 | root /www; 14 | 15 | location /api/v2 { 16 | proxy_pass http://{{ .Release.Name }}-yeti-api:8000; 17 | } 18 | 19 | location ~(^/docs|^/openapi.json) { 20 | proxy_pass http://{{ .Release.Name }}-yeti-api:8000; 21 | } 22 | 23 | location / { 24 | try_files $uri $uri/ /index.html; 25 | } 26 | } -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/redis/redis-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-redis-networkpolicy 5 | labels: 6 | app.kubernetes.io/component: redis 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | spec: 9 | egress: 10 | - {} 11 | ingress: 12 | - ports: 13 | - port: 6379 14 | protocol: TCP 15 | podSelector: 16 | matchLabels: 17 | app.kubernetes.io/component: redis 18 | policyTypes: 19 | - Ingress 20 | - Egress -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/redis/redis-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - port: 6379 13 | protocol: TCP 14 | targetPort: 6379 15 | selector: 16 | app.kubernetes.io/component: redis 17 | {{- include "yeti.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/redis/redis-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-redis 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: redis 8 | {{- include "yeti.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: redis 14 | {{- include "yeti.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: redis 19 | {{- include "yeti.selectorLabels" . | nindent 8 }} 20 | spec: 21 | securityContext: 22 | fsGroup: 1001 23 | fsGroupChangePolicy: Always 24 | hostNetwork: false 25 | hostIPC: false 26 | automountServiceAccountToken: false 27 | containers: 28 | - name: redis 29 | image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" 30 | imagePullPolicy: IfNotPresent 31 | command: ["redis-server" , "--appendonly yes"] 32 | securityContext: 33 | allowPrivilegeEscalation: false 34 | capabilities: 35 | drop: 36 | - ALL 37 | readOnlyRootFilesystem: true 38 | runAsGroup: 1001 39 | runAsNonRoot: true 40 | runAsUser: 1001 41 | seLinuxOptions: {} 42 | seccompProfile: 43 | type: RuntimeDefault 44 | env: 45 | - name: REDIS_REPLICATION_MODE 46 | value: "master" 47 | volumeMounts: 48 | - mountPath: /data 49 | name: data 50 | ports: 51 | - containerPort: 6379 52 | resources: 53 | {{- toYaml .Values.redis.resources | nindent 12 }} 54 | {{- with .Values.redis.nodeSelector }} 55 | nodeSelector: 56 | {{- toYaml . | nindent 8 }} 57 | {{- end }} 58 | volumeClaimTemplates: 59 | - metadata: 60 | name: data 61 | spec: 62 | accessModes: [ "ReadWriteOnce" ] 63 | resources: 64 | requests: 65 | storage: {{ .Values.redis.persistence.size }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-secret 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "yeti.labels" . | nindent 4 }} 8 | data: 9 | {{- if .Release.IsUpgrade }} 10 | {{ $secretName := printf "%s-yeti-secret" (.Release.Name) }} 11 | yeti-user: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "yeti-user" }} 12 | yeti-arangodb: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "yeti-arangodb" }} 13 | yeti-api: {{ index (lookup "v1" "Secret" .Release.Namespace $secretName).data "yeti-api" }} 14 | {{- else }} 15 | yeti-user: {{ randAlphaNum 32 | b64enc | quote }} 16 | yeti-arangodb: {{ randAlphaNum 16 | b64enc | quote }} 17 | yeti-api: {{ randNumeric 64 | lower | b64enc | quote }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/charts/yeti/templates/tasks-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-yeti-tasks 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: tasks 8 | {{- include "yeti.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: tasks 14 | {{- include "yeti.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/component: tasks 19 | {{- include "yeti.selectorLabels" . | nindent 8 }} 20 | spec: 21 | hostNetwork: false 22 | hostIPC: false 23 | automountServiceAccountToken: false 24 | containers: 25 | - name: tasks 26 | image: "{{ .Values.tasks.image.repository }}:{{ .Values.tasks.image.tag }}" 27 | imagePullPolicy: {{ .Values.tasks.image.pullPolicy }} 28 | command: ["sh", "-c", "/docker-entrypoint.sh tasks"] 29 | securityContext: 30 | allowPrivilegeEscalation: false 31 | capabilities: 32 | drop: 33 | - ALL 34 | privileged: false 35 | seccompProfile: 36 | type: RuntimeDefault 37 | env: 38 | {{- include "yeti.envs" . | nindent 12 }} 39 | resources: 40 | {{- toYaml .Values.tasks.resources | nindent 12 }} 41 | {{- with .Values.tasks.nodeSelector }} 42 | nodeSelector: 43 | {{- toYaml . | nindent 8 }} 44 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}:{{ .Chart.Version }}. 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | $ helm status {{ .Release.Name }} 7 | $ helm get all {{ .Release.Name }} 8 | $ kubectl get pods 9 | 10 | {{ if .Values.global.timesketch.enabled -}} 11 | To connect to the Timesketch UI, run: 12 | {{- if and (.Values.global.ingress.enabled) (.Values.global.ingress.timesketchHost) }} 13 | $ echo "Visit https://{{ .Values.global.ingress.timesketchHost }} to access Timesketch externally" 14 | {{- end }} 15 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-timesketch 5000:5000 16 | $ echo "Visit http://127.0.0.1:5000 to access Timesketch" 17 | 18 | {{ if .Values.timesketch.config.createUser -}} 19 | Login to Timesketch with the User `timesketch`. To get your password run: 20 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-timesketch-secret -o jsonpath="{.data.timesketch-user}" | base64 -d; echo "" 21 | {{- end }} 22 | {{- end }} 23 | 24 | {{ if .Values.global.yeti.enabled -}} 25 | To connect to the Yeti URL, run: 26 | {{- if and (.Values.global.ingress.enabled) (.Values.global.ingress.yetiHost) }} 27 | $ echo "Visit https://{{ .Values.global.ingress.yetiHost }} to access Yeti externally" 28 | {{- end }} 29 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-yeti 9000:9000 30 | $ echo "Visit http://127.0.0.1:9000 to access Yeti through port-forwarding" 31 | 32 | Login to Yeti with the User `yeti`. To get your password run: 33 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-yeti-secret -o jsonpath="{.data.yeti-user}" | base64 -d; echo "" 34 | {{- end }} 35 | 36 | {{ if .Values.global.openrelik.enabled -}} 37 | To connect to the OpenRelik URL, run: 38 | {{- if and (.Values.global.ingress.enabled) (.Values.global.ingress.openRelikFrontendHost) }} 39 | $ echo "Visit https://{{ .Values.global.ingress.openRelikFrontendHost }} to access OpenRelik UI externally" 40 | $ echo "Visit https://{{ .Values.global.ingress.openRelikAPIHost }} to access OpenRelik API externally" 41 | {{- end }} 42 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-openrelik 8711:8711 43 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-openrelik-api 8710:8710 44 | $ echo "Visit http://127.0.0.1:8711 to access the OpenRelik UI" 45 | 46 | Login to OpenRelik with the User `openrelik`. To get your password run: 47 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-openrelik-secret -o jsonpath="{.data.openrelik-user}" | base64 -d; echo "" 48 | {{- end }} 49 | 50 | {{ if .Values.global.grr.enabled -}} 51 | To connect to the GRR URL, run: 52 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-grr-admin 8000:8000 53 | {{- end }} 54 | 55 | {{ if .Values.global.hashr.enabled -}} 56 | To copy data for HashR to index, run: 57 | $ kubectl --namespace {{ .Release.Namespace }} cp / {{ .Release.Name }}-hashr-data-manager:/mnt/hashrvolume/data/ 58 | {{- end }} 59 | 60 | Run the following commands on your workstation to orchestrate collection and processing of forensic data with dfTimewolf: 61 | $ git clone https://github.com/log2timeline/dftimewolf && cd dftimewolf 62 | $ pip3 install poetry 63 | $ poetry install && poetry shell 64 | $ dftimewolf -h 65 | $ If using Timesketch, use the credentials provided in this chart when prompted 66 | -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "osdfir.labels" -}} 5 | helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }} 6 | {{ include "osdfir.selectorLabels" . }} 7 | {{- if .Chart.AppVersion }} 8 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 9 | {{- end }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | date: "{{ now | htmlDate }}" 12 | {{- end }} 13 | 14 | {{/* 15 | Selector labels 16 | */}} 17 | {{- define "osdfir.selectorLabels" -}} 18 | app.kubernetes.io/name: osdfir 19 | app.kubernetes.io/instance: {{ .Release.Name }} 20 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/certs/cert-manager-issuer.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.global.ingress.enabled .Values.global.ingress.certManager }} 2 | apiVersion: cert-manager.io/v1 3 | kind: Issuer 4 | metadata: 5 | name: {{ .Release.Name }}-osdfir-letsencrypt-production 6 | labels: 7 | {{- include "osdfir.labels" . | nindent 4 }} 8 | annotations: 9 | helm.sh/hook: "pre-install" 10 | helm.sh/hook-delete-policy: "before-hook-creation" 11 | spec: 12 | acme: 13 | server: https://acme-v02.api.letsencrypt.org/directory 14 | privateKeySecretRef: 15 | name: {{ .Release.Name }}-osdfir-letsencrypt-production 16 | solvers: 17 | - http01: 18 | ingress: 19 | name: {{ .Release.Name }}-osdfir-ingress 20 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/certs/tls-secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.global.ingress.enabled (or .Values.global.ingress.selfSigned .Values.global.ingress.certManager) }} 2 | {{- $ca := genCA "osdfir-ca" 365 }} 3 | {{- $cert := genSignedCert "osdfir-apps" nil (list .Values.global.ingress.timesketchHost .Values.global.ingress.yetiHost .Values.global.ingress.openRelikAPIHost .Values.global.ingress.openRelikFrontendHost) 365 $ca }} 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: {{ .Release.Name }}-osdfir-tls 8 | namespace: {{ .Release.Namespace | quote }} 9 | annotations: 10 | helm.sh/hook: "pre-install" 11 | helm.sh/hook-delete-policy: "before-hook-creation" 12 | type: kubernetes.io/tls 13 | data: 14 | tls.crt: {{ $cert.Cert | b64enc }} 15 | tls.key: {{ $cert.Key | b64enc }} 16 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/gcp/frontendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce") }} 2 | apiVersion: networking.gke.io/v1beta1 3 | kind: FrontendConfig 4 | metadata: 5 | name: {{ .Release.Name }}-osdfir-frontend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | redirectToHttps: 9 | enabled: true 10 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/gcp/managedcertificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.global.ingress.enabled) (.Values.global.ingress.gcp.managedCertificates) }} 2 | apiVersion: networking.gke.io/v1 3 | kind: ManagedCertificate 4 | metadata: 5 | name: {{ .Release.Name }}-osdfir-managed-ssl 6 | namespace: {{ .Release.Namespace | quote }} 7 | spec: 8 | domains: 9 | {{- if and .Values.global.timesketch.enabled .Values.global.ingress.timesketchHost }} 10 | - {{ .Values.global.ingress.timesketchHost }} 11 | {{- end }} 12 | {{- if and .Values.global.yeti.enabled .Values.global.ingress.yetiHost }} 13 | - {{ .Values.global.ingress.yetiHost }} 14 | {{- end }} 15 | {{- if and .Values.global.openrelik.enabled .Values.global.ingress.openRelikFrontendHost }} 16 | - {{ .Values.global.ingress.openRelikFrontendHost }} 17 | {{- end }} 18 | {{- if and .Values.global.openrelik.enabled .Values.global.ingress.openRelikAPIHost }} 19 | - {{ .Values.global.ingress.openRelikAPIHost }} 20 | {{- end }} 21 | {{- end }} -------------------------------------------------------------------------------- /charts/osdfir-infrastructure/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.ingress.enabled -}} 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: {{ .Release.Name }}-osdfir-ingress 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "osdfir.labels" . | nindent 4 }} 9 | annotations: 10 | kubernetes.io/ingressClassName: {{ .Values.global.ingress.className }} 11 | {{- if .Values.global.ingress.gcp.managedCertificates }} 12 | networking.gke.io/managed-certificates: {{ .Release.Name }}-osdfir-managed-ssl 13 | {{- end }} 14 | {{- if .Values.global.ingress.certManager }} 15 | kubernetes.io/tls-acme: "true" 16 | cert-manager.io/issuer: {{ .Release.Name }}-osdfir-letsencrypt-production 17 | {{- end }} 18 | {{- if (eq .Values.global.ingress.className "gce") }} 19 | {{- if .Values.global.ingress.gcp.staticIPName }} 20 | kubernetes.io/ingress.global-static-ip-name: {{ .Values.global.ingress.gcp.staticIPName }} 21 | networking.gke.io/v1beta1.FrontendConfig: {{ .Release.Name }}-osdfir-frontend-config 22 | {{- else }} 23 | {{- fail "A valid .Values.global.ingress.gcp.staticIPName entry is required when using the GCE Ingress" }} 24 | {{- end }} 25 | {{- end }} 26 | spec: 27 | {{- if or .Values.global.ingress.selfSigned .Values.global.ingress.certManager }} 28 | tls: 29 | - hosts: 30 | {{- if .Values.global.ingress.timesketchHost }} 31 | - {{ .Values.global.ingress.timesketchHost | quote }} 32 | {{- end }} 33 | {{- if .Values.global.ingress.yetiHost }} 34 | - {{ .Values.global.ingress.yetiHost | quote }} 35 | {{- end }} 36 | {{- if .Values.global.ingress.openRelikFrontendHost }} 37 | - {{ .Values.global.ingress.openRelikFrontendHost | quote }} 38 | {{- end }} 39 | {{- if .Values.global.ingress.openRelikAPIHost }} 40 | - {{ .Values.global.ingress.openRelikAPIHost | quote }} 41 | {{- end }} 42 | secretName: {{ .Release.Name }}-osdfir-tls 43 | {{- end }} 44 | rules: 45 | {{- if .Values.global.ingress.timesketchHost }} 46 | - host: {{ .Values.global.ingress.timesketchHost }} 47 | http: 48 | paths: 49 | - path: / 50 | pathType: Prefix 51 | backend: 52 | service: 53 | name: {{ .Release.Name }}-timesketch-nginx 54 | port: 55 | number: 8080 56 | {{- end }} 57 | {{- if .Values.global.ingress.yetiHost }} 58 | - host: {{.Values.global.ingress.yetiHost }} 59 | http: 60 | paths: 61 | - path: / 62 | pathType: Prefix 63 | backend: 64 | service: 65 | name: {{ .Release.Name }}-yeti 66 | port: 67 | number: 9000 68 | {{- end }} 69 | {{- if .Values.global.ingress.openRelikFrontendHost }} 70 | - host: {{.Values.global.ingress.openRelikFrontendHost }} 71 | http: 72 | paths: 73 | - path: / 74 | pathType: Prefix 75 | backend: 76 | service: 77 | name: {{ .Release.Name }}-openrelik 78 | port: 79 | number: 8711 80 | {{- end }} 81 | {{- if .Values.global.ingress.openRelikAPIHost }} 82 | - host: {{.Values.global.ingress.openRelikAPIHost }} 83 | http: 84 | paths: 85 | - path: / 86 | pathType: Prefix 87 | backend: 88 | service: 89 | name: {{ .Release.Name }}-openrelik-api 90 | port: 91 | number: 8710 92 | {{- end }} 93 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/dfdewey/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/standalone/dfdewey/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: postgresql 3 | repository: https://charts.bitnami.com/bitnami 4 | version: 14.3.1 5 | - name: opensearch 6 | repository: https://opensearch-project.github.io/helm-charts/ 7 | version: 2.18.0 8 | digest: sha256:5a62d8c85755de1ff7e46cb3b75749a9b04f901fb6da3b469340c525627f2f1f 9 | generated: "2024-03-14T13:41:14.447320047+11:00" 10 | -------------------------------------------------------------------------------- /charts/standalone/dfdewey/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dfdewey 3 | version: 1.0.0 4 | description: A Helm chart for dfDewey datastore Kubernetes deployments. 5 | keywords: 6 | - dfdewey 7 | - dfir 8 | - processing 9 | - indexing 10 | - security 11 | home: "https://github.com/google/dfdewey" 12 | dependencies: 13 | - name: postgresql 14 | version: 14.3.1 15 | repository: https://charts.bitnami.com/bitnami 16 | - name: opensearch 17 | version: 2.18.0 18 | repository: https://opensearch-project.github.io/helm-charts/ 19 | maintainers: 20 | - name: Open Source DFIR 21 | email: osdfir-maintainers@googlegroups.com 22 | url: https://github.com/google/osdfir-infrastructure 23 | sources: 24 | - https://github.com/google/osdfir-infrastructure 25 | icon: https://user-images.githubusercontent.com/52063018/101560727-fc827900-3a17-11eb-93a1-f2a0589b6b6b.png 26 | appVersion: "latest" 27 | annotations: 28 | category: Security 29 | licenses: Apache-2.0 30 | -------------------------------------------------------------------------------- /charts/standalone/dfdewey/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "dfdewey.name" -}} 5 | {{- default .Chart.Name | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | */}} 11 | {{- define "dfdewey.fullname" -}} 12 | {{- if contains .Chart.Name .Release.Name }} 13 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 14 | {{- else }} 15 | {{- printf "%s-%s" .Release.Name "dfdewey" | trunc 63 | trimSuffix "-" }} 16 | {{- end }} 17 | {{- end }} 18 | 19 | {{/* 20 | Create chart name and version as used by the chart label. 21 | */}} 22 | {{- define "dfdewey.chart" -}} 23 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 24 | {{- end }} 25 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: redis 3 | repository: https://charts.bitnami.com/bitnami 4 | version: 19.3.2 5 | - name: oauth2-proxy 6 | repository: https://charts.bitnami.com/bitnami 7 | version: 5.3.0 8 | - name: dfdewey 9 | repository: https://google.github.io/osdfir-infrastructure/ 10 | version: 1.0.0 11 | digest: sha256:6c0c5f81d133cf28a6504d01571d17b1fed42b7908bfa3ef0b4d1a913b62fc03 12 | generated: "2024-09-23T10:08:20.718691-07:00" 13 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: turbinia 3 | version: 1.2.0 4 | description: A Helm chart for Turbinia Kubernetes deployments. 5 | keywords: 6 | - turbinia 7 | - dfir 8 | - processing 9 | - scaling 10 | - security 11 | home: "https://github.com/google/turbinia" 12 | dependencies: 13 | - condition: redis.enabled 14 | name: redis 15 | version: 19.3.2 16 | repository: https://charts.bitnami.com/bitnami 17 | - condition: oauth2proxy.enabled 18 | name: oauth2-proxy 19 | alias: oauth2proxy 20 | version: 5.3.0 21 | repository: https://charts.bitnami.com/bitnami 22 | - condition: global.dfdewey.enabled 23 | name: dfdewey 24 | repository: https://google.github.io/osdfir-infrastructure/ 25 | version: 1.0.0 26 | maintainers: 27 | - name: Open Source DFIR 28 | email: osdfir-maintainers@googlegroups.com 29 | url: https://github.com/google/osdfir-infrastructure 30 | sources: 31 | - https://github.com/google/osdfir-infrastructure 32 | icon: https://raw.githubusercontent.com/google/turbinia/master/web/src/assets/turbinia-logo-mark.png 33 | appVersion: "20240820" 34 | annotations: 35 | category: Security 36 | licenses: Apache-2.0 37 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}:{{ .Chart.Version }} 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | 7 | $ helm status {{ .Release.Name }} 8 | $ helm get all {{ .Release.Name }} 9 | $ kubectl get pods 10 | 11 | To connect to the Turbinia URL, run: 12 | {{- if and (.Values.ingress.enabled) (.Values.ingress.host) }} 13 | $ echo "Visit https://{{ .Values.ingress.host }} to access Turbinia externally" 14 | {{- end }} 15 | {{- if .Values.oauth2proxy.enabled }} 16 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-oauth2proxy {{ .Values.oauth2proxy.service.port }}:{{ .Values.oauth2proxy.service.port }} 17 | $ echo "Visit http://127.0.0.1:{{ .Values.oauth2proxy.service.port }} to access Turbinia through port-forwarding" 18 | {{- else }} 19 | $ kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ .Release.Name }}-turbinia {{ include "turbinia.service.port" . }}:{{ include "turbinia.service.port" . }} 20 | $ echo "Visit http://127.0.0.1:{{ include "turbinia.service.port" . }} to access Turbinia through port-forwarding" 21 | {{- end }} 22 | 23 | To install the Turbinia client, run: 24 | $ pip3 install turbinia-client 25 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ include "turbinia.fullname" . }}-secret -o jsonpath="{.data.turbinia-secret}" | base64 -d > ~/.turbinia_api_config.json 26 | 27 | Run the following commands on your workstation to orchestrate collection and processing of forensic data with dfTimewolf: 28 | $ git clone https://github.com/log2timeline/dftimewolf && cd dftimewolf 29 | $ pip3 install poetry 30 | $ poetry install && poetry shell 31 | $ dftimewolf -h 32 | {{- if and .Values.oauth2proxy.enabled .Values.oauth2proxy.configuration.existingSecret }} 33 | $ If using Turbinia with the Oauth2 Proxy, use the command below to generate the necessary config 34 | $ kubectl get secret --namespace {{ .Release.Namespace }} {{ include "turbinia.fullname" . }}-secret -o jsonpath="{.data.dftimewolf-secret}" | base64 -d > ~/.dftimewolf_turbinia_secrets.json 35 | $ Replace `client_secret` in `~/.dftimewolf_turbinia_secrets.json` with the secret from your configured native or desktop OAuth app. 36 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/_initContainer.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Init Container for when a Turbinia pod starts. To prevent duplicate code, 3 | this file has been created which then applies to both the Turbinia Server, API, 4 | and Worker pod upon startup. 5 | */}} 6 | {{- define "turbinia.initContainer" -}} 7 | - name: init-turbinia 8 | image: alpine 9 | command: ['sh', '-c', '/init/init-turbinia.sh'] 10 | env: 11 | {{- if and .Values.redis.enabled .Values.redis.auth.enabled }} 12 | - name: REDIS_PASSWORD 13 | valueFrom: 14 | # Referencing from charts/redis/templates/_helpers.tpl 15 | secretKeyRef: 16 | name: {{ include "redis.secretName" .Subcharts.redis }} 17 | key: {{ include "redis.secretPasswordKey" .Subcharts.redis }} 18 | {{- end }} 19 | {{- if and .Values.config.existingVertexSecret .Values.gcp.enabled }} 20 | - name: VERTEX_APIKEY 21 | valueFrom: 22 | secretKeyRef: 23 | name: {{ .Values.config.existingVertexSecret }} 24 | key: "turbinia-vertexapi" 25 | {{- end }} 26 | volumeMounts: 27 | - mountPath: /mnt/turbiniavolume 28 | name: turbiniavolume 29 | - mountPath: /init 30 | name: init-turbinia 31 | - mountPath: /etc/turbinia 32 | name: turbinia-configs 33 | - mountPath: /tmp/turbinia 34 | name: user-configs 35 | {{- end }} 36 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/api-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "turbinia.fullname" . }}-api 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: api 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: api 14 | {{- include "turbinia.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | annotations: 18 | # Restart pod if values.yaml parameters that affect the config were changed 19 | checksum/config: {{ include (print $.Template.BasePath "/init-configmap.yaml") . | sha256sum }} 20 | {{- if .Values.metrics.enabled }} 21 | prometheus.io/port: {{ .Values.metrics.port | quote }} 22 | prometheus.io/scrape: "true" 23 | {{- end }} 24 | labels: 25 | app.kubernetes.io/component: api 26 | {{- include "turbinia.selectorLabels" . | nindent 8 }} 27 | spec: 28 | serviceAccountName: {{ include "turbinia.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.api.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | {{- include "turbinia.initContainer" . | nindent 8 }} 33 | containers: 34 | - name: api 35 | securityContext: 36 | {{- toYaml .Values.api.securityContext | nindent 12 }} 37 | image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag | default .Chart.AppVersion }}" 38 | imagePullPolicy: {{ .Values.api.image.pullPolicy }} 39 | livenessProbe: 40 | exec: 41 | command: ['sh', '-c', "ps aux | grep api_server | grep -v grep"] 42 | initialDelaySeconds: 5 43 | periodSeconds: 5 44 | env: 45 | - name: TURBINIA_EXTRA_ARGS 46 | value: "-d" 47 | - name: NODE_NAME 48 | valueFrom: 49 | fieldRef: 50 | fieldPath: spec.nodeName 51 | volumeMounts: 52 | - mountPath: /var/log 53 | name: logs 54 | - mountPath: /mnt/turbiniavolume 55 | name: turbiniavolume 56 | - mountPath: /etc/turbinia 57 | name: turbinia-configs 58 | ports: 59 | {{- if .Values.metrics.enabled }} 60 | - containerPort: {{ .Values.metrics.port }} 61 | {{- end }} 62 | - containerPort: 8000 63 | resources: 64 | {{- toYaml .Values.api.resources | nindent 12 }} 65 | volumes: 66 | - name: turbiniavolume 67 | persistentVolumeClaim: 68 | claimName: {{ include "turbinia.pvc.name" . }} 69 | readOnly: false 70 | - name: logs 71 | emptyDir: {} 72 | - name: init-turbinia 73 | configMap: 74 | name: {{ include "turbinia.fullname" . }}-init-configmap 75 | defaultMode: 0777 76 | - name: turbinia-configs 77 | emptyDir: {} 78 | - name: user-configs 79 | configMap: 80 | name: {{ include "turbinia.configmap" . }} 81 | optional: true 82 | {{- with .Values.api.nodeSelector }} 83 | nodeSelector: 84 | {{- toYaml . | nindent 8 }} 85 | {{- end }} 86 | {{- with .Values.api.affinity }} 87 | affinity: 88 | {{- toYaml . | nindent 8 }} 89 | {{- end }} 90 | {{- with .Values.api.tolerations }} 91 | tolerations: 92 | {{- toYaml . | nindent 8 }} 93 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/certs/cert-manager-issuer.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.ingress.enabled .Values.ingress.certManager }} 2 | apiVersion: cert-manager.io/v1 3 | kind: Issuer 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }}-letsencrypt-production 6 | labels: 7 | {{- include "turbinia.labels" . | nindent 4 }} 8 | annotations: 9 | helm.sh/hook: "pre-install" 10 | helm.sh/hook-delete-policy: "before-hook-creation" 11 | spec: 12 | acme: 13 | server: https://acme-v02.api.letsencrypt.org/directory 14 | privateKeySecretRef: 15 | name: {{ include "turbinia.fullname" . }}-letsencrypt-production 16 | solvers: 17 | - http01: 18 | ingress: 19 | name: {{ include "turbinia.fullname" . }}-ingress 20 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/certs/tls-secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.ingress.enabled (or .Values.ingress.selfSigned .Values.ingress.certManager) }} 2 | {{- $ca := genCA "turbinia-ca" 365 }} 3 | {{- $cert := genSignedCert "turbinia-apps" nil (list .Values.ingress.host) 365 $ca }} 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: {{ include "turbinia.fullname" . }}-tls 8 | namespace: {{ .Release.Namespace | quote }} 9 | annotations: 10 | helm.sh/hook: "pre-install" 11 | helm.sh/hook-delete-policy: "before-hook-creation" 12 | type: kubernetes.io/tls 13 | data: 14 | tls.crt: {{ $cert.Cert | b64enc }} 15 | tls.key: {{ $cert.Key | b64enc }} 16 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/crds/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" -}} 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | name: {{ printf "%s-%s" .Release.Name "turbinia-metrics-servicemonitor" }} 6 | spec: 7 | selector: 8 | matchLabels: 9 | monitoring: enabled 10 | endpoints: 11 | - port: http-metrics 12 | {{ end -}} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/gcp/backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if or (and (.Values.ingress.enabled) (eq .Values.ingress.className "gce") (not .Values.oauth2proxy.enabled)) (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce") (not .Values.oauth2proxy.enabled)) }} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: "{{ .Release.Name }}-backend-config" 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | timeoutSec: 900 11 | healthCheck: 12 | checkIntervalSec: 5 13 | timeoutSec: 5 14 | healthyThreshold: 2 15 | unhealthyThreshold: 2 16 | type: HTTP 17 | {{- if .Values.oauth2proxy.enabled }} 18 | requestPath: /ping 19 | port: 4180 20 | {{- else }} 21 | requestPath: /web 22 | port: 8000 23 | {{- end }} 24 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/gcp/frontendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.ingress.enabled) (eq .Values.ingress.className "gce") }} 2 | apiVersion: networking.gke.io/v1beta1 3 | kind: FrontendConfig 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }}-frontend-config 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | redirectToHttps: 11 | enabled: true 12 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/gcp/managedcertificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.ingress.enabled) (.Values.ingress.gcp.managedCertificates) }} 2 | apiVersion: networking.gke.io/v1 3 | kind: ManagedCertificate 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }}-managed-ssl 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | domains: 11 | - {{ required "A valid .Values.ingress.host entry is required!" .Values.ingress.host }} 12 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.worker.autoscaling.enabled }} 2 | apiVersion: autoscaling/v1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }} 6 | labels: 7 | {{- include "turbinia.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "turbinia.fullname" . }}-worker 13 | minReplicas: {{ .Values.worker.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.worker.autoscaling.maxReplicas }} 15 | targetCPUUtilizationPercentage: {{ .Values.worker.autoscaling.targetCPUUtilizationPercentage }} 16 | {{- end }} 17 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/metrics/server-metrics-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metrics.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }}-server-metrics 6 | labels: 7 | monitoring: enabled 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | ports: 11 | - port: {{ .Values.metrics.port }} 12 | targetPort: {{ .Values.metrics.port }} 13 | protocol: TCP 14 | name: http-metrics 15 | selector: 16 | app.kubernetes.io/component: server 17 | {{- include "turbinia.selectorLabels" . | nindent 4 }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/metrics/worker-metrics-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metrics.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "turbinia.fullname" . }}-worker-metrics 6 | labels: 7 | monitoring: enabled 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | ports: 11 | - port: {{ .Values.metrics.port }} 12 | targetPort: {{ .Values.metrics.port }} 13 | protocol: TCP 14 | name: http-metrics 15 | selector: 16 | app.kubernetes.io/component: worker 17 | {{- include "turbinia.selectorLabels" . | nindent 4 }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if not (.Values.global.existingPVC) }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | annotations: 6 | helm.sh/resource-policy: keep 7 | name: {{ include "turbinia.pvc.name" . }} 8 | namespace: {{ .Release.Namespace | quote }} 9 | spec: 10 | {{- include "turbinia.storage.class" . | nindent 2 }} 11 | accessModes: 12 | {{- range .Values.persistence.accessModes }} 13 | - {{ . | quote }} 14 | {{- end }} 15 | resources: 16 | requests: 17 | storage: {{ .Values.persistence.size | quote }} 18 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ template "turbinia.fullname" . }}-secret 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | {{- include "turbinia.labels" . | nindent 4 }} 8 | stringData: 9 | {{- if and .Values.oauth2proxy.enabled .Values.oauth2proxy.configuration.existingSecret }} 10 | dftimewolf-secret: | 11 | { 12 | installed: 13 | { 14 | "client_id": "{{ index (lookup "v1" "Secret" .Release.Namespace .Values.oauth2proxy.configuration.existingSecret).data "client-id-native" | b64dec }}", 15 | "client_secret": "", 16 | "redirect_uris": [ "https://{{ .Values.ingress.host }}.com/oauth2/callback" ], 17 | "project_id": "{{ .Values.gcp.projectID }}", 18 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 19 | "token_uri": "https://oauth2.googleapis.com/token", 20 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs" 21 | } 22 | } 23 | {{- end }} 24 | turbinia-secret: | 25 | { 26 | "default": { 27 | "description": "This file is used by turbinia-client to determine the location of the API server and if authentication will be used. These options should match your Turbinia deployment.", 28 | "comments": "By default, the credentials and client secrets files are located in the user's home directory.", 29 | "API_SERVER_ADDRESS": "http://localhost", 30 | "API_SERVER_PORT": 8000, 31 | "API_AUTHENTICATION_ENABLED": false, 32 | "CLIENT_SECRETS_FILENAME": ".client_secrets.json", 33 | "CREDENTIALS_FILENAME": ".credentials_default.json" 34 | } 35 | } -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/server-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "turbinia.fullname" . }}-server 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app.kubernetes.io/component: server 8 | {{- include "turbinia.labels" . | nindent 4 }} 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/component: server 14 | {{- include "turbinia.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | annotations: 18 | # Restart pod if values.yaml parameters that affect the config were changed the config 19 | checksum/config: {{ include (print $.Template.BasePath "/init-configmap.yaml") . | sha256sum }} 20 | {{- if .Values.metrics.enabled }} 21 | prometheus.io/port: {{ .Values.metrics.port | quote }} 22 | prometheus.io/scrape: "true" 23 | {{- end }} 24 | labels: 25 | app.kubernetes.io/component: server 26 | {{- include "turbinia.selectorLabels" . | nindent 8 }} 27 | spec: 28 | serviceAccountName: {{ include "turbinia.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.server.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | {{- include "turbinia.initContainer" . | nindent 8 }} 33 | containers: 34 | - name: server 35 | securityContext: 36 | {{- toYaml .Values.server.securityContext | nindent 12 }} 37 | image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default .Chart.AppVersion }}" 38 | imagePullPolicy: {{ .Values.server.image.pullPolicy }} 39 | env: 40 | - name: TURBINIA_EXTRA_ARGS 41 | value: "-d" 42 | - name: NODE_NAME 43 | valueFrom: 44 | fieldRef: 45 | fieldPath: spec.nodeName 46 | volumeMounts: 47 | - mountPath: /mnt/turbiniavolume 48 | name: turbiniavolume 49 | - mountPath: /etc/turbinia 50 | name: turbinia-configs 51 | ports: 52 | {{- if .Values.metrics.enabled }} 53 | - containerPort: {{ .Values.metrics.port }} 54 | {{- end }} 55 | resources: 56 | {{- toYaml .Values.server.resources | nindent 12 }} 57 | volumes: 58 | - name: turbiniavolume 59 | persistentVolumeClaim: 60 | claimName: {{ include "turbinia.pvc.name" . }} 61 | readOnly: false 62 | - name: init-turbinia 63 | configMap: 64 | name: {{ include "turbinia.fullname" . }}-init-configmap 65 | defaultMode: 0744 66 | - name: turbinia-configs 67 | emptyDir: {} 68 | - name: user-configs 69 | configMap: 70 | name: {{ include "turbinia.configmap" . }} 71 | optional: true 72 | {{- with .Values.server.nodeSelector }} 73 | nodeSelector: 74 | {{- toYaml . | nindent 8 }} 75 | {{- end }} 76 | {{- with .Values.server.affinity }} 77 | affinity: 78 | {{- toYaml . | nindent 8 }} 79 | {{- end }} 80 | {{- with .Values.server.tolerations }} 81 | tolerations: 82 | {{- toYaml . | nindent 8 }} 83 | {{- end }} -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ .Release.Name }}-turbinia 5 | {{- if or (and (.Values.ingress.enabled) (eq .Values.ingress.className "gce") (not .Values.oauth2proxy.enabled)) (and (.Values.global.ingress.enabled) (eq .Values.global.ingress.className "gce") (not .Values.oauth2proxy.enabled)) }} 6 | annotations: 7 | cloud.google.com/neg: '{"ingress": true}' 8 | cloud.google.com/backend-config: '{"ports": {"8000": "{{ .Release.Name }}-backend-config"}}' 9 | {{- end }} 10 | labels: 11 | {{- include "turbinia.labels" . | nindent 4 }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - port: {{ include "turbinia.service.port" . }} 16 | protocol: TCP 17 | targetPort: 8000 18 | selector: 19 | app.kubernetes.io/component: api 20 | {{- include "turbinia.selectorLabels" . | nindent 4 }} 21 | -------------------------------------------------------------------------------- /charts/standalone/turbinia/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | {{- if not (lookup "v1" "ServiceAccount" .Release.Namespace .Values.serviceAccount.name) -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "turbinia.serviceAccountName" . }} 7 | namespace: {{ .Release.Namespace | quote }} 8 | labels: 9 | {{- include "turbinia.labels" . | nindent 4 }} 10 | {{- if .Values.serviceAccount.annotations }} 11 | annotations: 12 | {{ toYaml .Values.serviceAccount.annotations | indent 4 }} 13 | {{- end }} 14 | {{- end }} 15 | {{- end }} -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Before you begin 6 | 7 | ### Sign our Contributor License Agreement 8 | 9 | Contributions to this project must be accompanied by a 10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 11 | You (or your employer) retain the copyright to your contribution; this simply 12 | gives us permission to use and redistribute your contributions as part of the 13 | project. 14 | 15 | If you or your current employer have already signed the Google CLA (even if it 16 | was for a different project), you probably don't need to do it again. 17 | 18 | Visit to see your current agreements or to 19 | sign a new one. 20 | 21 | ### Review our Community Guidelines 22 | 23 | This project follows 24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 25 | 26 | ## Contribution process 27 | 28 | 1. Fork this repository, develop, and test your changes. 29 | 2. Submit a pull request. 30 | 31 | When submitting a PR make sure that it: 32 | 33 | * Must follow [Helm best practices](https://helm.sh/docs/chart_best_practices/). 34 | * No lint issues from running `helm lint` against your local chart. 35 | * The changes have been tested locally. 36 | * Any change to a chart requires a version bump following [semver](https://semver.org/) principles. The only exception is if the change was related to documentation. 37 | 38 | ### Code Reviews 39 | 40 | All submissions, including submissions by project members, require review. We 41 | use GitHub pull requests for this purpose. Consult 42 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 43 | information on using pull requests. 44 | -------------------------------------------------------------------------------- /docs/images/cluster-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/cluster-info.png -------------------------------------------------------------------------------- /docs/images/dashboard-deployment-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-deployment-detail.png -------------------------------------------------------------------------------- /docs/images/dashboard-deployments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-deployments.png -------------------------------------------------------------------------------- /docs/images/dashboard-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-overview.png -------------------------------------------------------------------------------- /docs/images/dashboard-pod-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-pod-detail.png -------------------------------------------------------------------------------- /docs/images/dashboard-pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-pods.png -------------------------------------------------------------------------------- /docs/images/dashboard-secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/dashboard-secrets.png -------------------------------------------------------------------------------- /docs/images/grr-fleetspeak-demo-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/grr-fleetspeak-demo-architecture.png -------------------------------------------------------------------------------- /docs/images/notes-txt-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/notes-txt-secret.png -------------------------------------------------------------------------------- /docs/images/notes-txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/osdfir-infrastructure/c94b63233ebf7921e389929c3295f04d01d660cd/docs/images/notes-txt.png -------------------------------------------------------------------------------- /extras/gcp/tf/output.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | output "mysqldb_ip_address" { 18 | description = "The IP address of the grr/fleetspeak MySQL DB." 19 | value = google_sql_database_instance.instance.private_ip_address 20 | } 21 | 22 | output "fleetspeak_frontend" { 23 | description = "The Fleetspeak Frontend" 24 | value = local.hostname 25 | } 26 | 27 | output "project_id" { 28 | description = "The Project ID" 29 | value = var.project_id 30 | } 31 | 32 | output "region" { 33 | description = "The Region" 34 | value = var.region 35 | } 36 | 37 | output "zone" { 38 | description = "The Zone" 39 | value = var.zone 40 | } 41 | 42 | output "artifact_registry_id" { 43 | description = "The Artifact Registry ID" 44 | value = google_artifact_registry_repository.artifact_registry.repository_id 45 | } 46 | 47 | output "gke_cluster_location" { 48 | description = "The location of the GKE cluster" 49 | value = google_container_cluster.osdfir_cluster.location 50 | } 51 | 52 | output "gke_cluster_name" { 53 | description = "The name of the GKE cluster" 54 | value = google_container_cluster.osdfir_cluster.name 55 | } 56 | 57 | output "fleetspeak_cert_loadbalancer" { 58 | description = "The cert" 59 | value = data.google_compute_ssl_certificate.fleetspeak_cert_loadbalancer.certificate 60 | } 61 | 62 | output "grr_blobstore_bucket" { 63 | description = "The GRR Blobstore GCS bucket" 64 | value = google_storage_bucket.grr_blobstore.name 65 | } 66 | 67 | output "grr_fleetspeak_service_topic" { 68 | description = "The GRR Fleetspeak Service Topic" 69 | value = google_pubsub_topic.grr_fleetspeak_service_topic.name 70 | } 71 | 72 | output "grr_fleetspeak_service_subscription" { 73 | description = "The GRR Fleetspeak Service Subscription" 74 | value = google_pubsub_subscription.grr_fleetspeak_service_subscription.name 75 | } 76 | -------------------------------------------------------------------------------- /extras/gcp/tf/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | variable "project_id" { 18 | description = "Google Cloud Project Identifier" 19 | } 20 | 21 | variable "region" { 22 | description = "region" 23 | default = "europe-west1" 24 | } 25 | 26 | variable "zone" { 27 | description = "zone" 28 | default = "europe-west1-b" 29 | } 30 | 31 | variable "grr_pool_num_nodes" { 32 | description = "number of GRR nodes" 33 | default = 2 34 | } 35 | 36 | variable "nodepool" { 37 | description = "GRR nodepool" 38 | default = "grr" 39 | } 40 | 41 | variable "nodepool_machine_type" { 42 | description = "GRR nodepool machine type" 43 | default = "n2-standard-4" 44 | } 45 | 46 | variable "address_name" { 47 | description = "name for the fleetspeak public IP address" 48 | default = "fleetspeak-frontend" 49 | } 50 | 51 | variable "db_tier" { 52 | description = "tier for the the MySQL DB" 53 | default = "db-f1-micro" 54 | } 55 | -------------------------------------------------------------------------------- /extras/tools/helper.sh: -------------------------------------------------------------------------------- 1 | # Setup some useful k8s aliases 2 | alias k=kubectl 3 | # Apply a yaml file 4 | alias kaf='kubectl apply -f' 5 | # Exec into a pod 6 | alias ke='_ke(){ kubectl exec --stdin --tty $1 -- /bin/bash; unset -f _ke; }; _ke' 7 | # Get logs 8 | alias kl='kubectl logs' 9 | alias kl1h='kubectl logs --since 1h' 10 | alias kl1m='kubectl logs --since 1m' 11 | alias kl1s='kubectl logs --since 1s' 12 | # Get resources 13 | alias kgp='kubectl get pods' 14 | alias kgd='kubectl get deployment' 15 | alias kgs='kubectl get svc' 16 | alias kgi='kubectl get ingress' 17 | alias kgn='kubectl get nodes -o wide' 18 | # Describe resources 19 | alias kdp='kubectl describe pods' 20 | alias kdd='kubectl describe deployment' 21 | alias kds='kubectl describe svc' 22 | alias kdi='kubectl describe ingress' 23 | # Delete resources 24 | alias kdf='kubectl delete -f' 25 | alias kdeld='kubectl delete deployment' 26 | alias kdelcm='kubectl delete configmap' 27 | alias kdels='kubectl delete svc' 28 | alias kdeli='kubectl delete ingress' 29 | # Restart resources 30 | alias krrd='kubectl rollout restart deployment' 31 | alias krrp='kubectl rollout restart pod' 32 | alias krrs='kubectl rollout restart svc' --------------------------------------------------------------------------------