Skip to content

Access Control

Overview

MenoTime implements role-based access control (RBAC) and the principle of least privilege to ensure that users and services can only access the resources necessary to perform their job functions. This document defines access control policies, user roles, and authorization procedures.

Golden Rule: Users should have the minimum access required to do their job, nothing more.

Principle of Least Privilege

The principle of least privilege is a security concept that requires granting the minimum level of access rights needed to perform required tasks.

Application

At MenoTime, this means:

  • Developers: Access to DEV and STAGING environments only (not PROD)
  • DevOps/SRE: Access to all environments, but limited to infrastructure management
  • Database Administrators: Access to database systems only, not application servers
  • Clinical Staff: Access only to patient data relevant to their job function
  • Executives: Access to dashboards and reports, not raw data
  • Vendors/Contractors: Access only to specific resources needed; temporary and monitored

Quarterly Access Reviews

Every quarter, access is reviewed to ensure it is still necessary and aligned with current job responsibilities.

Process:

  1. Manager review (manager confirms access is still needed)
  2. System audit (infrastructure team audits actual access in CloudTrail)
  3. Access removal (access removed if no longer necessary)
  4. Approval (Security Officer reviews and documents)
  5. Report (quarterly access review report generated)

IAM User and Role Structure

MenoTime's AWS IAM structure separates access by role type and environment.

User Categories

Category Purpose Environments MFA Required Credential Rotation
Developer Build/test features DEV, STAGING Yes 60 days
DevOps/SRE Manage infrastructure DEV, STAGING, PROD Yes 45 days
Database Admin Database operations STAGING (limited), PROD Yes 30 days
Security Security operations DEV, STAGING, PROD (audit-only) Yes 30 days
Product/Analytics Data analysis STAGING (de-identified data only) Yes 90 days

Role Structure

menotime-aws-account/
├── iam/users/
│   ├── john.developer
│   ├── sarah.devops
│   ├── alex.dba
│   └── chris.security
├── iam/roles/
│   ├── menotime-developer-role
│   ├── menotime-devops-role
│   ├── menotime-dba-role
│   ├── menotime-security-role
│   ├── menotime-ecs-task-role
│   ├── menotime-lambda-role
│   └── menotime-rds-iam-db-auth-role
└── iam/policies/
    ├── developer-policy
    ├── devops-policy
    ├── dba-policy
    └── security-policy

IAM Policies by Role

Developer Role

Developers have access to DEV and STAGING environments only. They can: - Deploy applications - Access CloudWatch logs for debugging - Read (not modify) RDS in STAGING - Update S3 buckets in DEV/STAGING - View CloudFormation stacks

They cannot: - Access production RDS - Modify production security groups - Access production Secrets Manager - Delete production resources - Access production API Gateway

Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListEC2Resources",
      "Effect": "Allow",
      "Action": [
        "ec2:Describe*"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        }
      }
    },
    {
      "Sid": "DevelopmentInstanceAccess",
      "Effect": "Allow",
      "Action": [
        "ec2:StartInstances",
        "ec2:StopInstances",
        "ec2:RebootInstances",
        "ec2:GetConsoleOutput"
      ],
      "Resource": "arn:aws:ec2:us-east-1:ACCOUNT_ID:instance/*",
      "Condition": {
        "StringEquals": {
          "ec2:ResourceTag/Environment": "dev"
        }
      }
    },
    {
      "Sid": "DevelopmentRDSAccess",
      "Effect": "Allow",
      "Action": [
        "rds:DescribeDBInstances",
        "rds:DescribeDBClusters",
        "rds-db:connect"
      ],
      "Resource": "arn:aws:rds:us-east-1:ACCOUNT_ID:db/menotime-dev*"
    },
    {
      "Sid": "StagingRDSReadOnly",
      "Effect": "Allow",
      "Action": [
        "rds:DescribeDBInstances"
      ],
      "Resource": "arn:aws:rds:us-east-1:ACCOUNT_ID:db/menotime-staging*"
    },
    {
      "Sid": "ECSDeployment",
      "Effect": "Allow",
      "Action": [
        "ecs:UpdateService",
        "ecs:DescribeServices",
        "ecs:DescribeTaskDefinition",
        "ecs:RegisterTaskDefinition"
      ],
      "Resource": [
        "arn:aws:ecs:us-east-1:ACCOUNT_ID:service/menotime-dev/*",
        "arn:aws:ecs:us-east-1:ACCOUNT_ID:service/menotime-staging/*"
      ]
    },
    {
      "Sid": "CloudWatchLogsAccess",
      "Effect": "Allow",
      "Action": [
        "logs:GetLogEvents",
        "logs:DescribeLogStreams",
        "logs:DescribeLogGroups"
      ],
      "Resource": "arn:aws:logs:us-east-1:ACCOUNT_ID:log-group:/menotime/dev*"
    },
    {
      "Sid": "S3DevAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::menotime-dev-*",
        "arn:aws:s3:::menotime-dev-*/*"
      ]
    },
    {
      "Sid": "ProhibitProductionAccess",
      "Effect": "Deny",
      "Action": "*",
      "Resource": [
        "arn:aws:rds:*:ACCOUNT_ID:db/menotime-prod*",
        "arn:aws:s3:::menotime-prod-*",
        "arn:aws:secretsmanager:*:ACCOUNT_ID:secret:menotime/prod/*"
      ]
    }
  ]
}

DevOps/SRE Role

DevOps engineers have infrastructure management access across all environments.

They can: - Launch and terminate EC2 instances - Manage RDS databases (create snapshots, modify parameters) - Update IAM roles and policies - Manage CloudFormation stacks - Access all CloudWatch logs - Manage auto-scaling groups - Update VPC and security group rules - Access Secrets Manager (STAGING/PROD, limited)

They cannot: - Delete production data or resources without multi-approval - Modify IAM user accounts - View application source code - Directly access database contents

Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EC2FullManagement",
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "RDSManagement",
      "Effect": "Allow",
      "Action": [
        "rds:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotLike": {
          "aws:RequestedRegion": "eu-*"
        }
      }
    },
    {
      "Sid": "IAMRoleManagement",
      "Effect": "Allow",
      "Action": [
        "iam:CreateRole",
        "iam:PutRolePolicy",
        "iam:UpdateAssumeRolePolicy",
        "iam:AttachRolePolicy",
        "iam:DetachRolePolicy",
        "iam:ListRole*",
        "iam:GetRole*"
      ],
      "Resource": "arn:aws:iam::ACCOUNT_ID:role/menotime-*",
      "Condition": {
        "StringNotLike": {
          "iam:RoleName": "menotime-root-*"
        }
      }
    },
    {
      "Sid": "CloudWatchFullAccess",
      "Effect": "Allow",
      "Action": [
        "logs:*",
        "cloudwatch:*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "SecretsManagerProd",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": "arn:aws:secretsmanager:*:ACCOUNT_ID:secret:menotime/prod/*",
      "Condition": {
        "StringEquals": {
          "aws:username": "sre-team-only"
        }
      }
    },
    {
      "Sid": "ProhibitDestructiveActions",
      "Effect": "Deny",
      "Action": [
        "rds:DeleteDBInstance",
        "s3:DeleteBucket",
        "ec2:TerminateInstances"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        },
        "StringLike": {
          "aws:userid": "*:menotime-prod"
        }
      }
    }
  ]
}

Database Administrator Role

Database administrators manage RDS instances and can perform administrative operations.

They can: - Modify database parameters - Create and restore snapshots - Manage database users and authentication - Monitor performance and logs - Create temporary access for developers (limited, monitored)

