diff --git a/infrastructure/kustomization.yaml b/infrastructure/kustomization.yaml
index d03694ee6b054d4275f21a9503097cef2000f7ce..e46fbadb4530aabad0df2f3bbb567c7ca819a150 100644
--- a/infrastructure/kustomization.yaml
+++ b/infrastructure/kustomization.yaml
@@ -11,6 +11,7 @@ resources:
   - nginx-system
   - longhorn
   - monitoring
+  - loki
   - flux-system
   - k8up
   - postgres
diff --git a/infrastructure/loki/README.md b/infrastructure/loki/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bc94e93bf496ae3d360dc47b4d6a15d4447383f6
--- /dev/null
+++ b/infrastructure/loki/README.md
@@ -0,0 +1,12 @@
+Loki
+===
+
+Keeping all logs centralised.
+
+
+Links
+---
+
+- [Docs](https://grafana.com/docs/loki/latest/)
+- [Helm Chart](https://artifacthub.io/packages/helm/grafana/loki-stack)
+- [Source Code](https://github.com/grafana/loki)
diff --git a/infrastructure/loki/kustomization.yaml b/infrastructure/loki/kustomization.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..64dc3a10084453f0ea8dd37c82dced3e7b5260f0
--- /dev/null
+++ b/infrastructure/loki/kustomization.yaml
@@ -0,0 +1,12 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+namespace: loki-system
+resources:
+  - namespace.yaml
+  - repository.yaml
+  - loki.yaml
+  - promtail.yaml
+  - ../../shared/networkpolicies/allow-from-monitoring.yaml
+  - ../../shared/networkpolicies/allow-from-same-namespace.yaml
+patchesStrategicMerge:
+  - networkpolicy.yaml
diff --git a/infrastructure/loki/loki.yaml b/infrastructure/loki/loki.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..60a5de42caaf528fa08f7a05508b992983983ec2
--- /dev/null
+++ b/infrastructure/loki/loki.yaml
@@ -0,0 +1,150 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: loki
+  namespace: loki-system
+spec:
+  releaseName: loki
+  chart:
+    spec:
+      chart: loki
+      sourceRef:
+        kind: HelmRepository
+        name: grafana
+        namespace: loki-system
+      version: 3.2.0
+  interval: 5m
+  upgrade:
+    remediation:
+      retries: -1
+    crds: CreateReplace
+  install:
+    remediation:
+      retries: -1
+    crds: CreateReplace
+  valuesFrom:
+    - kind: ConfigMap
+      name: loki-base-values
+      valuesKey: values.yaml
+    - kind: Secret
+      name: loki-override-values
+      valuesKey: values-overrides.yaml
+      optional: true
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: loki-base-values
+  namespace: loki-system
+data:
+  values.yaml: |
+    loki:
+      auth_enabled: false
+      commonConfig:
+        replication_factor: 1
+      storage:
+        type: s3
+        s3:
+          endpoint: loki-minio.loki-system.svc.cluster.local:9000
+          insecure: true
+          accessKeyId: loki
+          secretAccessKey: supersecret
+          s3ForcePathStyle: true
+    read:
+      replicas: 2
+    write:
+      replicas: 2
+    ruler:
+      enabled: false
+    monitoring:
+      enabled: true
+      selfMonitoring:
+        grafanaAgent:
+          installOperator: false
+    networkPolicy:
+      enabled: true
+      metrics:
+        namespaceSelector:
+          matchLabels:
+            monitoring.shivering-isles.com/network-access-required: "true"
+        podSelector:
+          matchLabels:
+            app.kubernetes.io/name: prometheus
+      ingress:
+        namespaceSelector:
+            matchLabels:
+              ingress.shivering-isles.com/network-access-required: "true"
+      alertmanager:
+        namespaceSelector:
+          matchLabels:
+            monitoring.shivering-isles.com/network-access-required: "true"
+        podSelector:
+          matchLabels:
+            app.kubernetes.io/name: alertmanager
+      externalStorage:
+        ports:
+          - 9000
+    minio:
+      enabled: true
+      mode: standalone
+      rootUser: loki
+      rootPassword: supersecret
+      persistence:
+        size: 50Gi
+      networkPolicy:
+        enabled: true
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-from-grafana
+spec:
+  policyTypes:
+  - Ingress
+  ingress:
+  - from:
+    - namespaceSelector:
+        matchLabels:
+          monitoring.shivering-isles.com/network-access-required: "true"
+      podSelector:
+        matchLabels:
+          app.kubernetes.io/name: grafana
+  podSelector:
+    matchLabels:
+      app.kubernetes.io/component: gateway
+      app.kubernetes.io/instance: loki
+      app.kubernetes.io/name: loki
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-from-job-to-minio
+spec:
+  policyTypes:
+  - Egress
+  egress:
+  - ports:
+    - protocol: TCP
+      port: 9000
+  podSelector:
+    matchLabels:
+      app: minio-job
+      release: loki
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: datasource-loki
+  namespace: loki-system
+  labels:
+    grafana_datasource: "1"
+data:
+  loki-stack-datasource.yaml: |-
+    apiVersion: 1
+    datasources:
+    - name: Loki
+      type: loki
+      access: proxy
+      url: http://loki-gateway.loki-system.svc.cluster.local
+      version: 1
+      isDefault: false
diff --git a/infrastructure/loki/namespace.yaml b/infrastructure/loki/namespace.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d0ca51d76589fd85a39b3fff4444923825a33dd9
--- /dev/null
+++ b/infrastructure/loki/namespace.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: loki-system
+  labels:
+    kyverno.shivering-isles.com/class: "system"
+    pod-security.kubernetes.io/enforce: privileged
+    pod-security.kubernetes.io/audit: privileged
+    pod-security.kubernetes.io/warn: privileged
diff --git a/infrastructure/loki/networkpolicy.yaml b/infrastructure/loki/networkpolicy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ac6be27a3d659b793e2132c2a8572cdd4f4a2de6
--- /dev/null
+++ b/infrastructure/loki/networkpolicy.yaml
@@ -0,0 +1,10 @@
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-from-monitoring
+spec:
+  podSelector:
+    matchLabels:
+      app.kubernetes.io/instance: loki
+      app.kubernetes.io/name: loki
diff --git a/infrastructure/loki/promtail.yaml b/infrastructure/loki/promtail.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dab6957a09720873577ba5cca667dc2fdab985ab
--- /dev/null
+++ b/infrastructure/loki/promtail.yaml
@@ -0,0 +1,97 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: promtail
+  namespace: loki-system
+spec:
+  releaseName: promtail
+  chart:
+    spec:
+      chart: promtail
+      sourceRef:
+        kind: HelmRepository
+        name: grafana
+        namespace: loki-system
+      version: 6.4.0
+  interval: 5m
+  upgrade:
+    remediation:
+      retries: -1
+    crds: CreateReplace
+  install:
+    remediation:
+      retries: -1
+    crds: CreateReplace
+  valuesFrom:
+    - kind: ConfigMap
+      name: promtail-base-values
+      valuesKey: values.yaml
+    - kind: Secret
+      name: promtail-override-values
+      valuesKey: values-overrides.yaml
+      optional: true
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: promtail-base-values
+  namespace: loki-system
+data:
+  values.yaml: |
+    serviceMonitor:
+      enabled: true
+    networkPolicy:
+      enabled: true
+      metrics:
+        namespaceSelector:
+          matchLabels:
+            monitoring.shivering-isles.com/network-access-required: "true"
+        podSelector:
+          matchLabels:
+            app.kubernetes.io/name: prometheus
+    # Required for journald collection
+    containerSecurityContext:
+      privileged: true
+      capabilities: null
+      allowPrivilegeEscalation: true
+    config:
+      snippets:
+        extraScrapeConfigs: |
+          # Add an additional scrape config for journald
+          - job_name: journal
+            journal:
+              path: /var/log/journal
+              max_age: 12h
+              labels:
+                job: systemd-journal
+            relabel_configs:
+              - source_labels:
+                  - __journal__hostname
+                target_label: hostname
+
+              # example label values: kubelet.service, containerd.service
+              - source_labels:
+                  - __journal__systemd_unit
+                target_label: unit
+
+              # example label values: debug, notice, info, warning, error
+              - source_labels:
+                  - __journal_priority_keyword
+                target_label: level
+
+    # Mount journal directory and machine-id file into promtail pods
+    extraVolumes:
+      - name: journal
+        hostPath:
+          path: /var/log/journal
+      - name: machine-id
+        hostPath:
+          path: /etc/machine-id
+
+    extraVolumeMounts:
+      - name: journal
+        mountPath: /var/log/journal
+        readOnly: true
+      - name: machine-id
+        mountPath: /etc/machine-id
+        readOnly: true
diff --git a/infrastructure/loki/repository.yaml b/infrastructure/loki/repository.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0fb22c30c06c5717a510f4a12186bf99e24c2807
--- /dev/null
+++ b/infrastructure/loki/repository.yaml
@@ -0,0 +1,8 @@
+apiVersion: source.toolkit.fluxcd.io/v1beta1
+kind: HelmRepository
+metadata:
+  name: grafana
+  namespace: loki-system
+spec:
+  interval: 30m
+  url: https://grafana.github.io/helm-charts
diff --git a/infrastructure/monitoring/release.yaml b/infrastructure/monitoring/release.yaml
index 0fc2e5ec7b78e1ef553121827a6a56d4e2536960..a96fd15a7225cf4f43bdc739a50a5f702bc05734 100644
--- a/infrastructure/monitoring/release.yaml
+++ b/infrastructure/monitoring/release.yaml
@@ -98,6 +98,7 @@ data:
         datasources:
           enabled: true
           defaultDatasourceEnabled: true
+          searchNamespace: ALL
     kubeApiServer:
       enabled: true
     kubelet: