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.