chore(conf): move away from confspirator
diff --git a/atmosphere/cmd/operator.py b/atmosphere/cmd/operator.py
index fbef0e1..9a1fc52 100644
--- a/atmosphere/cmd/operator.py
+++ b/atmosphere/cmd/operator.py
@@ -1,46 +1,24 @@
 import time
 
-from watchdog.events import FileSystemEventHandler
-from watchdog.observers import Observer
-
-from atmosphere import config, flows, logger
-from atmosphere.config import CONF
+from atmosphere import flows, logger
+from atmosphere.models import config
 
 LOG = logger.get_logger()
 
 
-class AtmosphereFileSystemEventHandler(FileSystemEventHandler):
-    def on_modified(self, event):
-        LOG.info("Detected change in config file, reloading")
-        # NOTE(mnaser): Honestly, after two days, I have no idea why overriding
-        #               the CONF object directly doesn't work, instead we override
-        #               all of it's attribute one by one and.. that works.
-        conf = config.load_config(event.src_path)
-        for c in config._root_config:
-            group = conf.get(c.name)
-            setattr(CONF, c.name, group)
-        engine = flows.get_engine()
-        engine.run()
-
-
 def main():
     LOG.info("Starting Atmosphere operator")
 
-    engine = flows.get_engine()
+    cfg = config.load_from_file()
+
+    engine = flows.get_engine(cfg)
     engine.run()
     LOG.info("Atmosphere operator successfully started")
 
-    observer = Observer()
-    observer.schedule(
-        AtmosphereFileSystemEventHandler(), config.CONFIG_FILE, recursive=True
-    )
-
-    observer.start()
     try:
         while True:
             time.sleep(1)
     except KeyboardInterrupt:
-        observer.stop()
-    observer.join()
+        pass
 
     LOG.info("Stopping Atmosphere operator")
diff --git a/atmosphere/config/__init__.py b/atmosphere/config/__init__.py
deleted file mode 100644
index 1f8fe0c..0000000
--- a/atmosphere/config/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import os
-import sys
-
-import confspirator
-from confspirator import groups
-
-from atmosphere.config import images, memcached
-
-_root_config = groups.ConfigGroup("atmosphere")
-_root_config.register_child_config(images.config_group)
-_root_config.register_child_config(memcached.config_group)
-
-CONFIG_FILE = os.environ.get("ATMOSPHERE_CONFIG", "/etc/atmosphere/config.toml")
-
-
-def load_config(file=CONFIG_FILE):
-    if "pytest" in sys.modules:
-        return confspirator.load_dict(_root_config, {}, test_mode=True)
-
-    return confspirator.load_file(_root_config, file)
-
-
-CONF = load_config()
diff --git a/atmosphere/config/images.py b/atmosphere/config/images.py
deleted file mode 100644
index 2520187..0000000
--- a/atmosphere/config/images.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from confspirator import fields, groups
-
-config_group = groups.ConfigGroup("images")
-
-config_group.register_child_config(
-    fields.StrConfig(
-        "memcached",
-        required=True,
-        default="docker.io/library/memcached:1.6.17",
-        help_text="Memcached image",
-    ),
-)
-config_group.register_child_config(
-    fields.StrConfig(
-        "memcached_exporter",
-        required=True,
-        default="quay.io/prometheus/memcached-exporter:v0.10.0",
-        help_text="Prometheus Memcached exporter image",
-    ),
-)
diff --git a/atmosphere/config/memcached.py b/atmosphere/config/memcached.py
deleted file mode 100644
index 11acbfb..0000000
--- a/atmosphere/config/memcached.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import uuid
-
-from confspirator import fields, groups
-
-config_group = groups.ConfigGroup("memcached")
-
-config_group.register_child_config(
-    fields.BoolConfig(
-        "enabled",
-        default=True,
-        required=True,
-        help_text="Enable Atmosphere-managed Memcached",
-    ),
-)
-config_group.register_child_config(
-    fields.StrConfig(
-        "secret_key",
-        required=True,
-        help_text="Encryption secret key",
-        test_default=uuid.uuid4().hex,
-    ),
-)
-config_group.register_child_config(
-    fields.DictConfig(
-        "overrides",
-        help_text="Override Helm chart values",
-        default={},
-    )
-)
diff --git a/atmosphere/flows.py b/atmosphere/flows.py
index 29b3de1..77ba09b 100644
--- a/atmosphere/flows.py
+++ b/atmosphere/flows.py
@@ -1,22 +1,21 @@
 from taskflow import engines
 from taskflow.patterns import graph_flow
 
