diff --git a/ctrl/internal/application/app.go b/ctrl/internal/application/app.go
index c20936457b5f138b4dfc959bc5610408ffc55480..efbcbc62a0e24e0757448bf4bbd972483a5d85b9 100644
--- a/ctrl/internal/application/app.go
+++ b/ctrl/internal/application/app.go
@@ -1,7 +1,9 @@
 package application
 
 import (
+	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/core/ports"
 	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/infrastructure/interaction"
+	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/infrastructure/store"
 	"code.fbi.h-da.de/danet/costaquanta/libs/logging"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
 	"go.uber.org/zap"
@@ -11,6 +13,7 @@ type Application struct {
 	tracer        *sdktrace.TracerProvider
 	HealthServer  *interaction.HealthServer
 	RoutingServer *interaction.RoutingServer
+	KmsStore      ports.KmsStore
 }
 
 func NewApplication(log *zap.Logger, tracer *sdktrace.TracerProvider) *Application {
@@ -22,9 +25,16 @@ func NewApplication(log *zap.Logger, tracer *sdktrace.TracerProvider) *Applicati
 	routingTracer := tracer.Tracer("routingServer")
 	routerSrv := interaction.NewRoutingServer(routingLogger, routingTracer)
 
+	// Create the in-memory KMS store, as we currently have no other option.
+	// Can be replaced by a store choice via flags or config file later.
+	kmsStoreLogger := logging.CreateChildLogger(log, "KmsStore")
+	kmsStoreTracer := tracer.Tracer("KmsStore")
+	kmsStore := store.NewInMemoryKmsStore(kmsStoreLogger, kmsStoreTracer)
+
 	return &Application{
 		tracer:        tracer,
 		HealthServer:  healthSrv,
 		RoutingServer: routerSrv,
+		KmsStore:      kmsStore,
 	}
 }
diff --git a/ctrl/internal/core/model/kms.go b/ctrl/internal/core/model/kms.go
new file mode 100644
index 0000000000000000000000000000000000000000..1a7bff23959c3803ccb8747d51ad0c10ee6fb9cc
--- /dev/null
+++ b/ctrl/internal/core/model/kms.go
@@ -0,0 +1,14 @@
+package model
+
+import "github.com/google/uuid"
+
+type KMS struct {
+	Id   uuid.UUID
+	Name string
+	// Many more fields missing, add when needed.
+	// Should represent everything defined in the kms config api spec.
+}
+
+func NewKMS(id uuid.UUID, name string) *KMS {
+	return &KMS{Id: id, Name: name}
+}
diff --git a/ctrl/internal/core/ports/kms_store.go b/ctrl/internal/core/ports/kms_store.go
new file mode 100644
index 0000000000000000000000000000000000000000..895c1ca50cfa92aac3c1826aef8dad9e5e3d1af3
--- /dev/null
+++ b/ctrl/internal/core/ports/kms_store.go
@@ -0,0 +1,16 @@
+package ports
+
+import (
+	"context"
+
+	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/core/model"
+	"github.com/google/uuid"
+)
+
+type KmsStore interface {
+	Create(context.Context, model.KMS) (model.KMS, error)
+	Get(context.Context, uuid.UUID) (model.KMS, error)
+	GetAll(context.Context) ([]model.KMS, error)
+	Update(context.Context, model.KMS) (model.KMS, error)
+	Delete(context.Context, uuid.UUID) error
+}
diff --git a/ctrl/internal/infrastructure/store/in_memory_kms_store.go b/ctrl/internal/infrastructure/store/in_memory_kms_store.go
new file mode 100644
index 0000000000000000000000000000000000000000..cd3e80f44fc49cf7f0d1dfdf3c298ef71fa28da6
--- /dev/null
+++ b/ctrl/internal/infrastructure/store/in_memory_kms_store.go
@@ -0,0 +1,140 @@
+package store
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sync"
+
+	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/core/model"
+	"github.com/google/uuid"
+	"go.opentelemetry.io/otel/trace"
+	"go.uber.org/zap"
+)
+
+// Implements the KmsStore interface.
+type InMemoryKmsStore struct {
+	// The key is the ID of the KMS, and the value is the KMS object.
+	// The ID of the element is therefore stored twice, as the key and in the value object.
+	// This has to be checked by the store implementation, so that no error happens.
+	dataStore map[uuid.UUID]model.KMS
+	// Used to lock the dataStore
+	dsMutex sync.Mutex
+
+	logger *zap.SugaredLogger
+	tracer trace.Tracer
+}
+
+func NewInMemoryKmsStore(logger *zap.SugaredLogger, tracer trace.Tracer) *InMemoryKmsStore {
+	inMemoryKmsStore := &InMemoryKmsStore{
+		dataStore: make(map[uuid.UUID]model.KMS),
+		dsMutex:   sync.Mutex{},
+		logger:    logger,
+		tracer:    tracer,
+	}
+
+	return inMemoryKmsStore
+}
+
+func (s *InMemoryKmsStore) Create(ctx context.Context, inputKms model.KMS) (model.KMS, error) {
+	_, span := s.tracer.Start(ctx, "Create KMS")
+	defer span.End()
+
+	s.dsMutex.Lock()
+	defer s.dsMutex.Unlock()
+
+	if _, kmsAlreadyExists := s.dataStore[inputKms.Id]; kmsAlreadyExists {
+		s.logger.Errorw("KMS already exists in database",
+			"kmsId", inputKms.Id.String(),
+			"kmsName", inputKms.Name)
+
+		errorString := fmt.Sprintf(
+			"kms with id %s already exists in database",
+			inputKms.Id.String(),
+		)
+
+		return model.KMS{}, errors.New(errorString)
+	} else {
+		s.dataStore[inputKms.Id] = inputKms
+	}
+
+	return s.dataStore[inputKms.Id], nil
+}
+
+func (s *InMemoryKmsStore) Get(ctx context.Context, id uuid.UUID) (model.KMS, error) {
+	_, span := s.tracer.Start(ctx, "Get KMS")
+	defer span.End()
+
+	s.dsMutex.Lock()
+	defer s.dsMutex.Unlock()
+
+	kms, kmsExists := s.dataStore[id]
+	if !kmsExists {
+		s.logger.Errorw("KMS not found in database",
+			"kmsId", id.String())
+
+		errorString := fmt.Sprintf("no kms found with id %s", id.String())
+
+		return model.KMS{}, errors.New(errorString)
+	}
+
+	return kms, nil
+}
+
+func (s *InMemoryKmsStore) GetAll(ctx context.Context) ([]model.KMS, error) {
+	_, span := s.tracer.Start(ctx, "GetAll KMS")
+	defer span.End()
+
+	s.dsMutex.Lock()
+	defer s.dsMutex.Unlock()
+
+	kmsList := make([]model.KMS, 0, len(s.dataStore))
+	for _, kms := range s.dataStore {
+		kmsList = append(kmsList, kms)
+	}
+
+	return kmsList, nil
+}
+
+func (s *InMemoryKmsStore) Update(ctx context.Context, inputKms model.KMS) (model.KMS, error) {
+	_, span := s.tracer.Start(ctx, "Update KMS")
+	defer span.End()
+
+	s.dsMutex.Lock()
+	defer s.dsMutex.Unlock()
+
+	_, kmsExists := s.dataStore[inputKms.Id]
+	if !kmsExists {
+		s.logger.Errorw("KMS not found in database",
+			"kmsId: ", inputKms.Id.String(),
+			"kmsName: ", inputKms.Name)
+		errorString := fmt.Sprintf("no kms found with id %s", inputKms.Id.String())
+
+		return model.KMS{}, errors.New(errorString)
+	}
+
+	s.dataStore[inputKms.Id] = inputKms
+
+	return s.dataStore[inputKms.Id], nil
+}
+
+func (s *InMemoryKmsStore) Delete(ctx context.Context, id uuid.UUID) error {
+	_, span := s.tracer.Start(ctx, "Delete KMS")
+	defer span.End()
+
+	s.dsMutex.Lock()
+	defer s.dsMutex.Unlock()
+
+	_, kmsExists := s.dataStore[id]
+	if !kmsExists {
+		s.logger.Errorw("KMS not found in database",
+			"kmsId: ", id.String())
+		errorString := fmt.Sprintf("no kms found with id %s", id.String())
+
+		return errors.New(errorString)
+	}
+
+	delete(s.dataStore, id)
+
+	return nil
+}
diff --git a/ctrl/internal/infrastructure/store/in_memory_kms_store_test.go b/ctrl/internal/infrastructure/store/in_memory_kms_store_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7edb39e64ad9cb1fafe04461d1102006bc936bc8
--- /dev/null
+++ b/ctrl/internal/infrastructure/store/in_memory_kms_store_test.go
@@ -0,0 +1,243 @@
+package store
+
+import (
+	"context"
+	"testing"
+
+	"code.fbi.h-da.de/danet/costaquanta/ctrl/internal/core/model"
+	"code.fbi.h-da.de/danet/costaquanta/libs/logging"
+	"github.com/google/uuid"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"go.opentelemetry.io/otel/trace/noop"
+)
+
+func createCtxAndStoreForTest() (*InMemoryKmsStore, context.Context) {
+	// Create a tracer which does nothing but satisfies the interface
+	tracer := noop.NewTracerProvider().Tracer("kmsStoreTest")
+
+	// Creates a logger for the tests
+	parentLogger := logging.CreateProductionLogger("kms")
+	childLogger := logging.CreateChildLogger(parentLogger, "kmsStoreTest")
+
+	ctx := context.Background()
+
+	return NewInMemoryKmsStore(childLogger, tracer), ctx
+}
+
+func TestInMemoryKmsStoreCreate(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Create one KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		createdKms, err := store.Create(ctx, kms)
+		require.NoError(t, err)
+		assert.Equal(t, kms, createdKms)
+		assert.Equal(t, kms, store.dataStore[kms.Id])
+	})
+
+	t.Run("Create an already existing KMS should result in error", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+		kms1Id := uuid.New()
+
+		kms1 := model.KMS{Id: kms1Id, Name: "Test KMS"}
+		_, err := store.Create(ctx, kms1)
+		require.NoError(t, err)
+
+		kms2 := model.KMS{Id: kms1Id, Name: "Test KMS"}
+		_, err = store.Create(ctx, kms2)
+
+		assert.Equal(t, kms1, store.dataStore[kms1Id])
+		assert.Len(t, store.dataStore, 1)
+
+		require.Error(t, err)
+	})
+
+	t.Run("Create multiple KMS with different IDs", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		for range 100 {
+			kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+			_, err := store.Create(ctx, kms)
+			require.NoError(t, err)
+		}
+
+		assert.Len(t, store.dataStore, 100)
+	})
+}
+
+func TestInMemoryKmsStoreUpdate(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Update one KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		// Update the KMS
+		kms.Name = "Updated KMS"
+		updatedKms, err := store.Update(ctx, kms)
+		require.NoError(t, err)
+		assert.Equal(t, kms, updatedKms)
+
+		assert.Equal(t, kms, store.dataStore[kms.Id])
+		assert.Len(t, store.dataStore, 1)
+	})
+
+	t.Run("Update not existing KMS should result in error", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		kms2 := model.KMS{Id: uuid.New(), Name: "Updated KMS"}
+
+		// Update the KMS which does not exist.
+		_, err := store.Update(ctx, kms2)
+		require.Error(t, err)
+
+		assert.Len(t, store.dataStore, 1)
+		assert.Equal(t, kms, store.dataStore[kms.Id])
+	})
+}
+
+func TestInMemoryKmsStoreGet(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Get one KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		returnedKms, err := store.Get(ctx, kms.Id)
+		require.NoError(t, err)
+		assert.Equal(t, kms, returnedKms)
+
+		assert.Equal(t, returnedKms, store.dataStore[kms.Id])
+		assert.Len(t, store.dataStore, 1)
+	})
+
+	t.Run("Get not existing KMS should result in error", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		// Store ist currently empty
+		_, err := store.Get(ctx, uuid.New())
+		require.Error(t, err)
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		// Store is not empty, but we request an non existing uuid
+		_, err = store.Get(ctx, uuid.New())
+		require.Error(t, err)
+	})
+}
+
+func TestInMemoryKmsStoreGetAll(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Get all KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		for range 100 {
+			kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+			store.dataStore[kms.Id] = kms
+		}
+
+		returnedSlice, err := store.GetAll(ctx)
+		require.NoError(t, err)
+		assert.Len(t, returnedSlice, 100)
+
+		idMap := make(map[uuid.UUID]bool)
+		for _, kms := range returnedSlice {
+			assert.Equal(t, "Test KMS", kms.Name)
+			_, exists := idMap[kms.Id]
+			assert.False(t, exists)
+			idMap[kms.Id] = true
+		}
+	})
+
+	t.Run(
+		"Get all KMS when none available should result in empty return slice",
+		func(t *testing.T) {
+			t.Parallel()
+			store, ctx := createCtxAndStoreForTest()
+
+			returnedSlice, err := store.GetAll(ctx)
+			require.NoError(t, err)
+			assert.Empty(t, returnedSlice)
+
+			assert.Empty(t, returnedSlice)
+		},
+	)
+}
+
+func TestInMemoryKmsStoreDelete(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Delete one KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		err := store.Delete(ctx, kms.Id)
+		require.NoError(t, err)
+
+		assert.Empty(t, store.dataStore)
+	})
+
+	t.Run("Delete one KMS should only delete the exact KMS", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		for range 99 {
+			kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+			store.dataStore[kms.Id] = kms
+		}
+		assert.Len(t, store.dataStore, 100)
+
+		err := store.Delete(ctx, kms.Id)
+		require.NoError(t, err)
+
+		_, err = store.Get(ctx, kms.Id)
+		require.Error(t, err)
+
+		assert.Len(t, store.dataStore, 99)
+	})
+
+	t.Run("Delete not existing KMS should result in error", func(t *testing.T) {
+		t.Parallel()
+		store, ctx := createCtxAndStoreForTest()
+
+		// Store ist currently empty
+		err := store.Delete(ctx, uuid.New())
+		require.Error(t, err)
+
+		kms := model.KMS{Id: uuid.New(), Name: "Test KMS"}
+		store.dataStore[kms.Id] = kms
+
+		// Store is not empty, but we request an non existing uuid
+		err = store.Delete(ctx, uuid.New())
+		require.Error(t, err)
+
+		assert.Equal(t, kms, store.dataStore[kms.Id])
+		assert.Len(t, store.dataStore, 1)
+	})
+}
diff --git a/go.mod b/go.mod
index e8bb12203594b8d90430f88a78eaf7c600a84d94..8b45236a07e4b85643d6082fa8806895bf8166ff 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,9 @@ go 1.24
 
 require (
 	github.com/caarlos0/env/v11 v11.3.1
+	github.com/google/uuid v1.6.0
 	github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.1
+	github.com/stretchr/testify v1.10.0
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0
 	go.opentelemetry.io/otel v1.35.0
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0
@@ -18,10 +20,11 @@ require (
 
 require (
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/google/uuid v1.6.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect
@@ -33,4 +36,5 @@ require (
 	golang.org/x/text v0.22.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index db8e9b44ebdb9f554a47ac8c3bd63abf55803013..82ada2ccf3631a33271aa0a0b059a95a72f2bb05 100644
--- a/go.sum
+++ b/go.sum
@@ -19,8 +19,14 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.1 h1:KcFzXwzM/kGhIRHvc8jdix
 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.1/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
@@ -65,5 +71,8 @@ google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
 google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/justfile b/justfile
index 7f0178e59d003b6487680e649295ab7df5a8cbff..db8ec8798a1574601bd00310bd843bc30e973873 100644
--- a/justfile
+++ b/justfile
@@ -10,6 +10,9 @@ run-ctrl:
 build-api:
     buf generate
 
+test:
+    go test ./...
+
 lint:
     docker run --rm -t -v $(pwd):/app -w /app \
     --user $(id -u):$(id -g) \