Forms Portal — Compliance Controls Mapping¶
Classification: CONFIDENTIAL — Internal Use Only
Document version
v1.0 — 2026-04-18 — derived from forms-backend/compliance/cis-pci-nist-mitre.md at Phase 1 cut.
This document is the authoritative mapping of the Forms Portal (forms.greenpeace.us) implementation against CIS Controls v8, PCI-DSS v4.0, NIST 800-53 Rev 5, and MITRE ATT&CK mitigations. It is reviewed quarterly by the Director of Cyber Security and requires owner sign-off before production cutover (tracked in Cowork Task 6 of the Phase 1 runbook).
The operational/architecture description of the portal lives at Forms Portal — forms.greenpeace.us. This page covers controls and evidence only.
Data classification¶
| Data element | Classification | Handling |
|---|---|---|
| Submission field values (default) | CONFIDENTIAL | AES-256-GCM envelope encryption, per-submission DEK wrapped by KMS |
Searchable field mirrors (searchable: true) |
INTERNAL | Plaintext JSONB column, indexed for admin search |
| Attachments | CONFIDENTIAL | GCS with CMEK, signed URLs, ClamAV scanned, 7-year retention lock |
| Submitter identity (email, username) | INTERNAL | Plaintext columns (operational necessity for audit) |
| Audit log | CONFIDENTIAL | Append-only (REVOKE UPDATE/DELETE), 7-year retention |
| DEK wrapping key | RESTRICTED | Cloud KMS, CMEK, software-protected, automatic 90-day rotation |
Encryption — data in transit¶
| Channel | Protocol | Enforcement |
|---|---|---|
| Browser → Cloud Run | TLS 1.3, HSTS 2yr + preload | Cloud Run managed cert; HSTS header set in app.py |
| Cloud Run → Cloud SQL | TLS 1.3 + mTLS via Cloud SQL Connector | IAM auth; enable_iam_auth=True in db.py |
| Cloud Run → KMS / GCS / Secret Manager | TLS 1.3 (Google private endpoints) | Service account OAuth2 via ADC |
| Cloud Run → HappyFox | HTTPS (TLS 1.2+) | Validated in requests call |
| Cloud Run → VPC (private IP) | TLS via Cloud SQL Connector | vpc-egress=private-ranges-only |
Encryption — data at rest¶
| Asset | Cipher | Key |
|---|---|---|
| Cloud SQL storage | AES-256 (Google-managed layer) + CMEK (customer-managed) | gpus-forms-cmek |
| Cloud SQL automated backups | Same as instance | Inherited |
| Submission field values | AES-256-GCM | Per-submission DEK, wrapped by KMS key gpus-forms-dek-wrapper |
| GCS attachments bucket | AES-256 + CMEK | gpus-forms-cmek |
| GCS backup bucket | AES-256 + CMEK | gpus-forms-cmek |
| Secret Manager | AES-256 (Google-managed) | Managed |
CIS Controls v8¶
| Control | Title | Implementation |
|---|---|---|
| 3.11 | Encrypt Sensitive Data at Rest | CMEK on Cloud SQL + GCS; AES-256-GCM envelope on submission fields |
| 3.12 | Segment Data Processing | Dedicated service account gpus-forms-backend@; private IP; VPC connector |
| 4.4 | Firewall | Cloud SQL private IP only; Cloud Armor WAF at edge; Cloud Run no-allow-unauthenticated |
| 5.1 | Account Management | Okta SSO via OIDC; users table mirrors Okta identity; roles admin/viewer only |
| 6.3 | Multi-factor Authentication | MFA enforced by Okta policy at tenant level |
| 6.8 | Privileged Account Access | Admin role granted in users table; audited via user_granted/user_revoked events |
| 8.2 | Audit Log Collection | Append-only audit_log table; structured JSON to Cloud Logging → CEDAR |
| 8.3 | Log Storage | 7-year retention; Cloud Logging sink to GCS with bucket lock |
| 8.5 | Centralized Log Management | Cloud Logging → CEDAR Elasticsearch (existing pipeline) |
| 8.11 | Audit Log Review | Wazuh rules 100020–100025 on MAPLE; SOC dashboard Tickets tab |
| 10.6 | Vulnerability Scanning | Cloud Build step runs bandit + pip-audit; OAK OpenVAS weekly; Artifact Registry vuln scanning |
| 13.1 | Threat Detection | Wazuh rules trigger SOC auto-ticketing at level ≥ 10 |
| 16.1 | Secure Application Development | Pydantic input validation; parameterized SQL via SQLAlchemy; CSRF tokens; security headers |
PCI-DSS v4.0¶
Forms portal does not process cardholder data. PCI-DSS mapping documented for defense-in-depth alignment only.
| Req | Implementation |
|---|---|
| 1.2.1 | Inbound traffic restricted — Cloud Run auth required, Cloud Armor WAF filters |
| 2.2.1 | Secure configuration — CIS-hardened base image, distroless python, non-root container user |
| 3.5 | Key management — KMS-wrapped DEK; rule 100024 fires on decrypt failure |
| 3.6 | Key rotation — KMS automatic 90-day rotation; re-encrypt job runs on key version change |
| 4.1 | Strong cryptography for transmission — TLS 1.3, HSTS preload |
| 6.5.9 | Protect against CSRF — Flask-WTF CSRF tokens; rule 100022 logs rejects |
| 7.1 | Access to data limited to need — forms_viewer RLS role; admin actions audited |
| 8.3.6 | Password complexity — N/A (Okta SSO, no passwords in forms portal) |
| 10.2.1–10.2.7 | Audit trails — audit_log captures auth, admin, decrypt, export events |
| 10.3 | Audit trail protection — REVOKE UPDATE/DELETE on audit_log; central forwarding to CEDAR |
| 10.7 | Log retention — 7 years |
| 11.3 | Vulnerability scans — OpenVAS weekly (OAK); image scan on every build |
NIST 800-53 Rev 5¶
| Control | Implementation |
|---|---|
| AC-2 | Account Management — Okta + users table sync |
| AC-3 | Access Enforcement — @require_role decorators; Postgres RLS |
| AC-6 | Least Privilege — 2 roles only; service account scoped to Cloud SQL client + KMS encrypter/decrypter + GCS object creator/viewer |
| AU-2 | Event Logging — audit_log table + Cloud Logging |
| AU-6 | Audit Record Review — Wazuh rules + SOC dashboard |
| AU-9 | Protection of Audit Information — append-only, REVOKE UPDATE/DELETE |
| AU-11 | Audit Record Retention — 7 years |
| CM-7 | Least Functionality — minimal container, no shell, distroless-style |
| IA-2 | Identification & Authentication — Okta OIDC, JWT verification |
| IA-5 | Authenticator Management — handled by Okta |
| SC-8 | Transmission Confidentiality — TLS 1.3 everywhere |
| SC-12 | Cryptographic Key Establishment — KMS-managed CMEK + DEK |
| SC-13 | Cryptographic Protection — AES-256-GCM, FIPS-validated via BoringCrypto in GCP |
| SC-28 | Protection of Info at Rest — envelope encryption + CMEK |
| SI-4 | System Monitoring — Prometheus + Wazuh |
| SI-10 | Information Input Validation — pydantic |
MITRE ATT&CK mitigations¶
| Technique | Mitigation |
|---|---|
| T1078 (Valid Accounts) | Okta MFA; role-based access; account lifecycle via Okta lifecycle management |
| T1190 (Exploit Public-Facing Application) | Cloud Armor OWASP rules; pydantic input validation; bandit + pip-audit on build |
| T1213 (Data from Information Repositories) | RLS on submissions; decrypt events audited; bulk export rule 100025 |
| T1537 (Transfer Data to Cloud Account) | Egress restricted to private ranges; signed URLs for attachments; bulk export alerts |
| T1552 (Unsecured Credentials) | All secrets in Secret Manager; no passwords in code or env vars; IAM auth for DB |
| T1562 (Impair Defenses) | Audit log append-only at DB role level; separate forms_readonly role for reports |
Control ownership¶
| Area | Owner | Review cadence |
|---|---|---|
| Cryptographic controls | Director of Cyber Security | Quarterly |
| Access controls (Okta + RLS) | Director of Cyber Security | Quarterly |
| Audit log review | SOC | Weekly (via SOC dashboard) |
| Vulnerability scanning | SOC (OAK) | Weekly |
| Key rotation verification | Director of Cyber Security | Quarterly |
| Retention policy enforcement | Director of Cyber Security | Monthly (purge job audit) |
Sign-off before production¶
- [ ] Director of Cyber Security reviews this document
- [ ] Wazuh rules deployed and verified firing on test events
- [ ] Prometheus alerts routed to correct email/Slack channels
- [ ] OAK OpenVAS target added, baseline scan complete with zero criticals
- [ ] Penetration test scope includes forms portal (update
pentest-schedule.md) - [ ] Disaster recovery test completed (restore from GCS backup, verify decrypt works)
- [ ] IRP (
irp.md) updated with forms-portal-specific playbook entries
Rotation verification log¶
Quarterly execution log for Cowork Task 8 (forms-portal credential rotation check) from forms-backend/RUNBOOK-COWORK.md. Each run records one line per check with status PASS / FLAG / ACTION-NEEDED and any operator notes. This skill never rotates secrets automatically — it verifies state and raises follow-ups.
2026-04-20 — Q2 2026 check (automated run)¶
Executed by: Cowork scheduled task forms-portal-credential-rotation-quarterly (agent, unattended — Rajesh not present for interactive walk-through).
Verification evidence available to the agent was limited to the repo — no gcloud CLI, no GCP Console session, and no HappyFox support channel were reachable from the scheduled-task sandbox. Items that require live console state are therefore logged as ACTION-NEEDED for Rajesh to complete manually and back-fill into this log at the next available window.
| # | Check | Status | Notes |
|---|---|---|---|
| 1 | HappyFox credentials rotation (gpus-forms-happyfox-api-key, gpus-forms-happyfox-auth-code) |
ACTION-NEEDED | Requires an outbound ticket/email to HappyFox support (not executable by agent). If HappyFox confirms rotation, procedure is: add new version to Secret Manager, verify /health + one test submission, disable (not delete) previous version. |
| 2 | Okta client secret rotation policy | PASS (with FLAG for MFA) | config.py references OKTA_CLIENT_ID only (SPA); no OKTA_CLIENT_SECRET env var or secret exists. SPA pattern has no secret to rotate (RUNBOOK-COWORK.md Task 4, Option A confirms reuse of existing "Greenpeace.US" SPA app, client id 0oadhpjktd5UfCMDm0x7). FLAG: MFA enforcement on the Okta sign-on policy needs manual confirmation in Okta Admin each quarter — not verifiable from the repo. |
| 3 | KMS key rotation timestamps (gpus-forms-cmek, gpus-forms-dek-wrapper) |
ACTION-NEEDED | Keys were created with --rotation-period=90d per Step 3 of RUNBOOK-CLAUDE-CODE.md, so automatic rotation is configured. Per-version rotation timestamps (must be within the last 100 days) require GCP Console → Security → KMS → keyring gpus-forms (us-central1) and are not visible to the agent. |
| 4 | Cloud SQL backups (gpus-forms-db: 7 retained, PITR enabled, latest <24h) |
ACTION-NEEDED | Requires GCP Console → Cloud SQL → gpus-forms-db → Backups tab. Not verifiable from the repo. |
Overall result: 1 PASS (with secondary FLAG), 3 ACTION-NEEDED.
Follow-up: A 7-day Cowork follow-up has been scheduled (forms-portal-rotation-followup-2026-q2) to walk Rajesh through items 1, 3, and 4 live and back-fill verified statuses into this log. The MFA-enforcement FLAG on item 2 should be closed out during the same session.
Forms Portal Compliance Controls · v1.0 · 2026-04-18 · GPUS-IT · Classification: CONFIDENTIAL — Internal Use Only