-from atmosphere.config import CONF
 from atmosphere.tasks import constants
 from atmosphere.tasks.composite import openstack_helm
 from atmosphere.tasks.kubernetes import flux, v1
 
 
-def get_engine():
+def get_engine(config):
     return engines.load(
-        get_deployment_flow(),
+        get_deployment_flow(config),
         executor="greenthreaded",
         engine="parallel",
         max_workers=4,
     )
 
 
-def get_deployment_flow():
+def get_deployment_flow(config):
     flow = graph_flow.Flow("deploy").add(
         # kube-system
         v1.ApplyNamespaceTask(name=constants.NAMESPACE_KUBE_SYSTEM),
@@ -146,7 +145,7 @@
         ),
     )
 
-    if CONF.memcached.enabled:
+    if config.memcached.enabled:
         flow.add(
             openstack_helm.ApplyReleaseSecretTask(
                 namespace=constants.NAMESPACE_OPENSTACK, chart="memcached"
diff --git a/atmosphere/models/config.py b/atmosphere/models/config.py
new file mode 100644
index 0000000..20ad2ce
--- /dev/null
+++ b/atmosphere/models/config.py
@@ -0,0 +1,77 @@
+import os
+
+import tomli
+from schematics import types
+
+from atmosphere.models import base
+
+CONFIG_FILE = os.environ.get("ATMOSPHERE_CONFIG", "/etc/atmosphere/config.toml")
+
+
+class AcmeIssuerSolverConfig(base.Model):
+    type = types.StringType(choices=("http", "route53"), default="http", required=True)
+
+    @classmethod
+    def _claim_polymorphic(cls, data):
+        return data.get("type", cls.type.default) == cls.TYPE
+
+
+class HttpAcmeIssuerSolverConfig(AcmeIssuerSolverConfig):
+    TYPE = "http"
+
+
+class Route53AcmeIssuerSolverConfig(AcmeIssuerSolverConfig):
+    TYPE = "route53"
+
+    access_key_id = types.StringType(required=True)
+    secret_access_key = types.StringType(required=True)
+    hosted_zone_id = types.StringType(required=True)
+
+
+class Issuer(base.Model):
+    type = types.StringType(
+        choices=("self-signed", "acme"), default="acme", required=True
+    )
+
+    @classmethod
+    def _claim_polymorphic(cls, data):
+        return data.get("type", cls.type.default) == cls.TYPE
+
+
+class AcmeIssuerConfig(Issuer):
+    TYPE = "acme"
+
+    email = types.StringType(required=True)
+    server = types.URLType(default="https://acme-v02.api.letsencrypt.org/directory")
+    solver = types.PolyModelType(
+        [HttpAcmeIssuerSolverConfig, Route53AcmeIssuerSolverConfig], required=True
+    )
+
+
+class SelfSignedIssuerConfig(Issuer):
+    TYPE = "self-signed"
+
+
+class MemcachedImagesConfig(base.Model):
+    memcached = types.StringType(default="docker.io/library/memcached:1.6.17")
+    exporter = types.StringType(default="quay.io/prometheus/memcached-exporter:v0.10.0")
+
+
+class MemcachedConfig(base.Model):
+    enabled = types.BooleanType(default=True)
+    secret_key = types.StringType(required=True)
+    images = types.ModelType(MemcachedImagesConfig, default=MemcachedImagesConfig())
+    overrides = types.DictType(types.BaseType(), default={})
+
+
+class Config(base.Model):
+    memcached = types.ModelType(MemcachedConfig, required=True)
+    issuer = types.DictType(
+        types.PolyModelType([AcmeIssuerConfig, SelfSignedIssuerConfig])
+    )
+
+    @classmethod
+    def load_from_file(cls, path=CONFIG_FILE):
+        with open(path, "rb") as fd:
+            data = tomli.load(fd)
+            return cls(data, validate=True)
diff --git a/atmosphere/models/openstack_helm/endpoints.py b/atmosphere/models/openstack_helm/endpoints.py
index 7de615b..f86980e 100644
--- a/atmosphere/models/openstack_helm/endpoints.py
+++ b/atmosphere/models/openstack_helm/endpoints.py
@@ -1,6 +1,5 @@
 from schematics import types
 
-from atmosphere.config import CONF
 from atmosphere.models import base
 
 
@@ -20,12 +19,12 @@
     auth = types.ModelType(OsloCacheEndpointAuth)
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         return cls(
             {
                 "auth": OsloCacheEndpointAuth(
                     {
-                        "memcache_secret_key": CONF.memcached.secret_key,
+                        "memcache_secret_key": config.memcached.secret_key,
                     }
                 )
             }
@@ -50,7 +49,7 @@
     hosts = types.ModelType(OsloDbEndpointHosts, default=OsloDbEndpointHosts())
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         pass
 
 
@@ -68,11 +67,13 @@
     }
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         endpoint = cls()
 
         for endpoint_name in cls.ENDPOINTS[chart]:
-            endpoint[endpoint_name] = cls.MAPPINGS[endpoint_name].for_chart(chart)
+            endpoint[endpoint_name] = cls.MAPPINGS[endpoint_name].for_chart(
+                chart, config
+            )
         endpoint.validate()
 
         return endpoint
diff --git a/atmosphere/models/openstack_helm/images.py b/atmosphere/models/openstack_helm/images.py
index 32b03dd..7ed5283 100644
--- a/atmosphere/models/openstack_helm/images.py
+++ b/atmosphere/models/openstack_helm/images.py
@@ -1,6 +1,5 @@
 from schematics import types
 
-from atmosphere.config import CONF
 from atmosphere.models import base
 
 
@@ -13,11 +12,11 @@
     prometheus_memcached_exporter = types.StringType(required=True)
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         return cls(
             {
-                "memcached": CONF.images.memcached,
-                "prometheus_memcached_exporter": CONF.images.memcached_exporter,
+                "memcached": config.memcached.images.memcached,
+                "prometheus_memcached_exporter": config.memcached.images.exporter,
             }
         )
 
@@ -31,9 +30,9 @@
     }
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         return cls(
             {
-                "tags": cls.MAPPINGS[chart].for_chart(chart),
+                "tags": cls.MAPPINGS[chart].for_chart(chart, config),
             }
         )
diff --git a/atmosphere/models/openstack_helm/monitoring.py b/atmosphere/models/openstack_helm/monitoring.py
index e67b656..c508f3c 100644
--- a/atmosphere/models/openstack_helm/monitoring.py
+++ b/atmosphere/models/openstack_helm/monitoring.py
@@ -11,7 +11,7 @@
     prometheus = types.ModelType(PrometheusMonitoring)
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         if chart == "memcached":
             return Monitoring(
                 {
diff --git a/atmosphere/models/openstack_helm/values.py b/atmosphere/models/openstack_helm/values.py
index 516d50c..afa3eab 100644
--- a/atmosphere/models/openstack_helm/values.py
+++ b/atmosphere/models/openstack_helm/values.py
@@ -1,10 +1,6 @@
-import mergedeep
-import yaml
-from oslo_serialization import base64
 from schematics import types
 from schematics.transforms import blacklist
 
-from atmosphere.config import CONF
 from atmosphere.models import base
 from atmosphere.models.openstack_helm import endpoints, images, monitoring
 
@@ -17,23 +13,15 @@
     monitoring = types.ModelType(monitoring.Monitoring)
 
     class Options:
-        roles = {"default": blacklist("chart")}
+        roles = {"default": blacklist("chart", "config")}
 
     @classmethod
-    def for_chart(cls, chart):
+    def for_chart(cls, chart, config):
         return cls(
             {
                 "chart": chart,
-                "endpoints": endpoints.Endpoints.for_chart(chart),
-                "images": images.Images.for_chart(chart),
-                "monitoring": monitoring.Monitoring.for_chart(chart),
+                "endpoints": endpoints.Endpoints.for_chart(chart, config),
+                "images": images.Images.for_chart(chart, config),
+                "monitoring": monitoring.Monitoring.for_chart(chart, config),
             }
         )
-
-    @property
-    def secret_data(self):
-        data = self.to_native()
-        overrides = getattr(CONF, self.chart).overrides
-        values = mergedeep.merge({}, data, overrides)
-        values_yaml = yaml.dump(values, default_flow_style=False)
-        return {"values.yaml": base64.encode_as_text(values_yaml)}
diff --git a/atmosphere/tasks/composite/openstack_helm.py b/atmosphere/tasks/composite/openstack_helm.py
index 856ac1e..5f329b9 100644
--- a/atmosphere/tasks/composite/openstack_helm.py
+++ b/atmosphere/tasks/composite/openstack_helm.py
@@ -1,5 +1,9 @@
+import mergedeep
 import pykube
+import yaml
+from oslo_serialization import base64
 
+from atmosphere.models import config
 from atmosphere.models.openstack_helm import values
 from atmosphere.tasks import constants
 from atmosphere.tasks.kubernetes import base, flux, v1
@@ -7,10 +11,19 @@
 
 class ApplyReleaseSecretTask(v1.ApplySecretTask):
     def __init__(self, namespace: str, chart: str, *args, **kwargs):
+        cfg = config.Config.load_from_file()
+        vals = values.Values.for_chart(chart, cfg)
+
+        data = values.to_native()
+        overrides = getattr(cfg, chart).overrides
+
+        vals = mergedeep.merge({}, data, overrides)
+        values_yaml = yaml.dump(vals, default_flow_style=False)
+
         super().__init__(
             namespace,
             f"atmosphere-{chart}",
-            values.Values.for_chart(chart).secret_data,
+            {"values.yaml": base64.encode_as_text(values_yaml)},
             *args,
             **kwargs,
         )
diff --git a/atmosphere/tests/e2e/test_operator.py b/atmosphere/tests/e2e/test_operator.py
index bf3cbfe..adc59e4 100644
--- a/atmosphere/tests/e2e/test_operator.py
+++ b/atmosphere/tests/e2e/test_operator.py
@@ -33,10 +33,8 @@
     args = {
         "atmosphere_image": docker_image,
         "atmosphere_config": {
-            "atmosphere": {
-                "memcached": {
-                    "secret_key": "foobar",
-                }
+            "memcached": {
+                "secret_key": "foobar",
             }
         },
     }
diff --git a/atmosphere/tests/integration/test_deploy.py b/atmosphere/tests/integration/test_deploy.py
index 41ee1c3..9d0210d 100644
--- a/atmosphere/tests/integration/test_deploy.py
+++ b/atmosphere/tests/integration/test_deploy.py
@@ -1,8 +1,7 @@
-import confspirator
 import pykube
 
 from atmosphere import flows
-from atmosphere.config import CONF
+from atmosphere.models import config
 
 
 def test_kubernetes_version(flux_cluster):
@@ -17,7 +16,8 @@
         "label", "node", "pytest-kind-control-plane", "openstack-control-plane=enabled"
     )
 
-    engine = flows.get_engine()
+    cfg = config.Config.get_mock_object()
+    engine = flows.get_engine(cfg)
     engine.run()
 
     initial_memcache_secret = pykube.Secret.objects(
@@ -25,16 +25,9 @@
     ).get_by_name("atmosphere-memcached")
     assert initial_memcache_secret.exists()
 
-    with confspirator.modify_conf(
-        CONF,
-        {
-            "atmosphere.memcached.secret_key": [
-                {"operation": "override", "value": "not-secret"}
-            ],
-        },
-    ):
-        engine = flows.get_engine()
-        engine.run()
+    cfg.memcached.secret_key = "not-secret"
+    engine = flows.get_engine(cfg)
+    engine.run()
 
     updated_memcache_secret = pykube.Secret.objects(
         flux_cluster.api, namespace="openstack"
diff --git a/atmosphere/tests/unit/models/openstack_helm/test_endpoints.py b/atmosphere/tests/unit/models/openstack_helm/test_endpoints.py
index 9957a78..3f5cfb5 100644
--- a/atmosphere/tests/unit/models/openstack_helm/test_endpoints.py
+++ b/atmosphere/tests/unit/models/openstack_helm/test_endpoints.py
@@ -2,7 +2,7 @@
 import requests
 import yaml
 
-from atmosphere.config import CONF
+from atmosphere.models import config
 from atmosphere.models.openstack_helm import endpoints as osh_endpoints
 
 # XXX(mnaser): Once we have the details of our charts codified, we can get rid
@@ -30,18 +30,21 @@
     data = yaml.safe_load(raw_data)
 
     chart_keys = data["endpoints"].keys() - ignored_keys
-    atmosphere_keys = osh_endpoints.Endpoints.for_chart(chart).to_native().keys()
+
+    cfg = config.Config.get_mock_object()
+    atmosphere_keys = osh_endpoints.Endpoints.for_chart(chart, cfg).to_native().keys()
 
     assert chart_keys == atmosphere_keys
 
 
 def test_endpoint_for_chart_memcached():
-    endpoints = osh_endpoints.Endpoints.for_chart("memcached")
+    cfg = config.Config.get_mock_object()
+    endpoints = osh_endpoints.Endpoints.for_chart("memcached", cfg)
 
     assert {
         "oslo_cache": {
             "auth": {
-                "memcache_secret_key": CONF.memcached.secret_key,
+                "memcache_secret_key": cfg.memcached.secret_key,
             }
         }
     } == endpoints.to_primitive()
diff --git a/atmosphere/tests/unit/models/openstack_helm/test_images.py b/atmosphere/tests/unit/models/openstack_helm/test_images.py
index c529c49..a724b34 100644
--- a/atmosphere/tests/unit/models/openstack_helm/test_images.py
+++ b/atmosphere/tests/unit/models/openstack_helm/test_images.py
@@ -1,33 +1,13 @@
-import confspirator
-
-from atmosphere.config import CONF
+from atmosphere.models import config
 from atmosphere.models.openstack_helm import images as osh_images
 
 
-def test_images_for_chart_memcached_with_defaults():
+def test_images_for_chart_memcached():
+    cfg = config.Config.get_mock_object()
     assert {
         "pull_policy": "Always",
         "tags": {
-            "memcached": CONF.images.memcached,
-            "prometheus_memcached_exporter": CONF.images.memcached_exporter,
+            "memcached": cfg.memcached.images.memcached,
+            "prometheus_memcached_exporter": cfg.memcached.images.exporter,
         },
-    } == osh_images.Images.for_chart("memcached").to_primitive()
-
-
-@confspirator.modify_conf(
-    CONF,
-    {
-        "atmosphere.images.memcached": [{"operation": "override", "value": "foo"}],
-        "atmosphere.images.memcached_exporter": [
-            {"operation": "override", "value": "bar"}
-        ],
-    },
-)
-def test_images_for_chart_memcached_with_overrides():
-    assert {
-        "pull_policy": "Always",
-        "tags": {
-            "memcached": "foo",
-            "prometheus_memcached_exporter": "bar",
-        },
-    } == osh_images.Images.for_chart("memcached").to_primitive()
+    } == osh_images.Images.for_chart("memcached", cfg).to_primitive()
diff --git a/atmosphere/tests/unit/models/openstack_helm/test_values.py b/atmosphere/tests/unit/models/openstack_helm/test_values.py
index d5e8f1d..8ed2dfa 100644
--- a/atmosphere/tests/unit/models/openstack_helm/test_values.py
+++ b/atmosphere/tests/unit/models/openstack_helm/test_values.py
@@ -1,22 +1,23 @@
-from atmosphere.config import CONF
+from atmosphere.models import config
 from atmosphere.models.openstack_helm import values as osh_values
 
 
 class TestMemcachedValues:
     def test_values_for_chart(self):
-        values = osh_values.Values.for_chart("memcached")
+        cfg = config.Config.get_mock_object()
+        values = osh_values.Values.for_chart("memcached", cfg)
 
         assert {
             "endpoints": {
                 "oslo_cache": {
-                    "auth": {"memcache_secret_key": CONF.memcached.secret_key}
+                    "auth": {"memcache_secret_key": cfg.memcached.secret_key}
                 }
             },
             "images": {
                 "pull_policy": "Always",
                 "tags": {
-                    "memcached": CONF.images.memcached,
-                    "prometheus_memcached_exporter": CONF.images.memcached_exporter,
+                    "memcached": cfg.memcached.images.memcached,
+                    "prometheus_memcached_exporter": cfg.memcached.images.exporter,
                 },
             },
             "monitoring": {
diff --git a/poetry.lock b/poetry.lock
index 613801f..cc587e2 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -165,23 +165,6 @@
 test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
 
 [[package]]
-name = "confspirator"
-version = "0.3.0"
-description = "A config library for handling nested incode config groups."
-category = "main"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-netaddr = ">=0.7.18"
-pbr = ">=5.2.0"
-python-slugify = ">=3.0.2"
-PyYAML = ">=5.1"
-rfc3986 = ">=1.2.0"
-six = ">=1.12.0"
-toml = ">=0.10.2"
-
-[[package]]
 name = "cookiecutter"
 version = "2.1.1"
 description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template."
@@ -779,7 +762,7 @@
 name = "python-slugify"
 version = "6.1.2"
 description = "A Python slugify application that also handles Unicode"
-category = "main"
+category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
@@ -824,17 +807,6 @@
 use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
 
 [[package]]
-name = "rfc3986"
-version = "2.0.0"
-description = "Validating URI References per RFC 3986"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-idna2008 = ["idna"]
-
-[[package]]
 name = "rich"
 version = "12.5.1"
 description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
@@ -958,23 +930,15 @@
 name = "text-unidecode"
 version = "1.3"
 description = "The most basic Text::Unidecode port"
-category = "main"
+category = "dev"
 optional = false
 python-versions = "*"
 
 [[package]]
-name = "toml"
-version = "0.10.2"
-description = "Python Library for Tom's Obvious, Minimal Language"
-category = "main"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-
-[[package]]
 name = "tomli"
 version = "2.0.1"
 description = "A lil' TOML parser"
-category = "dev"
+category = "main"
 optional = false
 python-versions = ">=3.7"
 
@@ -1034,17 +998,6 @@
 socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 
 [[package]]
-name = "watchdog"
-version = "2.1.9"
-description = "Filesystem events monitoring"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-watchmedo = ["PyYAML (>=3.10)"]
-
-[[package]]
 name = "wcwidth"
 version = "0.2.5"
 description = "Measures the displayed width of unicode strings in a terminal"
@@ -1063,7 +1016,7 @@
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.10"
-content-hash = "2467ec3e1730d789b4b33c269da9c86b57a804c7560c78eeb05dd08784da4017"
+content-hash = "9b2037d4a4a41305e6950728f58b0f7d59e60bc87f8d93db7ff2741e7992d5c8"
 
 [metadata.files]
 ansible-compat = [
@@ -1126,9 +1079,6 @@
     {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
     {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
 ]
-confspirator = [
-    {file = "confspirator-0.3.0.tar.gz", hash = "sha256:065c22e8c317c623668fd71c6c40038829b934ec320785c7d21e05b6a5b2c711"},
-]
 cookiecutter = [
     {file = "cookiecutter-2.1.1-py2.py3-none-any.whl", hash = "sha256:9f3ab027cec4f70916e28f03470bdb41e637a3ad354b4d65c765d93aad160022"},
     {file = "cookiecutter-2.1.1.tar.gz", hash = "sha256:f3982be8d9c53dac1261864013fdec7f83afd2e42ede6f6dd069c5e149c540d5"},
@@ -1648,10 +1598,6 @@
     {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
     {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
 ]
-rfc3986 = [
-    {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"},
-    {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"},
-]
 rich = [
     {file = "rich-12.5.1-py3-none-any.whl", hash = "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb"},
     {file = "rich-12.5.1.tar.gz", hash = "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca"},
@@ -1692,10 +1638,6 @@
     {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
     {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
 ]
-toml = [
-    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
-    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
-]
 tomli = [
     {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
@@ -1716,33 +1658,6 @@
     {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
     {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
 ]
-watchdog = [
-    {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"},
-    {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d"},
-    {file = "watchdog-2.1.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658"},
-    {file = "watchdog-2.1.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591"},
-    {file = "watchdog-2.1.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33"},
-    {file = "watchdog-2.1.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846"},
-    {file = "watchdog-2.1.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3"},
-    {file = "watchdog-2.1.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654"},
-    {file = "watchdog-2.1.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39"},
-    {file = "watchdog-2.1.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7"},
-    {file = "watchdog-2.1.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd"},
-    {file = "watchdog-2.1.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3"},
-    {file = "watchdog-2.1.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d"},
-    {file = "watchdog-2.1.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_armv7l.whl", hash = "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_i686.whl", hash = "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_ppc64.whl", hash = "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_s390x.whl", hash = "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1"},
-    {file = "watchdog-2.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6"},
-    {file = "watchdog-2.1.9-py3-none-win32.whl", hash = "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1"},
-    {file = "watchdog-2.1.9-py3-none-win_amd64.whl", hash = "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c"},
-    {file = "watchdog-2.1.9-py3-none-win_ia64.whl", hash = "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428"},
-    {file = "watchdog-2.1.9.tar.gz", hash = "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609"},
-]
 wcwidth = [
     {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
     {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
diff --git a/pyproject.toml b/pyproject.toml
index d09bb04..650687b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,14 +12,13 @@
 python = "^3.10"
 schematics = "^2.1.1"
 pykube-ng = "^22.7.0"
-confspirator = "^0.3.0"
-watchdog = "^2.1.9"
 structlog = "^22.1.0"
 rich = "^12.5.1"
 better-exceptions = "^0.3.3"
 mergedeep = "^1.3.4"
 taskflow = "^5.0.0"
 eventlet = "^0.33.1"
+tomli = "^2.0.1"
 
 [tool.poetry.group.dev.dependencies]
 pytest = "^7.1.3"
diff --git a/roles/atmosphere/defaults/main.yml b/roles/atmosphere/defaults/main.yml
index 7075517..5f20539 100644
--- a/roles/atmosphere/defaults/main.yml
+++ b/roles/atmosphere/defaults/main.yml
@@ -1,7 +1,6 @@
 atmosphere_image: quay.io/vexxhost/atmosphere:0.3.0 # x-release-please-version
 
 atmosphere_config:
-  atmosphere:
-    memcached:
-      secret_key: "{{ openstack_helm_endpoints_memcached_secret_key }}"
-      overrides: "{{ openstack_helm_infra_memcached_values | default({}) }}"
+  memcached:
+    secret_key: "{{ openstack_helm_endpoints_memcached_secret_key }}"
+    overrides: "{{ openstack_helm_infra_memcached_values | default({}) }}"