Introduction
Setting up a Canonical Academy exam platform requires careful planning, robust infrastructure, and meticulous attention to security and performance. As an IT operations team, you’re tasked with deploying a system that not only validates technical skills but also maintains high availability, ensures data integrity, and provides a seamless experience for candidates worldwide.
This comprehensive guide walks you through every critical step—from initial infrastructure assessment through ongoing maintenance—to help you build a secure, scalable exam platform that meets industry standards and regulatory requirements.
Assess Your Infrastructure Requirements
Before deploying any infrastructure, you need a clear understanding of what your exam platform demands. This assessment phase determines whether your current resources are sufficient or if you need to invest in additional capacity.
Evaluate Server Capacity and Availability Needs
Start by estimating concurrent user load during peak exam times. Consider:
- Expected number of simultaneous exam takers during peak hours
- Geographic distribution of candidates (affects latency requirements)
- Exam duration and frequency (affects sustained load patterns)
- Growth projections for the next 12-24 months
For a mid-sized deployment, plan for at least 2-4 dedicated servers in a load-balanced configuration. Each server should have:
- CPU: 8+ cores (Intel Xeon or equivalent)
- RAM: 32GB minimum (64GB recommended)
- Storage: SSD-backed storage with RAID 1 or RAID 10 for redundancy
- Network: Gigabit or higher connectivity with redundant uplinks
High availability is non-negotiable. Design for N+1 redundancy, meaning if one server fails, the remaining infrastructure can handle full load.
Plan Your Database Architecture for User and Exam Data
Your database layer stores critical information: user credentials, exam questions, responses, scores, and analytics. This requires careful architectural planning.
Database considerations:
- PostgreSQL or MySQL for relational data (user profiles, exam results)
- Redis for session management and caching
- Elasticsearch for analytics and search functionality
Implement database replication across multiple nodes:
Primary Database (Write Operations)
↓
Replica 1 (Read Operations)
↓
Replica 2 (Backup/Failover)
Plan for:
- Automated backups every 4-6 hours
- Point-in-time recovery capability (minimum 30 days retention)
- Separate read replicas to distribute query load
- Connection pooling to manage concurrent database connections efficiently
Determine CDN Requirements for Global Access
A Content Delivery Network ensures exam materials, static assets, and API responses reach candidates quickly, regardless of geographic location.
CDN deployment strategy:
- Use a global CDN provider (Cloudflare, AWS CloudFront, Akamai)
- Cache static assets (CSS, JavaScript, images) with long TTLs
- Cache API responses selectively (exam metadata, not real-time data)
- Implement geographic routing to direct users to nearest edge servers
- Plan for 50-100ms latency targets globally
Identify Security Protocols and Compliance Obligations
Document all regulatory and security requirements:
- GDPR (if serving EU candidates)
- CCPA (if serving California residents)
- HIPAA (if exam data relates to healthcare)
- SOC 2 Type II compliance
- Industry-specific standards (ISO 27001, etc.)
Create a compliance matrix documenting:
- Data encryption requirements (at-rest and in-transit)
- Access control policies
- Audit logging requirements
- Data retention and deletion policies
- Incident response procedures
Design Your Platform Architecture
A well-designed architecture separates concerns, improves scalability, and simplifies maintenance. Your exam platform should follow a layered approach.
Build a Responsive Web Application Layer
The web application is candidates’ primary interface. It must be responsive, fast, and accessible.
Technology stack recommendations:
- Frontend Framework: React, Vue.js, or Angular for dynamic user interfaces
- Server-side Rendering: Next.js or Nuxt.js for improved performance and SEO
- Responsive Design: Mobile-first approach supporting tablets and desktops
- Accessibility: WCAG 2.1 AA compliance for users with disabilities
Key features to implement:
- User registration and profile management
- Exam scheduling and countdown timers
- Real-time question display with progress tracking
- Secure exam environment (prevent tab switching, disable copy/paste)
- Results dashboard with detailed performance analytics
Implement a Robust API Layer
The API layer enables third-party integrations and separates frontend from backend logic.
API architecture best practices:
- RESTful design with clear resource endpoints
- API versioning (v1, v2) for backward compatibility
- Rate limiting to prevent abuse (e.g., 100 requests/minute per user)
- OAuth 2.0 for secure third-party integrations
- API documentation using OpenAPI/Swagger
Critical API endpoints:
POST /api/v1/auth/login
POST /api/v1/auth/logout
GET /api/v1/exams
GET /api/v1/exams/{examId}
POST /api/v1/exams/{examId}/start
POST /api/v1/exams/{examId}/submit
GET /api/v1/results/{resultId}
Structure Your Database Layer for Performance
Database design directly impacts platform performance and scalability.
Schema design principles:
- Normalize user and exam data to reduce redundancy
- Denormalize selectively for frequently-accessed analytics
- Partition large tables by date or user ID for faster queries
- Index strategically on columns used in WHERE and JOIN clauses
Example table structure:
-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_email (email)
);
-- Exams table
CREATE TABLE exams (
id UUID PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
duration_minutes INT NOT NULL,
passing_score INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Exam results table
CREATE TABLE exam_results (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
exam_id UUID NOT NULL REFERENCES exams(id),
score INT NOT NULL,
passed BOOLEAN NOT NULL,
started_at TIMESTAMP NOT NULL,
completed_at TIMESTAMP NOT NULL,
INDEX idx_user_id (user_id),
INDEX idx_exam_id (exam_id),
INDEX idx_completed_at (completed_at)
);
Set Up Analytics Infrastructure for Exam Insights
Analytics provide visibility into exam effectiveness and candidate performance.
Analytics components:
- Event tracking: Capture user actions (login, question viewed, answer submitted)
- Data warehouse: Aggregate data for historical analysis
- Visualization: Dashboards showing pass rates, question difficulty, time-to-completion
- Real-time monitoring: Alert on anomalies (unusual failure rates, performance degradation)
Key metrics to track:
- Pass/fail rates by exam and demographic
- Average time per question
- Question difficulty and discrimination indices
- Platform uptime and response times
- User engagement and completion rates
Install and Configure Core Components
With requirements assessed and architecture designed, you’re ready to deploy infrastructure and configure the platform.
Deploy Server Infrastructure with Redundancy
Step 1: Provision servers
Deploy at least 3 application servers in a load-balanced configuration:
Load Balancer (HAProxy or NGINX)
├── App Server 1 (Primary)
├── App Server 2 (Secondary)
└── App Server 3 (Tertiary)
Step 2: Configure load balancing
Use NGINX or HAProxy to distribute traffic:
upstream exam_platform {
server app1.internal:8080 weight=1;
server app2.internal:8080 weight=1;
server app3.internal:8080 weight=1;
# Health check
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r
\r
";
check_http_expect_alive http_2xx;
}
server {
listen 443 ssl http2;
server_name exams.canonical.com;
ssl_certificate /etc/ssl/certs/exam_platform.crt;
ssl_certificate_key /etc/ssl/private/exam_platform.key;
location / {
proxy_pass http://exam_platform;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Step 3: Configure database replication
For PostgreSQL, set up streaming replication:
# On primary server
sudo -u postgres psql -c "ALTER SYSTEM SET wal_level = replica;"
sudo -u postgres psql -c "ALTER SYSTEM SET max_wal_senders = 3;"
sudo -u postgres psql -c "ALTER SYSTEM SET max_replication_slots = 3;"
# Restart PostgreSQL
sudo systemctl restart postgresql
# Create replication user
sudo -u postgres psql -c "CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'secure_password';"
# On replica server
sudo -u postgres pg_basebackup -h primary.internal -D /var/lib/postgresql/13/main -U replicator -v -P -W
# Configure recovery
echo "standby_mode = 'on'" | sudo tee -a /var/lib/postgresql/13/main/recovery.conf
echo "primary_conninfo = 'host=primary.internal port=5432 user=replicator password=secure_password'" | sudo tee -a /var/lib/postgresql/13/main/recovery.conf
sudo systemctl restart postgresql
Configure User Authentication and Identity Management
Implement secure authentication using industry-standard protocols.
Option 1: LDAP/Active Directory Integration
For enterprise environments, integrate with existing directory services:
# Install LDAP authentication module
sudo apt-get install libpam-ldapd
# Configure LDAP
sudo nano /etc/nslcd.conf
# Add:
# uri ldap://ldap.canonical.internal
# base dc=canonical,dc=com
# binddn cn=admin,dc=canonical,dc=com
# bindpw admin_password
sudo systemctl restart nslcd
Option 2: OAuth 2.0 / OpenID Connect
For modern applications, use OAuth 2.0:
# Python example using Flask and python-oauth2
from flask import Flask, redirect, url_for
from authlib.integrations.flask_client import OAuth
app = Flask(__name__)
oauth = OAuth(app)
google = oauth.register(
name='google',
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={'scope': 'openid email profile'}
)
@app.route('/login')
def login():
redirect_uri = url_for('authorize', _external=True)
return google.authorize_redirect(redirect_uri)
@app.route('/authorize')
def authorize():
token = google.authorize_access_token()
user = token.get('userinfo')
# Store user in database
return redirect('/dashboard')
Option 3: Multi-Factor Authentication (MFA)
Enhance security with MFA:
# Using pyotp for TOTP (Time-based One-Time Password)
import pyotp
import qrcode
def setup_mfa(user_id):
secret = pyotp.random_base32()
totp = pyotp.TOTP(secret)
# Generate QR code
qr = qrcode.QRCode()
qr.add_data(totp.provisioning_uri(name=user_id, issuer_name='Canonical Academy'))
qr.make()
# Store secret in database
store_mfa_secret(user_id, secret)
return qr
def verify_mfa(user_id, token):
secret = get_mfa_secret(user_id)
totp = pyotp.TOTP(secret)
return totp.verify(token)
Set Exam Parameters and Scoring Rules
Configure exam-specific settings in your platform:
# Exam configuration model
class ExamConfig:
def __init__(self, exam_id):
self.exam_id = exam_id
self.duration_minutes = 120
self.total_questions = 50
self.passing_score = 70 # percentage
self.question_randomization = True
self.show_results_immediately = False
self.allow_review = True
self.allow_retakes = True
self.retake_wait_days = 7
self.negative_marking = False
self.marks_per_question = 2
def calculate_score(self, correct_answers, total_questions):
"""Calculate percentage score"""
return (correct_answers / total_questions) * 100
def determine_pass_fail(self, score):
"""Determine if candidate passed"""
return score >= self.passing_score
def get_certificate_eligible(self, score):
"""Determine if candidate qualifies for certificate"""
return score >= 80 # Higher threshold for certificates
Enable Accessibility Features for All Candidates
Ensure your platform is usable by everyone, including people with disabilities.
WCAG 2.1 AA compliance checklist:
- Color contrast: Minimum 4.5:1 for normal text, 3:1 for large text
- Keyboard navigation: All functionality accessible via keyboard
- Screen reader support: Proper semantic HTML and ARIA labels
- Text alternatives: Alt text for all images
- Captions and transcripts: For any video content
- Adjustable text size: Support for browser zoom and text scaling
- Focus indicators: Clear visual indication of keyboard focus
Implementation example:
<!-- Proper semantic HTML -->
<form aria-label="Exam question form">
<fieldset>
<legend>Question 1: What is the capital of France?</legend>
<div class="question-options">
<label>
<input type="radio" name="q1" value="paris" aria-describedby="q1-help">
Paris
</label>
<label>
<input type="radio" name="q1" value="london">
London
</label>
<label>
<input type="radio" name="q1" value="berlin">
Berlin
</label>
</div>
<p id="q1-help" class="help-text">Select the correct answer</p>
</fieldset>
<button type="submit" aria-label="Submit answer and move to next question">
Next Question
</button>
</form>
<style>
/* Ensure sufficient color contrast */
body {
color: #212121; /* Dark gray on white = 18:1 contrast */
background-color: #ffffff;
}
/* Clear focus indicators */
button:focus,
input:focus {
outline: 3px solid #4A90E2;
outline-offset: 2px;
}
</style>
Implement Security and Compliance
Security is paramount for an exam platform. Candidates trust you with their personal data and exam integrity depends on robust security controls.

Deploy SSL Certificates and Encryption Protocols
Step 1: Obtain SSL certificates
Use Let’s Encrypt for free, auto-renewing certificates:
# Install Certbot
sudo apt-get install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot certonly --nginx -d exams.canonical.com -d www.exams.canonical.com
# Auto-renewal
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
Step 2: Configure TLS 1.2+ only
# /etc/nginx/nginx.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Step 3: Encrypt data at rest
For sensitive data in databases:
from cryptography.fernet import Fernet
import os
# Generate encryption key (store securely in environment variables)
encryption_key = os.environ.get('ENCRYPTION_KEY')
cipher = Fernet(encryption_key)
def encrypt_sensitive_data(data):
"""Encrypt PII before storing in database"""
return cipher.encrypt(data.encode()).decode()
def decrypt_sensitive_data(encrypted_data):
"""Decrypt PII when needed"""
return cipher.decrypt(encrypted_data.encode()).decode()
# Usage
encrypted_ssn = encrypt_sensitive_data("123-45-6789")
# Store encrypted_ssn in database
Configure Firewalls and Intrusion Detection Systems
Step 1: Set up UFW (Uncomplicated Firewall)
# Enable UFW
sudo ufw enable
# Allow SSH (with rate limiting)
sudo ufw limit 22/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow database replication (internal only)
sudo ufw allow from 10.0.0.0/8 to any port 5432
# Deny all other inbound traffic
sudo ufw default deny incoming
sudo ufw default allow outgoing
Step 2: Deploy Intrusion Detection System (IDS)
# Install Suricata IDS
sudo apt-get install suricata
# Configure Suricata
sudo nano /etc/suricata/suricata.yaml
# Key settings:
# - home-net: "[192.168.1.0/24,10.0.0.0/8]"
# - external-net: "!$HOME_NET"
# - threat-detection rules enabled
# Start Suricata
sudo systemctl start suricata
sudo systemctl enable suricata
# Monitor alerts
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'
Step 3: Implement Web Application Firewall (WAF)
# Using ModSecurity with NGINX
# Install ModSecurity
sudo apt-get install libnginx-mod-http-modsecurity
# Configure ModSecurity rules
sudo nano /etc/nginx/modsecurity/modsecurity.conf
# Set: SecRuleEngine On
# Add OWASP Core Rule Set
sudo git clone https://github.com/coreruleset/coreruleset /etc/nginx/modsecurity/crs
sudo mv /etc/nginx/modsecurity/crs/crs-setup.conf.example /etc/nginx/modsecurity/crs/crs-setup.conf
# Enable in NGINX
# modsecurity on;
# modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
Establish Data Protection and Privacy Controls
Step 1: Implement role-based access control (RBAC)
from enum import Enum
class UserRole(Enum):
CANDIDATE = "candidate"
PROCTOR = "proctor"
ADMIN = "admin"
AUDITOR = "auditor"
class Permission(Enum):
VIEW_OWN_RESULTS = "view_own_results"
VIEW_ALL_RESULTS = "view_all_results"
MANAGE_EXAMS = "manage_exams"
MANAGE_USERS = "manage_users"
VIEW_AUDIT_LOGS = "view_audit_logs"
# Role-permission mapping
ROLE_PERMISSIONS = {
UserRole.CANDIDATE: [Permission.VIEW_OWN_RESULTS],
UserRole.PROCTOR: [Permission.VIEW_ALL_RESULTS],
UserRole.ADMIN: [Permission.MANAGE_EXAMS, Permission.MANAGE_USERS],
UserRole.AUDITOR: [Permission.VIEW_AUDIT_LOGS]
}
def check_permission(user_role, required_permission):
"""Verify user has required permission"""
return required_permission in ROLE_PERMISSIONS.get(user_role, [])
# Usage in API
@app.route('/api/v1/results')
def get_results():
user = get_current_user()
if not check_permission(user.role, Permission.VIEW_ALL_RESULTS):
return {"error": "Unauthorized"}, 403
return get_all_results()
Step 2: Implement data retention policies
from datetime import datetime, timedelta
import schedule
def delete_old_exam_data():
"""Delete exam data older than retention period"""
retention_days = 365 # 1 year
cutoff_date = datetime.now() - timedelta(days=retention_days)
# Delete old results (but keep aggregate statistics)
ExamResult.query.filter(ExamResult.completed_at < cutoff_date).delete()
# Delete old user activity logs
ActivityLog.query.filter(ActivityLog.timestamp < cutoff_date).delete()
db.session.commit()
logger.info(f"Deleted exam data older than {cutoff_date}")
# Schedule daily at 2 AM
schedule.every().day.at("02:00").do(delete_old_exam_data)
Step 3: Implement audit logging
from datetime import datetime
import json
class AuditLog:
def __init__(self, user_id, action, resource, details):
self.user_id = user_id
self.action = action # CREATE, READ, UPDATE, DELETE
self.resource = resource # exam, result, user
self.details = details
self.timestamp = datetime.utcnow()
self.ip_address = request.remote_addr
def log(self):
"""Store audit log in database"""
log_entry = {
'user_id': self.user_id,
'action': self.action,
'resource': self.resource,
'details': json.dumps(self.details),
'timestamp': self.timestamp,
'ip_address': self.ip_address
}
AuditLogEntry.create(**log_entry)
# Usage
def update_exam_score(exam_id, new_score):
old_score = get_exam_score(exam_id)
# Update score
update_database(exam_id, new_score)
# Log the change
audit = AuditLog(
user_id=current_user.id,
action='UPDATE',
resource='exam_result',
details={'exam_id': exam_id, 'old_score': old_score, 'new_score': new_score}
)
audit.log()
Document Compliance with GDPR and Industry Standards
Step 1: Create data processing agreement (DPA)
Document how you handle personal data:
# Data Processing Agreement
## Data Controller
Canonical Academy
## Data Processor
[Your Organization]
## Personal Data Processed
- Name, email, phone number
- Exam responses and scores
- IP addresses and device information
- Login timestamps
## Processing Purpose
- Exam administration and scoring
- Performance analytics
- Compliance and audit
## Data Retention
- Exam results: 3 years
- User activity logs: 1 year
- Personal data: Until account deletion + 30 days
## Security Measures
- AES-256 encryption at rest
- TLS 1.2+ encryption in transit
- Role-based access control
- Regular security audits
- Incident response procedures
Step 2: Implement GDPR compliance features
# Right to access
@app.route('/api/v1/users/<user_id>/data-export', methods=['GET'])
def export_user_data(user_id):
"""Export all personal data for a user (GDPR Article 15)"""
if not user_owns_data(user_id):
return {"error": "Unauthorized"}, 403
user_data = {
'profile': get_user_profile(user_id),
'exam_results': get_user_exam_results(user_id),
'activity_logs': get_user_activity_logs(user_id)
}
return jsonify(user_data)
# Right to be forgotten
@app.route('/api/v1/users/<user_id>', methods=['DELETE'])
def delete_user_account(user_id):
"""Delete user account and associated data (GDPR Article 17)"""
if not user_owns_data(user_id):
return {"error": "Unauthorized"}, 403
# Anonymize instead of delete (for audit trail)
anonymize_user_data(user_id)
return {"message": "Account deleted successfully"}, 200
# Consent management
class ConsentManager:
def __init__(self, user_id):
self.user_id = user_id
def get_consent_status(self):
"""Get user's consent preferences"""
return {
'marketing_emails': get_consent(self.user_id, 'marketing'),
'analytics': get_consent(self.user_id, 'analytics'),
'third_party_sharing': get_consent(self.user_id, 'third_party')
}
def update_consent(self, consent_type, value):
"""Update user consent"""
store_consent(self.user_id, consent_type, value)
log_consent_change(self.user_id, consent_type, value)
Establish Monitoring and Maintenance Protocols
Proactive monitoring and maintenance prevent issues before they impact candidates.
Set Up Performance Monitoring Tools
Step 1: Deploy Prometheus for metrics collection
# Install Prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.40.0/prometheus-2.40.0.linux-amd64.tar.gz
tar xvfz prometheus-2.40.0.linux-amd64.tar.gz
sudo mv prometheus-2.40.0.linux-amd64 /opt/prometheus
# Configure Prometheus
sudo nano /opt/prometheus/prometheus.yml
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'exam-platform'
static_configs:
- targets: ['localhost:9090']
- job_name: 'app-servers'
static_configs:
- targets: ['app1.internal:9100', 'app2.internal:9100', 'app3.internal:9100']
- job_name: 'database'
static_configs:
- targets: ['db.internal:9187']
- job_name: 'nginx'
static_configs:
- targets: ['lb.internal:9113']
Step 2: Deploy Grafana for visualization
# Install Grafana
sudo apt-get install grafana-server
# Start Grafana
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
# Access at http://localhost:3000 (default: admin/admin)
Step 3: Create monitoring dashboards
Key metrics to monitor:
-
Application Performance
-
Request latency (p50, p95, p99)
-
Error rate (5xx responses)
-
Throughput (requests/second)
-
Active connections
-
Database Performance
-
Query latency
-
Slow queries (>1 second)
-
Connection pool utilization
-
Replication lag
-
Infrastructure
-
CPU utilization
-
Memory usage
-
Disk I/O
-
Network bandwidth
-
Business Metrics
-
Exams started/completed
-
Pass rate
-
Average score
-
Candidate satisfaction
Configure User Activity and Security Logging
Step 1: Implement centralized logging with ELK Stack
# Install Elasticsearch
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.5.0-linux-x86_64.tar.gz
tar xvfz elasticsearch-8.5.0-linux-x86_64.tar.gz
sudo mv elasticsearch-8.5.0 /opt/elasticsearch
# Install Logstash
wget https://artifacts.elastic.co/downloads/logstash/logstash-8.5.0-linux-x86_64.tar.gz
tar xvfz logstash-8.5.0-linux-x86_64.tar.gz
sudo mv logstash-8.5.0 /opt/logstash
# Install Kibana
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.5.0-linux-x86_64.tar.gz
tar xvfz kibana-8.5.0-linux-x86_64.tar.gz
sudo mv kibana-8.5.0 /opt/kibana
Step 2: Configure Logstash to collect logs
# /opt/logstash/config/logstash.conf
input {
file {
path => "/var/log/exam-platform/app.log"
start_position => "beginning"
codec => json
}
file {
path => "/var/log/nginx/access.log"
start_position => "beginning"
}
file {
path => "/var/log/suricata/eve.json"
start_position => "beginning"
codec => json
}
}
filter {
if [type] == "app" {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{DATA:logger} %{GREEDYDATA:message}" }
}
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "exam-platform-%{+YYYY.MM.dd}"
}
}
Step 3: Create security alerts
# Alert on suspicious activities
SECURITY_ALERTS = {
'multiple_failed_logins': {
'condition': 'failed_login_count > 5 in 15 minutes',
'action': 'lock_account_temporarily'
},
'unusual_access_pattern': {
'condition': 'access_from_multiple_countries in 1 hour',
'action': 'require_mfa_verification'
},
'data_exfiltration': {
'condition': 'large_data_download > 100MB',
'action': 'alert_security_team'
},
'privilege_escalation': {
'condition': 'user_role_change_without_approval',
'action': 'alert_admin'
}
}
Plan Regular Backup and Disaster Recovery Procedures
Step 1: Implement automated backups
“`bash
!/bin/bash
/usr/local/bin/backup-exam-platform.sh
BACKUPDIR=”/mnt/backups”
RETENTIONDAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
Backup database
echo “Backing up PostgreSQL database…”
sudo -u postgres pgdump examplatform | gzip > $BACKUPDIR/dbbackup_$DATE.sql.gz