Skip to content

Claude Code Complete Guide

Claude Code Enterprise Deployment - Secure Implementation in Corporate Environments

Target Audience

  • Target Audience
  • Platform/SRE Engineers
  • Security/GRC Managers
  • Development Managers/Engineering Managers
  • Prerequisites
  • Basic AWS/GCP ope...

Deployment Path - Choose Your Optimal Route

  1. Add Claude Code extension to IDE
  2. Configure vendor settings via environment variables (Bedrock/Vertex)
  3. Verify operations and run tests

Jump to Bedrock Basic Setup

  1. Configure minimal IAM permissions
  2. Set up VPC/Private endpoints
  3. Deploy LLM Gateway
  4. Configure audit logs and cost monitoring

Jump to Security Measures

Key Points

  • AWS Bedrock Integration

    Full integration with enterprise AWS infrastructure

  • Google Vertex AI Support

    Secure operations in GCP environments

  • Security Compliance

    Meets enterprise security requirements

  • Proxy Support

    Works in corporate network environments

📖 Enterprise Deployment Overview

Important Notice on Data Usage Policy

Enterprise/Bedrock/Vertex usage covered in this article is NOT subject to the Consumer data usage policy changes in April 2025.

  • Enterprise/Team plans: No training use, complete audit logs
  • Bedrock/Vertex API: Contract-based usage, data protection guaranteed
  • Details: Anthropic Official Announcement

Claude Code enterprise deployment integrates with existing corporate infrastructure while adhering to security policies. Direct integration with cloud providers prevents data cross-border transfer and meets compliance requirements.

Key Deployment Patterns

graph TB
    A[Corporate Network] --> B[Corporate Proxy]
    B --> C[LLM Gateway]
    C --> D[AWS Bedrock<br/>Direct Claude Integration]
    C --> E[Google Vertex AI<br/>Direct Claude Integration]
    C --> F[Azure OpenAI<br/>*Gateway-routed separate LLM]

    A --> G[Claude Code CLI]
    G --> H[Internal Developers]
    G --> I[CI/CD Pipeline]

    style D fill:#9cf,stroke:#333,stroke-width:2px
    style E fill:#9cf,stroke:#333,stroke-width:2px
    style F fill:#faa,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5

Architecture Notes

  • Bedrock/Vertex AI: Direct Claude integration (vendor officially supported)
  • Azure OpenAI: Example of multi-provider integration via LLM Gateway (Claude not available)

🛡️ Governance Control Points

Claude Code provides a management framework centered on managed-settings.json, enabling enterprise IT administrators to centrally control user settings.

managed-settings.json Deployment Paths

OSPath
macOS/Library/Application Support/ClaudeCode/managed-settings.json
Linux / WSL/etc/claude-code/managed-settings.json
WindowsC:\Program Files\ClaudeCode\managed-settings.json

Control Functions

Control LayerFeatureConfiguration LocationDescription
HooksallowManagedHooksOnlymanaged-settings.jsonDisable user/project/plugin hooks
HooksdisableAllHooksmanaged-settings.jsonDisable all hooks
MCPmanaged-mcp.jsonSystem directoryCentrally manage MCP server configuration
MCPallowedMcpServersmanaged-settings.jsonAllowlist of permitted MCP servers
MCPdeniedMcpServersmanaged-settings.jsonBlocklist of denied MCP servers
PermissionsallowManagedPermissionRulesOnlymanaged-settings.jsonApply managed rules only
PermissionsdisableBypassPermissionsModemanaged-settings.jsonDisable bypass permissions mode
AuthforceLoginMethodmanaged-settings.jsonForce claudeai or console login
AuthforceLoginOrgUUIDmanaged-settings.jsonAuto-select organization
PluginsstrictKnownMarketplacesmanaged-settings.jsonRestrict plugin marketplaces
NotificationscompanyAnnouncementsmanaged-settings.jsonDisplay announcements at startup

Configuration Example

// managed-settings.json
{
  "forceLoginMethod": "console",
  "forceLoginOrgUUID": "your-org-uuid-here",
  "allowManagedHooksOnly": true,
  "disableBypassPermissionsMode": true,
  "allowedMcpServers": ["approved-server-1", "approved-server-2"],
  "deniedMcpServers": ["untrusted-server"],
  "allowManagedPermissionRulesOnly": true,
  "strictKnownMarketplaces": true,
  "companyAnnouncements": "Please use only approved MCP servers per security policy."
}

