Skip to main content

AWS Account Setup & Access Strategy

Platform Account — Not App-Specific

This document describes the SPW Healthcare Innovations platform AWS account (spwhi-platform). Ward Mitra is the first tenant. Future apps (Field Assist, etc.) will onboard to the same EKS cluster under separate namespaces. All conventions here apply to the entire SPWHI platform — not Ward Mitra alone.


Account Structure

AWS Organizations (SPW Healthcare Innovations)
├── Existing account (POC) ← keep as-is, manual changes allowed
│ └── Ward Mitra POC deployment
└── spwhi-platform (NEW) ← this document
└── IaC-only · Terraform is the only path to change anything

Why a separate account?

ConcernReason
Clean blast radiusA misconfigured change in the POC cannot affect production
IaC disciplineEnforced by SCPs at org level — not by trust or convention
Audit clarityEvery change in spwhi-platform is either a Terraform apply or a BreakGlass emergency — nothing in between
Multi-tenancyAll SPWHI apps share this account's EKS cluster under namespace isolation
Cost visibilityAWS Cost Explorer shows platform vs POC spend clearly

IaC-Only Discipline

Terraform is the only way to create, modify, or delete any resource in spwhi-platform.

This is not a convention. It is enforced by Service Control Policies (SCPs) applied at the AWS Organizations level. SCPs override even AdministratorAccess — no IAM permission can bypass them.

What SCPs enforce

