Required Permissions
20.1 Overview
MCM connects to your cloud accounts using credentials you provide directly when you onboard an account — there is no cross-account IAM role or trust relationship. The permissions attached to that credential are exactly what determine which MCM modules can function for that account and what data they can see or change.
Each module below lists the permissions required, why MCM needs each one, and a ready-to-use policy you can copy straight into your cloud provider's console. Every permission block shows a provider tab — switch between them to see what applies to each. Only enable the modules you plan to use, and grant only the permissions listed for them — this follows the principle of least privilege.
| Provider / Integration | Credential Type |
|---|---|
| AWS | Access Key ID + Secret Access Key (IAM user) |
| Azure | App Registration / Service Principal (Client ID, Client Secret, Tenant ID, Subscription ID) |
| GitHub | Personal Access Token with repository read access |
| Docker Hub | Access Token (read-only) |
| Docker | Client TLS certificate, for a self-hosted registry/host |
| Ubuntu Hosts | SSH private key or password, for a user with sudo access |
Most modules only need read/describe/list access. Each module below calls out the specific cases where MCM performs a write action in your account.
Every JSON block is a ready-to-paste AWS IAM policy or Azure custom role definition — just replace the <your-aws-account-id> / <your-subscription-id> placeholder before creating it. In AWS, paste it into IAM → Policies → Create Policy → JSON. In Azure, paste it into Subscription → Access Control (IAM) → Add custom role → JSON — the Azure JSON blocks use the same format the Portal itself expects (properties → permissions → actions), not the flatter format shown by Azure PowerShell/CLI, so it uploads without a validation error. A Download link under each block saves it as a .json file if you'd rather upload a file than copy-paste.
Policy size limit: "exceeds the non-whitespace character limit of 2048"
AWS caps the combined size of all inline policies on an IAM user at 2,048 non-whitespace characters — across every inline policy on that user, not per policy. If you paste these blocks into IAM → Users → (your user) → Add permissions → Create inline policy, you will hit this limit after one or two modules. To avoid it, create each block as a customer-managed policy instead (IAM → Policies → Create policy → JSON, limit 6,144 characters per policy) and attach it to the user, one policy per module. Managed policies don't count against the inline limit; an IAM user can have up to 10 managed policies attached by default (quota can be raised), or attach them to an IAM group and add the user to it. If you've already used the inline limit, delete or convert the existing inline policies the same way.
20.2 Discovery
Discovery performs a read-only inventory scan across every connected account — all 6 providers are supported.
| Category | Permissions | Why It's Needed |
|---|---|---|
| Account & Regions | sts:GetCallerIdentity, ec2:DescribeRegions | Confirms the credential belongs to your account during onboarding, and finds which AWS regions to scan |
| Compute | ec2:DescribeInstances, ec2:DescribeInstanceStatus, ec2:DescribeInstanceTypes, ec2:DescribeIamInstanceProfileAssociations, ec2:DescribeKeyPairs, ec2:DescribeImages | Lists your EC2 instances, their status and type, attached IAM instance profiles, key pairs, and AMIs for the resource inventory |
| Networking | ec2:DescribeVpcs, ec2:DescribeSubnets, ec2:DescribeRouteTables, ec2:DescribeInternetGateways, ec2:DescribeSecurityGroups, ec2:DescribeNetworkAcls | Maps your network topology — VPCs, subnets, routing, gateways, and security groups — into the inventory |
| Storage | ec2:DescribeVolumes, ec2:DescribeSnapshots, s3:ListAllMyBuckets, s3:GetBucketLocation, s3:GetBucketTagging, s3:GetBucketPolicy, s3:GetBucketPolicyStatus, s3:GetBucketAcl, s3:GetEncryptionConfiguration, s3:GetBucketVersioning, s3:GetBucketLogging, s3:GetBucketPublicAccessBlock, s3:GetBucketWebsite, s3:GetLifecycleConfiguration, s3:GetReplicationConfiguration, s3:GetBucketObjectLockConfiguration, s3:GetBucketNotification | Reads EBS volume/snapshot metadata, and every S3 bucket's configuration (encryption, versioning, policy, logging, replication) for the inventory |
| Database | rds:DescribeDBInstances, rds:ListTagsForResource | Lists RDS database instances and their tags |
| Containers | eks:ListClusters, eks:DescribeCluster, eks:ListTagsForResource | Lists EKS clusters and their tags |
| IAM | iam:ListPolicies, iam:GetPolicy, iam:GetPolicyVersion, iam:ListPolicyTags, iam:ListEntitiesForPolicy, iam:ListUsers, iam:GetUser, iam:ListAttachedUserPolicies, iam:ListUserPolicies, iam:GetUserPolicy, iam:ListGroupsForUser, iam:ListMFADevices, iam:GetLoginProfile, iam:ListUserTags | Reads IAM users and customer-managed policies so Discovery can include identity/access details in the inventory |
Custom Tags
Supported for both AWS and Azure.
| Permissions | Why It's Needed |
|---|---|
tag:TagResources, tag:UntagResources, ec2:CreateTags, ec2:DeleteTags, iam:TagRole, iam:TagPolicy, iam:TagUser, ce:ListCostAllocationTags, ce:UpdateCostAllocationTagsStatus, organizations:DescribeOrganization | Lets you create custom tags and apply or remove them on resources (including tagging previously untagged resources), and activates them as AWS cost allocation tags so FinOps can break down costs by tag. The Organizations check confirms the account is the management/payer account before doing this org-wide. |
Tagging an IAM role, policy, or user through tag:TagResources also requires that IAM resource's own tag action — AWS treats the generic Resource Groups Tagging API as a proxy that still checks the underlying service's permission, so iam:TagRole / iam:TagPolicy / iam:TagUser are needed alongside tag:TagResources, not instead of it. The same applies to removing tags (iam:UntagRole / iam:UntagPolicy / iam:UntagUser) if you use that capability.
20.3 FinOps
20.3.1 Cost & Usage Report
MCM ingests your Cost & Usage Report (CUR) / Cost Details export on an ongoing basis. On AWS, if your account doesn't already have a CUR configured, MCM creates one automatically — there's currently no option to point MCM at an existing export without letting it manage the setup, so both the read and setup permissions are needed together.
| Permissions | Why It's Needed |
|---|---|
s3:ListBucket, s3:GetObject, s3:DeleteObject, s3:CreateBucket, s3:PutBucketPolicy, s3:PutBucketTagging, bcm-data-exports:ListExports, bcm-data-exports:GetExport, bcm-data-exports:CreateExport | Creates the S3 bucket and Data Export definition if one doesn't already exist, then reads the daily Cost & Usage Report files from it going forward — removing files after they've been processed to limit storage growth |
This bucket and export always use MCM's own fixed naming convention — bucket mcm-cur-<your-aws-account-id> and export mcm-cur-report — so, unlike most permissions on this page, this one can be scoped to those exact resources instead of Resource: "*".
20.3.2 Cost Forecasting
| Permissions | Why It's Needed |
|---|---|
ce:GetCostForecast | Powers the Forecast dashboard by asking AWS Cost Explorer to project future spend |
20.3.3 Recommendations (Right-Sizing, Reserved Instances, Savings Plans)
| Permissions | Why It's Needed |
|---|---|
compute-optimizer:GetEC2InstanceRecommendations, compute-optimizer:GetAutoScalingGroupRecommendations, compute-optimizer:GetEBSVolumeRecommendations, compute-optimizer:GetLambdaFunctionRecommendations, compute-optimizer:GetECSServiceRecommendations, compute-optimizer:GetRDSDatabaseRecommendations, ce:GetReservationPurchaseRecommendation, ce:GetSavingsPlansPurchaseRecommendation | Compute Optimizer actions drive Right-Sizing recommendations; the two Cost Explorer actions drive Reserved Instance and Savings Plan recommendations |
Tag Compliance reporting and Budget Management are evaluated from data already ingested above — neither needs any additional cloud provider permissions.
20.4 Governance
Governance runs read-only compliance checks (CIS Benchmark, GDPR, HIPAA, ISO, NIST, SOC 2) against your connected accounts and hosts. None of MCM's built-in policies modify or remediate anything automatically — every permission below only grants read access or, for Ubuntu, the ability to run a check script.
| Category | Permissions | Why It's Needed |
|---|---|---|
| Account, IAM & Access | iam:GetAccountPasswordPolicy, iam:GetAccountSummary, iam:GenerateCredentialReport, iam:GetCredentialReport, iam:ListUsers, iam:ListRoles, iam:ListPolicies, iam:ListGroups, iam:ListMFADevices, iam:ListUserPolicies, iam:ListRolePolicies, iam:GetRolePolicy, iam:ListAttachedGroupPolicies, iam:GetPolicyVersion, access-analyzer:ListAnalyzers | Evaluates password policy, MFA enrollment, credential age, and inline/attached IAM policies against framework controls |
| Logging & Monitoring | cloudtrail:DescribeTrails, cloudtrail:GetTrailStatus, config:DescribeConfigurationRecorders, config:DescribeConfigurationRecorderStatus, guardduty:ListDetectors, guardduty:GetDetector, logs:DescribeLogGroups | Confirms CloudTrail, AWS Config, and GuardDuty are enabled, as required by most compliance frameworks |
| Storage | s3:ListAllMyBuckets, s3:GetAccountPublicAccessBlock, s3:GetBucketLocation, s3:GetBucketAcl, s3:GetBucketPolicy, s3:GetBucketPolicyStatus, s3:GetBucketPublicAccessBlock, s3:GetEncryptionConfiguration, s3:GetBucketVersioning, s3:GetBucketLogging, s3:GetLifecycleConfiguration, s3:GetBucketObjectLockConfiguration, efs:DescribeFileSystems | Checks S3 bucket encryption, public access, versioning, and logging configuration, plus EFS file-system existence |
| Compute & Network | ec2:DescribeInstances, ec2:DescribeSecurityGroups, ec2:DescribeImages, ec2:DescribeVolumes, ec2:DescribeSnapshots, ec2:DescribeSnapshotAttribute, ec2:DescribeVpcs, ec2:DescribeFlowLogs, ec2:DescribeNetworkAcls, elasticloadbalancing:DescribeLoadBalancers, elasticloadbalancing:DescribeLoadBalancerAttributes, elasticloadbalancing:DescribeListeners | Checks security group exposure, EBS/snapshot public sharing, VPC flow log coverage, and load balancer logging |
| Database & Storage Services | rds:DescribeDBInstances, dynamodb:ListTables, dynamodb:DescribeTable, backup:ListBackupVaults | Checks RDS encryption/backup retention, DynamoDB table configuration, and backup vault existence |
| Encryption & Secrets | kms:ListKeys, kms:DescribeKey, kms:GetKeyRotationStatus, kms:GetKeyPolicy, secretsmanager:ListSecrets, ssm:DescribeParameters, acm:ListCertificates, acm:DescribeCertificate | Checks KMS key rotation and key policy exposure, Secrets Manager/SSM parameter existence, and ACM certificate expiry |
| Serverless & Messaging | lambda:ListFunctions, lambda:GetPolicy, sns:ListTopics, sns:GetTopicAttributes, sqs:ListQueues, sqs:GetQueueAttributes | Checks Lambda function resource policies for public exposure, and SNS/SQS topic/queue configuration |
| Containers & Other | ecr:DescribeRepositories, securityhub:GetFindings, guardduty:ListFindings, guardduty:GetFindings, shield:ListProtections, shield:DescribeSubscription | Folds in existing GuardDuty/Security Hub findings and Shield subscription status |
The AWS managed policies SecurityAudit and ViewOnlyAccess, attached together, cover most of the table above. The notable gaps you'll need to add explicitly are: s3:GetAccountPublicAccessBlock, iam:GenerateCredentialReport, iam:GetCredentialReport, kms:GetKeyPolicy, lambda:GetPolicy, sns:GetTopicAttributes, sqs:GetQueueAttributes, and shield:DescribeSubscription.
20.5 SecOps
20.5.1 Audit Log Security Scanning (AWS only)
MCM provisions a dedicated CloudTrail trail and S3 log bucket in your account if one doesn't already exist, then reads from it on an ongoing basis.
| Permissions | Why It's Needed |
|---|---|
s3:CreateBucket, s3:ListBucket, s3:GetObject, s3:PutBucketPolicy, s3:DeleteObject, s3:ListBucketVersions, s3:DeleteBucket, cloudtrail:DescribeTrails, cloudtrail:CreateTrail, cloudtrail:PutEventSelectors, cloudtrail:StartLogging, cloudtrail:StopLogging, cloudtrail:UpdateTrail, cloudtrail:DeleteTrail, cloudtrail:GetTrailStatus | Creates (if missing) and continuously reads a dedicated CloudTrail trail and S3 log bucket, so MCM can analyze account activity for security findings |
This bucket and trail always use MCM's own fixed naming convention — bucket mcm-cloudtrail-<your-aws-account-id> and trail mcm-cloudtrail — so, unlike most permissions on this page, this one can be scoped to those exact resources instead of Resource: "*".
20.5.2 Container Security (Docker Hub only)
| Permissions | Why It's Needed |
|---|---|
| Read-only access permission (set when creating the token under Account Settings → Security → Access Tokens) | Lets MCM pull your images so Trivy can scan them for vulnerabilities |
20.5.3 Source Code Security (GitHub)
| Permissions | Why It's Needed |
|---|---|
repo scope on a classic token, or Contents: Read-only on a fine-grained token | Lets MCM clone your repository so Trivy can scan it locally for vulnerabilities, secrets, and misconfigurations. No code-scanning, Dependabot, or secret-scanning API scopes are needed. |
20.5.4 Host Security (Ubuntu)
Host scanning is not an IAM/RBAC model — it's direct OS-level access.
| Permissions | Why It's Needed |
|---|---|
| Passwordless sudo | Lets MCM install and manage the Wazuh/Falco/Zeek security agents on your host |
The host also needs to accept SSH connections on port 22 (or a custom port you configure), and needs outbound HTTPS access to the agent package repositories plus outbound access to MCM's monitoring endpoint on the configured registration port.
20.6 Orchestration
Orchestration provisions infrastructure through Terraform, on both AWS and Azure. Most workspaces are built from one of two curated pickers — Existing Stacks (21 ready-made templates) or the Blueprint Canvas (a drag-and-drop palette of 30 resource types) — each covering a specific, known set of AWS and Azure resource types, listed below with the exact permissions they need. A third option, uploading raw Terraform Files, accepts arbitrary HCL with no resource-type restriction — permissions for that path genuinely do scale with whatever you author and can't be listed here; grant the credential used by that workspace whatever create/read/update/delete permissions match the resource types in your uploaded configuration.
For the curated catalog, Terraform needs full lifecycle access — create, read, update, and delete — for each resource type, not just read access.
| Resource Type | Permissions | Why It's Needed |
|---|---|---|
| VPC | ec2:CreateVpc, ec2:DescribeVpcs, ec2:DescribeVpcAttribute, ec2:ModifyVpcAttribute, ec2:DeleteVpc, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_vpc |
| Subnet | ec2:CreateSubnet, ec2:DescribeSubnets, ec2:ModifySubnetAttribute, ec2:DeleteSubnet, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_subnet |
| EC2 Instance | ec2:RunInstances, ec2:DescribeInstances, ec2:DescribeInstanceAttribute, ec2:ModifyInstanceAttribute, ec2:StopInstances, ec2:StartInstances, ec2:TerminateInstances, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_instance |
| S3 Bucket | s3:CreateBucket, s3:HeadBucket, s3:GetBucketPolicy, s3:GetBucketAcl, s3:PutBucketAcl, s3:GetBucketVersioning, s3:PutBucketVersioning, s3:GetEncryptionConfiguration, s3:PutEncryptionConfiguration, s3:GetBucketPublicAccessBlock, s3:PutBucketPublicAccessBlock, s3:GetBucketOwnershipControls, s3:PutBucketOwnershipControls, s3:GetBucketTagging, s3:PutBucketTagging, s3:DeleteBucket | Full lifecycle for aws_s3_bucket and its versioning/encryption/ownership/public-access sub-resources — this also covers the bucket-name availability check MCM runs while you're configuring the variable |
| Security Group | ec2:CreateSecurityGroup, ec2:DescribeSecurityGroups, ec2:AuthorizeSecurityGroupIngress, ec2:AuthorizeSecurityGroupEgress, ec2:RevokeSecurityGroupIngress, ec2:RevokeSecurityGroupEgress, ec2:DeleteSecurityGroup, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_security_group |
| Internet Gateway | ec2:CreateInternetGateway, ec2:DescribeInternetGateways, ec2:AttachInternetGateway, ec2:DetachInternetGateway, ec2:DeleteInternetGateway, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_internet_gateway |
| Route Table | ec2:CreateRouteTable, ec2:DescribeRouteTables, ec2:CreateRoute, ec2:ReplaceRoute, ec2:DeleteRoute, ec2:AssociateRouteTable, ec2:DisassociateRouteTable, ec2:DeleteRouteTable, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_route_table and aws_route_table_association |
| Network ACL | ec2:CreateNetworkAcl, ec2:DescribeNetworkAcls, ec2:CreateNetworkAclEntry, ec2:ReplaceNetworkAclEntry, ec2:DeleteNetworkAclEntry, ec2:DeleteNetworkAcl, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_network_acl |
| EBS Volume | ec2:CreateVolume, ec2:DescribeVolumes, ec2:ModifyVolume, ec2:DeleteVolume, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_ebs_volume |
| EBS Snapshot | ec2:CreateSnapshot, ec2:DescribeSnapshots, ec2:DeleteSnapshot, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_ebs_snapshot |
| Key Pair | ec2:ImportKeyPair, ec2:CreateKeyPair, ec2:DescribeKeyPairs, ec2:DeleteKeyPair, ec2:CreateTags, ec2:DeleteTags | Full lifecycle for aws_key_pair |
| IAM Role | iam:CreateRole, iam:GetRole, iam:UpdateRole, iam:UpdateAssumeRolePolicy, iam:PutRolePolicy, iam:GetRolePolicy, iam:DeleteRolePolicy, iam:AttachRolePolicy, iam:DetachRolePolicy, iam:ListRolePolicies, iam:ListAttachedRolePolicies, iam:DeleteRole, iam:TagRole, iam:UntagRole | Full lifecycle for aws_iam_role (Blueprint Canvas only) |
| Lambda Function | lambda:CreateFunction, lambda:GetFunction, lambda:GetFunctionConfiguration, lambda:UpdateFunctionCode, lambda:UpdateFunctionConfiguration, lambda:DeleteFunction, lambda:TagResource, lambda:UntagResource, lambda:ListTags, iam:PassRole | Full lifecycle for aws_lambda_function (Blueprint Canvas only); iam:PassRole lets Terraform attach the function's execution role |
| EKS Cluster | eks:CreateCluster, eks:DescribeCluster, eks:UpdateClusterConfig, eks:UpdateClusterVersion, eks:DeleteCluster, eks:TagResource, eks:UntagResource, eks:ListTagsForResource, iam:PassRole | Full lifecycle for aws_eks_cluster (Blueprint Canvas only); iam:PassRole lets Terraform attach the cluster's service role |
| RDS Instance | rds:CreateDBInstance, rds:DescribeDBInstances, rds:ModifyDBInstance, rds:DeleteDBInstance, rds:AddTagsToResource, rds:RemoveTagsFromResource, rds:ListTagsForResource | Full lifecycle for aws_db_instance (Blueprint Canvas only) |
20.7 Observability
Observability doesn't call any AWS or Azure cloud APIs — it connects directly over SSH to a host running Ubuntu, whether that host is a standalone Ubuntu server, an AWS EC2 instance, or an Azure VM. No AWS IAM or Azure RBAC permissions are required, so there's no policy JSON to provide.
| Permissions | Why It's Needed |
|---|---|
| No AWS IAM permissions — sudo/root access on the instance | Installs and runs an Elastic Agent on an Ubuntu-based EC2 instance to collect its metrics and logs |
The host also needs outbound HTTPS access to the agent package repository, and network access to MCM's Elastic stack endpoint.