Organization-Level CLAUDE.md (Managed CLAUDE.md)

To apply unified guidelines across the organization, you can place a CLAUDE.md at system-level paths. This CLAUDE.md has the highest precedence, overriding project-level and user-level settings.

OSPath
macOS/Library/Application Support/ClaudeCode/CLAUDE.md
Linux / WSL/etc/claude-code/CLAUDE.md
WindowsC:\Program Files\ClaudeCode\CLAUDE.md

Sandbox Configuration

You can configure sandbox functionality to isolate Bash command execution.

// Sandbox settings in managed-settings.json
{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "network": {
      "allowedDomains": ["github.com", "npmjs.org", "pypi.org"]
    },
    "excludedCommands": ["rm -rf /", "shutdown"]
  }
}
  • sandbox.enabled: Enable sandbox mode
  • sandbox.autoAllowBashIfSandboxed: Auto-allow Bash commands within sandbox
  • sandbox.network.allowedDomains: List of domains allowed for network access
  • sandbox.excludedCommands: Commands prohibited even within sandbox

🔧 AWS Bedrock Integration

1. Basic Configuration

# Enable AWS Bedrock
export CLAUDE_CODE_USE_BEDROCK=1
export AWS_REGION=us-east-1
export AWS_PROFILE=claude-code-production

# Create IAM Role
aws iam create-role --role-name ClaudeCodeRole --assume-role-policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}'

# Create minimal permissions policy
cat <<EOF > claude-code-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": "arn:aws:bedrock:*:*:inference-profile/us.anthropic.claude-*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:ListInferenceProfiles",
        "bedrock:GetInferenceProfile"
      ],
      "Resource": "*"
    }
  ]
}
EOF

# Create and attach policy
aws iam create-policy --policy-name ClaudeCodeMinimalPolicy --policy-document file://claude-code-policy.json
aws iam attach-role-policy --role-name ClaudeCodeRole --policy-arn arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/ClaudeCodeMinimalPolicy

2. Enterprise Configuration

# claude-config.yaml
bedrock:
  region: "us-east-1"
  # Claude Code recommends inference profile ID (with us. prefix)
  model_id: "us.anthropic.claude-sonnet-4-5-20250514-v1:0"
  max_tokens: 4000
  temperature: 0.1

  # VPC Configuration
  vpc_config:
    subnet_ids:
      - "subnet-12345678"
      - "subnet-87654321"
    security_group_ids:
      - "sg-abcdef12"

  # Encryption Settings
  encryption:
    kms_key_id: "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"

  # Logging Settings
  logging:
    cloudwatch_log_group: "/aws/bedrock/claude-code"
    retention_days: 30

3. Terraform Automation

# main.tf
resource "aws_bedrock_model_invocation_logging_configuration" "claude_code" {
  logging_config {
    cloud_watch_config {
      log_group_name = "/aws/bedrock/claude-code"
      role_arn       = aws_iam_role.bedrock_logging.arn
    }
    s3_config {
      bucket_name = aws_s3_bucket.bedrock_logs.bucket
      key_prefix  = "bedrock-logs/"
    }
    embedding_data_delivery_enabled = true
    image_data_delivery_enabled     = true
    text_data_delivery_enabled      = true
  }
}

resource "aws_s3_bucket" "bedrock_logs" {
  bucket = "claude-code-bedrock-logs-${random_id.bucket_suffix.hex}"

  tags = {
    Environment = "production"
    Purpose     = "bedrock-logging"
  }
}

resource "aws_s3_bucket_encryption_configuration" "bedrock_logs" {
  bucket = aws_s3_bucket.bedrock_logs.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.bedrock_key.arn
      sse_algorithm     = "aws:kms"
    }
  }
}

resource "aws_iam_role" "bedrock_logging" {
  name = "bedrock-logging-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "bedrock.amazonaws.com"
        }
      }
    ]
  })
}

🌐 Google Vertex AI Integration

1. Basic Configuration

# Enable Vertex AI
export CLAUDE_CODE_USE_VERTEX=1
export CLOUD_ML_REGION=us-central1
export ANTHROPIC_VERTEX_PROJECT_ID=your-project-id

# Create service account
gcloud iam service-accounts create claude-code-service \
  --display-name="Claude Code Service Account"

# Grant necessary permissions
gcloud projects add-iam-policy-binding your-project-id \
  --member="serviceAccount:claude-code-service@your-project-id.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"

# Create authentication key
gcloud iam service-accounts keys create claude-code-key.json \
  --iam-account=claude-code-service@your-project-id.iam.gserviceaccount.com

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/claude-code-key.json

2. Enterprise Configuration

# vertex-config.yaml
vertex_ai:
  project_id: "your-project-id"
  location: "us-central1"
  # Latest model example (check for latest version periodically)
  model_name: "claude-sonnet-4@20250514"

  # Endpoint Selection
  # Global: High availability, automatic failover
  # Regional: Data residency guarantee, strict compliance
  endpoint_type: "regional"  # Recommended: When data location requirements exist

  # VPC Configuration
  network: "projects/your-project-id/global/networks/default"
  subnet: "projects/your-project-id/regions/us-central1/subnetworks/default"

  # Security Settings
  encryption_spec:
    kms_key_name: "projects/your-project-id/locations/us-central1/keyRings/claude-code/cryptoKeys/vertex-ai"

  # Audit Logging
  audit_logging:
    enabled: true
    log_type: "DATA_READ"
    exempted_members: []

3. Kubernetes Operations

# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: claude-code-service
  namespace: ai-tools
spec:
  replicas: 3
  selector:
    matchLabels:
      app: claude-code-service
  template:
    metadata:
      labels:
        app: claude-code-service
    spec:
      serviceAccountName: claude-code-sa
      containers:
      - name: claude-code
        # Official image is not provided
        # Self-build required based on DevContainer
        image: your-registry.com/claude-code:v1.0.0
        # Build instructions: https://docs.anthropic.com/en/docs/claude-code/devcontainer
        env:
        - name: CLAUDE_CODE_USE_VERTEX
          value: "1"
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: "/var/secrets/google/key.json"
        - name: ANTHROPIC_VERTEX_PROJECT_ID
          valueFrom:
            secretKeyRef:
              name: vertex-config
              key: project-id
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
          readOnly: true
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: google-cloud-key
        secret:
          secretName: google-cloud-key
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: claude-code-sa
  namespace: ai-tools
  annotations:
    iam.gke.io/gcp-service-account: claude-code-service@your-project-id.iam.gserviceaccount.com

🔐 Security Measures

1. Network Security

# Corporate Proxy Configuration
export HTTPS_PROXY=https://proxy.company.com:8080
export HTTP_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.company.com

# SSL Certificate Configuration
export SSL_CERT_FILE=/etc/ssl/certs/company-ca-bundle.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/company-ca-bundle.crt

2. LLM Gateway Implementation

# llm_gateway.py
import os
import logging
from flask import Flask, request, jsonify
from werkzeug.middleware.proxy_fix import ProxyFix
import requests
from cryptography.fernet import Fernet
import boto3
from datetime import datetime

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)

