Zero-Trust Networking — "Network Sınırı" Yalanı Bitti#
"VPN'in arkasında olan her şey güvenilir" diye düşünmek 2026'da SolarWinds'ten beri antika. Saldırgan içeride; her bağlantı yeniden ispat etmeli."
Zero Trust = "kimseye varsayılan güven yok; her erişim doğrulanmış kimlik + kontekst + en az ayrıcalık". Bu rehber kavramı uygulanabilir hale indirir: BeyondCorp prensipleri, mTLS her yerde, service mesh authZ ve workload identity.
🎯 Zero Trust Prensipleri (NIST 800-207)#
| Prensip | Pratik anlamı |
|---|---|
| Never trust, always verify | Her API çağrısı authenticated + authorized |
| Least privilege | Hiçbir kimliğin gerek olmayan erişimi yok |
| Assume breach | Saldırgan zaten içeride varsay, lateral movement engelle |
| Verify explicitly | Identity + device + context + behavior her seferinde |
| Micro-segmentation | Network seviyesinde ince granül izolasyon |
| End-to-end encryption | Network güvenli olsa bile veri encrypted |
🏛️ Mimarinin Değişimi#
Eski (perimeter-based)#
[INTERNET] → [FIREWALL/VPN] → [TRUSTED INTERNAL NETWORK]
│
┌─────────────┼─────────────┐
▼ ▼ ▼
App A App B Database
(full trust) (full trust) (full trust)
Zero Trust#
[ANY NETWORK]
│
▼
[Identity Provider (OIDC)] ← her istek burada doğrulanır
│
▼
[Policy Engine] ← her istek için "izinli mi?" kararı
│
┌────┴────────────────────┐
▼ ▼
App A ←mTLS+JWT→ App B ←mTLS+JWT→ Database
(her bağlantı kanıtlanmış)
🛂 Identity-Based Access (BeyondCorp)#
Geleneksel#
- Geliştirici → VPN → internal IP → app
- VPN compromise = full network access
BeyondCorp / Zero Trust Access#
- Geliştirici → laptop'tan direkt internet → app
- Her istek IdP'de auth → device posture check → policy decision
Pratik araçlar: | Araç | Niche | |---|---| | Cloudflare Access | SaaS, kolay kurulum | | Tailscale | WireGuard tabanlı, ekip dostu | | Pomerium | Self-hosted, OSS | | Teleport | SSH/Kubernetes/DB access ile | | Google IAP | GCP ekosistem | | AWS Verified Access | AWS ekosistem |
Tailscale ACL örneği#
{
"groups": {
"group:devs": ["alice@example.com", "bob@example.com"],
"group:sre": ["ops@example.com"],
},
"acls": [
// Devs sadece dev cluster'a
{"action": "accept", "src": ["group:devs"], "dst": ["tag:dev-cluster:*"]},
// SRE her cluster'a
{"action": "accept", "src": ["group:sre"], "dst": ["tag:k8s:*"]},
// DB direkt erişim yok, bastion üzerinden
{"action": "accept", "src": ["group:sre"], "dst": ["tag:bastion:22"]},
],
"tagOwners": {
"tag:k8s": ["group:sre"],
"tag:bastion": ["group:sre"],
},
}
🔐 Workload Identity: SPIFFE/SPIRE#
Workload'lar (pod, VM, lambda) için kriptografik kimlik. Static credential yok; her workload'a kısa-ömürlü cert (SVID).
SPIFFE ID#
= "production trust domain'inde, payments namespace'inde, api-server SA'sı".SPIRE Server + Agent#
# SPIRE server (control plane)
helm install spire spiffe/spire \
-n spire --create-namespace
# Her node'a agent DaemonSet
# Agent → workload'a SVID dağıtır
Workload tarafı (SDK)#
// Go: workload SVID alır
import "github.com/spiffe/go-spiffe/v2/workloadapi"
source, _ := workloadapi.NewX509Source(ctx)
defer source.Close()
svid, _ := source.GetX509SVID()
// svid.Certificates → mTLS için kullanılır
# Python (pyspiffe)
from pyspiffe.workloadapi.default_workload_api_client import DefaultWorkloadApiClient
client = DefaultWorkloadApiClient()
svid_response = client.fetch_x509_svids()
🕸️ Service Mesh ile Zero Trust (Istio / Linkerd / Cilium)#
Karşılaştırma#
| Özellik | Istio | Linkerd | Cilium Service Mesh |
|---|---|---|---|
| Sidecar | Envoy proxy | linkerd2-proxy (Rust) | Sidecarless (eBPF) |
| Performans | Orta (sidecar overhead) | İyi | En iyi (eBPF) |
| mTLS otomatik | ✅ | ✅ | ✅ |
| L7 policy | ✅ (zengin) | Sınırlı | ✅ (Cilium NetworkPolicy) |
| Setup | Karmaşık | Basit | K8s + Cilium gerektirir |
| Best for | Multi-cluster, kompleks | Hızlı başla, basit ihtiyaç | Cilium kullanıyorsan |
🔑 Pratik öneri: Yeni başlıyorsan Linkerd. Cilium varsa Cilium Service Mesh (sidecarless). Multi-cluster + kompleks routing varsa Istio.
🔒 Istio AuthorizationPolicy#
Default deny#
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: default-deny
namespace: <NAMESPACE>
spec:
{} # boş policy = deny all
Whitelist: API → DB#
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: api-to-db
namespace: <NAMESPACE>
spec:
selector:
matchLabels:
app: postgres
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/<NS>/sa/api-server"]
to:
- operation:
ports: ["5432"]
JWT-bağlı request policy#
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: <NAMESPACE>
spec:
selector:
matchLabels:
app: api
jwtRules:
- issuer: "https://<IDP>"
jwksUri: "https://<IDP>/.well-known/jwks.json"
audiences: ["api.example.com"]
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: <NAMESPACE>
spec:
selector:
matchLabels:
app: api
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"]
when:
- key: request.auth.claims[scope]
values: ["read", "write"]
🛡️ Linkerd Zero Trust#
# linkerd: namespace tüm communication mTLS
apiVersion: policy.linkerd.io/v1beta3
kind: Server
metadata:
name: api-http
namespace: <NS>
spec:
podSelector:
matchLabels:
app: api
port: http
proxyProtocol: HTTP/1
---
apiVersion: policy.linkerd.io/v1beta3
kind: AuthorizationPolicy
metadata:
name: api-auth
namespace: <NS>
spec:
targetRef:
group: policy.linkerd.io
kind: Server
name: api-http
requiredAuthenticationRefs:
- kind: ServiceAccount
name: frontend
namespace: <NS>
🌐 Cilium NetworkPolicy (L7)#
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-zero-trust
namespace: <NS>
spec:
endpointSelector:
matchLabels:
app: api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
io.kubernetes.pod.namespace: <NS>
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/v1/users(/[0-9]+)?"
- method: "POST"
path: "/api/v1/orders"
headers:
- 'Content-Type: application/json'
egress:
- toEndpoints:
- matchLabels:
app: postgres
toPorts:
- ports:
- port: "5432"
protocol: TCP
- toFQDNs:
- matchName: "api.stripe.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
🔑 L7 zero trust: Sadece "API'den DB'ye port 5432 izinli" değil, "hangi HTTP method, hangi path, hangi header" seviyesinde.
🔑 mTLS Her Yerde#
Niye?#
- Internal network "güvenli" varsayımı çöktü
- Network sniffer compromise → unencrypted traffic'i okur
- Compliance (PCI DSS, HIPAA, ISO 27001) — internal mTLS bekleniyor
Kim verir?#
| Yöntem | Cert lifecycle |
|---|---|
| Istio Citadel | Otomatik, 24h rotation |
| Linkerd identity | Otomatik, 24h |
| cert-manager + intermediate CA | Manual veya auto-rotate |
| SPIFFE/SPIRE | Workload-bound, kısa ömürlü |
| HashiCorp Vault PKI | Dynamic, esnek |
cert-manager + cluster-internal CA#
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: internal-ca
spec:
ca:
secretName: internal-ca-key-pair
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-tls
namespace: <NS>
spec:
secretName: api-tls
issuerRef:
name: internal-ca
kind: ClusterIssuer
dnsNames:
- api.<NS>.svc.cluster.local
duration: 720h
renewBefore: 240h
🛂 Egress Control: "Pod Internet'e Çıkmasın" (Beklenmedikçe)#
Zero trust = ingress kadar egress önemli. Compromise → C2 callback engellensin.
Default-deny egress#
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: <NS>
spec:
podSelector: {}
policyTypes: [Egress]
egress: []
Whitelist: sadece DNS + internal + belirli external#
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: egress-allowlist
namespace: <NS>
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports: [{port: "53", protocol: ANY}]
- toEntities: [cluster]
- toFQDNs:
- matchName: "api.stripe.com"
- matchName: "registry.npmjs.org"
- matchPattern: "*.amazonaws.com"
🚨 Önce audit, sonra enforce. Mevcut traffic'i 1-2 hafta logla, baseline oluştur, sonra deny-all + whitelist.
🧰 Bastion / Jump Host Modern Hali#
Eski: SSH bastion#
Sorunlar: paylaşımlı kullanıcı, audit zor, key paylaşımı.Modern: Teleport / AWS SSM Session Manager / Cloudflare Zero Trust#
- Identity-bound (OIDC, kişiye özel)
- Audit her komut kayıt
- Session recording
- Just-in-time access (PIM): sadece onay sonrası 1 saat
# Teleport role
kind: role
version: v7
metadata:
name: db-readonly
spec:
allow:
db_labels: {env: prod, role: readonly}
db_users: ['{{external.email}}']
db_names: ['app']
options:
max_session_ttl: 1h
require_session_mfa: true
record_session: {default: strict}
🚫 Anti-Pattern Tablosu#
| Anti-pattern | Niye kötü | Doğru |
|---|---|---|
| "VPN içindeyim, güvendeyim" | VPN compromise = full access | Identity-bound + per-request auth |
Paylaşımlı SSH key (ec2-user.pem) | Audit yok, rotation imkansız | Teleport / SSM Session Manager |
| Internal API'lar mTLS'siz | Network sniffer okur | mTLS her servis-servis |
| Pod'lar internet'e açık egress | C2 callback engelsiz | Default-deny egress + allowlist |
| Tek IdP token uzun ömürlü | Compromise window büyük | Short TTL + refresh + step-up MFA |
| Service-to-service auth: shared secret env'de | Compromise lateralize | mTLS / SPIFFE workload identity |
| K8s ServiceAccount token mount default-on | Lateral movement | automountServiceAccountToken: false |
| Network policy var ama L4 (port) only | HTTP path/method anomalisi yakalanamaz | Cilium L7 / Istio AuthZ |
| BeyondCorp setup'ta device posture check yok | Compromised laptop tüm erişimi alır | Cloudflare Access + device cert |
| Audit log internal-only, SIEM yok | Forensic eksik | Tüm policy decision SIEM'de |
📊 Olgunluk Modeli (CISA Zero Trust Maturity Model)#
| Pillar | Traditional | Initial | Advanced | Optimal |
|---|---|---|---|---|
| Identity | Username/password | MFA | OIDC + risk-based | Phishing-resistant + continuous |
| Devices | Trust on connect | Inventory | Health check | Continuous compliance check |
| Networks | Static perimeter | Some segments | Micro-segments | Software-defined per workload |
| Apps | Public/Internal | TLS everywhere | mTLS + JWT | Workload identity (SPIFFE) |
| Data | Backup | Encryption at rest | Classification + DLP | Continuous risk scoring |
2026 hedefi (orta-büyük şirket): Çoğu pillar'da Advanced, kritik alanlarda (data, identity) Optimal'a yaklaşmak.
📋 Zero Trust Migration Checklist#
[ ] IdP merkezi (OIDC) — tüm user erişim oradan
[ ] MFA zorunlu (her IdP login)
[ ] Phishing-resistant MFA (FIDO2 / WebAuthn) hedefte
[ ] Device posture check (managed laptop, encrypted disk, OS güncel)
[ ] BeyondCorp gateway (Cloudflare Access / Tailscale / Pomerium)
[ ] VPN'siz mimari hedef olarak yazılı
[ ] Workload identity (SPIFFE veya cloud-native: AWS IRSA, GCP Workload Identity)
[ ] mTLS service-to-service her yerde (service mesh ya da SPIFFE)
[ ] L4 + L7 NetworkPolicy (Cilium veya Istio)
[ ] Default-deny egress + allowlist
[ ] DNS audit (egress'te FQDN bazında)
[ ] SSH/DB access: Teleport veya equivalent (kişiye-bound, audit, MFA)
[ ] Just-in-time access (PIM) kritik sistemler için
[ ] Tüm authZ kararı audit log → SIEM
[ ] Quarterly: zero trust gap analizi (CISA modeli üzerinden)
📚 Referanslar#
- NIST 800-207 — Zero Trust Architecture
- CISA Zero Trust Maturity Model v2.0
- Google BeyondCorp Papers — beyondcorp.com
- SPIFFE Spec — spiffe.io
- Istio Security Docs — istio.io/latest/docs/concepts/security/
- Linkerd Policy Docs — linkerd.io/2/features/server-policy/
- Cilium Network Policy — docs.cilium.io
Kubernetes-Hardening.md— RBAC + NetworkPolicySecrets-Management.md— workload identity09-Networking/— service mesh deep-dive (Faz 3)
"Zero trust 'yeni VPN' değildir; mimari değişim. 'Network'e güvenmek' yerine kimliğe + kanıta güvenmektir. Geçiş 2-3 yıl sürer; başlamayan, eskimiş kalmaktır."