Securing Microservices: Implementing Calico Network Policies for Java Applications

Article

Calico is a popular networking and network security solution for Kubernetes that provides advanced network policies to control traffic between pods, namespaces, and external services. For Java microservices, Calico enables fine-grained security controls, zero-trust networking, and compliance with security best practices.


What is Calico?

Calico is an open-source networking and network security solution for containers, virtual machines, and native host-based workloads. It provides:

  • Network Policies: Fine-grained control over pod-to-pod communication
  • Security Policies: Zero-trust network security models
  • Performance: High-performance networking with low latency
  • Compliance: Meets enterprise security and compliance requirements

Key Benefits for Java Applications:

  • Microservice Segmentation: Isolate Java services from each other
  • Egress Control: Control outbound traffic from Java applications
  • Ingress Security: Restrict inbound traffic to specific endpoints
  • Compliance: Meet regulatory requirements for network segmentation
  • Zero-Trust: Implement least-privilege network access

Calico Installation and Setup

1. Install Calico with Kubernetes

# Install Calico on a new Kubernetes cluster
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml
# Verify installation
kubectl get pods -n calico-system
# Install Calico CLI
curl -L https://github.com/projectcalico/calico/releases/latest/download/calicoctl-linux-amd64 -o calicoctl
chmod +x calicoctl
sudo mv calicoctl /usr/local/bin/

2. Verify Calico Installation

# Check Calico status
calicoctl get nodes
kubectl get tigerastatus
# Check network policies
kubectl get networkpolicies --all-namespaces
calicoctl get networkpolicy --all-namespaces

Java Application Architecture Example

Let's consider a typical Java microservices architecture:

Java Microservices Stack:
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   API Gateway   │────│   Order Service │────│  Payment Service│
│   (Spring Cloud)│    │  (Spring Boot)  │    │ (Quarkus)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘
│                       │                       │
│                       │                       │
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   User Service  │    │  Product Service│    │   Email Service │
│ (Micronaut)     │    │ (Spring Boot)   │    │ (Vert.x)        │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Basic Network Policies

1. Deny All Traffic by Default

# network-policies/default-deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: java-apps
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

2. Allow DNS Resolution

# network-policies/allow-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: java-apps
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns

Java Microservice Network Policies

1. Namespace Configuration

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: java-apps
labels:
name: java-apps
environment: production
team: backend-java
---
apiVersion: v1
kind: Namespace
metadata:
name: database
labels:
name: database
environment: production
team: database

2. API Gateway Network Policy

# network-policies/api-gateway-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-gateway-policy
namespace: java-apps
spec:
podSelector:
matchLabels:
app: api-gateway
version: "1.0.0"
# Ingress: Allow external traffic on HTTP/HTTPS
ingress:
- ports:
- port: 8080
protocol: TCP
- port: 8443
protocol: TCP
from:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
# Egress: Allow gateway to talk to backend services
egress:
- ports:
- port: 8080
protocol: TCP
to:
- podSelector:
matchLabels:
app: user-service
- podSelector:
matchLabels:
app: order-service
- podSelector:
matchLabels:
app: product-service
- ports:
- port: 5432
protocol: TCP
to:
- namespaceSelector:
matchLabels:
name: database
podSelector:
matchLabels:
app: postgresql
policyTypes:
- Ingress
- Egress

3. Order Service Network Policy

# network-policies/order-service-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: order-service-policy
namespace: java-apps
spec:
podSelector:
matchLabels:
app: order-service
version: "2.1.0"
# Ingress: Only allow from API Gateway and internal services
ingress:
- ports:
- port: 8080
protocol: TCP
from:
- podSelector:
matchLabels:
app: api-gateway
- podSelector:
matchLabels:
app: user-service
- podSelector:
matchLabels:
app: payment-service
# Egress: Allow order service to talk to dependencies
egress:
- ports:
- port: 8080
protocol: TCP
to:
- podSelector:
matchLabels:
app: user-service
- podSelector:
matchLabels:
app: payment-service
- podSelector:
matchLabels:
app: product-service
- ports:
- port: 5432
protocol: TCP
to:
- namespaceSelector:
matchLabels:
name: database
podSelector:
matchLabels:
app: postgresql
- ports:
- port: 9092
protocol: TCP
to:
- podSelector:
matchLabels:
app: kafka-broker
policyTypes:
- Ingress
- Egress