# Logging configuration
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class LLMGateway:
    def __init__(self):
        self.encryption_key = os.environ.get('ENCRYPTION_KEY')
        self.cipher_suite = Fernet(self.encryption_key)
        self.bedrock_client = boto3.client('bedrock-runtime')

    def encrypt_request(self, data):
        """Encrypt request data"""
        encrypted_data = self.cipher_suite.encrypt(data.encode())
        return encrypted_data

    def decrypt_response(self, encrypted_data):
        """Decrypt response data"""
        decrypted_data = self.cipher_suite.decrypt(encrypted_data)
        return decrypted_data.decode()

    def audit_log(self, user_id, request_type, success=True):
        """Record audit logs"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'user_id': user_id,
            'request_type': request_type,
            'success': success,
            'ip_address': request.remote_addr,
            'user_agent': request.user_agent.string
        }
        logger.info(f"AUDIT: {log_entry}")

        # Send to CloudWatch Logs
        cloudwatch = boto3.client('logs')
        cloudwatch.put_log_events(
            logGroupName='/aws/lambda/claude-code-gateway',
            logStreamName=f'audit-{datetime.utcnow().strftime("%Y-%m-%d")}',
            logEvents=[{
                'timestamp': int(datetime.utcnow().timestamp() * 1000),
                'message': str(log_entry)
            }]
        )

    def validate_request(self, request_data):
        """Validate request"""
        # Data sanitization
        if 'prompt' in request_data:
            prompt = request_data['prompt']

            # Check for forbidden keywords
            forbidden_keywords = ['password', 'secret', 'token', 'key']
            for keyword in forbidden_keywords:
                if keyword.lower() in prompt.lower():
                    return False, f"Forbidden keyword detected: {keyword}"

        return True, "Valid request"

gateway = LLMGateway()

@app.route('/v1/messages', methods=['POST'])
def proxy_to_bedrock():
    try:
        # Request authentication
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return jsonify({'error': 'Missing or invalid authorization'}), 401

        token = auth_header.split(' ')[1]
        user_id = validate_token(token)
        if not user_id:
            return jsonify({'error': 'Invalid token'}), 401

        # Request validation
        request_data = request.get_json()
        is_valid, error_msg = gateway.validate_request(request_data)
        if not is_valid:
            gateway.audit_log(user_id, 'INVALID_REQUEST', success=False)
            return jsonify({'error': error_msg}), 400

        # Request to Bedrock
        response = gateway.bedrock_client.invoke_model(
            # Use inference profile ID (resolves region dependency)
            modelId='us.anthropic.claude-sonnet-4-5-20250514-v1:0',
            body=json.dumps(request_data)
        )

        # Audit log
        gateway.audit_log(user_id, 'MODEL_INVOCATION', success=True)

        return jsonify(response), 200

    except Exception as e:
        logger.error(f"Error processing request: {str(e)}")
        return jsonify({'error': 'Internal server error'}), 500

def validate_token(token):
    """Token validation"""
    # JWT token validation logic
    # In actual implementation, integrate with corporate authentication system
    return "user123"  # Example

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, ssl_context='adhoc')

3. Data Protection

# Enterprise data encryption
#!/bin/bash
# data_protection.sh

# Generate encryption key
openssl rand -base64 32 > /secure/claude-code-key.txt

# File encryption
encrypt_file() {
    local input_file="$1"
    local output_file="$2"

    openssl enc -aes-256-cbc -salt -in "$input_file" -out "$output_file" -k "$(cat /secure/claude-code-key.txt)"
}

# File decryption
decrypt_file() {
    local encrypted_file="$1"
    local output_file="$2"

    openssl enc -aes-256-cbc -d -salt -in "$encrypted_file" -out "$output_file" -k "$(cat /secure/claude-code-key.txt)"
}

# Usage example
encrypt_file "sensitive_code.py" "sensitive_code.py.enc"
decrypt_file "sensitive_code.py.enc" "sensitive_code.py"

🏢 Organizational Rollout

1. Phased Deployment

# deployment-phases.yaml
phase_1:
  name: "Pilot Program"
  duration: "2 weeks"
  participants:
    - "Senior developers (5 people)"
    - "DevOps team (3 people)"
  scope:
    - "Internal tools development"
    - "Code review assistance"
  success_criteria:
    - "Productivity improvement > 20%"
    - "Zero security incidents"

phase_2:
  name: "Department Rollout"
  duration: "1 month"
  participants:
    - "All development teams (50 people)"
  scope:
    - "Full development lifecycle"
    - "CI/CD integration"
  success_criteria:
    - "Adoption rate > 80%"
    - "Code quality improvement"

phase_3:
  name: "Enterprise Wide"
  duration: "3 months"
  participants:
    - "All technical staff (200 people)"
  scope:
    - "All projects"
    - "Cross-team collaboration"
  success_criteria:
    - "ROI > 300%"
    - "Full security compliance"

2. Governance Framework

# governance_framework.py
from dataclasses import dataclass
from typing import List, Dict, Optional
from enum import Enum

class UserRole(Enum):
    ADMIN = "admin"
    DEVELOPER = "developer"
    VIEWER = "viewer"
    GUEST = "guest"

class ProjectType(Enum):
    INTERNAL = "internal"
    CUSTOMER_FACING = "customer_facing"
    CONFIDENTIAL = "confidential"

@dataclass
class AccessPolicy:
    role: UserRole
    allowed_models: List[str]
    max_tokens_per_day: int
    allowed_project_types: List[ProjectType]
    can_access_external_apis: bool
    audit_level: str

class GovernanceManager:
    def __init__(self):
        self.policies = {
            UserRole.ADMIN: AccessPolicy(
                role=UserRole.ADMIN,
                allowed_models=["claude-opus-4-6", "claude-sonnet-4-5", "claude-haiku-4-5"],
                max_tokens_per_day=100000,
                allowed_project_types=[ProjectType.INTERNAL, ProjectType.CUSTOMER_FACING, ProjectType.CONFIDENTIAL],
                can_access_external_apis=True,
                audit_level="full"
            ),
            UserRole.DEVELOPER: AccessPolicy(
                role=UserRole.DEVELOPER,
                allowed_models=["claude-sonnet-4-5", "claude-haiku-4-5"],
                max_tokens_per_day=50000,
                allowed_project_types=[ProjectType.INTERNAL, ProjectType.CUSTOMER_FACING],
                can_access_external_apis=False,
                audit_level="standard"
            ),
            UserRole.VIEWER: AccessPolicy(
                role=UserRole.VIEWER,
                allowed_models=["claude-haiku-4-5"],
                max_tokens_per_day=10000,
                allowed_project_types=[ProjectType.INTERNAL],
                can_access_external_apis=False,
                audit_level="minimal"
            )
        }

    def get_user_policy(self, user_id: str, role: UserRole) -> AccessPolicy:
        """Get user access policy"""
        return self.policies.get(role)

    def validate_request(self, user_id: str, request_data: Dict) -> bool:
        """Validate request legitimacy"""
        user_role = self.get_user_role(user_id)
        policy = self.get_user_policy(user_id, user_role)

        # Check model access permission
        if request_data.get('model') not in policy.allowed_models:
            return False

        # Check daily token limit
        daily_usage = self.get_daily_token_usage(user_id)
        if daily_usage >= policy.max_tokens_per_day:
            return False

        # Check project type
        project_type = self.get_project_type(request_data.get('project_id'))
        if project_type not in policy.allowed_project_types:
            return False

        return True

    def get_user_role(self, user_id: str) -> UserRole:
        """Get user role"""
        # In actual implementation, integrate with corporate ID system
        return UserRole.DEVELOPER

    def get_daily_token_usage(self, user_id: str) -> int:
        """Get user's daily token usage"""
        # In actual implementation, retrieve from usage database
        return 0

    def get_project_type(self, project_id: str) -> ProjectType:
        """Get project type"""
        # In actual implementation, retrieve from project management system
        return ProjectType.INTERNAL

