ECS タスクセットにおけるパブリック IP アドレス利用の無効化設定手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、ECS タスクセットはパブリック IP アドレスを自動的に割り当てないでくださいについて、リスクと対策を解説します。

ポリシーの説明

Amazon Elastic Container Service (ECS) のタスク定義またはサービス設定において、ネットワークモードがawsvpcの場合にパブリックIPアドレスの自動割り当てが無効になっている状態が推奨されます。

リスク

ECSタスクにパブリックIPアドレスを自動的に割り当てることで、以下のセキュリティリスクが発生します:

  1. インターネットからの直接アクセス: タスクがインターネットから直接アクセス可能になり、攻撃者の標的になるリスクが高まります
  2. 意図しないデータ露出: アプリケーションに脆弱性がある場合、外部から直接攻撃され、データ漏洩につながる可能性があります
  3. DDoS攻撃の標的: パブリックIPを持つコンテナは、DDoS攻撃の標的になりやすくなります
  4. セキュリティグループの誤設定: パブリックIPと組み合わさったセキュリティグループの誤設定により、意図しないポートが公開される可能性があります
  5. コンプライアンス違反: 多くのセキュリティ基準では、不要なパブリック露出を避けることが要求されています

修復方法

AWS CLIでの修復手順

まず、既存のECSサービスの現在の設定を確認します:

# ECSサービスの詳細を取得
aws ecs describe-services \\\\
  --cluster <cluster-name> \\\\
  --services <service-name> \\\\
  --region <region> \\\\
  --query 'services[0].networkConfiguration.awsvpcConfiguration'

# パブリックIPの自動割り当てが有効になっている場合は以下のように表示されます:
# "assignPublicIp": "ENABLED"

パブリックIPの自動割り当てを無効化します:

# 新しいネットワーク設定を作成
cat > network-config.json << 'EOF'
{
  "awsvpcConfiguration": {
    "subnets": ["subnet-xxx", "subnet-yyy"],
    "securityGroups": ["sg-xxx"],
    "assignPublicIp": "DISABLED"
  }
}
EOF

# ECSサービスを更新
aws ecs update-service \\\\
  --cluster <cluster-name> \\\\
  --service <service-name> \\\\
  --network-configuration file://network-config.json \\\\
  --region <region>

# 新しいタスクがプライベートIPで起動するようにサービスを再デプロイ
aws ecs update-service \\\\
  --cluster <cluster-name> \\\\
  --service <service-name> \\\\
  --force-new-deployment \\\\
  --region <region>

コンソールでの修復手順

AWSのコンソールを使用して、ECSタスクのパブリックIPアドレス自動割り当てを無効化します。

既存のECSサービスの修正手順

  1. AWSマネジメントコンソールにログインし、Amazon ECSサービスに移動します
  2. 左側のナビゲーションペインから「クラスター」を選択します
  3. 対象のクラスターをクリックして詳細画面を開きます
  4. サービス」タブを選択し、修正したいサービス名をクリックします
  5. サービスの詳細画面で「更新」ボタンをクリックします
  1. ネットワーク設定」セクションまでスクロールします
  2. パブリック IP」の設定を確認し、「無効」を選択します
  1. 必要に応じて、以下の代替設定を行います:
    • NAT Gateway経由のアウトバウンド通信: プライベートサブネットにタスクを配置し、NAT Gateway経由でインターネットアクセスを提供
    • VPCエンドポイント: AWS サービスへのアクセスにVPCエンドポイントを使用
    • ロードバランサー経由のインバウンド通信: Application Load BalancerやNetwork Load Balancerを使用してトラフィックをルーティング
  2. 次へ」をクリックして残りの設定を確認します
  3. サービスの更新」をクリックして変更を適用します

新規タスク定義の作成時の設定

  1. ECSコンソールで「タスク定義」を選択します
  2. 新しいタスク定義の作成」をクリックします
  3. タスク定義の設定で、ネットワークモードを「awsvpc」に設定した場合:
    • サービス作成時に「パブリック IP の自動割り当て」を「無効」に設定することを確認

プライベートサブネットでのインターネットアクセス設定

ECSタスクがプライベートサブネットで実行される場合、以下の方法でインターネットアクセスを提供します:

  1. NAT GatewayまたはNATインスタンスの設定
    • プライベートサブネットからのアウトバウンド通信を許可
    • Dockerイメージのプルや外部APIへのアクセスに必要
  2. VPCエンドポイントの設定
    • ECR、S3、CloudWatch LogsなどのAWSサービスへのプライベートアクセス
    • インターネットゲートウェイを経由しないセキュアな接続

Terraformでの修復手順

ECSタスクのパブリックIPアドレス自動割り当てを無効化するTerraformコードと、主要な修正ポイントを説明します。

# プライベートサブネット用のECSサービス設定
resource "aws_ecs_service" "private_service" {
  name            = "my-secure-service"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = 2
  launch_type     = "FARGATE"

  network_configuration {
    # パブリックIPの自動割り当てを無効化
    assign_public_ip = false

    # プライベートサブネットを使用
    subnets         = aws_subnet.private[*].id
    security_groups = [aws_security_group.ecs_tasks.id]
  }

  # ロードバランサーを使用してトラフィックをルーティング
  load_balancer {
    target_group_arn = aws_lb_target_group.app.arn
    container_name   = "app"
    container_port   = 80
  }

  depends_on = [aws_lb_listener.app]
}

# セキュリティグループ(必要最小限のアクセスのみ許可)
resource "aws_security_group" "ecs_tasks" {
  name        = "ecs-tasks-sg"
  description = "Security group for ECS tasks"
  vpc_id      = aws_vpc.main.id

  # ALBからのインバウンドトラフィックのみ許可
  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id]
  }

  # アウトバウンドトラフィック(NAT Gateway経由)
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "ecs-tasks-sg"
  }
}