4. Payment Service Network Policy

# network-policies/payment-service-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: payment-service-policy
namespace: java-apps
spec:
podSelector:
matchLabels:
app: payment-service
version: "1.3.0"
# Ingress: Only allow from Order Service
ingress:
- ports:
- port: 8080
protocol: TCP
from:
- podSelector:
matchLabels:
app: order-service
# Egress: Allow external payment gateway communication
egress:
- ports:
- port: 443
protocol: TCP
to:
- ipBlock:
cidr: 52.12.34.56/32  # Payment gateway IP
- ipBlock:
cidr: 34.56.78.90/32  # Backup payment gateway
- ports:
- port: 5432
protocol: TCP
to:
- namespaceSelector:
matchLabels:
name: database
podSelector:
matchLabels:
app: postgresql
policyTypes:
- Ingress
- Egress

Advanced Calico Network Policies

1. Global Network Policy (Calico-specific)

# calico-policies/global-network-policy.yaml
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: java-apps-global-policy
spec:
# Apply to all pods in all namespaces with Java app label
selector: has(team) && team in {'backend-java', 'java-microservices'}
# Order of precedence
order: 100
# Ingress rules
ingress:
- action: Allow
protocol: TCP
source:
selector: app == 'api-gateway'
destination:
ports: [8080, 8443]
- action: Allow
protocol: TCP
source:
selector: has(monitoring) && monitoring == 'true'
destination:
ports: [9090, 8081]  # Metrics and management ports
# Egress rules
egress:
- action: Allow
protocol: UDP
destination:
selector: k8s-app == 'kube-dns'
ports: [53]
- action: Allow
protocol: TCP
destination:
selector: app == 'postgresql'
ports: [5432]
- action: Deny
protocol: TCP
destination:
nets: [0.0.0.0/0]
ports: [25, 587, 465]  # Block SMTP by default
types:
- Ingress
- Egress

2. Application Layer Policy with Calico

# calico-policies/l7-policy.yaml
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: java-api-l7-policy
namespace: java-apps
spec:
selector: app in {'user-service', 'order-service', 'product-service'}
# HTTP-specific rules
ingress:
- action: Allow
protocol: TCP
source:
selector: app == 'api-gateway'
destination:
ports: [8080]
http:
methods: ['GET', 'POST', 'PUT', 'DELETE']
paths: ['/api/*']
- action: Allow
protocol: TCP
source:
selector: monitoring == 'true'
destination:
ports: [8080]
http:
methods: ['GET']
paths: ['/actuator/health', '/actuator/metrics', '/actuator/prometheus']
egress:
- action: Allow
protocol: TCP
destination:
selector: app == 'email-service'
http:
methods: ['POST']
paths: ['/api/emails']
types:
- Ingress
- Egress

3. Database Tier Network Policy

# calico-policies/database-policy.yaml
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: database-tier-policy
namespace: database
spec:
selector: app in {'postgresql', 'redis', 'mongodb'}
ingress:
- action: Allow
protocol: TCP
source:
selector: has(team) && team == 'backend-java'
destination:
ports: [5432]  # PostgreSQL
- action: Allow
protocol: TCP
source:
selector: has(team) && team == 'backend-java'
destination:
ports: [6379]  # Redis
- action: Allow
protocol: TCP
source:
selector: app == 'database-migrator'
destination:
ports: [5432]
# Deny all other ingress
- action: Deny
source: {}
egress:
- action: Allow  # Allow database to respond
destination: {}
types:
- Ingress
- Egress

Java Application Deployment with Network Policies