📊 Operations Monitoring

OpenTelemetry Observability

Claude Code natively supports OpenTelemetry (OTel), enabling real-time collection of session, cost, and token usage data.

Enabling via Environment Variables

# Enable OpenTelemetry telemetry
export CLAUDE_CODE_ENABLE_TELEMETRY=1

# Exporter configuration (e.g., OTLP)
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp

# Endpoint configuration
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.company.com:4317

# Resource attributes per team/department
export OTEL_RESOURCE_ATTRIBUTES="team.name=platform,department=engineering,environment=production"

Collected Metrics

Metric NameDescriptionType
session.countNumber of sessionsCounter
lines_of_code.countLines of code generatedCounter
cost.usageAPI usage costGauge
token.usageToken consumptionCounter
active_time.totalTotal active timeGauge

Collected Events

Event NameDescription
user_promptUser prompt submission
tool_resultTool execution result
api_requestAPI request
api_errorAPI error
tool_decisionTool selection decision

Multi-Team Support

By leveraging OTEL_RESOURCE_ATTRIBUTES, you can filter metrics by team or department.

# Team A
export OTEL_RESOURCE_ATTRIBUTES="team.name=frontend,cost_center=CC-001"

# Team B
export OTEL_RESOURCE_ATTRIBUTES="team.name=backend,cost_center=CC-002"

Dynamic Headers

For OTel collectors requiring authentication, use the otelHeadersHelper setting to dynamically generate headers.

// managed-settings.json
{
  "otelHeadersHelper": "/usr/local/bin/generate-otel-auth-header.sh"
}

1. Metrics Collection

# metrics_collector.py
import boto3
import json
from datetime import datetime
import psutil
import time

