12 KiB
12 KiB
Kubernetes Network Policies for Artifactory Services
This document provides NetworkPolicy configurations to restrict access to artifactory services, allowing only root path access externally while keeping all other endpoints internal-only.
Network Policy Strategy
Access Control Rules:
- External Access: Only
/(root/health check endpoints) - Internal Access: All endpoints from
192.168.100.0/24network - Service Communication: Allow pod-to-pod communication within namespace
Network Policies
1. Arti-API Network Policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: arti-api-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: arti-api
policyTypes:
- Ingress
- Egress
ingress:
# Allow internal network access to all endpoints
- from:
- ipBlock:
cidr: 192.168.100.0/24
ports:
- protocol: TCP
port: 8000
# Allow external access only to health/status endpoints
# Note: This requires an Ingress controller or service mesh
# to handle path-based routing restrictions
- from: [] # All external sources
ports:
- protocol: TCP
port: 8000
# Allow communication from other services in the same namespace
- from:
- namespaceSelector:
matchLabels:
name: default
- podSelector: {}
ports:
- protocol: TCP
port: 8000
egress:
# Allow outbound traffic for API functionality
- to: []
ports:
- protocol: TCP
port: 53 # DNS
- protocol: UDP
port: 53 # DNS
- to:
- podSelector: {} # Allow communication to other pods
2. Chart Museum Network Policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: chartmuseum-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: chartmuseum
policyTypes:
- Ingress
- Egress
ingress:
# Allow internal network access to all endpoints
- from:
- ipBlock:
cidr: 192.168.100.0/24
ports:
- protocol: TCP
port: 8080
# Allow external access only to health endpoint
- from: []
ports:
- protocol: TCP
port: 8080
# Allow communication from arti-api and other services
- from:
- podSelector:
matchLabels:
app: arti-api
- namespaceSelector:
matchLabels:
name: default
ports:
- protocol: TCP
port: 8080
egress:
# Allow outbound traffic
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
- to:
- podSelector: {}
3. Docker Registry Network Policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: docker-registry-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: docker-registry
policyTypes:
- Ingress
- Egress
ingress:
# Allow internal network access to all endpoints
- from:
- ipBlock:
cidr: 192.168.100.0/24
ports:
- protocol: TCP
port: 5000
# Allow external access only to health endpoint (/v2/)
- from: []
ports:
- protocol: TCP
port: 5000
# Allow communication from arti-api and other services
- from:
- podSelector:
matchLabels:
app: arti-api
- namespaceSelector:
matchLabels:
name: default
ports:
- protocol: TCP
port: 5000
egress:
# Allow outbound traffic
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
- to:
- podSelector: {}
Path-Based Access Control with Traefik v2
Since NetworkPolicy works at the network layer and cannot filter by HTTP paths, you need to combine it with Traefik IngressRoute for path-based restrictions.
Traefik v2 IngressRoute Configuration
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: arti-api-simple
namespace: artifactory
spec:
entryPoints:
- web
routes:
# Internal network gets full access
- match: Host(`api.artifactory.local`) && ClientIP(`192.168.100.0/24`)
kind: Rule
priority: 100
services:
- name: arti-api-service
port: 8000
middlewares:
- name: internal-headers
# External access - only health endpoints
- match: Host(`api.artifactory.local`) && (Path(`/`) || Path(`/health`))
kind: Rule
priority: 90
services:
- name: arti-api-service
port: 8000
middlewares:
- name: external-health-headers
# Block all other external access
- match: Host(`api.artifactory.local`)
kind: Rule
priority: 10
services:
- name: error-service
port: 80
middlewares:
- name: block-external
Complete Traefik Configuration Files
Two versions are provided:
traefik-simple.yaml- Simplified, easy to understand configurationtraefik-ingressroute.yaml- Full-featured with TLS and advanced middlewares
Key Features:
- Priority-based routing: Higher priority rules are evaluated first
- ClientIP matching: Uses
ClientIP()matcher to identify internal network - Path-based filtering: Specific paths allowed for external access
- Custom error pages: Friendly 403 pages with helpful information
- Middleware chaining: Headers and access control through middlewares
Deployment:
# Deploy the simplified version
kubectl apply -f traefik-simple.yaml
# Or deploy the full-featured version
kubectl apply -f traefik-ingressroute.yaml
Istio Service Mesh Configuration
If using Istio, you can implement more granular path-based access control:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: arti-api-access-control
namespace: default
spec:
selector:
matchLabels:
app: arti-api
rules:
# Allow internal network access to all paths
- from:
- source:
ipBlocks: ["192.168.100.0/24"]
# Allow external access only to health endpoints
- to:
- operation:
paths: ["/", "/health"]
# Deny all other external access
- from:
- source:
notIpBlocks: ["192.168.100.0/24"]
to:
- operation:
notPaths: ["/", "/health"]
when:
- key: request.headers[':path']
notValues: ["/", "/health"]
action: DENY
Complete Kubernetes Deployment with Network Policies
apiVersion: v1
kind: Namespace
metadata:
name: artifactory
labels:
name: artifactory
---
# Arti-API Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: arti-api
namespace: artifactory
labels:
app: arti-api
spec:
replicas: 1
selector:
matchLabels:
app: arti-api
template:
metadata:
labels:
app: arti-api
spec:
containers:
- name: arti-api
image: hexah/arti-api:1.0.1
ports:
- containerPort: 8000
env:
- name: PYTHONUNBUFFERED
value: "1"
volumeMounts:
- name: artifactory-storage
mountPath: /data
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: artifactory-storage
persistentVolumeClaim:
claimName: artifactory-pvc
---
# Arti-API Service
apiVersion: v1
kind: Service
metadata:
name: arti-api-service
namespace: artifactory
labels:
app: arti-api
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: 8000
protocol: TCP
selector:
app: arti-api
---
# Chart Museum Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: chartmuseum
namespace: artifactory
labels:
app: chartmuseum
spec:
replicas: 1
selector:
matchLabels:
app: chartmuseum
template:
metadata:
labels:
app: chartmuseum
spec:
containers:
- name: chartmuseum
image: chartmuseum/chartmuseum:latest
ports:
- containerPort: 8080
env:
- name: STORAGE
value: "local"
- name: STORAGE_LOCAL_ROOTDIR
value: "/data/charts"
- name: PORT
value: "8080"
- name: AUTH_ANONYMOUS_GET
value: "false"
- name: HTPASSWD_PATH
value: "/data/htpasswd"
- name: AUTH_REALM
value: "Chart Museum"
- name: ALLOW_OVERWRITE
value: "true"
- name: DISABLE_API
value: "false"
volumeMounts:
- name: artifactory-storage
mountPath: /data
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
volumes:
- name: artifactory-storage
persistentVolumeClaim:
claimName: artifactory-pvc
---
# Chart Museum Service
apiVersion: v1
kind: Service
metadata:
name: chartmuseum-service
namespace: artifactory
labels:
app: chartmuseum
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
protocol: TCP
selector:
app: chartmuseum
---
# Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: artifactory-network-policy
namespace: artifactory
spec:
podSelector: {} # Apply to all pods in namespace
policyTypes:
- Ingress
- Egress
ingress:
# Allow internal network full access
- from:
- ipBlock:
cidr: 192.168.100.0/24
# Allow limited external access (health checks only)
- from: []
ports:
- protocol: TCP
port: 8000 # Arti-API
- protocol: TCP
port: 8080 # Chart Museum
- protocol: TCP
port: 5000 # Docker Registry
# Allow inter-pod communication
- from:
- podSelector: {}
egress:
# Allow DNS
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
# Allow inter-pod communication
- to:
- podSelector: {}
# Allow outbound internet (for package downloads, etc.)
- to: []
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: artifactory-pvc
namespace: artifactory
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
Testing Network Policies
1. Test from Internal Network (192.168.100.x)
# Should work - internal access to all endpoints
curl http://arti-api-service.artifactory.svc.cluster.local:8000/users
curl http://chartmuseum-service.artifactory.svc.cluster.local:8080/api/charts
# Test from a pod in the internal network
kubectl run test-pod --rm -i --tty --image=curlimages/curl -- sh
# Inside the pod:
curl http://arti-api-service.artifactory.svc.cluster.local:8000/debian/packages
2. Test from External Network
# Should work - external access to health endpoints
curl http://your-ingress-ip/health
curl http://your-ingress-ip/
# Should be blocked - external access to management endpoints
curl http://your-ingress-ip/users # Should return 403 or timeout
curl http://your-ingress-ip/debian/packages # Should return 403 or timeout
3. Verify Network Policy
# Check network policies
kubectl get networkpolicies -n artifactory
# Describe policy
kubectl describe networkpolicy artifactory-network-policy -n artifactory
# Check if pods are selected by policy
kubectl get pods -n artifactory --show-labels
Key Points
- NetworkPolicy Limitations: NetworkPolicy works at Layer 3/4, not HTTP paths
- Path-Based Control: Use Ingress controllers or service mesh for HTTP path filtering
- Internal Network:
192.168.100.0/24gets full access to all endpoints - External Access: Limited to health check endpoints only
- Service Communication: Pods can communicate within the namespace
- DNS: Allow DNS traffic for service discovery
This configuration provides defense in depth by combining network-level and application-level access controls.