AWS IAM Policy Reference
This document outlines the IAM permissions required for NightOps to manage AWS resources. The policy follows the principle of least privilege, granting only the permissions necessary for each operation.
Quick Start
For a quick setup, use the complete policy below. For more granular control, see the Per-Service Policies section.
Complete NightOps Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2ReadAccess",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "EC2WriteAccess",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/nightops:managed": "true"
}
}
},
{
"Sid": "RDSReadAccess",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:ListTagsForResource"
],
"Resource": "*"
},
{
"Sid": "RDSWriteAccess",
"Effect": "Allow",
"Action": [
"rds:StartDBInstance",
"rds:StopDBInstance"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"rds:db-tag/nightops:managed": "true"
}
}
},
{
"Sid": "ECSReadAccess",
"Effect": "Allow",
"Action": [
"ecs:ListClusters",
"ecs:ListServices",
"ecs:DescribeServices",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "ECSWriteAccess",
"Effect": "Allow",
"Action": [
"ecs:UpdateService"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ecs:ResourceTag/nightops:managed": "true"
}
}
},
{
"Sid": "EKSReadAccess",
"Effect": "Allow",
"Action": [
"eks:ListClusters",
"eks:ListNodegroups",
"eks:DescribeCluster",
"eks:DescribeNodegroup"
],
"Resource": "*"
},
{
"Sid": "EKSWriteAccess",
"Effect": "Allow",
"Action": [
"eks:UpdateNodegroupConfig"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"eks:ResourceTag/nightops:managed": "true"
}
}
},
{
"Sid": "RedshiftReadAccess",
"Effect": "Allow",
"Action": [
"redshift:DescribeClusters",
"redshift:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "RedshiftWriteAccess",
"Effect": "Allow",
"Action": [
"redshift:PauseCluster",
"redshift:ResumeCluster"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"redshift:ResourceTag/nightops:managed": "true"
}
}
},
{
"Sid": "AutoScalingReadAccess",
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "AutoScalingWriteAccess",
"Effect": "Allow",
"Action": [
"autoscaling:UpdateAutoScalingGroup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/nightops:managed": "true"
}
}
}
]
}
Per-Service Policies
Use these individual policies if you only need NightOps to manage specific services.
EC2 Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2ReadAccess",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "EC2WriteAccess",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/nightops:managed": "true"
}
}
}
]
}
RDS Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RDSReadAccess",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:ListTagsForResource"
],
"Resource": "*"
},
{
"Sid": "RDSWriteAccess",
"Effect": "Allow",
"Action": [
"rds:StartDBInstance",
"rds:StopDBInstance"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"rds:db-tag/nightops:managed": "true"
}
}
}
]
}
ECS Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECSReadAccess",
"Effect": "Allow",
"Action": [
"ecs:ListClusters",
"ecs:ListServices",
"ecs:DescribeServices",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "ECSWriteAccess",
"Effect": "Allow",
"Action": [
"ecs:UpdateService"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ecs:ResourceTag/nightops:managed": "true"
}
}
}
]
}
EKS Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EKSReadAccess",
"Effect": "Allow",
"Action": [
"eks:ListClusters",
"eks:ListNodegroups",
"eks:DescribeCluster",
"eks:DescribeNodegroup"
],
"Resource": "*"
},
{
"Sid": "EKSWriteAccess",
"Effect": "Allow",
"Action": [
"eks:UpdateNodegroupConfig"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"eks:ResourceTag/nightops:managed": "true"
}
}
}
]
}
Redshift Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RedshiftReadAccess",
"Effect": "Allow",
"Action": [
"redshift:DescribeClusters",
"redshift:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "RedshiftWriteAccess",
"Effect": "Allow",
"Action": [
"redshift:PauseCluster",
"redshift:ResumeCluster"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"redshift:ResourceTag/nightops:managed": "true"
}
}
}
]
}
Auto Scaling Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AutoScalingReadAccess",
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "AutoScalingWriteAccess",
"Effect": "Allow",
"Action": [
"autoscaling:UpdateAutoScalingGroup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/nightops:managed": "true"
}
}
}
]
}
Cross-Account Access
For multi-account setups, create a role in each spoke account that NightOps can assume.
Trust Policy (Spoke Account)
Replace HUB_ACCOUNT_ID with your NightOps hub account ID:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::HUB_ACCOUNT_ID:role/NightOpsExecutionRole"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "YOUR_EXTERNAL_ID"
}
}
}
]
}
Hub Account Policy
The NightOps execution role in the hub account needs permission to assume roles in spoke accounts:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AssumeRoleInSpokeAccounts",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::*:role/NightOpsRole"
}
]
}
Permission Boundaries
For additional security, you can create a permission boundary that limits what NightOps can do:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyTaggedResources",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"rds:StartDBInstance",
"rds:StopDBInstance",
"ecs:UpdateService",
"eks:UpdateNodegroupConfig",
"redshift:PauseCluster",
"redshift:ResumeCluster",
"autoscaling:UpdateAutoScalingGroup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/nightops:managed": "true"
}
}
},
{
"Sid": "DenyDestructiveActions",
"Effect": "Deny",
"Action": [
"ec2:TerminateInstances",
"rds:DeleteDBInstance",
"ecs:DeleteService",
"eks:DeleteNodegroup",
"redshift:DeleteCluster",
"autoscaling:DeleteAutoScalingGroup"
],
"Resource": "*"
}
]
}
Permissions Summary Table
| Service | Read Actions | Write Actions |
|---|---|---|
| EC2 | DescribeInstances, DescribeInstanceStatus, DescribeTags | StartInstances, StopInstances |
| RDS | DescribeDBInstances, ListTagsForResource | StartDBInstance, StopDBInstance |
| ECS | ListClusters, ListServices, DescribeServices, DescribeClusters | UpdateService |
| EKS | ListClusters, ListNodegroups, DescribeCluster, DescribeNodegroup | UpdateNodegroupConfig |
| Redshift | DescribeClusters, DescribeTags | PauseCluster, ResumeCluster |
| ASG | DescribeAutoScalingGroups, DescribeTags | UpdateAutoScalingGroup |
| STS | - | AssumeRole (hub account only) |
Security Best Practices
All write actions are conditioned on the nightops:managed=true tag. This ensures NightOps can only modify resources explicitly opted-in for management.
Always use an External ID when configuring cross-account access to prevent the confused deputy problem.
Periodically review CloudTrail logs to audit NightOps actions and ensure only expected resources are being managed.
Next Steps
- AWS Supported Services - Learn about supported services