class MetricsCollector:
    def __init__(self):
        self.cloudwatch = boto3.client('cloudwatch')
        self.namespace = 'ClaudeCode/Enterprise'

    def collect_usage_metrics(self):
        """Collect usage metrics"""
        metrics = {
            'requests_per_minute': self.get_requests_per_minute(),
            'tokens_processed': self.get_tokens_processed(),
            'active_users': self.get_active_users(),
            'error_rate': self.get_error_rate(),
            'response_time': self.get_response_time()
        }

        for metric_name, value in metrics.items():
            self.cloudwatch.put_metric_data(
                Namespace=self.namespace,
                MetricData=[
                    {
                        'MetricName': metric_name,
                        'Value': value,
                        'Unit': 'Count',
                        'Timestamp': datetime.utcnow()
                    }
                ]
            )

    def collect_system_metrics(self):
        """Collect system metrics"""
        cpu_percent = psutil.cpu_percent(interval=1)
        memory_percent = psutil.virtual_memory().percent
        disk_percent = psutil.disk_usage('/').percent

        system_metrics = {
            'cpu_utilization': cpu_percent,
            'memory_utilization': memory_percent,
            'disk_utilization': disk_percent
        }

        for metric_name, value in system_metrics.items():
            self.cloudwatch.put_metric_data(
                Namespace=self.namespace,
                MetricData=[
                    {
                        'MetricName': metric_name,
                        'Value': value,
                        'Unit': 'Percent',
                        'Timestamp': datetime.utcnow()
                    }
                ]
            )

    def collect_business_metrics(self):
        """Collect business metrics"""
        business_metrics = {
            'code_lines_generated': self.get_code_lines_generated(),
            'bugs_fixed': self.get_bugs_fixed(),
            'time_saved_minutes': self.get_time_saved(),
            'cost_savings_usd': self.get_cost_savings()
        }

        for metric_name, value in business_metrics.items():
            self.cloudwatch.put_metric_data(
                Namespace=self.namespace,
                MetricData=[
                    {
                        'MetricName': metric_name,
                        'Value': value,
                        'Unit': 'Count',
                        'Timestamp': datetime.utcnow()
                    }
                ]
            )

# Periodic execution
def main():
    collector = MetricsCollector()

    while True:
        try:
            collector.collect_usage_metrics()
            collector.collect_system_metrics()
            collector.collect_business_metrics()
            print(f"Metrics collected at {datetime.utcnow()}")
        except Exception as e:
            print(f"Error collecting metrics: {e}")

        time.sleep(300)  # 5-minute intervals

if __name__ == "__main__":
    main()

2. Alert Configuration

# cloudwatch-alarms.yaml
Resources:
  HighErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: ClaudeCode-HighErrorRate
      AlarmDescription: Error rate is too high
      MetricName: error_rate
      Namespace: ClaudeCode/Enterprise
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 5.0
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Ref SNSTopic

  HighLatencyAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: ClaudeCode-HighLatency
      AlarmDescription: Response time is too high
      MetricName: response_time
      Namespace: ClaudeCode/Enterprise
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 5000
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Ref SNSTopic

  SNSTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: ClaudeCode-Alerts
      Subscription:
        - Protocol: email
          Endpoint: devops@company.com
        - Protocol: slack
          Endpoint: https://hooks.slack.com/services/YOUR/WEBHOOK/URL

💰 ROI and Cost Optimization

Measuring Implementation Impact

MetricImprovementAnnual Cost Savings
Development Efficiency40% increase$500,000
Bug Fix Time60% reduction$300,000
Code Review50% faster$200,000
Operations Work30% reduction$150,000
Total-$1,150,000

Cost Optimization Strategy

# cost_optimization.py
from datetime import datetime, timedelta
import boto3

class CostOptimizer:
    def __init__(self):
        self.ce = boto3.client('ce')

    def analyze_usage_patterns(self):
        """Analyze usage patterns"""
        end_date = datetime.now()
        start_date = end_date - timedelta(days=30)

        response = self.ce.get_cost_and_usage(
            TimePeriod={
                'Start': start_date.strftime('%Y-%m-%d'),
                'End': end_date.strftime('%Y-%m-%d')
            },
            Granularity='DAILY',
            Metrics=['BlendedCost', 'UsageQuantity'],
            GroupBy=[
                {'Type': 'DIMENSION', 'Key': 'SERVICE'},
                {'Type': 'DIMENSION', 'Key': 'USAGE_TYPE'}
            ]
        )

        return response

    def optimize_model_selection(self, request_complexity):
        """Model selection based on request complexity"""
        if request_complexity == 'simple':
            return 'claude-haiku-4-5'  # Low cost
        elif request_complexity == 'medium':
            return 'claude-sonnet-4-5'  # Balanced
        else:
            return 'claude-opus-4-6'  # High performance

    def batch_processing_optimization(self, requests):
        """Optimization through batch processing"""
        # Group similar requests
        grouped_requests = self.group_similar_requests(requests)

        optimized_requests = []
        for group in grouped_requests:
            # Combine requests for batch processing
            combined_request = self.combine_requests(group)
            optimized_requests.append(combined_request)

        return optimized_requests