Configure Envoy proxy with JWT authentication filters integrated with Keycloak OAuth2 provider for secure microservices communication and advanced rate limiting policies.
Prerequisites
- Root or sudo access
- Minimum 2GB RAM
- Open ports 8000, 8080, 9901
- Basic understanding of OAuth2 and JWT
What this solves
This tutorial implements JWT authentication for Envoy proxy using OAuth2 integration with Keycloak as the identity provider. You'll configure authentication filters, security policies, and rate limiting to secure your microservices architecture with token-based authentication.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg2 software-properties-common
Install Envoy proxy
Download and install the latest Envoy proxy release with official repository setup.
curl -sL 'https://deb.dl.getenvoy.io/public/gpg.8115BA8E629CC074.key' | sudo gpg --dearmor -o /usr/share/keyrings/getenvoy-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/getenvoy-keyring.gpg] https://deb.dl.getenvoy.io/public/deb/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/getenvoy.list
sudo apt update
sudo apt install -y getenvoy-envoy
Install and configure Keycloak OAuth2 provider
Set up Keycloak as the OAuth2 identity provider for JWT token generation and validation.
cd /opt
sudo wget https://github.com/keycloak/keycloak/releases/download/23.0.3/keycloak-23.0.3.tar.gz
sudo tar -xzf keycloak-23.0.3.tar.gz
sudo mv keycloak-23.0.3 keycloak
sudo chown -R keycloak:keycloak /opt/keycloak
sudo useradd -r -s /bin/false keycloak
Configure Keycloak service
Create systemd service file for Keycloak with production configuration.
[Unit]
Description=Keycloak OAuth2 Provider
After=network.target
[Service]
Type=exec
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/bin/kc.sh start-dev --http-host=0.0.0.0 --http-port=8080
Restart=on-failure
RestartSec=5
Environment=KEYCLOAK_ADMIN=admin
Environment=KEYCLOAK_ADMIN_PASSWORD=SecurePassword123!
WorkingDirectory=/opt/keycloak
[Install]
WantedBy=multi-user.target
Start Keycloak service
Enable and start the Keycloak service to begin OAuth2 provider setup.
sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
sudo systemctl status keycloak
Configure Keycloak realm and client
Create a realm and OAuth2 client for JWT token management. Access Keycloak admin console at http://your-server:8080.
# Create realm configuration
sudo mkdir -p /opt/keycloak/data/import
sudo tee /opt/keycloak/data/import/envoy-realm.json > /dev/null << 'EOF'
{
"realm": "envoy-auth",
"enabled": true,
"clients": [
{
"clientId": "envoy-client",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"clientAuthenticatorType": "client-secret",
"secret": "envoy-client-secret-123",
"redirectUris": ["*"],
"webOrigins": ["*"]
}
],
"users": [
{
"username": "testuser",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "TestPassword123!"
}
]
}
]
}
EOF
Create Envoy configuration directory
Set up directory structure for Envoy configuration files and certificates.
sudo mkdir -p /etc/envoy
sudo mkdir -p /etc/envoy/certs
sudo mkdir -p /var/log/envoy
sudo useradd -r -s /bin/false envoy
sudo chown -R envoy:envoy /var/log/envoy
Configure Envoy with JWT authentication
Create the main Envoy configuration with JWT authentication filters and OAuth2 integration.
admin:
address:
socket_address:
protocol: TCP
address: 127.0.0.1
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 8000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
keycloak_provider:
issuer: http://localhost:8080/realms/envoy-auth
audiences:
- envoy-client
remote_jwks:
http_uri:
uri: http://localhost:8080/realms/envoy-auth/protocol/openid-connect/certs
cluster: keycloak_cluster
timeout: 5s
cache_duration:
seconds: 300
payload_in_metadata: jwt_payload
rules:
- match:
prefix: /
requires:
provider_name: keycloak_provider
- name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 100
tokens_per_fill: 100
fill_interval: 60s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value:
numerator: 100
denominator: HUNDRED
response_headers_to_add:
- append: false
header:
key: x-local-rate-limit
value: 'true'
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: backend_service
clusters:
- name: backend_service
connect_timeout: 30s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 3000
health_checks:
- timeout: 1s
interval: 10s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: "/health"
- name: keycloak_cluster
connect_timeout: 5s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: keycloak_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
Configure advanced security policies
Add additional security filters for enhanced protection including CORS and security headers.
# Additional HTTP filters for security
security_filters:
cors_filter:
name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
security_headers_filter:
name: envoy.filters.http.local_reply
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.local_reply.v3.LocalReply
mappers:
- filter:
status_code_filter:
comparison:
op: EQ
value:
default_value: 200
runtime_key: unused_key
headers_to_add:
- header:
key: "X-Frame-Options"
value: "DENY"
append: false
- header:
key: "X-Content-Type-Options"
value: "nosniff"
append: false
- header:
key: "X-XSS-Protection"
value: "1; mode=block"
append: false
Create Envoy systemd service
Configure systemd service for Envoy proxy with proper user permissions and resource limits.
[Unit]
Description=Envoy Proxy
After=network.target
Wants=network.target
[Service]
Type=simple
User=envoy
Group=envoy
ExecStart=/usr/bin/envoy -c /etc/envoy/envoy.yaml --service-cluster envoy-proxy --service-node envoy-node-1
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
Set proper file permissions
Configure correct ownership and permissions for Envoy configuration files and directories.
sudo chown -R envoy:envoy /etc/envoy
sudo chmod 755 /etc/envoy
sudo chmod 644 /etc/envoy/envoy.yaml
sudo chmod 644 /etc/envoy/security-config.yaml
sudo chown -R envoy:envoy /var/log/envoy
sudo chmod 755 /var/log/envoy
Create sample backend service
Set up a simple Node.js backend service to test JWT authentication integration.
sudo mkdir -p /opt/backend
sudo tee /opt/backend/server.js > /dev/null << 'EOF'
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
res.setHeader('Content-Type', 'application/json');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
if (parsedUrl.pathname === '/health') {
res.writeHead(200);
res.end(JSON.stringify({status: 'healthy', timestamp: new Date().toISOString()}));
} else if (parsedUrl.pathname === '/api/protected') {
res.writeHead(200);
res.end(JSON.stringify({
message: 'Access granted - JWT authentication successful',
user: req.headers['x-envoy-jwt-payload'] || 'No JWT payload',
timestamp: new Date().toISOString()
}));
} else {
res.writeHead(404);
res.end(JSON.stringify({error: 'Not found'}));
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Backend service listening on 127.0.0.1:3000');
});
EOF
Install Node.js and start backend service
Install Node.js and create systemd service for the backend application.
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
sudo useradd -r -s /bin/false backend
sudo chown -R backend:backend /opt/backend
Create backend service systemd unit
Configure systemd service for the backend application with proper resource limits.
[Unit]
Description=Backend Service for Envoy JWT Testing
After=network.target
[Service]
Type=simple
User=backend
Group=backend
WorkingDirectory=/opt/backend
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Configure firewall rules
Open required ports for Envoy, Keycloak, and backend services with specific security rules.
sudo ufw allow 8000/tcp comment 'Envoy proxy'
sudo ufw allow 8080/tcp comment 'Keycloak OAuth2'
sudo ufw allow 9901/tcp comment 'Envoy admin'
sudo ufw --force enable
Start all services
Enable and start Envoy proxy, Keycloak, and backend services in the correct order.
sudo systemctl daemon-reload
sudo systemctl enable --now backend
sudo systemctl enable --now envoy
sudo systemctl status keycloak envoy backend
Configure OAuth2 client credentials
Obtain OAuth2 access token
Test OAuth2 token generation using Keycloak's token endpoint with client credentials flow.
curl -X POST \
http://localhost:8080/realms/envoy-auth/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password' \
-d 'client_id=envoy-client' \
-d 'client_secret=envoy-client-secret-123' \
-d 'username=testuser' \
-d 'password=TestPassword123!' | jq .
Create token extraction script
Create a helper script to extract and use JWT tokens for API testing.
#!/bin/bash
Extract JWT token from Keycloak
TOKEN_RESPONSE=$(curl -s -X POST \
http://localhost:8080/realms/envoy-auth/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password' \
-d 'client_id=envoy-client' \
-d 'client_secret=envoy-client-secret-123' \
-d 'username=testuser' \
-d 'password=TestPassword123!')
if [ $? -eq 0 ]; then
ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.access_token')
if [ "$ACCESS_TOKEN" != "null" ]; then
echo "Bearer $ACCESS_TOKEN"
else
echo "Error: Could not extract access token"
echo $TOKEN_RESPONSE | jq .
exit 1
fi
else
echo "Error: Failed to get token from Keycloak"
exit 1
fi
sudo chmod 755 /usr/local/bin/get-jwt-token
Verify your setup
Test the complete JWT authentication flow with OAuth2 integration.
# Check all services are running
sudo systemctl status keycloak envoy backend
Test Keycloak OAuth2 endpoint
curl -s http://localhost:8080/realms/envoy-auth/.well-known/openid-configuration | jq .
Test without authentication (should fail)
curl -v http://localhost:8000/api/protected
Get JWT token and test authenticated request
JWT_TOKEN=$(get-jwt-token)
echo "Using token: ${JWT_TOKEN:0:50}..."
Test with valid JWT token
curl -H "Authorization: $JWT_TOKEN" \
-v http://localhost:8000/api/protected
Check Envoy admin interface
curl -s http://localhost:9901/stats | grep jwt
Test rate limiting
for i in {1..10}; do
curl -H "Authorization: $JWT_TOKEN" \
-s -o /dev/null -w "%{http_code}\n" \
http://localhost:8000/api/protected
sleep 0.1
done
Advanced rate limiting configuration
Configure global rate limiting
Add Redis-backed global rate limiting for distributed environments. First install Redis.
sudo apt install -y redis-server
sudo systemctl enable --now redis-server
Update Envoy configuration for global rate limiting
Add global rate limiting configuration to work alongside JWT authentication. For more advanced Envoy configurations, see our Envoy gRPC load balancing tutorial.
# Global rate limiting configuration
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: rate_limit_cluster
timeout: 0.25s
Add to clusters section in main envoy.yaml
rate_limit_cluster:
name: rate_limit_cluster
connect_timeout: 1s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
protocol_selection: USE_CONFIGURED_PROTOCOL
http2_protocol_options: {}
load_assignment:
cluster_name: rate_limit_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8081
Security policy enforcement
Configure JWT validation policies
Add strict JWT validation rules including audience, issuer, and expiry checks.
# Enhanced JWT validation policies
jwt_validation_rules:
- name: strict_validation
requirements:
- provider_name: keycloak_provider
audiences: ["envoy-client"]
requirement_type: REQUIRES_ANY
match_conditions:
- name: "api_routes"
prefix: "/api/"
- name: "admin_routes"
prefix: "/admin/"
additional_requirements:
- custom_claim: "realm_access.roles"
values: ["admin", "super-admin"]
Token refresh validation
token_validation:
max_age_seconds: 3600
clock_skew_seconds: 30
verify_audience: true
verify_issuer: true
require_expiry: true
Implement request logging and monitoring
Configure comprehensive logging for JWT authentication events and security monitoring.
# Access logging configuration for JWT events
access_log_config:
- name: jwt_access_log
filter:
status_code_filter:
comparison:
op: GE
value:
default_value: 400
format: |
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"
%RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT%
%DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%
JWT_SUBJECT:"%REQ(X-JWT-SUBJECT)%" JWT_ISSUER:"%REQ(X-JWT-ISSUER)%"
REMOTE_ADDR:"%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
USER_AGENT:"%REQ(USER-AGENT)%"
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/jwt-access.log"
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Envoy fails to start | Configuration syntax error | envoy --mode validate -c /etc/envoy/envoy.yaml |
| JWT validation fails | JWKS endpoint unreachable | Check curl http://localhost:8080/realms/envoy-auth/protocol/openid-connect/certs |
| 401 Unauthorized responses | Invalid client secret or token expired | Regenerate token with get-jwt-token script |
| Rate limiting not working | Missing rate limit configuration | Check Envoy stats: curl localhost:9901/stats | grep rate_limit |
| Keycloak connection refused | Service not started or port blocked | sudo systemctl restart keycloak && sudo netstat -tlpn | grep 8080 |
| Backend service unreachable | Upstream cluster misconfigured | Check curl localhost:3000/health and Envoy cluster stats |
Next steps
- Scale Keycloak with high availability clustering
- Add mutual TLS with Vault PKI integration
- Monitor Envoy with Prometheus and Grafana dashboards
- Integrate Envoy with ModSecurity web application firewall
- Set up external authorization service for advanced policies
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
KEYCLOAK_VERSION="23.0.3"
KEYCLOAK_ADMIN_PASSWORD="${KEYCLOAK_ADMIN_PASSWORD:-SecurePassword123!}"
DOMAIN="${1:-localhost}"
# Usage
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
echo "Usage: $0 [domain]"
echo "Example: $0 example.com"
exit 0
fi
# Error handler
cleanup() {
echo -e "${RED}Installation failed. Cleaning up...${NC}"
systemctl stop envoy keycloak 2>/dev/null || true
systemctl disable envoy keycloak 2>/dev/null || true
}
trap cleanup ERR
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root${NC}"
exit 1
fi
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
;;
*)
echo -e "${RED}Unsupported distro: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Cannot detect OS distribution${NC}"
exit 1
fi
echo -e "${GREEN}Installing Envoy JWT Auth with OAuth2 on $PRETTY_NAME${NC}"
# Step 1: Update system
echo -e "${YELLOW}[1/8] Updating system packages...${NC}"
$PKG_UPDATE
$PKG_INSTALL curl wget gnupg2 software-properties-common tar nodejs npm
# Step 2: Install Envoy
echo -e "${YELLOW}[2/8] Installing Envoy proxy...${NC}"
if [[ "$PKG_MGR" == "apt" ]]; then
curl -sL 'https://deb.dl.getenvoy.io/public/gpg.8115BA8E629CC074.key' | gpg --dearmor -o /usr/share/keyrings/getenvoy-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/getenvoy-keyring.gpg] https://deb.dl.getenvoy.io/public/deb/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/getenvoy.list
apt update
$PKG_INSTALL getenvoy-envoy
else
curl -sL 'https://rpm.dl.getenvoy.io/public/gpg.CF716AF503183491.key' | rpm --import -
curl -sL 'https://rpm.dl.getenvoy.io/public/config.rpm.txt' > /etc/yum.repos.d/getenvoy-rpm-stable.repo
$PKG_INSTALL getenvoy-envoy
fi
# Step 3: Create users
echo -e "${YELLOW}[3/8] Creating service users...${NC}"
useradd -r -s /bin/false keycloak 2>/dev/null || true
useradd -r -s /bin/false envoy 2>/dev/null || true
# Step 4: Install Keycloak
echo -e "${YELLOW}[4/8] Installing Keycloak...${NC}"
cd /opt
wget -q https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz
tar -xzf keycloak-${KEYCLOAK_VERSION}.tar.gz
mv keycloak-${KEYCLOAK_VERSION} keycloak
chown -R keycloak:keycloak /opt/keycloak
rm keycloak-${KEYCLOAK_VERSION}.tar.gz
# Step 5: Configure Keycloak
echo -e "${YELLOW}[5/8] Configuring Keycloak...${NC}"
cat > /etc/systemd/system/keycloak.service << 'EOF'
[Unit]
Description=Keycloak OAuth2 Provider
After=network.target
[Service]
Type=exec
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/bin/kc.sh start-dev --http-host=0.0.0.0 --http-port=8080
Restart=on-failure
RestartSec=5
Environment=KEYCLOAK_ADMIN=admin
Environment=KEYCLOAK_ADMIN_PASSWORD=SecurePassword123!
WorkingDirectory=/opt/keycloak
[Install]
WantedBy=multi-user.target
EOF
# Step 6: Create Envoy configuration
echo -e "${YELLOW}[6/8] Configuring Envoy...${NC}"
mkdir -p /etc/envoy
cat > /etc/envoy/envoy.yaml << 'EOF'
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: backend_service }
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
keycloak_provider:
issuer: http://localhost:8080/realms/envoy-realm
audiences:
- envoy-client
remote_jwks:
http_uri:
uri: http://localhost:8080/realms/envoy-realm/protocol/openid_connect/certs
cluster: keycloak_cluster
timeout: 5s
rules:
- match: { prefix: "/api/" }
requires:
provider_name: keycloak_provider
- name: envoy.filters.http.router
clusters:
- name: backend_service
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: backend_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 3000
- name: keycloak_cluster
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: keycloak_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
EOF
chown envoy:envoy /etc/envoy/envoy.yaml
chmod 644 /etc/envoy/envoy.yaml
# Step 7: Create backend service
echo -e "${YELLOW}[7/8] Setting up backend service...${NC}"
mkdir -p /opt/backend
cat > /opt/backend/server.js << 'EOF'
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
res.setHeader('Content-Type', 'application/json');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
if (parsedUrl.pathname === '/health') {
res.writeHead(200);
res.end(JSON.stringify({status: 'healthy', timestamp: new Date().toISOString()}));
} else if (parsedUrl.pathname === '/api/protected') {
res.writeHead(200);
res.end(JSON.stringify({
message: 'Access granted - JWT authentication successful',
user: req.headers['x-envoy-jwt-payload'] || 'No JWT payload',
timestamp: new Date().toISOString()
}));
} else {
res.writeHead(404);
res.end(JSON.stringify({error: 'Not found'}));
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Backend service listening on 127.0.0.1:3000');
});
EOF
chown -R nobody:nobody /opt/backend
# Create systemd services
cat > /etc/systemd/system/envoy.service << 'EOF'
[Unit]
Description=Envoy Proxy
After=network.target
[Service]
Type=exec
User=envoy
Group=envoy
ExecStart=/usr/bin/envoy -c /etc/envoy/envoy.yaml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/backend.service << 'EOF'
[Unit]
Description=Backend API Service
After=network.target
[Service]
Type=exec
User=nobody
Group=nobody
ExecStart=/usr/bin/node /opt/backend/server.js
Restart=on-failure
RestartSec=5
WorkingDirectory=/opt/backend
[Install]
WantedBy=multi-user.target
EOF
# Step 8: Start services
echo -e "${YELLOW}[8/8] Starting services...${NC}"
systemctl daemon-reload
systemctl enable --now keycloak
systemctl enable --now backend
sleep 10
systemctl enable --now envoy
# Wait for services
echo -e "${YELLOW}Waiting for services to start...${NC}"
sleep 15
# Verification
echo -e "${YELLOW}Verifying installation...${NC}"
if systemctl is-active --quiet keycloak && systemctl is-active --quiet envoy && systemctl is-active --quiet backend; then
echo -e "${GREEN}✓ All services are running${NC}"
else
echo -e "${RED}✗ Some services failed to start${NC}"
exit 1
fi
# Test connectivity
if curl -s http://localhost:3000/health > /dev/null; then
echo -e "${GREEN}✓ Backend service responding${NC}"
else
echo -e "${RED}✗ Backend service not responding${NC}"
fi
if curl -s http://localhost:8080 > /dev/null; then
echo -e "${GREEN}✓ Keycloak responding${NC}"
else
echo -e "${RED}✗ Keycloak not responding${NC}"
fi
echo -e "${GREEN}Installation completed successfully!${NC}"
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Access Keycloak admin console: http://$DOMAIN:8080"
echo "2. Login with admin/SecurePassword123!"
echo "3. Create 'envoy-realm' realm and 'envoy-client' client"
echo "4. Test protected endpoint: curl http://$DOMAIN:10000/api/protected"
Review the script before running. Execute with: bash install.sh