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:
- Manager review (manager confirms access is still needed)
- System audit (infrastructure team audits actual access in CloudTrail)
- Access removal (access removed if no longer necessary)
- Approval (Security Officer reviews and documents)
- 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:
- Request temporary access from DBA with business justification
- DBA creates temporary database user with limited permissions
- Connection limited to 4 hours (auto-revoked)
- All queries logged in pgAudit
- 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:
- Onboarding approval from manager and Security Officer
- NDA and BAA executed before any access
- Temporary IAM user created with expiration date
- Limited scope of permissions (specific project only)
- MFA enforced from day 1
- Weekly audit of contractor access
- 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.