# VPCエンドポイント(ECRアクセス用)
resource "aws_vpc_endpoint" "ecr_api" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${data.aws_region.current.name}.ecr.api"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = aws_subnet.private[*].id
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true

  tags = {
    Name = "ecr-api-endpoint"
  }
}

resource "aws_vpc_endpoint" "ecr_dkr" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${data.aws_region.current.name}.ecr.dkr"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = aws_subnet.private[*].id
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true

  tags = {
    Name = "ecr-dkr-endpoint"
  }
}

# S3エンドポイント(ECRイメージレイヤー取得用)
resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${data.aws_region.current.name}.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = aws_route_table.private[*].id

  tags = {
    Name = "s3-endpoint"
  }
}

# タスク定義
resource "aws_ecs_task_definition" "app" {
  family                   = "my-app"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  execution_role_arn       = aws_iam_role.ecs_execution.arn
  task_role_arn           = aws_iam_role.ecs_task.arn

  container_definitions = jsonencode([
    {
      name  = "app"
      image = "${aws_ecr_repository.app.repository_url}:latest"
      portMappings = [
        {
          containerPort = 80
          protocol      = "tcp"
        }
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group"         = aws_cloudwatch_log_group.ecs.name
          "awslogs-region"        = data.aws_region.current.name
          "awslogs-stream-prefix" = "ecs"
        }
      }
    }
  ])
}

# データソース
data "aws_region" "current" {}

主要な修正ポイント:

  1. assign_public_ip = false: ECSサービスでパブリックIP自動割り当てを明示的に無効化
  2. プライベートサブネット使用: タスクをプライベートサブネットに配置
  3. ロードバランサー経由のアクセス: ALB/NLBを使用して外部からのトラフィックを安全にルーティング
  4. VPCエンドポイント: ECRやS3へのアクセスにVPCエンドポイントを使用し、インターネット経由を回避
  5. 最小権限のセキュリティグループ: 必要最小限のトラフィックのみを許可

修復の確認方法

修復が正しく適用されたことを確認するには、以下の手順を実行します:

AWS CLIでの確認

# ECSサービスのネットワーク設定を確認
aws ecs describe-services \\\\
  --cluster <cluster-name> \\\\
  --services <service-name> \\\\
  --region <region> \\\\
  --query 'services[0].{ServiceName:serviceName,AssignPublicIp:networkConfiguration.awsvpcConfiguration.assignPublicIp}'

# 実行中のタスクのENI情報を確認
TASK_ARN=$(aws ecs list-tasks --cluster <cluster-name> --service-name <service-name> --region <region> --query 'taskArns[0]' --output text)
aws ecs describe-tasks \\\\
  --cluster <cluster-name> \\\\
  --tasks $TASK_ARN \\\\
  --region <region> \\\\
  --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' \\\\
  --output text

# ENIの詳細を確認(パブリックIPが割り当てられていないことを確認)
ENI_ID=$(aws ecs describe-tasks --cluster <cluster-name> --tasks $TASK_ARN --region <region> --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' --output text)
aws ec2 describe-network-interfaces \\\\
  --network-interface-ids $ENI_ID \\\\
  --region <region> \\\\
  --query 'NetworkInterfaces[0].{PublicIp:Association.PublicIp,PrivateIp:PrivateIpAddress}'

テストスクリプトによる確認

#!/bin/bash
# ECSサービスのパブリックIP割り当てチェックスクリプト

CLUSTER_NAME="<your-cluster-name>"
REGION="<your-region>"

# すべてのECSサービスをチェック
SERVICES=$(aws ecs list-services --cluster $CLUSTER_NAME --region $REGION --query 'serviceArns' --output json)

echo "パブリックIPが有効なサービスをチェック中..."
PUBLIC_IP_ENABLED=false

for SERVICE_ARN in $(echo $SERVICES | jq -r '.[]'); do
    SERVICE_NAME=$(echo $SERVICE_ARN | awk -F'/' '{print $NF}')

    ASSIGN_PUBLIC_IP=$(aws ecs describe-services \\\\
        --cluster $CLUSTER_NAME \\\\
        --services $SERVICE_NAME \\\\
        --region $REGION \\\\
        --query 'services[0].networkConfiguration.awsvpcConfiguration.assignPublicIp' \\\\
        --output text 2>/dev/null)

    if [ "$ASSIGN_PUBLIC_IP" == "ENABLED" ]; then
        echo "WARNING: サービス $SERVICE_NAME にパブリックIPが有効です!"
        PUBLIC_IP_ENABLED=true
    fi
done

if [ "$PUBLIC_IP_ENABLED" == "false" ]; then
    echo "OK: すべてのECSサービスでパブリックIPの自動割り当てが無効です。"
fi

ベストプラクティス

  1. プライベートサブネットの使用
    • ECSタスクは常にプライベートサブネットに配置
    • NAT Gatewayを使用してアウトバウンド通信を提供
  2. VPCエンドポイントの活用
    • ECR、S3、CloudWatch Logs等へのアクセスにVPCエンドポイントを使用
    • データ転送コストの削減とセキュリティの向上
  3. ゼロトラストネットワークアーキテクチャ
    • コンテナからのアウトバウンド通信を厳密に制御
    • 必要な通信のみをホワイトリスト式で許可

最後に

この記事では、ECS タスクセットはパブリック IP アドレスを自動的に割り当てないでくださいについて、リスクと対策を解説しました。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考情報

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る