Security
This document covers security considerations and configurations for the cluster.
Security Overview
Network Security
Calico Network Policies
Calico enforces network policies to control pod-to-pod communication.
Default Deny Policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Allow Specific Traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Namespace Isolation
Each environment uses separate namespaces:
| Namespace | Purpose |
|---|---|
argocd | ArgoCD CD |
cert-manager | Certificate management |
metallb-system | Load balancer |
ingress-nginx | Ingress controller |
external-dns | DNS management |
calico-system | Network policies |
monitoring | Prometheus, Loki, Grafana |
local-path-storage | Storage provisioner |
default | User applications |
TLS Security
Certificate Configuration
All ingresses use cert-manager with Let's Encrypt:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- myapp.ssdk8s.xyz
secretName: myapp-tls
Certificate Details
| Property | Value |
|---|---|
| Issuer | Let's Encrypt Production |
| Validity | 90 days |
| Renewal | Automatic at 30 days before expiry |
| Key Size | 2048-bit RSA |
| Challenge | DNS-01 via Cloudflare |
Cloudflare API Token
Stored as Kubernetes secret:
kubectl get secret cloudflare-api-token -n cert-manager -o yaml
The Cloudflare API token must have minimal permissions: Zone:DNS:Edit only.
Access Control
OPA Gatekeeper
Gatekeeper enforces cluster-wide policies through admission control:
- Required Labels - All workloads must have
appandteamlabels - Required Resources - All containers must have CPU/memory limits
- No Privileged Containers - Blocks
privileged: trueandallowPrivilegeEscalation: true - Maximum Resources - Per-namespace resource limits
See OPA Gatekeeper for detailed policy documentation.
Kubernetes RBAC
Service Accounts
Each application should use a dedicated service account:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: default
Role-Based Access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: default
spec:
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: my-app
namespace: default
roleRef:
kind: Role
name: my-app-role
apiGroup: rbac.authorization.k8s.io
ArgoCD AppProject
The playground project restricts deployments:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: playground
namespace: argocd
spec:
sourceRepos:
- https://github.com/simran2491/k8s-playground-cluster.git
destinations:
- namespace: '*'
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: ''
kind: Namespace
- group: rbac.authorization.k8s.io
kind: ClusterRole
kind: ClusterRoleBinding
Secrets Management
Current Approach
Secrets are stored as Kubernetes Secrets:
kubectl create secret generic my-secret \
--from-literal=username=admin \
--from-literal=password=secret123 \
-n default
Kubernetes Secrets are base64-encoded, not encrypted by default. Enable encryption at rest for production.
Encryption at Rest
To enable encryption at rest, configure the API server:
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
Future: External Secrets
For production, consider:
- External Secrets Operator - Sync from AWS Secrets Manager, HashiCorp Vault
- Sealed Secrets - Encrypt secrets for Git storage
- SOPS - Encrypt secrets in Git with age/pgp keys
Security Best Practices
Pod Security
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
Image Security
- Use specific tags - Avoid
latestin production - Scan images - Use Trivy, Clair, or Snyk
- Use distroless - Minimal base images
Network Security
- Default deny - Start with deny-all policies
- Least privilege - Only allow required traffic
- Egress filtering - Control outbound traffic
Audit Logging
Enable Kubernetes audit logging:
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
Compliance Considerations
| Requirement | Implementation |
|---|---|
| Data Encryption | TLS everywhere, encryption at rest |
| Access Control | RBAC, AppProject restrictions |
| Audit Trail | Kubernetes audit logs, ArgoCD history |
| Network Segmentation | Calico network policies |
| Secret Management | Kubernetes secrets (consider external) |