Security Architecture
Security Architecture Document
Project: {{PROJECT_NAME}}
Version: {{VERSION}}
Date: {{DATE}}
Author: {{AUTHOR}}
Status: Draft | In Review | Approved
Reviewers: {{REVIEWERS}}
Classification: Confidential
Document History
| Version |
Date |
Author |
Changes |
| 0.1 |
{{DATE}} |
{{AUTHOR}} |
Initial draft |
1. Security Architecture Overview
Security Owner: {{SECURITY_OWNER_ROLE}} ({{CONTACT_EMAIL}})
Last Security Review: {{DATE}}
Next Scheduled Review: {{DATE}}
Compliance Targets: GDPR | PCI-DSS | SOC2 Type II | ISO 27001 | HIPAA | {{OTHER}}
Defense-in-Depth Overview
flowchart TB
subgraph Perimeter["Perimeter Security"]
DNS[DNS / DDoS Protection\nCloudflare / AWS Shield]
WAF[Web Application Firewall]
CDN[CDN — Edge TLS Termination]
end
subgraph Network["Network Security"]
LB[Load Balancer\nTLS 1.3]
SG[Security Groups / NACLs]
VPC[Private VPC — No public subnet\nfor data layer]
end
subgraph Application["Application Security"]
AUTH[Authentication Service\nJWT + MFA + Session]
AUTHZ[Authorization Layer\nRBAC + Policy Engine]
VALID[Input Validation\nSchema + Sanitization]
RATE[Rate Limiting\nPer IP + Per user]
end
subgraph Data["Data Security"]
ENCRYPT[Encryption at Rest\nAES-256]
TRANSIT[Encryption in Transit\nTLS 1.3 / mTLS]
MASK[PII Masking\nField-level encryption]
VAULT[Secrets Management\n{{VAULT_TOOL}}]
end
subgraph Monitoring["Security Monitoring"]
SIEM[SIEM / Log Aggregation]
IDS[Intrusion Detection]
ALERTS[Security Alerts\nPagerDuty]
AUDIT[Audit Trail\nImmutable logs]
end
DNS --> WAF --> CDN --> LB
LB --> SG --> VPC
VPC --> AUTH --> AUTHZ --> VALID
VALID --> RATE
RATE --> Data
Data --> Monitoring
2. Authentication Flows
2.1 Standard Login / Registration
sequenceDiagram
autonumber
actor User
participant FE as Frontend
participant GW as API Gateway
participant AUTH as Auth Service
participant DB as User Store
participant EMAIL as Email Service
User->>FE: Enter email + password
FE->>GW: POST /auth/login {email, password}
GW->>GW: Rate limit check (5 attempts/15min/IP)
GW->>AUTH: Validate credentials
AUTH->>DB: SELECT user WHERE email = $1
DB-->>AUTH: User record
AUTH->>AUTH: Verify bcrypt/Argon2 hash
alt Invalid credentials
AUTH-->>GW: 401 Unauthorized
GW->>AUTH: Log failed attempt (for lockout)
GW-->>FE: 401 Invalid credentials
Note over FE: Generic message — no user enumeration
end
alt MFA enabled
AUTH->>FE: 200 {mfa_required: true, session_id}
User->>FE: Enter TOTP code
FE->>AUTH: POST /auth/mfa {session_id, totp_code}
AUTH->>AUTH: Verify TOTP
end
AUTH->>AUTH: Generate JWT access + refresh tokens
AUTH->>DB: UPDATE last_login_at
AUTH-->>GW: {access_token, refresh_token, expires_in}
GW-->>FE: Set HttpOnly cookie (refresh) + access_token in body
FE->>FE: Store access_token in memory only
2.2 Token Refresh Flow
sequenceDiagram
autonumber
actor FE as Frontend
participant GW as API Gateway
participant AUTH as Auth Service
participant DB as Token Store
FE->>GW: POST /auth/refresh (HttpOnly cookie: refresh_token)
GW->>AUTH: Validate refresh token
AUTH->>DB: SELECT token WHERE value = hash($1) AND revoked = false
DB-->>AUTH: Token record
AUTH->>AUTH: Check expiry + rotation window
alt Token expired or revoked
AUTH-->>FE: 401 — Re-authenticate
end
AUTH->>DB: Revoke old refresh token (rotation)
AUTH->>AUTH: Generate new access_token + refresh_token
AUTH->>DB: Store new refresh token (hashed)
AUTH-->>FE: {access_token} + Set new HttpOnly cookie
2.3 Multi-Factor Authentication (MFA)
Methods supported:
| Method |
Library/Provider |
Notes |
| TOTP (Authenticator apps) |
{{TOTP_LIB}} |
RFC 6238, 30s window, 1 step tolerance |
| SMS OTP |
{{SMS_PROVIDER}} |
Fallback only — SIM swap risk |
| Hardware key (FIDO2/WebAuthn) |
{{WEBAUTHN_LIB}} |
Highest security, phishing-resistant |
| Recovery codes |
Custom |
10 codes, one-time use, bcrypt-hashed |
sequenceDiagram
autonumber
actor User
participant AUTH as Auth Service
participant DB as DB
User->>AUTH: POST /auth/mfa/setup (authenticated)
AUTH->>AUTH: Generate TOTP secret (160-bit entropy)
AUTH->>User: QR code + backup codes (shown ONCE)
User->>AUTH: POST /auth/mfa/verify {totp_code} (confirm setup)
AUTH->>AUTH: Verify TOTP code
AUTH->>DB: UPDATE user SET mfa_secret = encrypt($secret), mfa_enabled = true
AUTH->>DB: INSERT backup_codes (hashed, 10 codes)
AUTH-->>User: MFA enabled
2.4 SSO / OAuth2 Flow
sequenceDiagram
autonumber
actor User
participant FE as Frontend
participant AUTH as Auth Service
participant IDP as Identity Provider\n(Auth0 / Keycloak / Azure AD)
User->>FE: Click "Sign in with {{PROVIDER}}"
FE->>AUTH: GET /auth/sso/{{provider}}
AUTH->>IDP: Redirect with PKCE code_challenge
User->>IDP: Authenticate with IDP
IDP->>AUTH: Redirect with authorization_code
AUTH->>IDP: Exchange code for tokens (PKCE code_verifier)
IDP-->>AUTH: {id_token, access_token}
AUTH->>AUTH: Validate id_token signature + claims
AUTH->>AUTH: Find or create local user account
AUTH-->>FE: Issue local JWT (same flow as login)
3. Authorization Model
Model: RBAC (Role-Based Access Control) with resource-level conditions
3.1 Roles & Permissions Matrix
| Permission |
Owner |
Admin |
Member |
Viewer |
API |
| Manage tenant settings |
✓ |
— |
— |
— |
— |
| Manage billing |
✓ |
— |
— |
— |
— |
| Invite / remove users |
✓ |
✓ |
— |
— |
— |
| Create {{RESOURCE_1}} |
✓ |
✓ |
✓ |
— |
✓ |
| Read {{RESOURCE_1}} (own) |
✓ |
✓ |
✓ |
✓ |
✓ |
| Read {{RESOURCE_1}} (all) |
✓ |
✓ |
— |
— |
— |
| Update {{RESOURCE_1}} (own) |
✓ |
✓ |
✓ |
— |
✓ |
| Delete {{RESOURCE_1}} |
✓ |
✓ |
— |
— |
— |
| Export data |
✓ |
✓ |
— |
— |
— |
| View audit logs |
✓ |
✓ |
— |
— |
— |
3.2 Permission Hierarchy
SUPER_ADMIN (platform level — bypasses tenant isolation)
└── OWNER (tenant level — full control within tenant)
└── ADMIN (can manage users, not billing)
└── MEMBER (standard CRUD on own resources)
└── VIEWER (read-only)
└── API (scoped to specific permissions)
3.3 Resource-Level Conditions
Rule: Member can UPDATE {{resource}} IF:
resource.tenant_id == user.tenant_id AND
(resource.created_by == user.id OR user.role IN ['admin', 'owner'])
Rule: API key can READ {{resource}} IF:
api_key.tenant_id == resource.tenant_id AND
api_key.scopes CONTAINS '{{resource}}:read'
4. Data Encryption
4.1 Encryption at Rest
| Data Store |
Encryption Method |
Key Management |
| PostgreSQL |
AES-256 (transparent storage encryption) |
Cloud KMS |
| Redis |
AES-256 (cloud provider) |
Cloud KMS |
| Object Storage (S3/Blob) |
SSE-KMS (AES-256) |
Cloud KMS |
| Backups |
AES-256-GCM |
Separate backup KMS key |
| PII fields (field-level) |
AES-256-GCM (application layer) |
Application KMS key |
4.2 Encryption in Transit
TLS Configuration (minimum TLS 1.2, prefer TLS 1.3):
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
mTLS for internal service communication:
- All service-to-service calls within the cluster use mTLS
- Certificates managed by {{CERT_TOOL}} (e.g., cert-manager, Istio, Linkerd)
- Certificate rotation: Automatic every {{ROTATION_PERIOD}}
4.3 Field-Level Encryption for PII
Fields encrypted at application layer (before DB write):
- users.mfa_secret → AES-256-GCM, key: USER_MFA_KEY
- users.{{PII_FIELD}} → AES-256-GCM, key: USER_PII_KEY
- {{OTHER_SENSITIVE_FIELD}} → AES-256-GCM, key: {{KEY_NAME}}
Envelope encryption pattern:
Data → encrypted with DEK (Data Encryption Key)
DEK → encrypted with KEK (Key Encryption Key, stored in KMS)
Only DEK ciphertext stored in database
5. Network Security
5.1 Network Architecture
Internet
→ DDoS Protection ({{PROVIDER}})
→ WAF ({{WAF_TOOL}}) — blocks OWASP Top 10
→ CDN / Edge (TLS termination)
→ Load Balancer (re-encrypts to app — TLS)
→ Public Subnet (only LB + NAT Gateway)
→ Private Subnet (Application servers)
→ Data Subnet (DB, Cache — no internet access)
5.2 Security Groups / Firewall Rules
| Source |
Destination |
Port |
Protocol |
Action |
| Internet |
Load Balancer |
443 |
HTTPS |
ALLOW |
| Internet |
Any |
80 |
HTTP |
REDIRECT → 443 |
| Load Balancer |
App servers |
{{APP_PORT}} |
TCP |
ALLOW |
| App servers |
PostgreSQL |
5432 |
TCP |
ALLOW |
| App servers |
Redis |
6379 |
TCP |
ALLOW |
| App servers |
Message Queue |
{{MQ_PORT}} |
TCP |
ALLOW |
| Any |
Data Subnet |
Any |
Any |
DENY (default) |
| Internal |
Internal |
Any |
Any |
mTLS only |
5.3 WAF Rules
| Rule |
Action |
Notes |
| OWASP Core Rule Set |
Block |
ModSecurity CRS 3.3+ |
| SQL injection |
Block |
Including encoded variants |
| XSS |
Block |
Including DOM-based patterns |
| Path traversal |
Block |
../ patterns |
| Known bad IPs |
Block |
Threat intelligence feed |
| Bot traffic |
Challenge (CAPTCHA) |
Suspicious patterns |
| Rate limiting |
Block |
> {{RATE}} req/min from single IP |
| Geo-blocking |
Block |
Countries: {{BLOCKED_COUNTRIES}} (if applicable) |
6. API Security
6.1 Rate Limiting Strategy
| Tier |
Limit |
Window |
| Anonymous |
{{N}} req/min |
Per IP |
| Authenticated |
{{N}} req/min |
Per token |
| Admin |
{{N}} req/min |
Per token |
ALL inputs validated at:
1. API Gateway level — schema type checking
2. Controller level — DTO validation (class-validator / Zod / joi)
3. Service level — business rule validation
4. Database level — constraints + check constraints
Never trust client-supplied data. Always:
- Whitelist allowed characters where possible
- Enforce max length on all string fields
- Validate file types by magic bytes, not extension
- Use parameterized queries — NEVER string concatenation for SQL
6.3 CORS Policy
// Production CORS config
{
origin: ['https://app.{{DOMAIN}}', 'https://{{DOMAIN}}'],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
exposedHeaders: ['X-Request-ID', 'X-RateLimit-Remaining'],
credentials: true, // Required for HttpOnly cookies
maxAge: 86400 // 24h preflight cache
}
6.4 Content Security Policy
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{NONCE}';
style-src 'self' 'nonce-{NONCE}';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.{{DOMAIN}};
frame-ancestors 'none';
form-action 'self';
upgrade-insecure-requests;
7. OWASP Top 10 Mitigation Matrix
| OWASP Risk |
Mitigation |
Implementation |
Status |
| A01: Broken Access Control |
RBAC + resource ownership checks |
Auth middleware on every endpoint |
✓ |
| A02: Cryptographic Failures |
TLS 1.3 + AES-256-GCM + Argon2 |
See §4 |
✓ |
| A03: Injection |
Parameterized queries + ORM + WAF |
Never raw SQL interpolation |
✓ |
| A04: Insecure Design |
Threat modeling + security review |
Per-feature security review required |
Partial |
| A05: Security Misconfiguration |
IaC security scanning + hardened defaults |
Checkov / tfsec in CI |
✓ |
| A06: Vulnerable Components |
SCA scanning |
Snyk / Dependabot in CI + weekly scans |
✓ |
| A07: Auth Failures |
MFA + rate limiting + account lockout |
See §2 |
✓ |
| A08: Software Integrity |
Signed commits + container image signing |
Sigstore / cosign |
Partial |
| A09: Logging Failures |
Structured audit logs + SIEM |
See §9 |
✓ |
| A10: SSRF |
Allowlist for outbound HTTP + metadata blocking |
Deny internal IP ranges |
✓ |
9. Dependency Vulnerability Management
Scanning tools:
Remediation SLAs:
| Severity |
SLA |
Owner |
| Critical (CVSS ≥ 9.0) |
24 hours |
Security + affected team |
| High (CVSS 7.0-8.9) |
7 days |
Affected team |
| Medium (CVSS 4.0-6.9) |
30 days |
Affected team |
| Low (CVSS < 4.0) |
90 days |
Next sprint |
10. Security Logging & Audit Trail
Security Events Always Logged
| Event |
Data Logged |
Retention |
Alert? |
| Login success |
user_id, ip, user_agent, timestamp |
1 year |
No |
| Login failure |
ip, email_hash, attempt_count, timestamp |
1 year |
Yes (> 5 failures) |
| MFA verification |
user_id, method, success/failure |
1 year |
Yes (failure) |
| Password change |
user_id, ip, timestamp |
1 year |
Yes |
| Permission denied |
user_id, resource, action, timestamp |
1 year |
Aggregate alert |
| Account lockout |
user_id, ip, timestamp |
1 year |
Yes |
| Data export |
user_id, export_type, record_count |
2 years |
Yes (large exports) |
| Admin action |
actor_id, action, target, changes |
2 years |
Yes |
| API key created/revoked |
user_id, key_id, timestamp |
2 years |
No |
| Secret access |
service, secret_name, timestamp |
2 years |
Yes (unusual access) |
Log format: JSON structured, immutable (append-only), shipped to SIEM
SIEM: {{SIEM_TOOL}} — dashboard: {{LINK}}
Tamper protection: Logs signed with {{SIGNING_KEY}}, stored in write-once bucket
Approval
| Role |
Name |
Date |
Signature |
| Author |
|
|
|
| CISO / Security Lead |
|
|
|
| DPO |
|
|
|
| CTO |
|
|
|