They cannot: - View application source code - Modify AWS account settings - Delete databases without multi-approval - Access other AWS resources outside RDS

Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RDSAdministration",
      "Effect": "Allow",
      "Action": [
        "rds:DescribeDBInstances",
        "rds:DescribeDBClusters",
        "rds:DescribeDBClusterEndpoints",
        "rds:ModifyDBInstance",
        "rds:ModifyDBCluster",
        "rds:CreateDBSnapshot",
        "rds:RestoreDBInstanceFromDBSnapshot",
        "rds:ListTagsForResource",
        "rds:AddTagsToResource",
        "rds:DescribeDBClusterSnapshots"
      ],
      "Resource": "arn:aws:rds:*:ACCOUNT_ID:db/*"
    },
    {
      "Sid": "RDSIAMDatabaseAuth",
      "Effect": "Allow",
      "Action": [
        "rds-db:connect"
      ],
      "Resource": "arn:aws:rds-db:*:ACCOUNT_ID:dbuser:*/iamdb"
    },
    {
      "Sid": "CloudWatchRDSMetrics",
      "Effect": "Allow",
      "Action": [
        "logs:GetLogEvents",
        "logs:DescribeLogStreams"
      ],
      "Resource": "arn:aws:logs:*:ACCOUNT_ID:log-group:/aws/rds/*"
    },
    {
      "Sid": "SecretsManagerRDSRead",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:*:ACCOUNT_ID:secret:menotime/*/rds/*"
    }
  ]
}

Security Role (Audit/Monitoring)

Security team members can audit and monitor systems but have limited modification access.

They can: - View all CloudTrail logs - Access AWS Security Hub findings - Review IAM policies and roles - Monitor GuardDuty alerts - Read CloudWatch logs - List all IAM users and roles

They cannot: - Modify anything (read-only) - Access application data or databases - Modify security configurations

Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CloudTrailAccess",
      "Effect": "Allow",
      "Action": [
        "cloudtrail:LookupEvents",
        "cloudtrail:GetTrailStatus"
      ],
      "Resource": "*"
    },
    {
      "Sid": "SecurityHubAccess",
      "Effect": "Allow",
      "Action": [
        "securityhub:GetFindings",
        "securityhub:GetInsights",
        "securityhub:ListInsights"
      ],
      "Resource": "*"
    },
    {
      "Sid": "GuardDutyAccess",
      "Effect": "Allow",
      "Action": [
        "guardduty:GetFindings",
        "guardduty:ListDetectors",
        "guardduty:ListFindings"
      ],
      "Resource": "*"
    },
    {
      "Sid": "IAMReadOnly",
      "Effect": "Allow",
      "Action": [
        "iam:GetUser",
        "iam:GetRole",
        "iam:GetPolicy",
        "iam:ListUsers",
        "iam:ListRoles",
        "iam:ListPolicies",
        "iam:GetLoginProfile",
        "iam:ListMFADevices"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudWatchLogsReadOnly",
      "Effect": "Allow",
      "Action": [
        "logs:GetLogEvents",
        "logs:DescribeLogStreams",
        "logs:DescribeLogGroups"
      ],
      "Resource": "arn:aws:logs:*:ACCOUNT_ID:log-group:*"
    }
  ]
}

Environment-Specific Access

MenoTime maintains three environments with increasingly restrictive access.

DEV Environment

Purpose: Development and feature testing Data: Test data only; no real patient PHI Access: All developers Credentials: Shared-acceptable (for testing only); rotated every 60 days

# terraform/dev-access.tf
resource "aws_iam_policy" "dev_access" {
  name = "menotime-dev-access"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "ec2:*",
          "ecs:*",
          "cloudformation:*",
          "s3:*",
          "rds:*",
          "logs:*"
        ]
        Resource = "*"
        Condition = {
          StringEquals = {
            "aws:RequestedRegion" = "us-east-1"
          }
          StringLike = {
            "aws:userid" = "*:menotime-dev"
          }
        }
      }
    ]
  })
}

STAGING Environment

Purpose: Pre-production validation and testing Data: De-identified production-like data; no real PHI Access: Developers + QA/Testing team Credentials: Separate from PROD; rotated every 45 days

# terraform/staging-access.tf
resource "aws_iam_policy" "staging_access" {
  name = "menotime-staging-access"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = ["ecs:UpdateService", "ecs:DescribeServices"]
        Resource = "arn:aws:ecs:us-east-1:ACCOUNT_ID:service/menotime-staging/*"
      },
      {
        Effect   = "Allow"
        Action   = ["logs:GetLogEvents", "logs:DescribeLogStreams"]
        Resource = "arn:aws:logs:us-east-1:ACCOUNT_ID:log-group:/menotime/staging*"
      },
      {
        Effect   = "Allow"
        Action   = ["rds:DescribeDBInstances"]
        Resource = "arn:aws:rds:us-east-1:ACCOUNT_ID:db/menotime-staging*"
      },
      {
        Effect   = "Deny"
        Action   = ["secretsmanager:GetSecretValue"]
        Resource = "arn:aws:secretsmanager:*:ACCOUNT_ID:secret:menotime/prod/*"
      }
    ]
  })
}

PROD Environment

Purpose: Production system serving real patients Data: Real patient PHI (RESTRICTED classification) Access: Limited to DevOps/SRE team and on-call staff Credentials: Individual credentials; rotated every 30 days; highly restricted MFA: Mandatory for all access Approval: Changes require multi-approval process

# terraform/prod-access.tf
resource "aws_iam_policy" "prod_access" {
  name = "menotime-prod-access"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "ProdReadOnly"
        Effect = "Allow"
        Action = [
          "ec2:DescribeInstances",
          "ecs:DescribeServices",
          "rds:DescribeDBInstances"
        ]
        Resource = "*"
      },
      {
        Sid    = "ProdModifyWithApproval"
        Effect = "Allow"
        Action = [
          "ecs:UpdateService",
          "rds:CreateDBSnapshot"
        ]
        Resource = "*"
        Condition = {
          StringEquals = {
            "aws:username" = "sre-on-call"
          }
        }
      },
      {
        Sid    = "ProhibitDeletion"
        Effect = "Deny"
        Action = [
          "rds:DeleteDBInstance",
          "s3:DeleteBucket",
          "ec2:TerminateInstances"
        ]
        Resource = "*"
      }
    ]
  })
}

Service Roles (ECS Tasks, Lambda)

Applications running in ECS and Lambda do not use human IAM users. Instead, they assume service roles that grant only the permissions needed to run.

ECS Task Role

The ECS task role grants permissions for application containers to access AWS services.

# terraform/ecs-task-role.tf
resource "aws_iam_role" "ecs_task_role" {
  name = "menotime-ecs-task-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy" "ecs_task_policy" {
  name = "menotime-ecs-task-policy"
  role = aws_iam_role.ecs_task_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "ReadSecretsManager"
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue"
        ]
        Resource = "arn:aws:secretsmanager:*:ACCOUNT_ID:secret:menotime/prod/*"
      },
      {
        Sid    = "CloudWatchLogs"
        Effect = "Allow"
        Action = [
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "arn:aws:logs:*:ACCOUNT_ID:log-group:/menotime/prod*"
      },
      {
        Sid    = "RDSAccess"
        Effect = "Allow"
        Action = [
          "rds-db:connect"
        ]
        Resource = "arn:aws:rds-db:*:ACCOUNT_ID:dbuser:*/menotime_app"
      },
      {
        Sid    = "S3Access"
        Effect = "Allow"
        Action = [
          "s3:GetObject",
          "s3:PutObject"
        ]
        Resource = "arn:aws:s3:::menotime-prod-data/*"
      }
    ]
  })
}

Lambda Execution Role

Lambda functions assume an execution role to access AWS services.

# terraform/lambda-role.tf
resource "aws_iam_role" "lambda_execution_role" {
  name = "menotime-lambda-execution-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
  role       = aws_iam_role.lambda_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# Custom policy for application-specific permissions
resource "aws_iam_role_policy" "lambda_policy" {
  name = "menotime-lambda-policy"
  role = aws_iam_role.lambda_execution_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "dynamodb:GetItem",
          "dynamodb:Query"
        ]
        Resource = "arn:aws:dynamodb:*:ACCOUNT_ID:table/menotime-*"
      }
    ]
  })
}

Database Access Control

IAM Database Authentication

Instead of passwords, RDS database access is controlled via IAM roles.

PostgreSQL IAM Authentication:

# terraform/rds-iam-auth.tf
# Enable IAM auth on RDS
resource "aws_db_instance" "menotime_prod" {
  # ... other config ...
  iam_database_authentication_enabled = true
}

# Create database user that authenticates via IAM
# (Run this in the database)
resource "aws_db_subnet_group" "menotime" {
  name       = "menotime-subnet-group"
  subnet_ids = [aws_subnet.private1.id, aws_subnet.private2.id]
}

# Create an IAM role for the application
resource "aws_iam_role" "rds_iam_auth_role" {
  name = "menotime-rds-iam-auth-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::ACCOUNT_ID:role/menotime-ecs-task-role"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy" "rds_iam_auth_policy" {
  name = "menotime-rds-iam-auth-policy"
  role = aws_iam_role.rds_iam_auth_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "rds-db:connect"
        ]
        Resource = "arn:aws:rds-db:us-east-1:ACCOUNT_ID:dbuser:*/menotime_app"
      }
    ]
  })
}