1. Spring Boot Order Service Deployment

# k8s/order-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: java-apps
labels:
app: order-service
version: "2.1.0"
team: backend-java
monitoring: "true"
spec:
replicas: 3
selector:
matchLabels:
app: order-service
version: "2.1.0"
template:
metadata:
labels:
app: order-service
version: "2.1.0"
team: backend-java
monitoring: "true"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
serviceAccountName: order-service
containers:
- name: order-service
image: my-registry/order-service:2.1.0
ports:
- containerPort: 8080
name: http
- containerPort: 8081
name: management
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: JAVA_OPTS
value: "-Xmx512m -Xms256m -Djava.security.egd=file:/dev/./urandom"
- name: DATABASE_URL
value: "jdbc:postgresql://postgresql.database:5432/orders"
- name: KAFKA_BROKERS
value: "kafka-broker:9092"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8081
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8081
initialDelaySeconds: 30
periodSeconds: 5
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: java-apps
labels:
app: order-service
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
- port: 8081
targetPort: 8081
protocol: TCP
name: management
selector:
app: order-service
type: ClusterIP

2. Quarkus Payment Service Deployment

# k8s/payment-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
namespace: java-apps
labels:
app: payment-service
version: "1.3.0"
team: backend-java
monitoring: "true"
spec:
replicas: 2
selector:
matchLabels:
app: payment-service
version: "1.3.0"
template:
metadata:
labels:
app: payment-service
version: "1.3.0"
team: backend-java
monitoring: "true"
spec:
serviceAccountName: payment-service
containers:
- name: payment-service
image: my-registry/payment-service:1.3.0
ports:
- containerPort: 8080
name: http
env:
- name: QUARKUS_PROFILE
value: "prod"
- name: JAVA_OPTS
value: "-Xmx256m -Xms128m"
- name: PAYMENT_GATEWAY_URL
value: "https://api.payment-gateway.com"
- name: DATABASE_URL
value: "jdbc:postgresql://postgresql.database:5432/payments"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "250m"
---
apiVersion: v1
kind: Service
metadata:
name: payment-service
namespace: java-apps
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: payment-service
type: ClusterIP

Calico Security Policies

1. Zero-Trust Java Application Policy

# calico-policies/zero-trust-java.yaml
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: zero-trust-java-apps
spec:
selector: has(team) && team == 'backend-java'
order: 50
# Default deny all
types:
- Ingress
- Egress
---
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: zero-trust-order-service
namespace: java-apps
spec:
selector: app == 'order-service'
order: 100
# Explicitly allow only required traffic
ingress:
- action: Allow
protocol: TCP
source:
selector: app == 'api-gateway'
destination:
ports: [8080]
- action: Allow
protocol: TCP
source:
selector: app == 'payment-service'
destination:
ports: [8080]
egress:
- action: Allow
protocol: TCP
destination:
selector: app == 'user-service'
ports: [8080]
- action: Allow
protocol: TCP
destination:
selector: app == 'payment-service'
ports: [8080]
- action: Allow
protocol: TCP
destination:
namespaceSelector:
matchLabels:
name: database
podSelector:
matchLabels:
app: postgresql
ports: [5432]
- action: Allow
protocol: TCP
destination:
selector: app == 'kafka-broker'
ports: [9092]

2. Egress Control for External Services

# calico-policies/egress-control.yaml
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: java-apps-egress-control
spec:
selector: has(team) && team == 'backend-java'
order: 200
egress:
# Allow DNS
- action: Allow
protocol: UDP
destination:
selector: k8s-app == 'kube-dns'
ports: [53]
# Allow NTP
- action: Allow
protocol: UDP
destination:
nets: [169.254.169.123/32]  # AWS NTP
ports: [123]
# Allow specific external APIs
- action: Allow
protocol: TCP
destination:
nets: [52.12.34.56/32]  # Payment gateway
ports: [443]
- action: Allow
protocol: TCP
destination:
nets: [34.56.78.90/32]  # Email service
ports: [587]
- action: Allow
protocol: TCP
destination:
nets: [52.34.56.78/32]  # Monitoring service
ports: [443]
# Deny all other egress
- action: Deny
destination: {}

Monitoring and Troubleshooting

1. Calico Network Policy Verification

# Check network policies
kubectl get networkpolicies -n java-apps
calicoctl get networkpolicy -n java-apps
# Check global network policies
calicoctl get globalnetworkpolicy
# Check endpoints
calicoctl get workloadendpoints -n java-apps
# Check Felix status (Calico agent)
kubectl get pods -n calico-system
kubectl logs -n calico-system -l k8s-app=calico-node

2. Network Policy Testing Script

#!/bin/bash
# test-network-policies.sh
set -e
echo "Testing Java application network policies..."
# Test API Gateway accessibility
echo "1. Testing API Gateway external access..."
kubectl run -n java-apps test-curl --image=curlimages/curl:8.2.1 --rm -i --tty -- /bin/sh -c "
curl -v http://api-gateway.java-apps:8080/actuator/health
"
# Test service-to-service communication
echo "2. Testing Order Service to Payment Service..."
kubectl exec -n java-apps deployment/order-service -c order-service -- \
curl -v http://payment-service.java-apps:8080/actuator/health
# Test database access
echo "3. Testing Order Service to PostgreSQL..."
kubectl exec -n java-apps deployment/order-service -c order-service -- \
nc -zv postgresql.database 5432
# Test blocked connections
echo "4. Testing blocked connections (should fail)..."
kubectl exec -n java-apps deployment/payment-service -c payment-service -- \
curl -v http://user-service.java-apps:8080/actuator/health || echo "Expected failure"
echo "Network policy testing completed!"

3. Java Application Network Diagnostics

package com.example.diagnostics;
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
@RestControllerEndpoint(id = "network")
public class NetworkDiagnosticsEndpoint {
@GetMapping("/connections")
public ResponseEntity<Map<String, Object>> checkConnections() {
Map<String, Object> results = new HashMap<>();
// Check database connectivity
boolean dbReachable = checkConnection("postgresql.database", 5432);
results.put("database", dbReachable);
// Check dependent services
boolean userServiceReachable = checkConnection("user-service.java-apps", 8080);
results.put("userService", userServiceReachable);
boolean paymentServiceReachable = checkConnection("payment-service.java-apps", 8080);
results.put("paymentService", paymentServiceReachable);
// Check external services
boolean paymentGatewayReachable = checkConnection("api.payment-gateway.com", 443);
results.put("paymentGateway", paymentGatewayReachable);
return ResponseEntity.ok(results);
}
@PostMapping("/test-connection")
public ResponseEntity<Map<String, Object>> testConnection(@RequestBody ConnectionTestRequest request) {
boolean reachable = checkConnection(request.host(), request.port());
Map<String, Object> result = new HashMap<>();
result.put("host", request.host());
result.put("port", request.port());
result.put("reachable", reachable);
result.put("timestamp", java.time.Instant.now());
return ResponseEntity.ok(result);
}
private boolean checkConnection(String host, int port) {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), 5000);
return true;
} catch (Exception e) {
return false;
}
}
public record ConnectionTestRequest(String host, int port) {}
}

CI/CD Integration

1. Network Policy Validation in CI