SCP DenyWhy
iam:CreateUserNo new IAM users ever — only the BreakGlass user exists (created at bootstrap)
iam:CreateAccessKeyNo static long-lived credentials anywhere in the account
s3:DeleteBucket on spwhi-platform-tfstateTerraform state is permanent and protected
s3:DeleteObject on spwhi-platform-tfstate/*No corruption of state, even by admins
cloudtrail:StopLoggingAudit trail is always on — cannot be disabled
cloudtrail:DeleteTrailEven BreakGlass cannot hide their actions
* where aws:RequestedRegion != ap-south-1All resources stay within India (except global services: IAM, STS, CloudFront, Route 53)
No Exceptions

If you need to create a resource manually, you are doing something wrong. Either fix the Terraform pipeline or follow the BreakGlass procedure. The SCPs will block any attempt to bypass this.


User Types & Access Model

Three types of access exist in spwhi-platform. No exceptions.

spwhi-platform account

├── 🤖 Terraform (machine, OIDC) ← GitHub Actions only
├── 🔴 BreakGlass (human, emergency) ← max 2 people, MFA required
└── 👁 ReadOnly Dev (human, SSO) ← all developers, read-only console

🤖 Terraform — Machine Access (OIDC)

Not a human. Not an IAM user. No credentials stored anywhere.

Terraform runs exclusively through GitHub Actions using AWS OIDC federation. The workflow exchanges a short-lived GitHub JWT for temporary AWS STS credentials (1-hour TTL). No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY exists in GitHub Secrets.

How it works

GitHub Actions job starts

GitHub mints a signed JWT for this workflow run
(contains: repo, branch, workflow, sha)

Workflow calls AWS STS AssumeRoleWithWebIdentity
(JWT + IAM role ARN)

AWS validates JWT signature via GitHub OIDC JWKS endpoint
Checks trust policy: sub must match exactly

STS returns temp credentials — valid 1 hour, then auto-expire

Terraform plan / apply runs with these credentials

IAM Role: github-actions-terraform

PropertyValue
TypeIAM Role (OIDC-assumed, no IAM user)
Repo trustSPW-HEALTHCARE-INNOVATIONS-Pvt-Ltd/spwhi-infra only
Branch trustrefs/heads/main only (apply)
Console accessNone
Access keysNone
Session TTL1 hour (STS temp creds)
PermissionsS3 (tfstate), DynamoDB (lock), VPC, EKS, RDS, IAM, ACM, Route 53 — scoped to spwhi-* resources

GitHub Actions usage

- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/github-actions-terraform
aws-region: ap-south-1
role-session-name: terraform-${{ github.run_id }}
note

The id-token: write permission must be set on the job for OIDC token minting to work.

Other pipeline roles (same OIDC pattern)

RoleTrusted repoTrusted branchPermissions
github-actions-ecr-pushSPW-HEALTHCARE-INNOVATIONS-Pvt-Ltd/wardmitra-apiany (*)ECR push for WardMitra API Docker images
github-actions-s3-deploySPW-HEALTHCARE-INNOVATIONS-Pvt-Ltd/wardmitra-uimain onlyS3 sync + CloudFront invalidation for WardMitra UI

All three roles are provisioned by the spwhi-bootstrap Terraform repo (Day 0, one-time).


🔴 BreakGlass — Emergency Human Admin

For production emergencies only when the Terraform pipeline cannot be used.

Who has access

PersonRole
SparkOps Lead (Sanket Pethkar)Primary BreakGlass holder
SPW CTO / Senior DevSecondary BreakGlass holder

Maximum 2 people. No exceptions.

Account properties

PropertyValue
IAM usernamebreakglass
PolicyAdministratorAccess (AWS managed)
MFARequired — no console action possible without MFA token
Access keysNone (blocked by SCP iam:CreateAccessKey)
Console accessYes — AWS Management Console only
Credential storageSecure vault (1Password / LastPass restricted vault — shared only between 2 holders)

Alerting

Every BreakGlass login triggers an immediate alert:

CloudTrail → EventBridge rule (userIdentity.userName = "breakglass")
→ SNS topic
→ Email: devops@spwhealthcare.in
→ Slack: #spwhi-platform-alerts

No BreakGlass login should be silent. If the team doesn't see an alert, something is wrong.

When to use BreakGlass

Allowed:

  • EKS node group crashed and pods cannot be rescheduled
  • RDS instance unavailable and automated failover did not trigger
  • Terraform pipeline is broken and production is actively degraded
  • Security incident requiring immediate IAM revocation

Not allowed:

  • Convenience (pipeline too slow)
  • Skipping code review
  • Testing something before adding to Terraform
  • Any non-emergency situation

Post-use mandatory steps

Mandatory — Must be completed within 24 hours

Every BreakGlass session must be fully reconciled with Terraform before the incident is closed.

  1. Document every console action taken in #spwhi-platform-alerts Slack thread
  2. For each resource modified via console:
    • If Terraform already manages it → run terraform import to reconcile state
    • If new resource created → write Terraform code + terraform import → verify terraform plan shows no drift
  3. Verify clean state: terraform plan must output No changes before incident closure
  4. Rotate BreakGlass console password after every use
  5. Write incident report: what failed, what was changed manually, how it was reconciled

👁 ReadOnly Developer — Console Visibility

For all SPW developers and SparkOps team to observe what Terraform deployed.

No separate AWS password. Login via IAM Identity Center (SSO) using existing Google Workspace account.

How to log in

  1. Go to: https://spwhi.awsapps.com/start (SSO portal)
  2. Log in with your @spwhealthcare.in Google account
  3. Select spwhi-platform account
  4. Click Management Console — read-only session starts (8hr TTL)

What you can see

ServiceAccess
EKSView clusters, node groups, namespaces, workloads
CloudWatchView logs, metrics, alarms, dashboards
RDSView instance parameters, snapshots, event logs
S3List buckets, view object metadata (not download sensitive data)
EC2View instances, security groups, VPC layout
IAMView roles and policies (read-only)
SSM Parameter StoreView parameter names and metadata (not SecureString values)

What you cannot do

  • Create, modify, or delete any resource
  • Download objects from spwhi-platform-tfstate or spwhi-platform-velero-backup (permission boundary blocks this)
  • View SecureString parameter values (SSM) or Secrets Manager secret values
  • Access the BreakGlass IAM user or any OIDC roles

Permission set details

PropertyValue
IAM Identity Center Permission SetSPWHIReadOnlyDeveloper
Base policyReadOnlyAccess (AWS managed)
Permission boundaryDeny s3:GetObject on tfstate and velero-backup buckets
Identity sourceGoogle Workspace (spwhealthcare.in domain)
Session duration8 hours (auto-expire, re-login required)
Assigned groupspwhi-platform-readonly (Google Workspace group)
Adding a new developer

Add them to the spwhi-platform-readonly Google Workspace group. No AWS console changes needed. They will have access on next SSO login.


Naming Conventions

All resources in spwhi-platform follow these conventions. Ward Mitra is one app — prefixed accordingly.

S3 Buckets

BucketPurpose
spwhi-platform-tfstateTerraform remote state (all modules)
spwhi-platform-tflock (DynamoDB)Terraform state lock table
spwhi-platform-velero-backupEKS namespace backups (all apps)
spwhi-platform-loki-logsGrafana Loki log storage (all apps)
spwhi-platform-cloudtrail-logsCloudTrail audit logs
spwhi-ward-mitra-photosWard Mitra complaint photo uploads
spwhi-ward-mitra-web-prodWard Mitra React app static files

SSM Parameter Store paths

/spwhi/{app}/{env}/{service}/{key}

Examples:
/spwhi/ward-mitra/prod/app/jwt-secret
/spwhi/ward-mitra/prod/app/firebase-key
/spwhi/ward-mitra/prod/db/host
/spwhi/ward-mitra/staging/app/node-env
/spwhi/field-assist/prod/app/api-key ← future app, same pattern
/spwhi/platform/grafana/admin-password

IAM / IRSA Roles

spwhi-{app}-{service}

Examples:
spwhi-ward-mitra-backend ← Node.js API IRSA role
spwhi-ward-mitra-ai-inference ← AI inference IRSA role
spwhi-ward-mitra-admin ← Admin panel IRSA role
spwhi-platform-eso ← External Secrets Operator IRSA role
spwhi-platform-karpenter ← Karpenter controller IRSA role
spwhi-platform-velero ← Velero backup IRSA role
spwhi-platform-loki ← Loki S3 access IRSA role
github-actions-terraform ← GitHub Actions OIDC role (infra repo)
github-actions-ecr-push ← GitHub Actions OIDC role (app repo)
github-actions-s3-deploy ← GitHub Actions OIDC role (app repo)

EKS Namespaces

spwhi-platform EKS cluster

├── platform ← ArgoCD, Karpenter, ESO, ALB Controller, Monitoring, Velero
├── ward-mitra-prod ← Ward Mitra production workloads
├── ward-mitra-staging ← Ward Mitra staging
├── ward-mitra-dev ← Ward Mitra dev
├── field-assist-prod ← Future (same pattern)
└── field-assist-staging ← Future

GitHub Repository Structure

SPW-HEALTHCARE-INNOVATIONS-Pvt-Ltd (GitHub Org)

├── spwhi-bootstrap ← Day 0 only. OIDC provider + 3 GitHub Actions IAM roles.
│ │ Run manually once. No CI pipeline in this repo.
│ ├── main.tf ← aws_iam_openid_connect_provider
│ ├── iam_roles.tf ← github-actions-terraform/ecr-push/s3-deploy roles
│ ├── variables.tf
│ ├── outputs.tf ← exports all 3 role ARNs
│ └── README.md

├── spwhi-infra ← All AWS infrastructure (Terraform).
│ │ Pipeline: plan on PR, apply on main merge.
│ ├── bootstrap/ ← BreakGlass user, IAM Identity Center, SCPs, CloudTrail
│ ├── modules/
│ │ ├── vpc/
│ │ ├── eks/ ← cluster + node groups + Karpenter
│ │ ├── rds/
│ │ └── iam/ ← all IRSA roles, one module per app
│ ├── environments/
│ │ ├── dev/
│ │ ├── staging/
│ │ └── prod/
│ └── .github/workflows/
│ └── terraform.yml ← OIDC auth via github-actions-terraform role

├── wardmitra-api ← WardMitra API code
│ └── .github/workflows/
│ └── api.yml → EKS ward-mitra-prod namespace (ecr-push role)

├── wardmitra-ui ← WardMitra UI code
│ └── .github/workflows/
│ └── web.yml → S3 + CloudFront (s3-deploy role)

└── field-assist ← Future app (same split pattern as WardMitra)

Day 0 Bootstrap Sequence

Run in this exact order. Steps 1–4 are manual (local machine). Step 5 onwards is automated via GitHub Actions.
Step 1 — Create spwhi-platform AWS account via AWS Organizations console
(manual, done by SparkOps + SPW CTO together)

Step 2 — Create all 4 GitHub repos in SPW-HEALTHCARE-INNOVATIONS-Pvt-Ltd org:
spwhi-bootstrap, spwhi-infra, wardmitra-api, wardmitra-ui

Step 3 — Run spwhi-bootstrap Terraform locally
cd spwhi-bootstrap/
terraform init
terraform apply
→ Creates: OIDC provider + 3 GitHub Actions IAM roles
→ Note the 3 role ARNs from outputs

Step 4 — Add role ARNs as GitHub Actions variables (not secrets):
spwhi-infra repo: TERRAFORM_ROLE_ARN
wardmitra-api repo: ECR_PUSH_ROLE_ARN
wardmitra-ui repo: S3_DEPLOY_ROLE_ARN, CF_DISTRIBUTION_ID

Step 5 — Run spwhi-infra bootstrap/ module locally (one time only):
cd spwhi-infra/bootstrap/
terraform init && terraform apply
→ Creates: BreakGlass IAM user, IAM Identity Center setup,
CloudTrail, SCPs on AWS Organizations

Step 6 — Set MFA on BreakGlass user immediately
Store credentials in secure vault
Verify CloudTrail alarm fires when logging in (test login)

Step 7 — All future infra changes go through spwhi-infra pipeline
Local AWS credentials never needed again from this point

Step 8 — Assign spwhi-platform-readonly group in Google Workspace
Add all developers → they can SSO into read-only console immediately

Step 9 — Run spwhi-infra environments/dev/ pipeline
First real Terraform apply via GitHub Actions: VPC, EKS, RDS bootstrap

Access Summary Table

Terraform (OIDC)BreakGlassReadOnly Dev
TypeOIDC role (machine)IAM user (human)SSO permission set (human)
CountN/AMax 2All developers
Console✅ (MFA required)✅ (read-only)
CLI / Programmatic✅ (temp STS creds)✗ (blocked by SCP)
Can modify resources✅ (via Terraform)✅ (emergency only)
Credential typeTemp STS (1hr TTL)Console password + MFASSO session (8hr TTL)
Alert on use✅ immediate Slack + email
Post-use reconciliationN/A✅ mandatory (24hr)N/A
Provisioned byspwhi-bootstrapspwhi-infra/bootstrapIAM Identity Center


SparkOps Advisory Services · Sanket Pethkar · March 2026 · Confidential — SPW Healthcare Innovations Pvt. Ltd.