Skip to content

Repository files navigation

NHI Scan MCP

MCP server for scanning AWS IAM identities and identifying Non-Human Identities (NHIs) such as service accounts, automation users, and machine identities.

Overview

This tool scans AWS IAM users and roles to distinguish between human users and non-human identities. It analyzes naming patterns, authentication methods, access keys, MFA configuration, and IAM tags to classify identities with a confidence score. Optionally includes detailed permission analysis to assess access levels and identify potentially dangerous permissions.

Features

  • Scans all IAM users and roles in an AWS account
  • Classifies identities as human or non-human with confidence scoring
  • Categorizes NHIs by type (service roles, machine users, Lambda execution roles, etc.)
  • Optional permission analysis with access level assessment
  • Identifies dangerous permissions and potential security risks

Installation

Requirements

  • Python 3.10 or higher
  • AWS credentials with IAM read permissions

Setup

Clone the repository and install dependencies:

git clone https://github.com/yourusername/NHI-scan-mcp.git
cd NHI-scan-mcp
pip install -r requirements.txt

For development mode:

pip install -e .

Usage with Claude Desktop & Cursor

Claude Desktop Configuration

Add the NHI Scan MCP server to your Claude Desktop configuration file:

MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "nhi-scan": {
      "command": "python",
      "args": ["-m", "nhi_scan_mcp"],
      "cwd": "/absolute/path/to/NHI-scan-mcp",
      "env": {
        "AWS_ACCESS_KEY_ID": "your-key-id",
        "AWS_SECRET_ACCESS_KEY": "your-secret-key",
        "AWS_DEFAULT_REGION": "us-east-1"
      }
    }
  }
}

After configuration, restart Claude Desktop. The NHI scanning tools will be available for Claude to use automatically when you ask questions about AWS IAM security.

Cursor Configuration

Add the MCP server to your Cursor configuration:

  1. Open Cursor Settings
  2. Navigate to Features → MCP
  3. Add a new MCP server with the following configuration:
{
  "mcpServers": {
    "nhi-scan": {
      "command": "python",
      "args": ["-m", "nhi_scan_mcp"],
      "cwd": "/absolute/path/to/NHI-scan-mcp",
      "env": {
        "AWS_ACCESS_KEY_ID": "your-key-id",
        "AWS_SECRET_ACCESS_KEY": "your-secret-key",
        "AWS_DEFAULT_REGION": "us-east-1"
      }
    }
  }
}

Or create/edit .cursor/mcp_settings.json in your project root:

{
  "mcpServers": {
    "nhi-scan": {
      "command": "python",
      "args": ["-m", "nhi_scan_mcp"],
      "cwd": "/absolute/path/to/NHI-scan-mcp"
    }
  }
}

After configuration, restart Cursor. You can now ask the AI assistant to scan your AWS IAM for NHIs.

Example Prompts

Once configured, you can ask Claude or Cursor:

  • "Scan my AWS IAM and show me all non-human identities"
  • "List all service accounts in my AWS account with high confidence"
  • "Analyze the permissions for my current AWS credentials"
  • "Show me human users vs non-human identities with security recommendations"
  • "Get detailed information about the IAM user named 'jenkins-automation'"

Manual Usage

Starting the Server

python -m nhi_scan_mcp

Alternatively:

python src/nhi_scan_mcp/server.py

MCP Tools

The server exposes five tools for IAM scanning and analysis:

scan_iam_identities

Main scanning tool that lists all IAM identities, classifies NHIs, and optionally analyzes permissions.

Parameters:

  • aws_access_key_id (string, optional) - AWS access key ID
  • aws_secret_access_key (string, optional) - AWS secret access key
  • aws_session_token (string, optional) - Session token for temporary credentials
  • region (string, optional) - AWS region, defaults to us-east-1
  • include_permissions (boolean, optional) - Include permission analysis, defaults to false

Example:

{
  "aws_access_key_id": "AKIA...",
  "aws_secret_access_key": "...",
  "region": "us-west-2",
  "include_permissions": true
}

Returns: Complete scan results including all identities, NHI classifications, confidence scores, and optional permission analysis.

list_nhi_identities

Returns only non-human identities filtered by confidence threshold.

Parameters:

  • aws_access_key_id (string, optional)
  • aws_secret_access_key (string, optional)
  • aws_session_token (string, optional)
  • region (string, optional)
  • min_confidence (float, optional) - Minimum confidence threshold (0.0-1.0), defaults to 0.5

Returns: Filtered list of NHIs meeting the confidence threshold with classification details.

analyze_caller_permissions

Analyzes permissions for the AWS credentials being used to run the scan.

Parameters:

  • aws_access_key_id (string, optional)
  • aws_secret_access_key (string, optional)
  • aws_session_token (string, optional)
  • region (string, optional)

Returns: Permission analysis for the caller including access level and dangerous permissions.

get_identity_details

Retrieves detailed information for a specific IAM user or role.

Parameters:

  • identity_name (string, required) - Name of the IAM user or role
  • identity_type (string, optional) - Either "user" or "role", defaults to user
  • aws_access_key_id (string, optional)
  • aws_secret_access_key (string, optional)
  • aws_session_token (string, optional)
  • region (string, optional)

Returns: Complete identity details including NHI classification and permission analysis.

distinguish_users_vs_nhi

Provides a breakdown separating human users from non-human identities with statistics and recommendations.

Parameters:

  • aws_access_key_id (string, optional)
  • aws_secret_access_key (string, optional)
  • aws_session_token (string, optional)
  • region (string, optional)

Returns: Summary statistics, user lists by category, and security recommendations.

AWS Credentials

Credentials can be provided in the following order of precedence:

  1. Explicit parameters (aws_access_key_id, aws_secret_access_key)
  2. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  3. AWS credentials file (~/.aws/credentials)
  4. IAM role (when running on EC2/ECS)

Required IAM Permissions

The AWS credentials must have the following permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:ListUsers",
        "iam:ListRoles",
        "iam:ListUserTags",
        "iam:ListRoleTags",
        "iam:ListAccessKeys",
        "iam:ListMFADevices",
        "iam:GetUser",
        "iam:GetRole",
        "iam:ListAttachedUserPolicies",
        "iam:ListAttachedRolePolicies",
        "iam:ListUserPolicies",
        "iam:ListRolePolicies",
        "iam:GetPolicy",
        "iam:GetPolicyVersion",
        "iam:GetUserPolicy",
        "iam:GetRolePolicy",
        "iam:ListGroupsForUser",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

NHI Identification Methodology

IAM Users

The tool evaluates multiple signals to determine if a user is non-human:

  • Name patterns - Matches against common prefixes like svc-, app-, bot-, api-, lambda-, ci-, cd-, terraform-, ansible-, etc.
  • Password usage - Users with no password login history
  • Access keys - Presence of active programmatic access keys
  • MFA status - Absence of MFA devices (expected for human users)
  • Tags - Explicit tags marking service accounts, bots, or automation

Each signal contributes to a confidence score from 0.0 to 1.0. Users with confidence ≥ 0.5 are classified as NHIs.

IAM Roles

All roles are inherently non-human, but are further classified by analyzing their assume role policy:

  • Service roles - Trusted by AWS services (Lambda, EC2, ECS, etc.)
  • Lambda execution roles - Specifically for Lambda functions
  • EC2 instance profiles - For EC2 instances
  • Cross-account roles - Trust relationships with other AWS accounts
  • Federated roles - SAML or OIDC federation
  • Application roles - General application service roles

Python Library Usage

You can also use the modules directly in your own Python scripts:

Basic Scanning Example

from nhi_scan_mcp.aws_scanner import AWSIAMScanner
from nhi_scan_mcp.nhi_identifier import NHIIdentifier

# Initialize scanner (uses default AWS credential chain)
scanner = AWSIAMScanner()

# Or with explicit credentials:
# scanner = AWSIAMScanner(
#     aws_access_key_id="YOUR_KEY",
#     aws_secret_access_key="YOUR_SECRET",
#     region_name="us-east-1"
# )

# Get caller identity
caller = scanner.get_caller_identity()
print(f"Account: {caller['Account']}")

# List all IAM users and roles
users = scanner.list_users()
roles = scanner.list_roles()
print(f"Found {len(users)} users and {len(roles)} roles")

# Identify NHIs
identifier = NHIIdentifier()
identifications = identifier.identify_all(users, roles)

# Display results
for identification in identifications:
    if identification.is_nhi and identification.identity.identity_type == "user":
        print(f"🤖 {identification.identity.name}")
        print(f"   Category: {identification.nhi_category}")
        print(f"   Confidence: {identification.confidence:.2f}")

Permission Analysis Example

from nhi_scan_mcp.aws_scanner import AWSIAMScanner
from nhi_scan_mcp.permission_analyzer import PermissionAnalyzer

# Initialize scanner and analyzer
scanner = AWSIAMScanner()
analyzer = PermissionAnalyzer(scanner)

# Analyze your own permissions
caller_analysis = analyzer.analyze_caller_permissions()
print(f"Permission Level: {caller_analysis.permission_level}")
print(f"Admin Access: {caller_analysis.admin_access}")

if caller_analysis.dangerous_permissions:
    print("⚠️  Dangerous Permissions:")
    for perm in caller_analysis.dangerous_permissions:
        print(f"   - {perm}")

# Analyze specific user permissions
users = scanner.list_users()
for user in users:
    analysis = analyzer.analyze_user_permissions(user)
    print(f"{user.name}: {analysis.permission_level}")

Distinguishing Human vs NHI Example

from nhi_scan_mcp.aws_scanner import AWSIAMScanner
from nhi_scan_mcp.nhi_identifier import NHIIdentifier

scanner = AWSIAMScanner()
identifier = NHIIdentifier()

# Scan and identify
users = scanner.list_users()
roles = scanner.list_roles()
identifications = identifier.identify_all(users, roles)

# Separate human users from NHIs
human_users = []
nhi_users = []
uncertain_users = []

for identification in identifications:
    if identification.identity.identity_type != "user":
        continue
    
    if identification.nhi_category.value == "human_user":
        human_users.append(identification)
    elif identification.nhi_category.value == "uncertain":
        uncertain_users.append(identification)
    else:
        nhi_users.append(identification)

print(f"Human Users: {len(human_users)}")
print(f"NHI Users: {len(nhi_users)}")
print(f"Uncertain Users: {len(uncertain_users)}")

# Generate security recommendations
no_mfa_humans = [i for i in human_users if not i.identity.mfa_devices]
if no_mfa_humans:
    print(f"\n⚠️  {len(no_mfa_humans)} human users lack MFA!")
    for i in no_mfa_humans:
        print(f"   - {i.identity.name}")

License

MIT License - see LICENSE file for details.

Acknowledgments

Built with FastMCP for Model Context Protocol server implementation and boto3 for AWS API interactions.

About

MCP to scan IAM credentials and access level in AWS

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages