Migrate examples to tests_e2e directory structure
- Relocated all files and scripts from `examples` to `tests_e2e` for better organization. - Updated references and paths in configurations, scripts, and test files. - Adjusted `bump-version.sh` to handle the new `tests_e2e` structure. - Updated `.gitignore` to reflect path changes.
This commit is contained in:
parent
b34d7822e4
commit
d66c4f8595
51 changed files with 35 additions and 35 deletions
9
tests_e2e/kubernetes/.gitignore
vendored
Normal file
9
tests_e2e/kubernetes/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# kind installation directory
|
||||
.kind/
|
||||
|
||||
# kubectl config
|
||||
kubeconfig
|
||||
|
||||
# Test artifacts
|
||||
*.log
|
||||
service_tls_generated.yml
|
||||
50
tests_e2e/kubernetes/README.md
Normal file
50
tests_e2e/kubernetes/README.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Kubernetes Examples
|
||||
|
||||
Self-contained examples for EasyHAProxy ingress controller. **All documentation is in the YAML files as header comments.**
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Pick an example below
|
||||
2. Open the YAML file
|
||||
3. Read the header comments for complete instructions
|
||||
4. Run the commands step-by-step
|
||||
|
||||
## Prerequisites
|
||||
|
||||
All examples require:
|
||||
- EasyHAProxy installed in your Kubernetes cluster
|
||||
- Node labeled for EasyHAProxy deployment
|
||||
|
||||
See header comments in each file for detailed setup instructions.
|
||||
|
||||
## Basic Examples
|
||||
|
||||
| File | Description |
|
||||
|------------------------------------|--------------------------------------------|
|
||||
| [service.yml](service.yml) | Basic HTTP ingress with multiple domains |
|
||||
| [service_tls.yml](service_tls.yml) | HTTPS/TLS ingress with custom certificates |
|
||||
|
||||
## Plugin Examples
|
||||
|
||||
| File | Description |
|
||||
|----------------------------------------------|-----------------------------------------------------|
|
||||
| [jwt-validator.yml](jwt-validator.yml) | JWT token validation for API protection |
|
||||
| [ip-whitelist.yml](ip-whitelist.yml) | IP whitelist for admin panels or sensitive services |
|
||||
| [cloudflare.yml](cloudflare.yml) | Restore real client IPs when behind Cloudflare CDN |
|
||||
| [plugins-combined.yml](plugins-combined.yml) | Multiple plugins combined for layered security |
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
Each YAML file contains:
|
||||
- **WHAT THIS DEMONSTRATES** - Key features and concepts
|
||||
- **REQUIREMENTS** - Idempotent setup commands (safe to run multiple times)
|
||||
- **HOW TO START** - Command to apply the manifest
|
||||
- **HOW TO VERIFY IT'S WORKING** - Test commands with expected outputs
|
||||
- **CLEAN UP** - Commands to remove resources
|
||||
|
||||
## Additional Documentation
|
||||
|
||||
- [Kubernetes Installation Guide](../../docs/kubernetes.md)
|
||||
- [Helm Installation](../../docs/helm.md)
|
||||
- [Kubernetes Annotations Reference](../../docs/kubernetes.md#kubernetes-annotations)
|
||||
- [Using Plugins with Kubernetes](../../docs/kubernetes.md#using-plugins-with-kubernetes)
|
||||
140
tests_e2e/kubernetes/cloudflare.yml
Normal file
140
tests_e2e/kubernetes/cloudflare.yml
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: Cloudflare IP Restoration Plugin for Kubernetes
|
||||
# ==============================================================================
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - Restoring original visitor IPs when behind Cloudflare CDN
|
||||
# - Using ConfigMaps to mount Cloudflare IP ranges
|
||||
# - Detecting requests from Cloudflare IP ranges
|
||||
# - Accurate client IP logging for applications behind Cloudflare
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. Download Cloudflare IP ranges
|
||||
# curl -s https://www.cloudflare.com/ips-v4 > cloudflare_ips.lst
|
||||
# curl -s https://www.cloudflare.com/ips-v6 >> cloudflare_ips.lst
|
||||
#
|
||||
# # 3. Create ConfigMap with Cloudflare IPs
|
||||
# kubectl create configmap cloudflare-ips \
|
||||
# --from-file=cloudflare_ips.lst=cloudflare_ips.lst \
|
||||
# -n easyhaproxy
|
||||
#
|
||||
# # 4. Mount the ConfigMap in EasyHAProxy deployment:
|
||||
# # Edit your EasyHAProxy deployment and add:
|
||||
# # volumeMounts:
|
||||
# # - name: cloudflare-ips
|
||||
# # mountPath: /etc/haproxy/cloudflare_ips.lst
|
||||
# # subPath: cloudflare_ips.lst
|
||||
# # volumes:
|
||||
# # - name: cloudflare-ips
|
||||
# # configMap:
|
||||
# # name: cloudflare-ips
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f cloudflare.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check resources are created
|
||||
# kubectl get deployment,service,ingress -l app=webapp
|
||||
#
|
||||
# # Test via port-forward
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8080:80
|
||||
# curl -H "Host: myapp.example.local" http://localhost:8080
|
||||
# # Expected: 200 OK with JSON response containing headers, client_ip, and x_forwarded_for
|
||||
#
|
||||
# # Test IP translation with CF-Connecting-IP header
|
||||
# curl -H "Host: myapp.example.local" -H "CF-Connecting-IP: 1.2.3.4" http://localhost:8080
|
||||
# # Expected: x_forwarded_for should be "1.2.3.4"
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f cloudflare.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: webapp-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: webapp
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: webapp
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: webapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: webapp
|
||||
spec:
|
||||
containers:
|
||||
- name: webapp
|
||||
image: header-echo-server:test
|
||||
imagePullPolicy: Never
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
cpu: '0.1'
|
||||
memory: '64Mi'
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# Enable Cloudflare plugin with built-in IPs
|
||||
easyhaproxy.plugins: "cloudflare"
|
||||
|
||||
# Optional: Provide custom IP list as base64-encoded text (takes precedence over built-in IPs)
|
||||
# This is more Kubernetes-native than mounting ConfigMaps/files
|
||||
# Example IPs: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.1
|
||||
# How to create: printf "10.0.0.0/8\n172.16.0.0/12\n192.168.0.0/16\n127.0.0.1" | base64 -w 0
|
||||
# easyhaproxy.plugin.cloudflare.ip_list: "MTAuMC4wLjAvOAoxNzIuMTYuMC4wLzEyCjE5Mi4xNjguMC4wLzE2CjEyNy4wLjAuMQ=="
|
||||
|
||||
# Optional: Specify custom IP list file path (only used if ip_list is not provided)
|
||||
# easyhaproxy.plugin.cloudflare.ip_list_path: "/etc/haproxy/cloudflare_ips.lst"
|
||||
name: webapp-ingress-cloudflare
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: myapp.example.local
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: webapp-service
|
||||
port:
|
||||
number: 8080
|
||||
pathType: ImplementationSpecific
|
||||
124
tests_e2e/kubernetes/ip-whitelist.yml
Normal file
124
tests_e2e/kubernetes/ip-whitelist.yml
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: IP Whitelist Plugin for Kubernetes
|
||||
# ==============================================================================
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - Restricting access to specific IP addresses or CIDR ranges
|
||||
# - Using annotations for IP-based access control
|
||||
# - Protecting admin panels or sensitive services in Kubernetes
|
||||
# - Custom HTTP status code for blocked requests
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. IMPORTANT: Edit this file (line 80) and update allowed_ips
|
||||
# # with your actual office/VPN IP addresses or networks
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f ip-whitelist.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check resources are created
|
||||
# kubectl get deployment,service,ingress -l app=admin
|
||||
#
|
||||
# # Test from allowed IP
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8080:80
|
||||
# curl -H "Host: admin.example.local" http://localhost:8080
|
||||
# # Expected: 200 OK with "Admin Panel - IP Restricted" (if your IP is in allowed_ips)
|
||||
#
|
||||
# # Test from non-allowed IP
|
||||
# # Expected: HTTP 403 Forbidden
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f ip-whitelist.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: admin-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: admin
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: admin
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: admin
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: admin
|
||||
spec:
|
||||
containers:
|
||||
- name: admin
|
||||
image: byjg/static-httpserver
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Admin Panel - IP Restricted"
|
||||
resources:
|
||||
limits:
|
||||
cpu: '0.1'
|
||||
memory: '64Mi'
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# Enable IP whitelist plugin
|
||||
easyhaproxy.plugins: "ip_whitelist"
|
||||
|
||||
# Allow specific IPs and networks
|
||||
# UPDATE THIS with your actual office/VPN IPs!
|
||||
# For testing: includes localhost and Docker/Kubernetes private networks
|
||||
easyhaproxy.plugin.ip_whitelist.allowed_ips: "127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,203.0.113.0/24,198.51.100.42"
|
||||
|
||||
# Status code to return for blocked IPs
|
||||
easyhaproxy.plugin.ip_whitelist.status_code: "403"
|
||||
name: admin-ingress-whitelist
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: admin.example.local
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: admin-service
|
||||
port:
|
||||
number: 8080
|
||||
135
tests_e2e/kubernetes/jwt-validator-secret-example.yml
Normal file
135
tests_e2e/kubernetes/jwt-validator-secret-example.yml
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# Example demonstrating JWT validator with Kubernetes secret
|
||||
# This shows the recommended way to provide JWT public keys in Kubernetes
|
||||
#
|
||||
# IMPORTANT: Before applying this manifest, generate JWT keys by running:
|
||||
# cd /path/to/examples && bash generate-keys.sh
|
||||
#
|
||||
# Then create the secrets with your generated keys:
|
||||
# kubectl create secret generic jwt-pubkey-secret \
|
||||
# --from-file=pubkey=docker/jwt_pubkey.pem -n default
|
||||
# kubectl create secret generic jwt-custom-secret \
|
||||
# --from-file=rsa-public-key=docker/jwt_pubkey.pem -n default
|
||||
#
|
||||
# TWO ANNOTATION FORMATS:
|
||||
# 1. Auto-detect key (tries common variations):
|
||||
# easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "jwt-pubkey-secret"
|
||||
# Tries keys: pubkey, public-key, jwt.pub, tls.crt
|
||||
#
|
||||
# 2. Explicit key (no variations):
|
||||
# easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "jwt-pubkey-secret/rsa-public-key"
|
||||
# Only tries key: rsa-public-key
|
||||
|
||||
---
|
||||
# NOTE: Secrets should be created separately using your generated JWT keys
|
||||
# See instructions at the top of this file
|
||||
# The test fixture creates these secrets automatically
|
||||
|
||||
---
|
||||
# Deployment for API service
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: api
|
||||
spec:
|
||||
containers:
|
||||
- name: api
|
||||
image: byjg/static-httpserver
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Protected API - JWT Required"
|
||||
|
||||
---
|
||||
# Service to be protected with JWT
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: api-service
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: api
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
|
||||
---
|
||||
# Ingress Example 1: Auto-detect key (uses standard key name "pubkey")
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: api-ingress-jwt-auto
|
||||
namespace: default
|
||||
annotations:
|
||||
# Enable JWT validator plugin
|
||||
easyhaproxy.plugins: "jwt_validator"
|
||||
|
||||
# JWT validator configuration
|
||||
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
|
||||
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
|
||||
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
|
||||
|
||||
# Auto-detect: tries pubkey, public-key, jwt.pub, tls.crt
|
||||
easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "jwt-pubkey-secret"
|
||||
spec:
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: api.example.local
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: api-service
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
---
|
||||
# Ingress Example 2: Explicit key (uses custom key name "rsa-public-key")
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: api-ingress-jwt-explicit
|
||||
namespace: default
|
||||
annotations:
|
||||
# Enable JWT validator plugin
|
||||
easyhaproxy.plugins: "jwt_validator"
|
||||
|
||||
# JWT validator configuration
|
||||
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
|
||||
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
|
||||
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
|
||||
|
||||
# Explicit key: only tries "rsa-public-key" from the secret
|
||||
easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "jwt-custom-secret/rsa-public-key"
|
||||
|
||||
# Optional: Protect only specific paths
|
||||
# easyhaproxy.plugin.jwt_validator.paths: "/api,/admin"
|
||||
|
||||
# Optional: Allow anonymous access (JWT validated only if present)
|
||||
# easyhaproxy.plugin.jwt_validator.allow_anonymous: "true"
|
||||
spec:
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: api-custom.example.local
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: api-service
|
||||
port:
|
||||
number: 8080
|
||||
160
tests_e2e/kubernetes/jwt-validator.yml
Normal file
160
tests_e2e/kubernetes/jwt-validator.yml
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: JWT Validator Plugin for Kubernetes
|
||||
# ==============================================================================
|
||||
#
|
||||
# JWT PUBLIC KEY CONFIGURATION OPTIONS:
|
||||
# There are three ways to provide the JWT public key:
|
||||
#
|
||||
# 1. pubkey_path - Mount a file and reference the path (requires ConfigMap or Volume)
|
||||
# easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/haproxy/jwt_keys/api_pubkey.pem"
|
||||
#
|
||||
# 2. k8s_secret.pubkey - Reference a Kubernetes secret (RECOMMENDED)
|
||||
# Auto-detect key (tries common variations):
|
||||
# easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "my-jwt-secret"
|
||||
# Explicit key (no variations):
|
||||
# easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "my-jwt-secret/custom-key-name"
|
||||
# See jwt-validator-secret-example.yml for full example
|
||||
#
|
||||
# 3. pubkey - Inline base64-encoded key (for testing only, not recommended for production)
|
||||
# easyhaproxy.plugin.jwt_validator.pubkey: "LS0tLS1CRUdJTi..."
|
||||
#
|
||||
# This example shows option #1 (pubkey_path) for backward compatibility
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - JWT token validation for API protection in Kubernetes
|
||||
# - RS256 algorithm signature verification
|
||||
# - Using ConfigMaps to mount JWT public keys
|
||||
# - Issuer and audience validation
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. Generate RSA key pair (idempotent - skips if exists)
|
||||
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
||||
# [ -f jwt_pubkey.pem ] || openssl rsa -in jwt_private.pem -pubout -out jwt_pubkey.pem
|
||||
#
|
||||
# # 3. Create ConfigMap with public key
|
||||
# kubectl create configmap jwt-keys --from-file=api_pubkey.pem=jwt_pubkey.pem
|
||||
#
|
||||
# # 4. Mount the ConfigMap in EasyHAProxy deployment:
|
||||
# # Edit your EasyHAProxy deployment and add:
|
||||
# # volumeMounts:
|
||||
# # - name: jwt-keys
|
||||
# # mountPath: /etc/haproxy/jwt_keys
|
||||
# # volumes:
|
||||
# # - name: jwt-keys
|
||||
# # configMap:
|
||||
# # name: jwt-keys
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f jwt-validator.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check resources are created
|
||||
# kubectl get deployment,service,ingress -l app=api
|
||||
#
|
||||
# # Test without token (should fail)
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8080:80
|
||||
# curl -H "Host: api.example.local" http://localhost:8080
|
||||
# # Expected: HTTP 403 - Missing Authorization HTTP header
|
||||
#
|
||||
# # Generate test JWT at https://jwt.io with:
|
||||
# # - Algorithm: RS256
|
||||
# # - Payload: {"iss":"https://auth.example.com/","aud":"https://api.example.com","exp":9999999999}
|
||||
# # - Paste contents of jwt_private.pem in private key field
|
||||
#
|
||||
# # Test with valid token
|
||||
# TOKEN="eyJhbGc..." # Replace with your generated token
|
||||
# curl -H "Authorization: Bearer $TOKEN" -H "Host: api.example.local" http://localhost:8080
|
||||
# # Expected: 200 OK with "Protected API - JWT Required"
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f jwt-validator.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: api-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: api
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: api
|
||||
spec:
|
||||
containers:
|
||||
- name: api
|
||||
image: byjg/static-httpserver
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Protected API - JWT Required"
|
||||
resources:
|
||||
limits:
|
||||
cpu: '0.1'
|
||||
memory: '64Mi'
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# Enable JWT validator plugin
|
||||
easyhaproxy.plugins: "jwt_validator"
|
||||
|
||||
# JWT validator configuration
|
||||
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
|
||||
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
|
||||
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
|
||||
easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/haproxy/jwt_keys/api_pubkey.pem"
|
||||
name: api-ingress-jwt
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: api.example.local
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: api-service
|
||||
port:
|
||||
number: 8080
|
||||
pathType: ImplementationSpecific
|
||||
278
tests_e2e/kubernetes/plugins-combined.yml
Normal file
278
tests_e2e/kubernetes/plugins-combined.yml
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: Multiple Plugins Combined for Kubernetes
|
||||
# ==============================================================================
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - Using multiple security plugins together
|
||||
# - Different plugin combinations for different services
|
||||
# - Layered security approach in Kubernetes
|
||||
# - Three services with different security profiles:
|
||||
# 1. Public website: Cloudflare + path blocking
|
||||
# 2. Protected API: JWT validation + path blocking
|
||||
# 3. Admin panel: Strict IP whitelist
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. Generate JWT keys (idempotent - skips if exists)
|
||||
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
||||
# [ -f jwt_pubkey.pem ] || openssl rsa -in jwt_private.pem -pubout -out jwt_pubkey.pem
|
||||
# kubectl create configmap jwt-keys --from-file=api_pubkey.pem=jwt_pubkey.pem
|
||||
#
|
||||
# # 3. Download Cloudflare IPs
|
||||
# curl -s https://www.cloudflare.com/ips-v4 > cloudflare_ips.lst
|
||||
# curl -s https://www.cloudflare.com/ips-v6 >> cloudflare_ips.lst
|
||||
# kubectl create configmap cloudflare-ips \
|
||||
# --from-file=cloudflare_ips.lst=cloudflare_ips.lst \
|
||||
# -n easyhaproxy
|
||||
#
|
||||
# # 4. Mount ConfigMaps in EasyHAProxy deployment
|
||||
# # (See individual plugin examples for mount configuration)
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f plugins-combined.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check all resources are created
|
||||
# kubectl get deployment,service,ingress
|
||||
#
|
||||
# # Test public website (Cloudflare + path blocking)
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8080:80
|
||||
# curl -H "Host: website.example.local" http://localhost:8080
|
||||
# # Expected: 200 OK with "Public Website"
|
||||
# curl -H "Host: website.example.local" http://localhost:8080/admin
|
||||
# # Expected: HTTP 404 - Path blocked
|
||||
#
|
||||
# # Test protected API (JWT required)
|
||||
# curl -H "Host: api.example.local" http://localhost:8080
|
||||
# # Expected: HTTP 403 - Missing Authorization header
|
||||
#
|
||||
# # Test admin panel (IP whitelist)
|
||||
# curl -H "Host: admin.example.local" http://localhost:8080
|
||||
# # Expected: 200 OK from allowed IP, or HTTP 403 from blocked IP
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f plugins-combined.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
# Public website service
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: website-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
selector:
|
||||
app: website
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: website
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: website
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: website
|
||||
spec:
|
||||
containers:
|
||||
- name: website
|
||||
image: byjg/static-httpserver
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Public Website"
|
||||
resources:
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
# Public website ingress with Cloudflare + path blocking
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# Cloudflare IP restoration + deny pages
|
||||
easyhaproxy.plugins: "cloudflare,deny_pages"
|
||||
easyhaproxy.plugin.deny_pages.paths: "/admin,/wp-admin,/wp-login.php,/.env,/config"
|
||||
easyhaproxy.plugin.deny_pages.status_code: "404"
|
||||
name: website-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: website.example.local
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: website-service
|
||||
port:
|
||||
number: 8080
|
||||
pathType: ImplementationSpecific
|
||||
|
||||
---
|
||||
# API service
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: api-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
selector:
|
||||
app: api
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 5
|
||||
selector:
|
||||
matchLabels:
|
||||
app: api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: api
|
||||
spec:
|
||||
containers:
|
||||
- name: api
|
||||
image: byjg/static-httpserver
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Protected API"
|
||||
resources:
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
# API ingress with JWT + path blocking
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# JWT validation + block internal endpoints
|
||||
easyhaproxy.plugins: "jwt_validator,deny_pages"
|
||||
# JWT config
|
||||
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
|
||||
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
|
||||
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
|
||||
easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/haproxy/jwt_keys/api_pubkey.pem"
|
||||
# Block internal paths
|
||||
easyhaproxy.plugin.deny_pages.paths: "/internal,/debug,/metrics"
|
||||
easyhaproxy.plugin.deny_pages.status_code: "403"
|
||||
name: api-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: api.example.local
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: api-service
|
||||
port:
|
||||
number: 8080
|
||||
pathType: ImplementationSpecific
|
||||
|
||||
---
|
||||
# Admin service
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: admin-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
selector:
|
||||
app: admin
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: admin
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: admin
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: admin
|
||||
spec:
|
||||
containers:
|
||||
- name: admin
|
||||
image: byjg/static-httpserver
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "Admin Panel"
|
||||
resources:
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '32Mi'
|
||||
|
||||
---
|
||||
# Admin ingress with strict IP whitelist
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
# IP whitelist only (strictest security)
|
||||
easyhaproxy.plugins: "ip_whitelist"
|
||||
# UPDATE with your office/VPN IPs!
|
||||
easyhaproxy.plugin.ip_whitelist.allowed_ips: "203.0.113.0/24,10.0.0.0/8"
|
||||
easyhaproxy.plugin.ip_whitelist.status_code: "403"
|
||||
name: admin-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: admin.example.local
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: admin-service
|
||||
port:
|
||||
number: 8080
|
||||
pathType: ImplementationSpecific
|
||||
137
tests_e2e/kubernetes/service.yml
Normal file
137
tests_e2e/kubernetes/service.yml
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: Basic Kubernetes Ingress
|
||||
# ==============================================================================
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - Basic ingress configuration with EasyHAProxy
|
||||
# - Multiple domains pointing to the same service
|
||||
# - Complete deployment + service + ingress setup
|
||||
# - HTTP ingress without TLS
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. Label the node where EasyHAProxy will run
|
||||
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
||||
#
|
||||
# # 3. Add to /etc/hosts for local testing (idempotent)
|
||||
# grep -q "example.org" /etc/hosts || echo "<node-ip> example.org www.example.org" | sudo tee -a /etc/hosts
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f service.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check resources are created
|
||||
# kubectl get deployment,service,ingress container-example
|
||||
#
|
||||
# # Test via node IP
|
||||
# curl -H "Host: example.org" http://<node-ip>:31080
|
||||
# # Expected: 200 OK with "My Host Example"
|
||||
#
|
||||
# # Or use port-forward for testing
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8080:80
|
||||
# curl -H "Host: example.org" http://localhost:8080
|
||||
# # Expected: 200 OK with "My Host Example"
|
||||
#
|
||||
# # Test second domain
|
||||
# curl -H "Host: www.example.org" http://<node-ip>:31080
|
||||
# # Expected: Same response
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f service.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: container-example
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
rules:
|
||||
- host: example.org
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: container-example
|
||||
port:
|
||||
number: 8080
|
||||
- host: www.example.org
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: container-example
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: container-example
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
selector:
|
||||
app: container-example
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: container-example
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 10
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: container-example
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: container-example
|
||||
spec:
|
||||
containers:
|
||||
- name: container-example
|
||||
image: byjg/static-httpserver
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
cpu: '0.05'
|
||||
memory: '20Mi'
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '20Mi'
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "My Host Example"
|
||||
143
tests_e2e/kubernetes/service_tls.yml
Normal file
143
tests_e2e/kubernetes/service_tls.yml
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# ==============================================================================
|
||||
# EXAMPLE: TLS/SSL Kubernetes Ingress
|
||||
# ==============================================================================
|
||||
#
|
||||
# WHAT THIS DEMONSTRATES:
|
||||
# - HTTPS/TLS configuration with custom certificates
|
||||
# - Kubernetes TLS secrets for SSL certificates
|
||||
# - Complete deployment + service + secret + ingress with TLS
|
||||
# - Using pre-generated test certificates
|
||||
#
|
||||
# REQUIREMENTS (run these first):
|
||||
# ```bash
|
||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||
# kubectl create namespace easyhaproxy
|
||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/5.0.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||
#
|
||||
# # 2. Label the node where EasyHAProxy will run
|
||||
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
||||
#
|
||||
# # 3. Add to /etc/hosts for local testing (idempotent)
|
||||
# grep -q "host2.local" /etc/hosts || echo "<node-ip> host2.local" | sudo tee -a /etc/hosts
|
||||
#
|
||||
# # Note: This example uses embedded test certificates
|
||||
# # For production, create your own secret:
|
||||
# # kubectl create secret tls host2-tls --cert=cert.crt --key=cert.key
|
||||
# ```
|
||||
#
|
||||
# HOW TO START:
|
||||
# ```bash
|
||||
# kubectl apply -f service_tls.yml
|
||||
# ```
|
||||
#
|
||||
# HOW TO VERIFY IT'S WORKING:
|
||||
# ```bash
|
||||
# # Check resources are created
|
||||
# kubectl get deployment,service,ingress,secret tls-example
|
||||
# kubectl get secret host2-tls
|
||||
#
|
||||
# # Test HTTPS (using port-forward)
|
||||
# kubectl port-forward -n easyhaproxy deployment/easyhaproxy 8443:443
|
||||
# curl -k -H "Host: host2.local" https://localhost:8443
|
||||
# # Expected: 200 OK with "My Host Example"
|
||||
#
|
||||
# # Verify certificate
|
||||
# openssl s_client -showcerts -connect localhost:8443 -servername host2.local < /dev/null
|
||||
# # Expected: Certificate for host2.local
|
||||
# ```
|
||||
#
|
||||
# CLEAN UP:
|
||||
# ```bash
|
||||
# kubectl delete -f service_tls.yml
|
||||
# ```
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: tls-example
|
||||
namespace: default
|
||||
spec:
|
||||
# Use ingressClassName instead of the deprecated annotation
|
||||
# For backward compatibility, annotation kubernetes.io/ingress.class is still supported
|
||||
ingressClassName: easyhaproxy
|
||||
tls:
|
||||
- hosts:
|
||||
- host2.local
|
||||
secretName: host2-tls
|
||||
rules:
|
||||
- host: host2.local
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: tls-example
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: host2-tls
|
||||
namespace: default
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxVENDQXBHZ0F3SUJBZ0lVSWQ1Yjl0OXVxSDc4ZzAyRXpiV0Y2RktWdzNnd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1pERUxNQWtHQTFVRUJoTUNRbEl4RnpBVkJnTlZCQWdNRGxKcGJ5QmtaU0JLWVc1bGFYSnZNUmN3RlFZRApWUVFIREE1U2FXOGdaR1VnU21GdVpXbHliekVOTUFzR0ExVUVDZ3dFUVVOTlJURVVNQklHQTFVRUF3d0xhRzl6CmRESXViRzlqWVd3d0hoY05Nakl3T0RFMU1EUXlOekExV2hjTk1qTXdPREUxTURReU56QTFXakJrTVFzd0NRWUQKVlFRR0V3SkNVakVYTUJVR0ExVUVDQXdPVW1sdklHUmxJRXBoYm1WcGNtOHhGekFWQmdOVkJBY01EbEpwYnlCawpaU0JLWVc1bGFYSnZNUTB3Q3dZRFZRUUtEQVJCUTAxRk1SUXdFZ1lEVlFRRERBdG9iM04wTWk1c2IyTmhiRENDCkFTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTVNLdnJPYWhhdkNYbnZTRjUxMzFocG8KNms2NUM1N2pnUlE4NEZhRGo1TWJKT1ZsWVFWRnRNRzBYT2s3YStoaDV2MWZlNHdIMFI3STZGRG8wVjlzUytzcwprbzVic0VsYzF4WWxnNUhidUtxODl2UlNLZzZFRGx6dHgzQktiaTkxMlBtdDV2RkdOSjE2emN3NzdEVXJRSVhvCjRJL2I0YTNwbUJpV2o0M05vVElybVNXSHRzR3d3T2ozaUR2U3dlcWRZWEpJcjNocEhINXU2cG9oakRvUXZxRHoKSzZNdThwNm1oQ1VLTnM3S0ZKbk5Jbk5HMjVvUVQ2TzBuNE9HdG1nUmpMV29wZEVuT2hNa0tzZklvSTFYdGxYQgpMQkR2N2h1SUNrM3Q1eXd0ZkNReU8wOWtYN2xGSWdkNXJuNytNandINVdOZXFiUUp4dWFxam9YUW5OWlVnVXNDCkF3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZOaE1CRzhxNmEraUsybkVDd1ZUbjZCOUVYWk9NQjhHQTFVZEl3UVkKTUJhQUZOaE1CRzhxNmEraUsybkVDd1ZUbjZCOUVYWk9NQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUptdWR2eDgrcDVpSVVzVDhmbS9mYlZNMERBNnFXQUxEWVVKblRuM2o2THE0dnBmClBGQytxMUxtdVdmQlFNeXFLckhyUDNlNDkzRWN0WG9pU0taTzZpTjVkVkpJdXIwMk9qR3VpQUVjc1l1WTFuTG4KczlwaWlJK1VFd3hINnV4MU5hSFVuenNXYXVvQnZSaHpqWHZPNlNBVlNaSllhOWRZNW1pelhrbER5RE51RzVVMApsWHY5ZWdNR0JzeTBkRzZlRlhrVTVDUGR4V1U1NDB5STJzQ3RTQWo3eitXUlVENWs3Z0o3dFZvWTMvL2pIUVpHCjVTVFRtbTV0OWtwSVpUV2twdHlKb3M5b1pKRllNSVhxVzJGYzZ0eUxacFJwMzFSNzh0RHM2RVRJa1RvRGMwUlIKano2NnRoNkhJK1psZ0lCUWh3MDkraFlBaEJEZTkrRG1kL1N6UVpjPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRREVpcjZ6bW9XcndsNTcKMGhlZGQ5WWFhT3BPdVF1ZTQ0RVVQT0JXZzQrVEd5VGxaV0VGUmJUQnRGenBPMnZvWWViOVgzdU1COUVleU9oUQo2TkZmYkV2ckxKS09XN0JKWE5jV0pZT1IyN2lxdlBiMFVpb09oQTVjN2Nkd1NtNHZkZGo1cmVieFJqU2RlczNNCk8rdzFLMENGNk9DUDIrR3Q2WmdZbG8rTnphRXlLNWtsaDdiQnNNRG85NGc3MHNIcW5XRnlTSzk0YVJ4K2J1cWEKSVl3NkVMNmc4eXVqTHZLZXBvUWxDamJPeWhTWnpTSnpSdHVhRUUranRKK0RoclpvRVl5MXFLWFJKem9USkNySAp5S0NOVjdaVndTd1E3KzRiaUFwTjdlY3NMWHdrTWp0UFpGKzVSU0lIZWE1Ky9qSThCK1ZqWHFtMENjYm1xbzZGCjBKeldWSUZMQWdNQkFBRUNnZ0VCQUtjZWl0VlJPUVE1ZS9teFJSOUNmSzFzTkgvSDNOZTMvMVBrQjZYSXJGYWIKcUIzZXZFYXRaT3VvbjdBNk5LRWVUamwzN1NlK3BkU1ZaT1VYY3FDL0J6YnJhWnJlMytFaHJrcElqNzJBcFYrWQoyaXdaaVdWYWFKUWdJNHVaM21OQXc4UmFXSnNqNVMxYTlJOExET2lRNUlaNDVDbXZBQkRQSmVNU2N2SlN2UlJZCmU1TjBMNnN0cVM3WitJb3lHVktVZnAxaU5PMFl5eXdPVWlTa0lSWGdzY3VSWFpHWXBpR1BvbXNKK0pzMWVqelcKanlTdGxaSkVyNEwxMjg1ckdQcm1IcWpUd0ZkK2hHODBXYzQxNzl4TCtXUkU2SEJFVVpTaXk5NWZlNmtjUEhYWApCZ2lWWXRjRkttaUJpMmRUYnhsNGU5NHV0MjM5aTBIdGxKMVpKdExoK0JFQ2dZRUE4YTI5OEsyelhrSG9zeGhOCnRSckg3WGZNUFRrSEREZDNyeE0yMUxUK2ZJWHFpbkdVcDlMWWFEY2JqdVRQczhlMzN1S01kN1I2UTQweDg5eVcKSVhOa2EvVkwwUFhVZVY2N2FDVkxMcWdYRExHdWRsdUppbkgwWHZtSTBDbUJlY0ZTTXFJRm1RbGdxRVJvR0dzMwpVTWFjMHA4NzZUNFhrR1FRSmRmNjJiRnBFNFVDZ1lFQTBEQkgwUERsT3B3WGNjRGdYck1mYXlyOEhBaEkrRzVSCnlXUS8vOWlpcnRVODNjaHdJV3draDUzZUxMTXpMZ2RxSm5QaVd5YVVXNUJxem1ZdUQyM25oeGNRN1BOZElxT08KSDFzRTZ6cUxOc2h2NDZ0NVFLbGgxUTRxamQ3VXF0Z3JTclk2M1JYSkNNV1R3bk5NZURMdGo4Z2FLYmprckczUgpCTTJpbGR0NlVvOENnWUJYN05EVWxpMVNsb0gxWGxzdkQwNDdTOEZIYU03eWw5OTRGM0owVW1EZnBzemNqMVA0CjlwRjY0TW1xNC8zWXQwbGkwbU11VGIvSmdiM3hyWWdGSlhrY2VjS2FoRVZIM3JvcHVwK3Vtc0xBQUlpclVNUXEKVlNrRndKMFF0bmovZGVEVXdQTnVhT1g4Y2Q2NU81Q0ZWNnpJUjl4QkVERDhmQnNQMlpMT3ptZWZEUUtCZ1FERgptMjR2VnRoZC8xY0pkQ2dEKzBWeE5ZWERIZUlWWExGbzFTMGlMWUNOTG4zdGpabFJRQktVWHpaSmUzYXkwL3JmCnNOTkQ3YVNZSE1Za1R6eWRESmJjMVBvTnp4bXlEVWlUWHBPV3F5VUV4TS9mYkIxVlVQRTVoNDdBeHFkWjJvR04KRXRkZ2pwTVpMbUNJQzJTa0dzTCszTkpvazhVS0hkcHVFcm1tUUlNazVRS0JnUUNnRVdjWXRMWEMzWURZTUZkSQpVZ2NUZWJGcVNzM21MWWd1YjF4ZWtXM0lYUjJ5b200VjVmUVRMaUY3WWZuMmRwRFc0SWNNVTBVSkZZVnNVbGhLCmFHdGV0NFZtNU5uOCtNZ2hvdDV5QWpxTzl5QVVhdWI3d2dpZktJZTk5dFFLZDh1WnlDdkowaGh2bUREU2Z4NG0KQi9URWlGQU85OXlGNDlpU3hFVlNBUzZwcVE9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
type: kubernetes.io/tls
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: tls-example
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
selector:
|
||||
app: tls-example
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: tls-example
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 10
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: tls-example
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: tls-example
|
||||
spec:
|
||||
containers:
|
||||
- name: tls-example
|
||||
image: byjg/static-httpserver
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
cpu: '0.05'
|
||||
memory: '20Mi'
|
||||
requests:
|
||||
cpu: '0.05'
|
||||
memory: '20Mi'
|
||||
env:
|
||||
- name: TITLE
|
||||
value: "My Host Example"
|
||||
169
tests_e2e/kubernetes/setup-cluster.sh
Executable file
169
tests_e2e/kubernetes/setup-cluster.sh
Executable file
|
|
@ -0,0 +1,169 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
CLUSTER_NAME="easyhaproxy-test"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BIN_DIR="${SCRIPT_DIR}/.kind"
|
||||
KIND_BIN="${BIN_DIR}/kind"
|
||||
KUBECTL_BIN="${BIN_DIR}/kubectl"
|
||||
HELM_BIN="${BIN_DIR}/helm"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# Port configuration (matches test_kubernetes.py)
|
||||
HTTP_PORT=10080
|
||||
HTTPS_PORT=10443
|
||||
STATS_PORT=11936
|
||||
|
||||
echo -e "${BLUE}[1/9] Setting up kind cluster '${CLUSTER_NAME}'...${NC}"
|
||||
|
||||
# Ensure kind is installed
|
||||
if [ ! -f "${KIND_BIN}" ]; then
|
||||
echo "Installing kind locally..."
|
||||
mkdir -p "${BIN_DIR}"
|
||||
curl -Lo "${KIND_BIN}" "https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64"
|
||||
chmod +x "${KIND_BIN}"
|
||||
echo -e "${GREEN}✓ kind installed to ${KIND_BIN}${NC}"
|
||||
fi
|
||||
|
||||
# Ensure kubectl is installed
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
if [ ! -f "${KUBECTL_BIN}" ]; then
|
||||
echo "Installing kubectl locally..."
|
||||
mkdir -p "${BIN_DIR}"
|
||||
VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
|
||||
curl -Lo "${KUBECTL_BIN}" "https://dl.k8s.io/release/${VERSION}/bin/linux/amd64/kubectl"
|
||||
chmod +x "${KUBECTL_BIN}"
|
||||
echo -e "${GREEN}✓ kubectl installed to ${KUBECTL_BIN}${NC}"
|
||||
fi
|
||||
KUBECTL="${KUBECTL_BIN}"
|
||||
else
|
||||
KUBECTL="kubectl"
|
||||
fi
|
||||
|
||||
# Ensure helm is installed
|
||||
if ! command -v helm &> /dev/null; then
|
||||
if [ ! -f "${HELM_BIN}" ]; then
|
||||
echo "Installing helm locally..."
|
||||
mkdir -p "${BIN_DIR}"
|
||||
HELM_VERSION="v3.13.3"
|
||||
HELM_TAR="${BIN_DIR}/helm.tar.gz"
|
||||
curl -Lo "${HELM_TAR}" "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz"
|
||||
tar -xzf "${HELM_TAR}" -C "${BIN_DIR}" --strip-components=1 linux-amd64/helm
|
||||
rm "${HELM_TAR}"
|
||||
chmod +x "${HELM_BIN}"
|
||||
echo -e "${GREEN}✓ helm installed to ${HELM_BIN}${NC}"
|
||||
fi
|
||||
HELM="${HELM_BIN}"
|
||||
else
|
||||
HELM="helm"
|
||||
fi
|
||||
|
||||
# Check if cluster already exists
|
||||
echo -e "${BLUE}[1/9] Checking for existing cluster...${NC}"
|
||||
if ${KIND_BIN} get clusters 2>/dev/null | grep -q "^${CLUSTER_NAME}$"; then
|
||||
echo -e "${BLUE}Cluster '${CLUSTER_NAME}' already exists, deleting it first...${NC}"
|
||||
${KIND_BIN} delete cluster --name "${CLUSTER_NAME}"
|
||||
fi
|
||||
|
||||
# Create cluster config
|
||||
echo -e "${BLUE}[1/9] Writing cluster config...${NC}"
|
||||
CLUSTER_CONFIG="${BIN_DIR}/cluster-config.yaml"
|
||||
mkdir -p "${BIN_DIR}"
|
||||
cat > "${CLUSTER_CONFIG}" <<EOF
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
extraPortMappings:
|
||||
- containerPort: 80
|
||||
hostPort: ${HTTP_PORT}
|
||||
protocol: TCP
|
||||
- containerPort: 443
|
||||
hostPort: ${HTTPS_PORT}
|
||||
protocol: TCP
|
||||
- containerPort: 1936
|
||||
hostPort: ${STATS_PORT}
|
||||
protocol: TCP
|
||||
EOF
|
||||
|
||||
# Create cluster
|
||||
echo -e "${BLUE}[2/9] Creating kind cluster (this may take 1-2 minutes)...${NC}"
|
||||
${KIND_BIN} create cluster --name "${CLUSTER_NAME}" --config "${CLUSTER_CONFIG}"
|
||||
|
||||
# Set kubectl context
|
||||
echo -e "${BLUE}[3/9] Setting kubectl context...${NC}"
|
||||
${KUBECTL} config use-context "kind-${CLUSTER_NAME}"
|
||||
|
||||
# Wait for nodes to be ready
|
||||
echo -e "${BLUE}[3/9] Waiting for cluster nodes to be ready...${NC}"
|
||||
${KUBECTL} wait --for=condition=Ready nodes --all --timeout=30s
|
||||
|
||||
echo -e "${GREEN}✓ kind cluster '${CLUSTER_NAME}' is ready${NC}"
|
||||
|
||||
# Build and load local EasyHAProxy image
|
||||
echo -e "${BLUE}[4/9] Building local EasyHAProxy image (may take 30-60s)...${NC}"
|
||||
docker build -t byjg/easy-haproxy:local \
|
||||
-f "${PROJECT_ROOT}/build/Dockerfile" \
|
||||
"${PROJECT_ROOT}"
|
||||
|
||||
echo -e "${BLUE}[5/9] Loading image into kind cluster (may take 10-20s)...${NC}"
|
||||
${KIND_BIN} load docker-image byjg/easy-haproxy:local --name "${CLUSTER_NAME}"
|
||||
|
||||
# Generate EasyHAProxy manifest using Helm
|
||||
echo -e "${BLUE}[6/9] Generating EasyHAProxy manifest from Helm...${NC}"
|
||||
HELM_DIR="${PROJECT_ROOT}/helm"
|
||||
MANIFEST_PATH="${BIN_DIR}/easyhaproxy-local.yml"
|
||||
|
||||
${HELM} template ingress "${HELM_DIR}/easyhaproxy" \
|
||||
--namespace easyhaproxy \
|
||||
--set service.create=false \
|
||||
--set image.tag=local \
|
||||
--set image.pullPolicy=Never \
|
||||
> "${MANIFEST_PATH}"
|
||||
|
||||
# Install EasyHAProxy
|
||||
echo -e "${BLUE}[7/9] Creating easyhaproxy namespace...${NC}"
|
||||
${KUBECTL} create namespace easyhaproxy
|
||||
|
||||
echo -e "${BLUE}[7/9] Applying EasyHAProxy manifest...${NC}"
|
||||
${KUBECTL} apply -f "${MANIFEST_PATH}"
|
||||
|
||||
# Label the control-plane node
|
||||
echo -e "${BLUE}[8/9] Labeling control-plane node...${NC}"
|
||||
${KUBECTL} label nodes "${CLUSTER_NAME}-control-plane" \
|
||||
"easyhaproxy/node=master" --overwrite
|
||||
|
||||
# Wait for EasyHAProxy to be ready
|
||||
echo -e "${BLUE}[9/9] Waiting for EasyHAProxy pods to be ready...${NC}"
|
||||
if ${KUBECTL} wait --for=condition=Ready pods \
|
||||
-n easyhaproxy -l "app.kubernetes.io/name=easyhaproxy" \
|
||||
--timeout=30s 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ EasyHAProxy pods are ready${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Pods not ready within 30s. Checking status...${NC}"
|
||||
${KUBECTL} get pods -n easyhaproxy -o wide
|
||||
echo -e "\n${BLUE}Events:${NC}"
|
||||
${KUBECTL} get events -n easyhaproxy --sort-by=.lastTimestamp
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ All setup complete! Cluster is ready.${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}Cluster Information:${NC}"
|
||||
echo -e " Cluster name: ${CLUSTER_NAME}"
|
||||
echo -e " HTTP port: localhost:${HTTP_PORT}"
|
||||
echo -e " HTTPS port: localhost:${HTTPS_PORT}"
|
||||
echo -e " Stats port: localhost:${STATS_PORT}"
|
||||
echo ""
|
||||
echo -e "${BLUE}Useful commands:${NC}"
|
||||
echo -e " Apply example ingress: ${KUBECTL} apply -f ${SCRIPT_DIR}/service.yml"
|
||||
echo -e " Check EasyHAProxy logs: ${KUBECTL} logs -n easyhaproxy -l app.kubernetes.io/name=easyhaproxy -f"
|
||||
echo -e " Test with curl: curl -H 'Host: example.org' http://localhost:${HTTP_PORT}"
|
||||
echo -e " Delete cluster: ${SCRIPT_DIR}/teardown-cluster.sh"
|
||||
echo ""
|
||||
39
tests_e2e/kubernetes/teardown-cluster.sh
Executable file
39
tests_e2e/kubernetes/teardown-cluster.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
CLUSTER_NAME="easyhaproxy-test"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BIN_DIR="${SCRIPT_DIR}/.kind"
|
||||
KIND_BIN="${BIN_DIR}/kind"
|
||||
|
||||
# Check if kind binary exists
|
||||
if [ ! -f "${KIND_BIN}" ]; then
|
||||
# Try to use system kind
|
||||
if command -v kind &> /dev/null; then
|
||||
KIND_BIN="kind"
|
||||
else
|
||||
echo -e "${RED}✗ kind binary not found. Cannot delete cluster.${NC}"
|
||||
echo " Cluster may not exist or kind is not installed."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if cluster exists
|
||||
if ! ${KIND_BIN} get clusters 2>/dev/null | grep -q "^${CLUSTER_NAME}$"; then
|
||||
echo -e "${BLUE}Cluster '${CLUSTER_NAME}' does not exist. Nothing to delete.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Deleting kind cluster '${CLUSTER_NAME}'...${NC}"
|
||||
|
||||
if ${KIND_BIN} delete cluster --name "${CLUSTER_NAME}"; then
|
||||
echo -e "${GREEN}✓ Cluster deleted successfully${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Failed to delete cluster${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue