Create Least Privilege Policies

If you want a more streamlined method to create the least privilege policies and a cross-account role, use the CloudFormation template.
Prerequisite: We recommend that you create a CloudCheckr account before you create least privilege policies.

As part of your account preparation, you will create least privilege policies—individual policies you will attach to your cross-account role that allow CloudCheckr to access the AWS data it needs to create its reports.

Each least privilege policy provides permissions to a core function in our application:

  • Cost
  • Billing
  • Security/Compliance
  • Inventory
  • CloudTrail
  • CloudWatch Flow Logs

In theory, it may seem like one big policy would be easier to manage. But, by applying only selected policies, you ensures that whoever uses the cross-account role only has access to the permissions they need to do their job—and nothing more.

This procedure will show you how to create the least privileged policies in the AWS Management Console.


Procedure

  1. Log in to the AWS Management Console.
    The AWS services page opens.
  2. Scroll down to the Security, Identity & Compliance section and select IAM.
    The Welcome to Identity and Access Management screen displays.
  3. From the dashboard, click Policies.
    A list of policies displays.
  4. Click Create policy.
    The Create Policy page opens.
  5. For each core function of CloudCheckr that you want a cross-account role to have access to, follow these steps:
    1. Click a button to display the selected policy document.
      {
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"CloudCheckrCostPermissions",
      "Effect":"Allow",
      "Action":[
      "ce:GetReservationUtilization",
      "ce:GetSavingsPlansPurchaseRecommendation",
      "ec2:DescribeAccountAttributes",
      "ec2:DescribeAvailabilityZones",
      "ec2:DescribeReservedInstancesOfferings",
      "ec2:DescribeReservedInstances",
      "ec2:DescribeReservedInstancesListings",
      "ec2:DescribeHostReservationOfferings",
      "ec2:DescribeReservedInstancesModifications",
      "ec2:DescribeHostReservations",
      "ec2:DescribeInstances",
      "ec2:DescribeInstanceStatus",
      "ec2:DescribeRegions",
      "ec2:DescribeKeyPairs",
      "ec2:DescribePlacementGroups",
      "ec2:DescribeAddresses",
      "ec2:DescribeSpotInstanceRequests",
      "ec2:DescribeImages",
      "ec2:DescribeImageAttribute",
      "ec2:DescribeSnapshots",
      "ec2:DescribeVolumes",
      "ec2:DescribeTags",
      "ec2:DescribeNetworkInterfaces",
      "ec2:DescribeSecurityGroups",
      "ec2:DescribeInstanceAttribute",
      "ec2:DescribeVolumeStatus",
      "elasticache:DescribeReservedCacheNodes",
      "elasticache:DescribeReservedCacheNodesOfferings",
      "rds:DescribeReservedDBInstances",
      "rds:DescribeReservedDBInstancesOfferings",
      "rds:DescribeDBInstances",
      "redshift:DescribeReservedNodes",
      "redshift:DescribeReservedNodeOfferings",
      "s3:GetBucketACL",
      "s3:GetBucketLocation",
      "s3:GetBucketLogging",
      "s3:GetBucketPolicy",
      "s3:GetBucketTagging",
      "s3:GetBucketWebsite",
      "s3:GetBucketNotification",
      "s3:GetLifecycleConfiguration",
      "s3:List*",
      "dynamodb:DescribeReservedCapacity",
      "dynamodb:DescribeReservedCapacityOfferings",
      "iam:GetAccountAuthorizationDetails",
      "iam:ListRolePolicies",
      "iam:ListAttachedRolePolicies",
      "savingsplans:DescribeSavingsPlans"
      ],
      "Resource":"*"
      }
      ]
      }
      {
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"CostReadDBR",
      "Effect":"Allow",
      "Action":[
      "s3:GetBucketACL",
      "s3:GetBucketLocation",
      "s3:GetBucketLogging",
      "s3:GetBucketPolicy",
      "s3:GetBucketTagging",
      "s3:GetBucketWebsite",
      "s3:GetBucketNotification",
      "s3:GetLifecycleConfiguration",
      "s3:GetNotificationConfiguration",
      "s3:GetObject"
      ],
      "Resource":[
      "arn:aws:s3:::[YOUR DETAILED BILLING REPORT BUCKET]",
      "arn:aws:s3:::[YOUR DETAILED BILLING REPORT BUCKET]/*"
      ]
      }
      ]
      }
      {
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"CostReadCUR",
      "Effect":"Allow",
      "Action":[
      "s3:GetObject"
      ],
      "Resource":[
      "arn:aws:s3:::[YOUR COST AND USAGE REPORT BUCKET]",
      "arn:aws:s3:::[YOUR COST AND USAGE REPORT BUCKET]/*"
      ]
      }
      ]
      }
      {
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"Stmt1443712554000",
      "Effect":"Allow",
      "Action":[
      "s3:DeleteObject",
      "s3:GetBucketLocation",
      "s3:ListObject",
      "s3:PutObject",
      ],
      "Resource":[
      "arn:aws:s3:::your-target-S3-bucket-name-here*"
      ]
      }
      ]
      }
      { 
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"SecurityPermissons",
      "Effect":"Allow",
      "Action":[
      "acm:DescribeCertificate",
      "acm:ListCertificates",
      "acm:GetCertificate",
      "cloudtrail:DescribeTrails",
      "cloudtrail:GetTrailStatus",
      "logs:GetLogEvents",
      "logs:DescribeLogGroups",
      "logs:DescribeLogStreams",
      "config:DescribeConfigRules",
      "config:GetComplianceDetailsByConfigRule",
      "config:DescribeDeliveryChannels",
      "config:DescribeDeliveryChannelStatus",
      "config:DescribeConfigurationRecorders",
      "config:DescribeConfigurationRecorderStatus",
      "ec2:Describe*",
      "iam:Get*",
      "iam:List*",
      "iam:GenerateCredentialReport",
      "kms:DescribeKey",
      "kms:GetKeyPolicy",
      "kms:GetKeyRotationStatus",
      "kms:ListAliases",
      "kms:ListGrants",
      "kms:ListKeys",
      "kms:ListKeyPolicies",
      "kms:ListResourceTags",
      "rds:Describe*",
      "ses:ListIdentities",
      "ses:GetSendStatistics",
      "ses:GetIdentityDkimAttributes",
      "ses:GetIdentityVerificationAttributes",
      "ses:GetSendQuota",
      "sns:GetSnsTopic",
      "sns:GetTopicAttributes",
      "sns:GetSubscriptionAttributes",
      "sns:ListTopics",
      "sns:ListSubscriptionsByTopic",
      "sqs:ListQueues",
      "sqs:GetQueueAttributes"
      ],
      "Resource":"*"
      }
      ]
      }
      {
      "Version":"2012-10-17",
      "Statement":[
      {
      "Sid":"InventoryAndUtilization",
      "Effect":"Allow",
      "Action":[
      "access-analyzer:List*",
      "acm:DescribeCertificate",
      "acm:ListCertificates",
      "acm:GetCertificate",
      "ec2:Describe*",
      "ec2:GetConsoleOutput",
      "ec2:GetEbsEncryptionByDefault",
      "autoscaling:Describe*",
      "cloudformation:DescribeStacks",
      "cloudformation:GetStackPolicy",
      "cloudformation:GetTemplate",
      "cloudformation:ListStacks",
      "cloudformation:ListStackResources",
      "cloudfront:List*",
      "cloudfront:GetDistributionConfig",
      "cloudfront:GetStreamingDistributionConfig",
      "cloudhsm:Describe*",
      "cloudhsm:List*",
      "cloudsearch:Describe*",
      "cloudtrail:DescribeTrails",
      "cloudtrail:GetEventSelectors",
      "cloudtrail:GetTrailStatus",
      "cloudwatch:DescribeAlarms",
      "cloudwatch:GetMetricStatistics",
      "cloudwatch:ListMetrics",
      "cognito-identity:ListIdentities",
      "cognito-identity:ListIdentityPools",
      "cognito-idp:ListGroups",
      "cognito-idp:ListIdentityProviders",
      "cognito-idp:ListUserPools",
      "cognito-idp:ListUsers",
      "cognito-idp:ListUsersInGroup",
      "config:DescribeConfigRules",
      "config:GetComplianceDetailsByConfigRule",
      "config:Describe*",
      "datapipeline:ListPipelines",
      "datapipeline:GetPipelineDefinition",
      "datapipeline:DescribePipelines",
      "directconnect:DescribeLocations",
      "directconnect:DescribeConnections",
      "directconnect:DescribeVirtualInterfaces",
      "dynamodb:ListTables",
      "dynamodb:DescribeTable",
      "dynamodb:ListTagsOfResource",
      "ecs:ListClusters",
      "ecs:DescribeClusters",
      "ecs:ListContainerInstances",
      "ecs:DescribeContainerInstances",
      "ecs:ListServices",
      "ecs:DescribeServices",
      "ecs:ListTaskDefinitions",
      "ecs:DescribeTaskDefinition",
      "ecs:ListTasks",
      "ecs:DescribeTasks",
      "ssm:ListResourceDataSync",
      "ssm:ListAssociations",
      "ssm:ListDocumentVersions",
      "ssm:ListDocuments",
      "ssm:ListInstanceAssociations",
      "ssm:ListInventoryEntries",
      "elasticache:Describe*",
      "elasticache:List*",
      "elasticbeanstalk:Describe*",
      "elasticfilesystem:DescribeFileSystems",
      "elasticfilesystem:DescribeTags",
      "elasticloadbalancing:Describe*",
      "elasticmapreduce:Describe*",
      "elasticmapreduce:List*",
      "es:ListDomainNames",
      "es:ListTags",
      "es:DescribeElasticsearchDomains",
      "es:DescribeReservedElasticsearchInstances",
      "es:DescribeElasticsearchDomains",
      "glacier:ListTagsForVault",
      "glacier:DescribeVault",
      "glacier:GetVaultNotifications",
      "glacier:DescribeJob",
      "glacier:GetJobOutput",
      "glacier:ListJobs",
      "glacier:ListVaults",
      "iam:Get*",
      "iam:List*",
      "iam:GenerateCredentialReport",
      "iot:DescribeThing",
      "iot:ListThings",
      "kms:DescribeKey",
      "kms:GetKeyPolicy",
      "kms:GetKeyRotationStatus",
      "kms:ListAliases",
      "kms:ListGrants",
      "kms:ListKeys",
      "kms:ListKeyPolicies",
      "kms:ListResourceTags",
      "kinesis:ListStreams",
      "kinesis:DescribeStream",
      "kinesis:GetShardIterator",
      "kinesis:ListTagsForStream",
      "lambda:ListFunctions",
      "lambda:ListTags",
      "Organizations:List*",
      "Organizations:Describe*",
      "rds:Describe*",
      "rds:List*",
      "redshift:Describe*",
      "route53:ListHealthChecks",
      "route53:ListHostedZones",
      "route53:ListResourceRecordSets",
      "s3:GetBucketACL",
      "s3:GetBucketLocation",
      "s3:GetBucketLogging",
      "s3:GetBucketPolicy",
      "s3:GetBucketPublicAccessBlock",
      "s3:GetBucketTagging",
      "s3:GetBucketVersioning",
      "s3:GetBucketWebsite",
      "s3:GetBucketNotification",
      "s3:GetLifecycleConfiguration",
      "s3:List*",
      "sdb:ListDomains",
      "sdb:DomainMetadata",
      "ses:ListIdentities",
      "ses:GetSendStatistics",
      "ses:GetIdentityDkimAttributes",
      "ses:GetIdentityVerificationAttributes",
      "ses:GetSendQuota",
      "sns:GetTopicAttributes",
      "sns:GetSubscriptionAttributes",
      "sns:ListTopics",
      "sns:ListSubscriptionsByTopic",
      "sqs:ListQueues",
      "sqs:GetQueueAttributes",
      "storagegateway:Describe*",
      "storagegateway:List*",
      "support:*",
      "swf:ListClosedWorkflowExecutions",
      "swf:ListDomains",
      "swf:ListActivityTypes",
      "swf:ListWorkflowTypes",
      "wellarchitected:Get*",
      "wellarchitected:List*",
      "workspaces:DescribeWorkspaceDirectories",
      "workspaces:DescribeWorkspaceBundles",
      "workspaces:DescribeWorkspaces"
      ],
      "Resource":"*"
      }
      ]
      }
      {

      "Version":"2012-10-17",
      "Statement":[

      {
      "Sid":"CloudTrailPermissions",
      "Effect":"Allow",
      "Action":[
      "s3:GetBucketACL",
      "s3:GetBucketLocation",
      "s3:GetBucketLogging",
      "s3:GetBucketPolicy",
      "s3:GetBucketTagging",
      "s3:GetBucketWebsite",
      "s3:GetBucketNotification",
      "s3:GetLifecycleConfiguration",
      "s3:GetNotificationConfiguration",
      "s3:GetObject",
      "s3:List*"
      ],
      "Resource":[
      "arn:aws:s3:::[YOUR CLOUDTRAIL BUCKET]",
      "arn:aws:s3:::[YOUR CLOUDTRAIL BUCKET]/*"
      ]
      }
      ]
      }
      {

      "Version":"2012-10-17",
      "Statement":[

      {
      "Sid":"CloudWatchLogsSpecific",
      "Effect":"Allow",
      "Action":[

      "logs:GetLogEvents",
      "logs:DescribeLogGroups",
      "logs:DescribeLogStreams"
      ],
      "Resource":[

      "arn:aws:logs:*:*:*"
      ]
      }
      ]
      }
    2. Copy the entire contents of the policy document to your clipboard.
    3. Return to the Create Policy page in the AWS Management Console.
    4. Click the JSON tab.
    5. Replace the text in the JSON tab with the policy you just copied.
      For Billing and CloudTrail policies, replace the dummy S3 bucket name with the name of the S3 bucket where AWS stores your billing report.
    6. Click Review policy.
      The Review policy page opens.
    7. Type a name for the policy and click Create policy.
      A message at the top of the policy page indicates that your policy has been created.
  6. Repeat step 5 for each least privilege policy you want to attach to your cross-account role.
    If you are preparing your account for the first time and creating a cross-account role manually, continue to: Create a Cross-Account Role Manually.

Policy Structure Notes

CloudCheckr will attempt to ingest data from all of the AWS core features to populate the Cost, Billing, Security, Inventory, and CloudWatch Flow Log reports. Since CloudCheckr must make calls even to those categories where you have not enabled permissions, you will see Unauthorized Access attempts in your CloudTrail logs. These logs are only an indication of the CloudCheckr workflow and in no way reflect an attempt on the part of CloudCheckr to collect unauthorized information from customers.
To help you maintain a secure, least privilege configuration, CloudCheckr's Security/Compliance policy does not include any s3:GetObject permissions. But, you can add the s3:GetObject permission to the required reports.
As per the latest AWS requirements, CloudCheckr's CloudFormation template and the Inventory policy do not include the s3:GetEncryptionConfiguration by default. However, without this permission, CloudCheckr cannot get the information it needs to report on the S3 Bucket Without Default Encryption Enabled Best Practice Check (BPC). If you decide not to add this permission to your policy, we recommend that you ignore or disable this BPC to avoid any false negatives.

How did we do?