# .github/workflows/network-policy-validation.yml
name: Network Policy Validation
on:
push:
branches: [ main, develop ]
paths:
- 'k8s/network-policies/**'
- 'calico-policies/**'
jobs:
validate-network-policies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install CalicoCTL
run: |
curl -L https://github.com/projectcalico/calico/releases/latest/download/calicoctl-linux-amd64 -o calicoctl
chmod +x calicoctl
sudo mv calicoctl /usr/local/bin/
- name: Validate Kubernetes Network Policies
run: |
for file in k8s/network-policies/*.yaml; do
echo "Validating $file"
kubectl apply --dry-run=client -f "$file"
done
- name: Validate Calico Network Policies
run: |
for file in calico-policies/*.yaml; do
echo "Validating $file"
calicoctl apply --dry-run -f "$file"
done
- name: Check for policy conflicts
run: |
# Check for overlapping policies
echo "Checking for policy conflicts..."
# Add custom conflict detection logic here
test-network-policies:
runs-on: ubuntu-latest
needs: validate-network-policies
steps:
- uses: actions/checkout@v4
- name: Deploy to test cluster
run: |
kubectl apply -f k8s/network-policies/
kubectl apply -f calico-policies/
- name: Run network policy tests
run: |
./test-network-policies.sh

Best Practices

1. Network Policy Organization

  • Use descriptive names for policies
  • Group policies by application tier
  • Implement default deny-all policies
  • Use labels consistently for selectors

2. Security Practices

  • Implement zero-trust networking
  • Regularly review and update policies
  • Monitor policy violations
  • Use namespaces for isolation

3. Performance Considerations

  • Keep policy rules specific and minimal
  • Use global policies for common rules
  • Monitor policy impact on performance
  • Test policies in staging environments

Conclusion

Calico provides Java teams with powerful network security capabilities:

  • Fine-Grained Control: Precise control over microservice communication
  • Zero-Trust Security: Implement least-privilege network access
  • Compliance: Meet regulatory requirements for network segmentation
  • Performance: High-performance networking with security
  • Kubernetes Native: Seamless integration with Kubernetes

By implementing Calico network policies, Java microservices can operate in a secure, isolated environment while maintaining the flexibility and scalability required for modern cloud-native applications.

Pyroscope Profiling in Java
Explains how to use Pyroscope for continuous profiling in Java applications, helping developers analyze CPU and memory usage patterns to improve performance and identify bottlenecks.
https://macronepal.com/blog/pyroscope-profiling-in-java/

OpenTelemetry Metrics in Java: Comprehensive Guide
Provides a complete guide to collecting and exporting metrics in Java using OpenTelemetry, including counters, histograms, gauges, and integration with monitoring tools. (MACRO NEPAL)
https://macronepal.com/blog/opentelemetry-metrics-in-java-comprehensive-guide/

OTLP Exporter in Java: Complete Guide for OpenTelemetry
Explains how to configure OTLP exporters in Java to send telemetry data such as traces, metrics, and logs to monitoring systems using HTTP or gRPC protocols. (MACRO NEPAL)
https://macronepal.com/blog/otlp-exporter-in-java-complete-guide-for-opentelemetry/

Thanos Integration in Java: Global View of Metrics
Explains how to integrate Thanos with Java monitoring systems to create a scalable global metrics view across multiple Prometheus instances.

https://macronepal.com/blog/thanos-integration-in-java-global-view-of-metrics

Time Series with InfluxDB in Java: Complete Guide (Version 2)
Explains how to manage time-series data using InfluxDB in Java applications, including storing, querying, and analyzing metrics data.

https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide-2

Time Series with InfluxDB in Java: Complete Guide
Provides an overview of integrating InfluxDB with Java for time-series data handling, including monitoring applications and managing performance metrics.

https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide

Implementing Prometheus Remote Write in Java (Version 2)
Explains how to configure Java applications to send metrics data to Prometheus-compatible systems using the remote write feature for scalable monitoring.

https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide-2

Implementing Prometheus Remote Write in Java: Complete Guide
Provides instructions for sending metrics from Java services to Prometheus servers, enabling centralized monitoring and real-time analytics.

https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide

Building a TileServer GL in Java: Vector and Raster Tile Server
Explains how to build a TileServer GL in Java for serving vector and raster map tiles, useful for geographic visualization and mapping applications.

https://macronepal.com/blog/building-a-tileserver-gl-in-java-vector-and-raster-tile-server

Indoor Mapping in Java
Explains how to create indoor mapping systems in Java, including navigation inside buildings, spatial data handling, and visualization techniques.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper