From 211c7868a5c13a3460b700c83c4e9a44fad3710d Mon Sep 17 00:00:00 2001 From: DevMuhdIshaq Date: Sat, 27 Jun 2026 01:26:01 +0100 Subject: [PATCH 1/2] feat: add zero-trust network access baseline --- infrastructure/docs/zero-trust.md | 53 +++++++++++++++++++ .../security/zero-trust/cert-manager.yaml | 41 ++++++++++++++ .../security/zero-trust/mtls-config.yaml | 45 ++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 infrastructure/docs/zero-trust.md create mode 100644 infrastructure/security/zero-trust/cert-manager.yaml create mode 100644 infrastructure/security/zero-trust/mtls-config.yaml diff --git a/infrastructure/docs/zero-trust.md b/infrastructure/docs/zero-trust.md new file mode 100644 index 00000000..78aced48 --- /dev/null +++ b/infrastructure/docs/zero-trust.md @@ -0,0 +1,53 @@ +# Zero-trust network access + +This baseline implementation brings zero-trust controls to internal service communication for GistPin. + +## Objectives + +- Enforce mutual TLS between services +- Rotate certificates automatically before expiry +- Base access on workload identity rather than network location +- Emit audit logs for service-to-service access decisions +- Apply policy at the mesh layer for continuous enforcement + +## Components + +- mTLS policies in [infrastructure/security/zero-trust/mtls-config.yaml](../security/zero-trust/mtls-config.yaml) +- Certificate issuance and rotation in [infrastructure/security/zero-trust/cert-manager.yaml](../security/zero-trust/cert-manager.yaml) + +## Implementation notes + +### 1. Mutual TLS + +The mesh policy in the zero-trust configuration enables strict mTLS for workloads in the `gistpin` namespace. Traffic that does not present a valid client certificate is rejected before reaching the application. + +### 2. Certificate rotation + +The certificate manifest uses `cert-manager` to issue a workload certificate with a 90-day validity period and a 9-day renewal window. This keeps the service identity material fresh without manual intervention. + +### 3. Identity-based access + +Authorization policies use SPIFFE-style service identities from Kubernetes service accounts. This allows the platform to permit only approved workloads to access specific APIs. + +### 4. Audit logging + +Enable access logs and policy audit logs in the service mesh control plane so each allowed and denied request is traceable. Forward these logs to the central observability stack. + +### 5. Policy enforcement + +Treat the manifests in this folder as the default baseline and add namespace-specific policies as new services are onboarded. Review policies regularly and keep an allow-list approach for internal API access. + +## Apply the baseline + +```bash +kubectl apply -f infrastructure/security/zero-trust/mtls-config.yaml +kubectl apply -f infrastructure/security/zero-trust/cert-manager.yaml +``` + +## Operational checklist + +- Verify that the mesh control plane is installed and running +- Confirm `cert-manager` is deployed and healthy +- Check that service-to-service traffic is using mTLS +- Review certificate expiry and renewal events in the cluster +- Monitor audit logs for policy violations and unexpected access paths diff --git a/infrastructure/security/zero-trust/cert-manager.yaml b/infrastructure/security/zero-trust/cert-manager.yaml new file mode 100644 index 00000000..c69a5df3 --- /dev/null +++ b/infrastructure/security/zero-trust/cert-manager.yaml @@ -0,0 +1,41 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: gistpin-mtls-issuer +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: gistpin-mtls-cert + namespace: gistpin +spec: + secretName: gistpin-mtls-tls + duration: 2160h # 90 days + renewBefore: 216h # 9 days + commonName: "*.gistpin.svc.cluster.local" + dnsNames: + - "*.gistpin.svc.cluster.local" + issuerRef: + name: gistpin-mtls-issuer + kind: ClusterIssuer + privateKey: + algorithm: ECDSA + size: 256 + usages: + - digital signature + - key encipherment + - server auth + - client auth +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: cert-manager-webhook + namespace: cert-manager +spec: + minAvailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: webhook diff --git a/infrastructure/security/zero-trust/mtls-config.yaml b/infrastructure/security/zero-trust/mtls-config.yaml new file mode 100644 index 00000000..a49b32bd --- /dev/null +++ b/infrastructure/security/zero-trust/mtls-config.yaml @@ -0,0 +1,45 @@ +apiVersion: security.istio.io/v1beta1 +kind: PeerAuthentication +metadata: + name: default-strict-mtls + namespace: gistpin +spec: + selector: + matchLabels: + app.kubernetes.io/part-of: gistpin + mtls: + mode: STRICT +--- +apiVersion: networking.istio.io/v1beta1 +kind: DestinationRule +metadata: + name: gistpin-mtls + namespace: gistpin +spec: + host: "*.gistpin.svc.cluster.local" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + loadBalancer: + simple: ROUND_ROBIN +--- +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: backend-api-allow + namespace: gistpin +spec: + selector: + matchLabels: + app: backend + action: ALLOW + rules: + - from: + - source: + principals: + - cluster.local/ns/gistpin/sa/frontend + - cluster.local/ns/gistpin/sa/worker + to: + - operation: + methods: ["GET", "POST"] + paths: ["/api/*"] From 67d5bef5e6e0e6fbc6ab8a76830b82895b0addbf Mon Sep 17 00:00:00 2001 From: DevMuhdIshaq Date: Sat, 27 Jun 2026 01:27:48 +0100 Subject: [PATCH 2/2] feat: add loki log aggregation stack --- .../monitoring/grafana/loki-datasource.yml | 20 +++ infrastructure/monitoring/loki-config.yaml | 110 +++++++++++++++++ .../monitoring/promtail-config.yaml | 114 ++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 infrastructure/monitoring/grafana/loki-datasource.yml create mode 100644 infrastructure/monitoring/loki-config.yaml create mode 100644 infrastructure/monitoring/promtail-config.yaml diff --git a/infrastructure/monitoring/grafana/loki-datasource.yml b/infrastructure/monitoring/grafana/loki-datasource.yml new file mode 100644 index 00000000..e7986041 --- /dev/null +++ b/infrastructure/monitoring/grafana/loki-datasource.yml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-loki-datasource + namespace: monitoring + labels: + grafana_datasource: "1" +data: + loki-datasource.yaml: | + apiVersion: 1 + datasources: + - name: Loki + uid: loki + type: loki + access: proxy + url: http://loki:3100 + isDefault: false + editable: true + jsonData: + maxLines: 1000 diff --git a/infrastructure/monitoring/loki-config.yaml b/infrastructure/monitoring/loki-config.yaml new file mode 100644 index 00000000..d576f3e8 --- /dev/null +++ b/infrastructure/monitoring/loki-config.yaml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: loki-config + namespace: monitoring +data: + loki.yaml: | + auth_enabled: false + + server: + http_listen_port: 3100 + + common: + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + + schema_config: + configs: + - from: 2024-01-01 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + + storage_config: + filesystem: + directory: /loki/chunks + + compactor: + working_directory: /loki/boltdb-shipper-compactor + shared_store: filesystem + retention_enabled: true + + limits_config: + retention_period: 168h + ingestion_rate_mb: 16 + ingestion_burst_size_mb: 32 + reject_old_samples: true + reject_old_samples_max_age: 168h + + chunk_store_config: + max_look_back_period: 168h + + table_manager: + retention_deletes_enabled: true + retention_period: 168h +--- +apiVersion: v1 +kind: Service +metadata: + name: loki + namespace: monitoring +spec: + selector: + app: loki + ports: + - name: http + port: 3100 + targetPort: 3100 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: loki + namespace: monitoring +spec: + serviceName: loki + replicas: 1 + selector: + matchLabels: + app: loki + template: + metadata: + labels: + app: loki + spec: + containers: + - name: loki + image: grafana/loki:3.0.0 + args: + - -config.file=/etc/loki/loki.yaml + ports: + - containerPort: 3100 + name: http + volumeMounts: + - name: config + mountPath: /etc/loki + - name: storage + mountPath: /loki + volumes: + - name: config + configMap: + name: loki-config + volumeClaimTemplates: + - metadata: + name: storage + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 20Gi diff --git a/infrastructure/monitoring/promtail-config.yaml b/infrastructure/monitoring/promtail-config.yaml new file mode 100644 index 00000000..38af41ac --- /dev/null +++ b/infrastructure/monitoring/promtail-config.yaml @@ -0,0 +1,114 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: promtail-config + namespace: monitoring +data: + promtail.yaml: | + server: + http_listen_port: 9080 + grpc_listen_port: 0 + + positions: + filename: /tmp/positions.yaml + + clients: + - url: http://loki:3100/loki/api/v1/push + + scrape_configs: + - job_name: kubernetes-pods + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_namespace] + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + target_label: pod + - source_labels: [__meta_kubernetes_pod_container_name] + target_label: container + - source_labels: [__meta_kubernetes_pod_label_app] + target_label: app + - source_labels: [__meta_kubernetes_pod_node_name] + target_label: node + - action: replace + source_labels: [__meta_kubernetes_namespace] + target_label: kubernetes_namespace + - action: replace + source_labels: [__meta_kubernetes_pod_name] + target_label: kubernetes_pod + pipeline_stages: + - cri: {} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: promtail + namespace: monitoring +spec: + selector: + matchLabels: + app: promtail + template: + metadata: + labels: + app: promtail + spec: + serviceAccountName: promtail + containers: + - name: promtail + image: grafana/promtail:3.0.0 + args: + - -config.file=/etc/promtail/promtail.yaml + volumeMounts: + - name: config + mountPath: /etc/promtail + - name: varlog + mountPath: /var/log + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + - name: positions + mountPath: /tmp + volumes: + - name: config + configMap: + name: promtail-config + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers + - name: positions + emptyDir: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: promtail + namespace: monitoring +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: promtail +rules: + - apiGroups: [""] + resources: + - pods + - nodes + - namespaces + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: promtail +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: promtail +subjects: + - kind: ServiceAccount + name: promtail + namespace: monitoring