diff --git a/deployment/helm/.gitlab-ci.yml b/deployment/helm/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a04298159e10b963a6abe85e63dad6f2cc1a3539
--- /dev/null
+++ b/deployment/helm/.gitlab-ci.yml
@@ -0,0 +1,24 @@
+variables:
+  HELPERS_FILE: helm-package.yml
+
+image: nexus.tech.vereign.com:6001/helm:3.5.3
+
+include:
+  - project: '${HELPERS_PATH}'
+    file: '${HELPERS_FILE}'
+
+stages:
+  - lint
+  - package
+
+helm-lint:
+  extends: .helm-lint
+  stage: lint
+  tags:
+    - amd64-docker
+
+helm-package:
+  extends: .helm-package
+  stage: package
+  tags:
+    - amd64-docker
diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..153ed58be35559e15e39d3e6d600bd2b3eb48d6a
--- /dev/null
+++ b/deployment/helm/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v1
+appVersion: v1.0.1-rc
+description: cache deployment
+name: cache
+version: 1.0.1
+icon: "https://www.gxfs.eu/wp-content/uploads/2022/01/GFXS_DE_Logo.jpg"
diff --git a/deployment/helm/LICENSE b/deployment/helm/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..eb9b004561b927e8b86c0f1fe039c06ffcd3a4ac
--- /dev/null
+++ b/deployment/helm/LICENSE
@@ -0,0 +1,16 @@
+Deployment recipe for TSA cache service
+
+
+Copyright 2022 Vereign AG
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/deployment/helm/README.md b/deployment/helm/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..072894b4835806a12034115f54feab7c6168d953
--- /dev/null
+++ b/deployment/helm/README.md
@@ -0,0 +1,60 @@
+# cache
+
+![Version: 1.0.1](https://img.shields.io/badge/Version-1.0.1-informational?style=flat-square) ![AppVersion: v1.0.1-rc](https://img.shields.io/badge/AppVersion-v1.0.1--rc-informational?style=flat-square)
+
+cache deployment
+
+## Values
+
+| Key | Type | Default | Description |
+|-----|------|---------|-------------|
+| autoscaling.enabled | bool | `false` | Enable autoscaling |
+| autoscaling.maxReplicas | int | `3` | Maximum replicas |
+| autoscaling.minReplicas | int | `1` | Minimum replicas |
+| autoscaling.targetCPUUtilizationPercentage | int | `70` | CPU target for autoscaling trigger |
+| autoscaling.targetMemoryUtilizationPercentage | int | `70` | Memory target for autoscaling trigger |
+| cache.http.host | string | `""` |  |
+| cache.http.port | int | `8080` |  |
+| cache.http.timeout.idle | string | `"120s"` |  |
+| cache.http.timeout.read | string | `"10s"` |  |
+| cache.http.timeout.write | string | `"10s"` |  |
+| cache.nats.subject | string | `"external_cache_events"` |  |
+| cache.nats.url | string | `"nats.ocm:4222"` |  |
+| image.name | string | `"gaiax/cache"` | Image name |
+| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
+| image.pullSecrets | string | `"deployment-key-light"` | Image pull secret when internal image is used |
+| image.repository | string | `"eu.gcr.io/vrgn-infra-prj"` |  |
+| image.sha | string | `""` | Image sha, usually generated by the CI Uses image.tag if empty |
+| image.tag | string | `""` | Image tag Uses .Chart.AppVersion if empty |
+| ingress.annotations."cert-manager.io/cluster-issuer" | string | `"letsencrypt-production-http"` |  |
+| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` |  |
+| ingress.annotations."kubernetes.io/ingress.global-static-ip-name" | string | `"dev-light-public"` |  |
+| ingress.annotations."nginx.ingress.kubernetes.io/rewrite-target" | string | `"/$2"` |  |
+| ingress.enabled | bool | `true` |  |
+| ingress.frontendDomain | string | `"tsa.gxfs.dev"` |  |
+| ingress.frontendTlsSecretName | string | `"cert-manager-tls"` |  |
+| ingress.tlsEnabled | bool | `true` |  |
+| log.encoding | string | `"json"` |  |
+| log.level | string | `"debug"` |  |
+| metrics.enabled | bool | `true` | Enable prometheus metrics |
+| metrics.port | int | `2112` | Port for prometheus metrics |
+| name | string | `"cache"` | Application name |
+| nameOverride | string | `""` | Ovverwrites application name |
+| podAnnotations | object | `{}` |  |
+| redis.addr | string | `"redis-public-master.infra:6379"` |  |
+| redis.db | int | `0` |  |
+| redis.expiration | string | `"1h"` |  |
+| redis.pass | string | `""` |  |
+| redis.user | string | `""` |  |
+| replicaCount | int | `1` | Default number of instances to start  |
+| resources.limits.cpu | string | `"150m"` |  |
+| resources.limits.memory | string | `"128Mi"` |  |
+| resources.requests.cpu | string | `"25m"` |  |
+| resources.requests.memory | string | `"64Mi"` |  |
+| security.runAsGid | int | `0` | Group used by the apps |
+| security.runAsNonRoot | bool | `false` | by default, apps run as non-root |
+| security.runAsUid | int | `0` | User used by the apps |
+| service.port | int | `8080` |  |
+
+----------------------------------------------
+Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0)
diff --git a/deployment/helm/templates/_helpers.tpl b/deployment/helm/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..6955ccba19a0e68b2918305e46546f4741fea0aa
--- /dev/null
+++ b/deployment/helm/templates/_helpers.tpl
@@ -0,0 +1,88 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "app.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+*/}}
+{{- define "app.fullname" -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" $name .Release.Namespace | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create instance name based on app version and short image sha.
+*/}}
+{{- define "app.revision" -}}
+{{- default .Release.Name .Values.appRel | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "app.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "app.labels" -}}
+helm.sh/chart: {{ include "app.chart" . }}
+{{ include "app.selectorLabels" . }}
+app.kubernetes.io/version: {{ .Chart.AppVersion }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "app.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "app.name" . }}
+app.kubernetes.io/component: {{ include "app.fullname" . }}
+{{- end -}}
+
+{{/*
+Metrics Annotations
+*/}}
+{{- define "app.metricsAnnotations" -}}
+{{- if .Values.metrics.enabled -}}
+prometheus.io/scrape: "true"
+prometheus.io/port: "{{ .Values.metrics.port }}"
+prometheus.io/path: {{ .Values.metrics.path | default "/metrics" | quote }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Image string
+*/}}
+{{- define "app.image" -}}
+{{- if .Values.image.sha -}}
+{{ .Values.image.repository }}/{{ .Values.image.name }}@{{ .Values.image.sha }}
+{{- else -}}
+{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ default .Chart.AppVersion .Values.image.tag }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Security context
+*/}}
+{{- define "app.securitycontext" -}}
+runAsNonRoot: {{ .Values.security.runAsNonRoot | default false }}
+runAsGroup: {{ .Values.security.runAsGid | default 0 }}
+runAsUser: {{ .Values.security.runAsUid | default 0 }}
+fsGroup: {{ .Values.security.runAsGid | default 0 }}
+{{- end -}}
+
+{{/*
+PostgreSQL Connection  string URI
+*/}}
+{{- define "app.postgresql.connectionstring" -}}
+postgresql://{{ .Values.connectionManager.database.user }}:{{ .Values.connectionManager.database.password }}@{{ .Values.connectionManager.database.host }}:{{ .Values.connectionManager.database.port }}/{{ .Release.Namespace }}_{{ include "app.name" . | replace "-" "_" }}?schema={{ .Values.connectionManager.database.schema }}
+{{- end -}}
+
diff --git a/deployment/helm/templates/deployment.yaml b/deployment/helm/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..de4b1a5516b96fcf7ec091e5a4f41ab3908c44d0
--- /dev/null
+++ b/deployment/helm/templates/deployment.yaml
@@ -0,0 +1,89 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: "{{ template "app.name" . }}"
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "app.labels" . | nindent 4 }}
+    app.kubernetes.io/instance: {{ include "app.revision" . }}
+    app.kubernetes.io/part-of: rse
+spec:
+  replicas: {{ .Values.replicaCount }}
+  strategy:
+    type: RollingUpdate
+    rollingUpdate:
+      maxSurge: 1
+      maxUnavailable: 0
+  selector:
+    matchLabels:
+      {{- include "app.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "app.labels" . | nindent 8 }}
+      annotations:
+        {{- include "app.metricsAnnotations" . | nindent 8 }}
+{{- if .Values.podAnnotations }}
+{{ toYaml .Values.podAnnotations | indent 8 }}
+{{- end }}
+    spec:
+      securityContext:
+{{- include "app.securitycontext" . | nindent 8 }}
+      imagePullSecrets:
+        - name: {{ .Values.image.pullSecrets }}
+      containers:
+      - name: {{ template "app.name" . }}
+        image: "{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ default .Chart.AppVersion .Values.image.tag }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
+        env:
+          - name: LOG_LEVEL
+            value: {{ .Values.log.level | default "INFO" }}
+          - name: LOG_ENCODING
+            value: {{ .Values.log.encoding | default "json" }}
+          - name: HTTP_HOST
+            value: {{ .Values.cache.http.host | quote }}
+          - name: HTTP_PORT
+            value: {{ .Values.cache.http.port | quote }}
+          - name: HTTP_IDLE_TIMEOUT
+            value: {{ .Values.cache.http.timeout.idle | quote }}
+          - name: HTTP_READ_TIMEOUT
+            value: {{ .Values.cache.http.timeout.read | quote }}
+          - name: HTTP_WRITE_TIMEOUT
+            value: {{ .Values.cache.http.timeout.write | quote }}
+          - name: REDIS_ADDR
+            value: {{ .Values.redis.addr | quote }}
+          - name: REDIS_USER
+            value: {{ .Values.redis.user | quote }}
+          - name: REDIS_PASS
+            value: {{ .Values.redis.pass | quote }}
+          - name: REDIS_DB
+            value: {{ .Values.redis.db | quote }}
+          - name: REDIS_EXPIRATION
+            value: {{ .Values.redis.expiration | quote }}
+          - name: NATS_ADDR
+            value: {{ .Values.cache.nats.url | quote }}
+          - name: NATS_SUBJECT
+            value: {{ .Values.cache.nats.subject | quote }}
+          - name: TEST_ENC_VAR
+            value: {{ .Values.enc.var | quote }}
+{{- if .Values.extraVars }}
+{{ toYaml .Values.extraVars | indent 8 }}
+{{- end }}
+        ports:
+        {{- if .Values.metrics.enabled }}
+        - name: monitoring
+          containerPort: {{ .Values.metrics.port }}
+        {{- end }}
+        - name: http
+          containerPort: {{ .Values.cache.http.port }}
+        readinessProbe:
+          httpGet:
+            path: /readiness
+            port: {{ .Values.cache.http.port }}
+          initialDelaySeconds: 5
+          periodSeconds: 5
+          successThreshold: 2
+          failureThreshold: 2
+          timeoutSeconds: 5
+        resources:
+{{ toYaml .Values.resources | indent 10 }}
diff --git a/deployment/helm/templates/hpa.yaml b/deployment/helm/templates/hpa.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fc5c29e7463c24756cfa83754e8ab9336be7b8c2
--- /dev/null
+++ b/deployment/helm/templates/hpa.yaml
@@ -0,0 +1,27 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  labels:
+    {{- include "app.labels" . | nindent 4 }}
+  name: {{ template "app.name" . }}
+  namespace: {{ .Release.Namespace }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ template "app.name" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+{{- with .Values.autoscaling.targetCPUUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: cpu
+{{- end }}
+{{- with .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: memory
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/deployment/helm/templates/ingress.yaml b/deployment/helm/templates/ingress.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9a7fe3cdc72c9760e2cf07b7bb2228e77174eefd
--- /dev/null
+++ b/deployment/helm/templates/ingress.yaml
@@ -0,0 +1,29 @@
+{{- if .Values.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ template "app.name" . }}
+  namespace: {{ .Release.Namespace }}
+  annotations:
+{{ toYaml .Values.ingress.annotations | indent 4 }}
+  labels:
+    {{- include "app.labels" . | nindent 4 }}
+spec:
+{{- if .Values.ingress.tlsEnabled }}
+  tls:
+    - hosts:
+        - {{ .Values.ingress.frontendDomain }}
+      secretName: {{ .Values.ingress.frontendTlsSecretName }}
+{{- end }}
+  rules:
+    - host: {{ .Values.ingress.frontendDomain }}
+      http:
+        paths:
+          - path: /tsa/{{ template "app.name" . }}(/|$)(.*)
+            pathType: Prefix
+            backend:
+              service:
+                name: {{ template "app.name" . }}
+                port:
+                  number: {{ .Values.service.port }}
+{{- end }}
diff --git a/deployment/helm/templates/service.yaml b/deployment/helm/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..92420d98644c0abaa143b78a043163e6aff2877c
--- /dev/null
+++ b/deployment/helm/templates/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "app.name" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "app.labels" . | nindent 4 }}
+spec:
+  clusterIP: None
+  ports:
+  - name: http
+    targetPort: {{ .Values.service.port }}
+    port: {{ .Values.cache.http.port }}
+  selector:
+    {{- include "app.selectorLabels" . | nindent 4 }}
diff --git a/deployment/helm/values-override.yaml b/deployment/helm/values-override.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..82db69e74372f88d5e543c839b67b9cb462bb96a
--- /dev/null
+++ b/deployment/helm/values-override.yaml
@@ -0,0 +1,11 @@
+image:
+  repository: registry.gitlab.com/gaia-x/data-infrastructure-federation-services/tsa
+  # -- Image name
+  name: cache
+
+redis:
+  addr: "redis-master.tsa:6379"
+
+ingress:
+  frontendDomain: tsa.gxfs.dev 
+  frontendTlsSecretName: wildcard-gxfs-dev 
diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3d72bda32d558bd70138bd6c7816b6f3d6767321
--- /dev/null
+++ b/deployment/helm/values.yaml
@@ -0,0 +1,118 @@
+# -- Default number of instances to start 
+replicaCount: 1
+# -- Application name
+name: cache
+# -- Ovverwrites application name
+nameOverride: ""
+
+image:
+  repository: eu.gcr.io/vrgn-infra-prj
+  # -- Image name
+  name: gaiax/cache
+  # -- Image tag
+  # Uses .Chart.AppVersion if empty
+  tag: ""
+  # -- Image sha, usually generated by the CI
+  # Uses image.tag if empty
+  sha: ""
+  # -- Image pull policy
+  pullPolicy: IfNotPresent
+  # -- Image pull secret when internal image is used
+  pullSecrets: deployment-key-light
+
+
+podAnnotations: {}
+##
+## Pass extra environment variables to the container.
+##
+# extraVars:
+# - name: EXTRA_VAR_1
+#   value: extra-var-value-1
+# - name: EXTRA_VAR_2
+#   value: extra-var-value-2
+##
+## Create new service when true, and use the specified uner name when set to the name specified
+##
+
+resources:
+  requests:
+    cpu: 25m
+    memory: 64Mi
+  limits:
+    cpu: 150m
+    memory: 128Mi
+
+## Configure pod autoscaling
+##
+
+autoscaling:
+  # -- Enable autoscaling
+  enabled: false
+  # -- Minimum replicas
+  minReplicas: 1
+  # -- Maximum replicas
+  maxReplicas: 3
+  # -- CPU target for autoscaling trigger
+  targetCPUUtilizationPercentage: 70
+  # -- Memory target for autoscaling trigger
+  targetMemoryUtilizationPercentage: 70
+##
+## Prometheus Exporter / Metrics
+##
+
+metrics:
+  # -- Enable prometheus metrics
+  enabled: true
+  # -- Port for prometheus metrics
+  port: 2112
+
+log:
+  level: "debug"
+  encoding: json
+
+##
+## Kubernetes [SecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) object.
+##
+
+security:
+  # -- by default, apps run as non-root
+  runAsNonRoot: false
+  # -- User used by the apps
+  runAsUid: 0
+  # -- Group used by the apps
+  runAsGid: 0
+##
+##
+service:
+  port: 8080
+
+cache:
+  http:
+    host: ""
+    port: 8080
+    timeout:
+      idle: 120s
+      read: 10s
+      write: 10s
+  nats:
+    url: nats.ocm:4222
+    subject: external_cache_events
+
+redis:
+  addr: "redis-public-master.infra:6379"
+  user: ""
+  pass: ""
+  db: 0
+  expiration: 1h
+
+ingress:
+  enabled: true
+  annotations:
+    kubernetes.io/ingress.class: nginx
+    nginx.ingress.kubernetes.io/rewrite-target: /$2
+  tlsEnabled: true
+  frontendDomain: gaiax.vereign.com
+  frontendTlsSecretName: cert-manager-tls
+
+enc:
+  var: ivan