diff --git a/.github/workflows/release-helm-charts.yaml b/.github/workflows/release-helm-charts.yaml new file mode 100644 index 0000000..375d88a --- /dev/null +++ b/.github/workflows/release-helm-charts.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 Authors of SentryFlow + +name: Release Helm charts + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag which has to be updated" + type: "string" + required: true + +jobs: + release_helm_charts: + if: github.repository == '5GSEC/sentryflow' + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + + - name: Generate a token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.ACTIONS_APP_ID }} + private-key: ${{ secrets.ACTIONS_APP_PRIVATE_KEY }} + repositories: charts + + - name: Publish Helm chart + uses: stefanprodan/helm-gh-pages@master + with: + # Access token which can push to a different repo in the same org + token: ${{ steps.generate-token.outputs.token }} + charts_dir: deployments/ + # repo where charts would be published + owner: 5GSEC + repository: charts + branch: gh-pages + charts_url: https://5gsec.github.io/charts/ + commit_username: "github-actions[bot]" + commit_email: "github-actions[bot]@users.noreply.github.com" diff --git a/.github/workflows/stable-release.yaml b/.github/workflows/stable-release.yaml index 2d5b964..783b3ce 100644 --- a/.github/workflows/stable-release.yaml +++ b/.github/workflows/stable-release.yaml @@ -52,3 +52,39 @@ jobs: WORKING_DIRECTORY: filter/envoy/envoy-wasm-filters NAME: sentryflow-httpfilter secrets: inherit + + update-image-tags-in-helm-charts: + if: github.repository == '5GSEC/sentryflow' + needs: [ release-sentryflow-image ] + permissions: + pull-requests: write + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Get tag + id: tag + run: | + if [ ${{ github.ref }} == "refs/heads/main" ]; then + echo "tag=latest" >> $GITHUB_OUTPUT + else + echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT + fi + + - name: Update images tag + run: | + ./hack/update-image-tag.sh ${{ steps.tag.outputs.tag }} + + - name: Create PR to update images tag in Helm charts + uses: peter-evans/create-pull-request@v7 + with: + branch: update-helm-${{ steps.tag.outputs.tag }} + commit-message: "[skip ci] Update Helm Chart To ${{ steps.tag.outputs.tag }}" + committer: "github-actions[bot] " + author: "github-actions[bot] " + title: "[skip ci] Update Helm Chart To ${{ steps.tag.outputs.tag }}" + base: main + signoff: true + delete-branch: true diff --git a/deployments/sentryflow/.helmignore b/deployments/sentryflow/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deployments/sentryflow/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deployments/sentryflow/Chart.yaml b/deployments/sentryflow/Chart.yaml new file mode 100644 index 0000000..60650b7 --- /dev/null +++ b/deployments/sentryflow/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: sentryflow +description: A Helm chart for SentryFlow + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.0" diff --git a/deployments/sentryflow/Readme.md b/deployments/sentryflow/Readme.md new file mode 100644 index 0000000..560b227 --- /dev/null +++ b/deployments/sentryflow/Readme.md @@ -0,0 +1,39 @@ +# Install SentryFlow + +Install SentryFlow using the official 5GSEC Helm charts. + +### Add SentryFlow repo + +```shell +helm repo add 5gsec https://5gsec.github.io/charts +helm repo update 5gsec +``` + +### Update `values.yaml` file according to your requirements. + +```shell +helm show values 5gsec/sentryflow > values.yaml +``` + +Configure SentryFlow receiver by following [this](../../docs/receivers.md). + +### Deploy SentryFlow + +```shell +helm install --values values.yaml sentryflow 5gsec/sentryflow-n sentryflow --create-namespace +``` + +Install SentryFlow using Helm charts locally (for testing) + +```bash +cd deployments/sentryflow/ +helm upgrade --install sentryflow . -n sentryflow --create-namespace +``` + +## Uninstall + +To uninstall, just run: + +```bash +helm uninstall sentryflow -n sentryflow +``` diff --git a/deployments/sentryflow/templates/NOTES.txt b/deployments/sentryflow/templates/NOTES.txt new file mode 100644 index 0000000..f0cdf38 --- /dev/null +++ b/deployments/sentryflow/templates/NOTES.txt @@ -0,0 +1,3 @@ +Thank you for installing SentryFlow. +Your release is named '{{ include "sentryflow.fullname" . }}' and deployed in '{{ .Release.Namespace }}' namespace. +For more info please visit: https://github.com/5GSEC/SentryFlow diff --git a/deployments/sentryflow/templates/_helpers.tpl b/deployments/sentryflow/templates/_helpers.tpl new file mode 100644 index 0000000..1174b74 --- /dev/null +++ b/deployments/sentryflow/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "sentryflow.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sentryflow.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sentryflow.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "sentryflow.labels" -}} +helm.sh/chart: {{ include "sentryflow.chart" . }} +{{ include "sentryflow.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "sentryflow.selectorLabels" -}} +app.kubernetes.io/name: {{ include "sentryflow.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "sentryflow.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "sentryflow.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deployments/sentryflow/templates/clusterrole.yaml b/deployments/sentryflow/templates/clusterrole.yaml new file mode 100644 index 0000000..7ff37f6 --- /dev/null +++ b/deployments/sentryflow/templates/clusterrole.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "sentryflow.fullname" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - networking.istio.io + verbs: + - get + - create + - delete + resources: + - envoyfilters + - apiGroups: + - extensions.istio.io + verbs: + - get + - create + - delete + resources: + - wasmplugins + + - apiGroups: + - "" + verbs: + - get + resources: + - configmaps + - apiGroups: + - apps + verbs: + - get + resources: + - deployments diff --git a/deployments/sentryflow/templates/clusterrolebinding.yaml b/deployments/sentryflow/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..a2c9f0c --- /dev/null +++ b/deployments/sentryflow/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "sentryflow.fullname" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "sentryflow.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "sentryflow.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/deployments/sentryflow/templates/configmap.yaml b/deployments/sentryflow/templates/configmap.yaml new file mode 100644 index 0000000..e55df05 --- /dev/null +++ b/deployments/sentryflow/templates/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: sentryflow + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.config }} +data: + config.yaml: |2- + {{- toYaml . | nindent 4 }} +{{- end }} diff --git a/deployments/sentryflow/templates/deployment.yaml b/deployments/sentryflow/templates/deployment.yaml new file mode 100644 index 0000000..d411a70 --- /dev/null +++ b/deployments/sentryflow/templates/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "sentryflow.fullname" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "sentryflow.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "sentryflow.labels" . | nindent 8 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "sentryflow.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.args }} + args: + {{- toYaml . | nindent 12 }} + {{- end}} + ports: + - name: exporter + containerPort: {{ index .Values.service.ports 0 "port" }} + - name: receiver + containerPort: {{ index .Values.service.ports 1 "port" }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deployments/sentryflow/templates/hpa.yaml b/deployments/sentryflow/templates/hpa.yaml new file mode 100644 index 0000000..a865979 --- /dev/null +++ b/deployments/sentryflow/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "sentryflow.fullname" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "sentryflow.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/deployments/sentryflow/templates/pre-delete-job.yaml b/deployments/sentryflow/templates/pre-delete-job.yaml new file mode 100644 index 0000000..83ef0c0 --- /dev/null +++ b/deployments/sentryflow/templates/pre-delete-job.yaml @@ -0,0 +1,77 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: sentryflow-pre-deletion-cleanup + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": hook-succeeded +rules: + - apiGroups: + - apps + verbs: + - get + - patch + resources: + - deployments + - deployments/scale +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sentryflow-pre-deletion-cleanup + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "-4" + "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: true +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: sentryflow-pre-deletion-cleanup + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "-3" + "helm.sh/hook-delete-policy": hook-succeeded +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: sentryflow-pre-deletion-cleanup +subjects: + - kind: ServiceAccount + name: sentryflow-pre-deletion-cleanup + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: sentryflow-pre-deletion-cleanup + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "-2" + "helm.sh/hook-delete-policy": hook-succeeded +spec: + template: + metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + serviceAccountName: sentryflow-pre-deletion-cleanup + restartPolicy: Never + containers: + - name: pre-deletion-cleanup + image: "bitnami/kubectl:1.30" + imagePullPolicy: IfNotPresent + command: + - kubectl + - -n + - {{ .Release.Namespace }} + - scale + - deploy + - {{ include "sentryflow.fullname" . }} + - --replicas + - "0" diff --git a/deployments/sentryflow/templates/service.yaml b/deployments/sentryflow/templates/service.yaml new file mode 100644 index 0000000..c92909b --- /dev/null +++ b/deployments/sentryflow/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "sentryflow.fullname" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + {{- include "sentryflow.selectorLabels" . | nindent 4 }} diff --git a/deployments/sentryflow/templates/serviceaccount.yaml b/deployments/sentryflow/templates/serviceaccount.yaml new file mode 100644 index 0000000..3a0a0c9 --- /dev/null +++ b/deployments/sentryflow/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "sentryflow.serviceAccountName" . }} + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + {{- with .Values.genericLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/deployments/sentryflow/templates/tests/test-connection.yaml b/deployments/sentryflow/templates/tests/test-connection.yaml new file mode 100644 index 0000000..df26dec --- /dev/null +++ b/deployments/sentryflow/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "sentryflow.fullname" . }}-test-connection" + labels: + {{- include "sentryflow.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: [ 'wget' ] + args: [ '{{ include "sentryflow.fullname" . }}:{{ index .Values.service.ports 1 "port" }}/healthz' ] + restartPolicy: Never diff --git a/deployments/sentryflow/values.yaml b/deployments/sentryflow/values.yaml new file mode 100644 index 0000000..7d5fa1e --- /dev/null +++ b/deployments/sentryflow/values.yaml @@ -0,0 +1,143 @@ +# Default values for SentryFlow. + +# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ +image: + repository: docker.io/5gsec/sentryflow + # This sets the pull policy for images. + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: latest + +# Arguments to pass SentryFlow container +args: + - --config + - /var/lib/sentryflow/config.yaml + # Uncomment the following to turn on debug mode +# - --development +# - "true" + +# This is to override the chart name. +nameOverride: "" +fullnameOverride: "" + +# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +genericLabels: + app.kubernetes.io/part-of: sentryflow + +podSecurityContext: + fsGroup: 2000 + runAsNonRoot: true + +securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + +# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ +service: + # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: ClusterIP + ports: + - name: exporter + port: 8888 # Make sure to use the same port as `.exporter.grpc.port` field of `config` + targetPort: 8888 # Make sure to use the same port as `.filters.server.port` field of `config` + protocol: TCP + - name: receiver + port: 9999 # Make sure to use the same port as `.filters.server.port` field of `config` + targetPort: 9999 # Make sure to use the same port as `.filters.server.port` field of `config` + protocol: TCP + +resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 500m + memory: 256Mi + +# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +livenessProbe: + httpGet: + path: /healthz + port: receiver + httpHeaders: + - name: status + value: "200" +readinessProbe: + httpGet: + path: /healthz + port: receiver + httpHeaders: + - name: status + value: "200" + +# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/ +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# Traffic sources configuration +config: + filters: + server: + port: 9999 + + # Envoy filter is required for `istio-sidecar` service-mesh receiver. + # Uncomment the following if you want to use `istio-sidecar` traffic source +# envoy: +# uri: 5gsec/sentryflow-httpfilter:latest + + # Following is required for `nginx-inc-ingress-controller` receiver. + # Uncomment the following if you want to use `nginx-inc-ingress-controller` traffic source + # nginxIngress: + # deploymentName: nginx-ingress-controller + # configMapName: nginx-ingress + # sentryFlowNjsConfigMapName: sentryflow-njs + + receivers: # aka sources + # Uncomment the following receivers according to your requirement. +# serviceMeshes: + # To get API observability from Istio service mesh uncomment the following +# - name: istio-sidecar +# namespace: istio-system + + # others: + # To get API observability from F5 nginx ingress controller uncomment the following + # - name: nginx-inc-ingress-controller + # namespace: default + + # - name: nginx-webserver + + exporter: + grpc: + port: 8888 + +volumes: + - name: sentryflow + configMap: + name: sentryflow + defaultMode: 420 + +volumeMounts: + - name: sentryflow + mountPath: "/var/lib/sentryflow/" + readOnly: true diff --git a/scripts/add-license-header b/hack/add-license-header similarity index 100% rename from scripts/add-license-header rename to hack/add-license-header diff --git a/scripts/license.header b/hack/license.header similarity index 100% rename from scripts/license.header rename to hack/license.header