Praxi Medicare Security Architecture
This is Praxi's security architecture in the context of Medicare claiming. It accompanies the Software Product Description as part of Praxi's Services Australia submission under Interface Agreement 2020 v2.1 and Services Australia's Third Party Security Policy v2.1, and is also written to satisfy tenant security questionnaires when practices complete their own Privacy Impact Assessments and assurance reviews.
The audience for this page is technical: SA Developer Liaison reviewers, tenant Chief Information Security Officers, third-party assurance reviewers, and auditors. End-user-facing security guidance lives elsewhere (Security Overview, Audit Logs).
Data classification
Praxi classifies Medicare-related data into four sensitivity tiers and applies controls per tier. The tiers determine encryption requirements, access-control granularity, and audit-logging intensity.
| Tier | Examples | At-rest protection | Access control |
|---|---|---|---|
| Sensitive (PHI) | Medicare card number, IRN, IHI, DVA file number, own-PRODA private keys | AES-256-GCM application-layer encryption + AWS KMS at storage layer | Practice isolation, access checks and audit records |
| Sensitive (clinical) | Clinical notes, assessment responses, risk flags, safety plans | AWS KMS at storage layer; specific PHI fields additionally AES-256-GCM-encrypted | Tenant-scoped RLS + permission decorator |
| Personal | Patient name, DOB, address, contact details | AWS KMS at storage layer | Tenant-scoped RLS + permission decorator |
| Operational | Audit log entries, SA claimId references, MBS item codes, service dates | AWS KMS at storage layer; insert-only audit table | Tenant-scoped RLS + permission decorator + 7-year retention |
Medicare card numbers, IRN, IHI, and DVA file number receive the strongest protection because they are government-issued identifiers whose disclosure carries direct identity-theft and benefits-fraud risk under Australian law.
Encryption at rest
Database encryption
Aurora PostgreSQL encrypts all storage at rest with AWS-managed KMS. Praxi does not run Aurora unencrypted in any environment, including non-production.
In addition, the most sensitive fields receive a second layer of application-layer encryption with AES-256-GCM authenticated encryption applied in Praxi's cryptography service before the data reaches the database. The fields covered by this second layer are:
- Patient Medicare card number and IRN.
- Patient IHI (Individual Healthcare Identifier).
- Patient DVA file number.
- Own-PRODA private keys.
- The full SA response payload, because it contains echoed patient information.
Platform PRODA private keys and the platform SA API client identifier use Secrets Manager custody, described below.
The application-layer encryption uses a 256-bit master key stored in AWS Secrets Manager. Per-field encryption derives an HKDF sub-key with a per-record salt. The IV is 96 bits; the auth tag is 128 bits. Algorithm parameters are non-configurable and constant across all environments.
Object storage encryption
S3 buckets storing claim attachments (signed DB4 PDFs, supporting documents)
enforce KMS encryption with bucket policies that deny s3:PutObject requests
lacking the x-amz-server-side-encryption-aws-kms-key-id header. Bucket
ownership is locked to the Praxi production account.
Cache encryption
Amazon ElastiCache (Redis) is configured with at-rest encryption and in-transit TLS. The Redis cluster is reachable only from the API task ENIs in the production VPC — no public access route exists.
Secrets encryption
AWS Secrets Manager holds platform PRODA private keys, the platform SA API client identifier and application encryption keys. Access is restricted through AWS identity controls and recorded in CloudTrail. Own-PRODA private keys are encrypted separately at rest. See key management below for rotation and recovery.
Encryption in transit
| Connection | Protocol | Cipher discipline |
|---|---|---|
| Browser → Praxi web/ops/api | TLS 1.2+ (TLS 1.3 preferred) | AWS-managed certificate, modern cipher suite |
| iOS → Praxi api | TLS 1.2+ (TLS 1.3 preferred) | System trust + HSTS; no certificate pinning currently |
| Praxi api → PRODA + MCOL | TLS 1.2 | Per Services Australia's published TLS profile |
| Praxi api → Aurora PostgreSQL | TLS 1.2+ | AWS-managed |
| Praxi api → Redis (ElastiCache) | TLS 1.2+ | AWS-managed |
| Praxi api → Keycloak | TLS 1.2+ | Internal ALB |
| Praxi api → AWS Secrets Manager / S3 / Bedrock | TLS 1.2+ | AWS-managed via VPC endpoints |
| Inter-AZ replication | AWS-managed | KMS-encrypted in-flight |
Praxi does not run any cleartext production traffic. The only HTTP-without-TLS
traffic on production hosts is the loopback connection from the application
container to the OpenTelemetry CloudWatch Agent sidecar
(http://localhost:4318/v1/traces), which never leaves the task ENI.
iOS transport security relies on App Transport Security (TLS 1.2+ enforced by
the OS), system certificate trust, and HSTS — the configuration Apple recommends
for apps whose backend certificates rotate on managed infrastructure. An earlier
certificate-pinning configuration was removed on 2026-05-08 because it was a
non-functional placeholder (an empty NSPinnedLeafIdentities); Praxi treats a
control that does not work as worse than a documented decision not to carry it.
Pinning would be re-introduced only alongside a certificate-rotation runbook and
maintained SPKI hashes.
Authentication and access control
Identity provider
Praxi runs a self-hosted Keycloak 23 cluster on ECS Fargate with two realms:
| Realm | Audience | Auth strategy | Cookie |
|---|---|---|---|
praxi | Tenant users — practitioners, practice staff, clients | OIDC Authorisation Code + PKCE | access_token (httpOnly) |
praxi-ops | Praxi staff — platform admins, support engineers | Direct Access Grants (server-side BFF) | ops_access_token (httpOnly) |
Tenant users and Praxi staff are in separate realms, with separate Keycloak
databases. There is no cross-realm trust. The tenant realm's frontendUrl is
https://auth.praxi.au; the ops realm uses the same authoriser but with
separate client credentials.
JWTs are issued by Keycloak as RS256-signed bearer tokens stored exclusively in
httpOnly secure same-site cookies. Praxi has never stored JWTs in
localStorage, sessionStorage, or any client-accessible store; ESLint
enforces the prohibition on writes to local-storage from auth-related code
paths.
Authorisation model
Praxi checks access against the user's role and the permitted scope of work. Practitioners can access their authorised claim workflows; authorised practice staff can manage practice-wide claiming. Platform operations access is separate, restricted to the operator's duties and audited.
MFA
Keycloak TOTP is required for all Praxi staff in the praxi-ops realm. Tenant
MFA is policy-controlled per organisation; the default for new organisations is
MFA-required for practice_owner and practice_manager roles.
Session handling
- Access token lifetime: 60 minutes
- Refresh token lifetime: 24 hours, single-use rotation
Idle session: 30 minutes (configurable per realm)Max session lifetime: 12 hours- Healthcare MFA flow honours the SSO cookie via an alternative auth-cookie step.
Tenant data isolation
Practice data is isolated at the database layer through row-level security. Application access checks also restrict each request to its authorised practice and scope. Automated checks review isolation policies; these checks do not by themselves establish deployed enforcement.
Praxi staff use a separate operations access boundary with explicit access checks. Cross-tenant queries (e.g. for ops support investigating a tenant issue) are visible in the ops audit log.
PRODA key management
Medicare Online claims use House of Praxi's PRODA organisation by default, under the vendor model described in MCOL Q&A 5. A practice may choose its own PRODA organisation or Tyro instead. Practitioners remain responsible for their claims regardless of the authentication choice.
For the default service, Praxi links each practice Location ID (Minor ID) to House of Praxi's PRODA organisation. A signed HW027 is required for each provider number at each location. The practitioner signs it; question 3 is left blank when using Praxi's PRODA. Practices choosing their own PRODA manage their own linking and enter their own PRODA registration authority number in question 3. The Services Australia API client identifier is one platform value across practices; it is separate from the PRODA organisation and device identity.
Key custody, rotation and environment isolation
Platform private keys are held in AWS Secrets Manager. The platform uses a primary B2B device with a standby for continuity. A recorded standby is not proof of a healthy connection: its activation, key, expiry and authentication history must be checked. Key rotation stages a replacement, verifies acceptance by Services Australia and promotes the verified version. An incomplete or uncertain rotation requires review before the affected device returns to service.
These are key-custody controls, not evidence that production credentials or a standby device are ready. Practices choosing their own PRODA have separate keys, encrypted at rest with AES-256-GCM. Recovery depends on the available verified key or backup and may require a new device activation code.
Non-production environments use vendor-test PRODA and claiming endpoints. Production uses live endpoints except for the explicitly designated Medicare Test Clinic, which uses vendor test. Reserved certification Location IDs are refused for other production practices. Invalid endpoint configuration blocks requests rather than allowing a live/test fallback.
Praxi must report a PRODA credential compromise to Services Australia within 12 hours of awareness. Containment, evidence preservation and recovery run alongside notification; investigation must not delay reporting.
Keys are generated as 2048-bit RSA. Scheduled rotation checks run every six hours, with rotation due within 30 days of key expiry. Device renewal is a separate requirement from key rotation.
Authentication-failure handling
A PRODA health monitor runs every 15 minutes. Practice-owner notifications apply to practices using their own PRODA; platform device failures require Praxi operations review. The own-PRODA thresholds are:
| Failures (rolling) | Action |
|---|---|
| 3 | Alert the practice owner with an urgent staff notification |
| 5 | Hard lock the tenant's PRODA submissions (matches SA's server-side 5-failure lockout) |
The lockout reset is a manual, audit-logged action performed by Praxi's operations team.
Audit logging
Every mutation against the application is captured by a global audit interceptor
wired into the request pipeline of the main API and every microservice. The
interceptor writes a row to the audit log (or to CloudWatch for the secondary
microservices) for every POST, PUT, PATCH, and DELETE request.
Audit log row contents:
- Who acted (user ID, role, organisation ID at time of action)
- What changed (HTTP method, controller, endpoint, before/after diff with PHI redacted)
- When (UTC millisecond timestamp)
- Where from (IP, user-agent)
- Request and response IDs (for correlation with traces)
The audit table is insert-only. Updates and deletes are blocked by RLS policy and by database role permissions. Retention is 7 years per Privacy Act 1988. CloudWatch archive copies are written to S3 in a long-term storage class with object-lock at the bucket level for the SA-specific compliance trail.
Decryption of any encrypted PHI field is also audited — every field decryption emits an audit event recording the actor, the field, and the record.
DNS and certificate management
- DNS is hosted on AWS Route 53.
- DNSSEC is enabled for
praxi.auand all subdomains in production. The signing-key rotation procedure is Praxi's internal DNSSEC rotation runbook. The DNSSEC infrastructure is protected by an OU-wide guardrail:terraform destroyagainst DNSSEC resources is denied at the SCP layer (it wouldSERVFAILthe apex domain). - Public-facing TLS certificates are issued by AWS Certificate Manager with automated renewal.
- HSTS is enforced on every public Praxi domain.
Container security
| Control | Implementation |
|---|---|
| Image vulnerability scanning | Trivy on every build via .github/workflows/_build-ecs-service.yml; fails on CRITICAL/HIGH CVEs |
| Image signing | Cosign keyless signing via sigstore Rekor; production deploys verify the signature |
| Image provenance | Signed at build time; verified at deploy gate |
| Base image hardening | Minimal Alpine + Debian-slim bases; user is non-root |
| Runtime hardening | ECS Fargate (no host-level access); read-only root filesystem where feasible |
| Patch cadence | Image rebuild on every push to main; dependency updates ride trunk-based delivery |
Cryptographic image provenance is provided by Cosign keyless (OIDC) signing at build time. SLSA provenance attestation and SBOM publication are planned, not current controls — they await the GitHub plan upgrade required for private-repo attestations and are not counted in the table above.
Application security
| Control | Implementation |
|---|---|
| Static analysis (SAST) | Semgrep — SQL injection, XSS, OWASP Top 10 — gates every PR via .github/workflows/sast.yml |
| Infrastructure-as-code | tfsec + Checkov on every Terraform change via .github/workflows/terraform-security.yml |
| Secret detection | Pre-commit hook + GitHub secret scanning |
| Dependency vulnerabilities | npm audit + Renovate-managed bumps; weekly automated patch sweep |
| Container vulnerabilities | Trivy on every image build |
| Input validation | Zod schemas via @anatine/zod-nestjs at every controller boundary |
| Output encoding | React's default escaping; dangerouslySetInnerHTML blocked at pre-commit |
| CSRF protection | Same-site cookies + CSRF tokens on state-changing API calls |
| Rate limiting | Shared per-client request limits with burst and sustained thresholds |
Operational security
- Production access — ECS Fargate is the runtime; no SSH or container shell exec is permitted from outside the deploy pipeline. Engineers needing diagnostic access do so via AWS SSM Session Manager bound to the task IAM role, which is audit-logged at the CloudTrail layer.
- Bastion-less network design — there are no bastion hosts. AWS SSM Session Manager replaces SSH.
- Observability — CloudWatch Logs (logs), AWS X-Ray + Application Signals
(traces, via OpenTelemetry), CloudWatch Metrics + Prometheus
/metricsendpoint (metrics). PHI is sanitised at the OTEL request hook before any export. - Change control — trunk-based CI/CD via GitHub Actions OIDC, with six active production gates: staging-green-for-SHA, clinical-hours, migration-phase predecessor, live-state compliance probe, Cosign signature verification, GitHub App JIT token. A seventh explicit-human-approval gate is deferred until first ops hire per ADR-009.
- Rollback — CodeDeploy blue/green for the API service; rollback shifts traffic to the previous task definition via the ops portal's Command Centre.
Incident response
A full incident-response one-pager for Medicare-relevant incidents is at Incident Response. The SLAs Praxi commits to:
| Trigger | Notification deadline |
|---|---|
| Cyber incident affecting Services Australia data | 12 hours from detection |
| Notifiable Data Breach (OAIC) | 3 business days for draft notification; 30 days final |
| Service outage affecting claim submission | Before close of next business day; as soon as practicable |
Subprocessors
Praxi uses a small set of subprocessors for Medicare-related processing. The full disclosure is at Medicare Data Flow and the public register is at https://praxi.au/trust/sub-processors. In summary:
- AWS Australia — cloud infrastructure, ap-southeast-2 only.
- Services Australia — destination of every claim submission. Not a subprocessor in the strict sense; SA is the benefit administrator under federal statute.
- Anthropic via AWS Bedrock (Sydney) — AI MBS-item suggestion only. Bedrock requests never include Medicare card number, IRN, IHI, or DVA file number. Only structural appointment metadata.
- Keycloak (self-hosted) — not a subprocessor; identity provider operated by Praxi.
- Amazon SES — transactional email; no Medicare data flows through SES, only practitioner email addresses and notification text.
No third-party analytics SDK processes Medicare data. No cross-region cloud observability service processes Medicare data. No foreign-jurisdiction payment processor handles Medicare claim data — SA pays the practice's nominated bank account directly.
Compliance
| Framework | Status |
|---|---|
| Privacy Act 1988 (Australia) | Aligned. Praxi acts as service provider; tenants are primary APP entities. See Privacy Impact Assessment. |
| Interface Agreement 2020 v2.1 (SA) | Aligned. SLAs documented in Incident Response. |
| Third Party Security Policy v2.1 (SA) | Aligned. Essential Eight Maturity Level 3 targeted, ap-southeast-2 data residency enforced via AWS SCP. |
| Essential Eight (ACSC) | Maturity Level 3 alignment in progress. MFA, application allowlisting (container image signing), patching, restricted admin privileges, multi-factor for privileged accounts, backups, and macro restriction all implemented. |
| ISO/IEC 27001 | Aligned (not formally certified). |
| SOC 2 Type II | In progress — controls defined, first observation window underway. |
| IRAP | Not certified; targeted for FY27 if a federal-government tenant materialises. |
| Notifiable Data Breach scheme (OAIC) | Aligned. Praxi maintains an internal breach-response plan as the authoritative procedure. |
Cross-references
- Software Product Description — the product identity that this security architecture protects.
- Privacy Impact Assessment — privacy-risk register.
- Incident Response — incident-notification SLAs and procedures.
- Medicare Data Flow — subprocessor disclosure for tenants.
- Per-claim Audit Trail — what is logged about every claim.
- Audit Logs — Praxi's general audit-logging architecture.
SA spec conformance — Verified against Interface Agreement 2020 v2.1, Third Party Security Policy v2.1, PRODA B2B Unattended V4.2, Version Control Policy v2.0 on 2026-05-13; re-verified against the implementation on 2026-08-12.