Application Connection (Python):

import boto3
import psycopg2

# Get auth token from RDS service
rds_client = boto3.client('rds')

token = rds_client.generate_db_auth_token(
    DBHostname='menotime-prod.cluster-xxx.us-east-1.rds.amazonaws.com',
    Port=5432,
    DBUser='menotime_app',
    Region='us-east-1'
)

# Connect using token as password
conn = psycopg2.connect(
    host='menotime-prod.cluster-xxx.us-east-1.rds.amazonaws.com',
    user='menotime_app',
    password=token,
    database='menotime_prod',
    ssl='require'
)

Security Groups

Network security groups control which IP addresses can connect to the database.

# terraform/security-groups.tf
resource "aws_security_group" "rds_prod" {
  name        = "menotime-rds-prod-sg"
  description = "Security group for MenoTime production RDS"
  vpc_id      = aws_vpc.menotime.id

  # Allow connections from application security group only
  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.app_prod.id]
    description     = "PostgreSQL from application servers"
  }

  # Allow connections from bastion host for emergency access
  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.bastion.id]
    description     = "PostgreSQL from bastion (temporary access only)"
  }

  # Deny all egress (databases don't need outbound)
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = []
    description = "No outbound access"
  }

  tags = {
    Name = "menotime-rds-prod-sg"
  }
}

Temporary Database Access

If developers or DBAs need temporary database access:

  1. Request temporary access from DBA with business justification
  2. DBA creates temporary database user with limited permissions
  3. Connection limited to 4 hours (auto-revoked)
  4. All queries logged in pgAudit
  5. Audit log reviewed after session ends
-- DBA: Create temporary user for 4 hours
CREATE USER temp_access WITH PASSWORD 'randompassword123!';
ALTER USER temp_access SET log_statement = 'all';

-- Grant limited read-only access
GRANT CONNECT ON DATABASE menotime_prod TO temp_access;
GRANT USAGE ON SCHEMA public TO temp_access;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO temp_access;

-- Set session time limit (4 hours)
ALTER USER temp_access VALID UNTIL '2024-01-15 14:00:00';

-- DBA: Drop user after session
DROP USER temp_access;

Contractors and Temporary Access

Contractors and vendors may need temporary AWS access. Access is granted with additional restrictions.

Contractor Access Process:

  1. Onboarding approval from manager and Security Officer
  2. NDA and BAA executed before any access
  3. Temporary IAM user created with expiration date
  4. Limited scope of permissions (specific project only)
  5. MFA enforced from day 1
  6. Weekly audit of contractor access
  7. Offboarding on contract end date (automatic access revocation)

Contractor Policy Example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ContractorProjectAccess",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "ecs:DescribeServices"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:username": "contractor-john-doe"
        },
        "DateGreaterThan": {
          "aws:CurrentTime": "2024-01-01T00:00:00Z"
        },
        "DateLessThan": {
          "aws:CurrentTime": "2024-03-31T23:59:59Z"
        }
      }
    },
    {
      "Sid": "ContractorProhibitProduction",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "arn:aws:*:*:ACCOUNT_ID:*",
      "Condition": {
        "StringLike": {
          "aws:userid": "*:menotime-prod"
        }
      }
    }
  ]
}

Audit and Compliance

Quarterly Access Reviews

Every quarter, access is reviewed and documented.

Review Checklist:

  • ✓ Verify all IAM users are still active employees
  • ✓ Confirm each user's access matches their current role
  • ✓ Remove access for employees who changed roles
  • ✓ Audit CloudTrail logs for unauthorized actions
  • ✓ Verify MFA is enabled for all users
  • ✓ Check for unused or stale access credentials
  • ✓ Document review results and approvals

Access Violation Consequences

  • First violation: Warning and immediate access removal
  • Repeated violations: Suspension from AWS access; escalation to management
  • Severe violations: Disciplinary action up to termination

Questions? Contact the Security Officer at security@timelessbiotech.com.