Serverless Agentsを利用してECS Fargate環境でSysdig Secureを利用してみた〜Terraform編〜
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。
今回は、Sysdig Secureから提供されているServerless Agentsを利用して、ECS Fargate環境でデプロイされるコンテナのランタイム検知をしてみようと思います。
Sysdig Secureとは
Sysdig Secureとは、Sysdig社から提供されるセキュリティ製品の1つでクラウド環境やコンテナ環境の脆弱性の検知、保護等を行う製品です。
Sysdig Secure is part of Sysdig’s container intelligence platform. Sysdig uses a unified platform to deliver security, monitoring, and forensics in a cloud, container and microservices-friendly architecture integrated with Docker and Kubernetes. Sysdig Secure takes a services-aware approach to protect workloads while bringing deep cloud and container visibility, posture management (compliance, benchmarks, CIEM), vulnerability scanning, forensics and threat detection and blocking.
Sysdig Secureより引用
Serverless Agentsとは
今回利用するServerless Agentsとは、AWS Fargateのようなサーバレス環境でSysdig Secureを起動するために必要なエージェントになります。
ECS on Fargateの場合、ECS on EC2とは違いコンテナを起動するホストにエージェントをインストールできないため、Serverless Agentsをサイドカーコンテナの形式でデプロイする必要があります。
構成要素
Serverless Agentsは、「Agents」と名前がついている通り、2種類のエージェントで構成されています。
ECS on Fargate環境下でSysdig Secureを起動するには、各エージェントを必要な数、デプロイする必要があります。
- The Sysdig serverless orchestrator agent(以後、orchestrator agent)
- 各VPCごとに1つ必要
- 後続のThe Sysdig serverless workload agentからデータを収集し、Sysdig SaaSのエンドポイントへ転送する
- The Sysdig serverless workload agent(以後、workload agent)
- 各タスクごとに必要
- 同一タスク内に含まれるコンテナの情報をorchestrator agentに転送する
AWS Fargate Serverless Agents - Architectureより引用
今回はTerraformデプロイであることと、もう少し深掘りして全体像を表すと以下になります。
また、今回使用したコードは以下に格納しました。自由にカスタマイズしてご利用いただければと思います。
VPC周りの作成
では、VPCも含めて今回の構成をセットアップしてみます。
terraform-aws-modules/vpc/awsを利用してデプロイします。
どのような通信が行われているかも含めて確認したいため、今回はVPCフローログもデプロイします。
プロバイダー設定
terraform { required_providers { aws = { source = "hashicorp/aws" version = "4.37.0" } } } provider "aws" { region = "ap-northeast-1" } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region data "aws_region" "current" {} # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity data "aws_caller_identity" "self" {}
変数設定
variable "prefix" { type = string default = "sysdig-fargate" }
S3(VPCフローログ用)
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket resource "aws_s3_bucket" "flowlog" { bucket = "${var.prefix}-flowlog-${data.aws_caller_identity.self.account_id}" force_destroy = true } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls resource "aws_s3_bucket_ownership_controls" "flowlog" { bucket = aws_s3_bucket.flowlog.id rule { object_ownership = "BucketOwnerEnforced" } } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy resource "aws_s3_bucket_policy" "flowlog" { bucket = aws_s3_bucket.flowlog.id policy = templatefile("${path.module}/policy_document/bucket_flowlog.json", { bucket_arn = aws_s3_bucket.flowlog.arn account_id = data.aws_caller_identity.self.account_id region = data.aws_region.current.name }) } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration resource "aws_s3_bucket_server_side_encryption_configuration" "flowlog" { bucket = aws_s3_bucket.flowlog.id rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block resource "aws_s3_bucket_public_access_block" "flowlog" { bucket = aws_s3_bucket.flowlog.id block_public_acls = true block_public_policy = true restrict_public_buckets = true ignore_public_acls = true depends_on = [ aws_s3_bucket_policy.flowlog, aws_s3_bucket_ownership_controls.flowlog ] }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AWSLogDeliveryWrite", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "${bucket_arn}/*", "Condition": { "StringEquals": { "aws:SourceAccount": "${account_id}", "s3:x-amz-acl": "bucket-owner-full-control" }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:${region}:${account_id}:*" } } } ] }
# https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest module "vpc" { source = "terraform-aws-modules/vpc/aws" name = var.prefix cidr = "10.0.0.0/16" azs = ["${data.aws_region.current.name}a", "${data.aws_region.current.name}c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] enable_nat_gateway = true single_nat_gateway = true enable_flow_log = true flow_log_destination_type = "s3" flow_log_destination_arn = aws_s3_bucket.flowlog.arn flow_log_traffic_type = "ALL" }
全体像で表すと以下まで作成完了しました。
orchestrator agentの作成
Sysdig公式からorchestrator agentを作成するためにModuleが提供されています。
今回はこちらのModuleを利用して、orchestrator agentを作成してみようと思います。
# https://registry.terraform.io/modules/sysdiglabs/fargate-orchestrator-agent/aws/latest module "fargate-orchestrator-agent" { source = "sysdiglabs/fargate-orchestrator-agent/aws" version = "0.2.0" vpc_id = module.vpc.vpc_id subnets = module.vpc.private_subnets access_key = var.sysdig_access_key # Sysdig access key collector_host = "ingest.au1.sysdig.com" # Sysdig collector host (default:"collector.sysdigcloud.com") collector_port = "6443" # Sysdig collector port (default:"6443") name = "${var.prefix}-orchestrator" # Identifier for module resources agent_image = "quay.io/sysdig/orchestrator-agent:latest" # Orchestrator agent image assign_public_ip = false # Provisions a public IP for the service. Required when using an Internet Gateway for egress. }
access_keyについて
module内で指定した「access_key」について補足します。
access_keyは、Sysdig Secureコンソール画面から取得できます。
「Your access key」からアクセスキーをコピーします。
コピーが完了したら、variables.tf
とterraform.tfvars
を利用して設定していきます。
variable "prefix" { type = string default = "sysdig-fargate" } variable "sysdig_access_key" { type = string default = "" sensitive = true }
sysdig_access_key = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
collector_hostについて
module内で指定した「collector_host」について補足します。
collector_hostは、Sysdigのアカウント作成時に指定したリージョンによって設定値が異なります。
私の場合、Asia Pacific (Sydney)を指定したため、「ingest.au1.sysdig.com
」を指定する必要があります。
詳しくは以下をご覧ください。
orchestrator agentの作成が完了すると以下のような構成になっています。
workload agentとアプリケーションコンテナの作成
続いて、workload agentをサイドカー形式でアプリケーションコンテナと一緒にデプロイします。
今回、アプリケーションコンテナはFalco Securityより提供されているfalcosecurity/event-generatorを利用してみようと思います。
詳しい使い方は以下をご覧ください。
タスク定義の作成
タスク定義の作成を行います。
sysdig_fargate_workload_agentを利用して、workload agentを組み込んだタスク定義を作成します。
はじめに、sysdig_fargate_workload_agent
はSysdigプロバイダーによって提供されているためプロバイダーの設定を更新します。
terraform { required_providers { aws = { source = "hashicorp/aws" version = "4.37.0" } # ここ sysdig = { source = "sysdiglabs/sysdig" version = "0.5.40" } } } provider "aws" { region = "ap-northeast-1" } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region data "aws_region" "current" {} # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity data "aws_caller_identity" "self" {} # ここ provider "sysdig" { sysdig_secure_url = "https://app.au1.sysdig.com" sysdig_secure_api_token = var.sysdig_access_key }
次にworkload agentを利用しない場合のタスク定義を定めます。
今回のタスク定義は以下になります。(Terraformで値を受け渡しするため、マネジメントコンソール上で表示される内容と一部異なります。)
[ { "name": "event-generator", "essential": true, "image": "falcosecurity/event-generator", "entryPoint": ["/bin/event-generator"], "command": [ "run", "syscall", "--loop" ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-region": "${region}", "awslogs-group": "${log_group_name}", "awslogs-stream-prefix": "${log_stream_prefix}" } } } ]
上記のタスク定義にsysdig_fargate_workload_agentを利用して、workload agentを組み込みます。
# https://registry.terraform.io/providers/sysdiglabs/sysdig/latest/docs/data-sources/fargate_workload_agent data "sysdig_fargate_workload_agent" "instrumented_envent_generator" { container_definitions = templatefile("${path.module}/task_definition/event_generator.json", { region = data.aws_region.current.name log_group_name = aws_cloudwatch_log_group.task.name log_stream_prefix = "${var.prefix}-event-generator" }) sysdig_access_key = var.sysdig_access_key workload_agent_image = "quay.io/sysdig/workload-agent:latest" orchestrator_host = module.fargate-orchestrator-agent.orchestrator_host orchestrator_port = module.fargate-orchestrator-agent.orchestrator_port log_configuration { region = data.aws_region.current.name group = aws_cloudwatch_log_group.workload_agent.name stream_prefix = "${var.prefix}-workload-agent" } }
最後にsysdig_fargate_workload_agent
のアウトプットを利用して、タスク定義を作成します。
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition resource "aws_ecs_task_definition" "envent_generator" { family = "${var.prefix}-td-event-generator" requires_compatibilities = [ "FARGATE" ] network_mode = "awsvpc" cpu = "1024" memory = "2048" container_definitions = data.sysdig_fargate_workload_agent.instrumented_envent_generator.output_container_definitions execution_role_arn = aws_iam_role.task_exec.arn runtime_platform { operating_system_family = "LINUX" cpu_architecture = "X86_64" } }
サービスの作成
タスク定義が作成できたため、ECSクラスター、サービスをデプロイしていきます。
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role resource "aws_iam_role" "task_exec" { name = "${var.prefix}-role-task-exection" assume_role_policy = file("${path.module}/policy_document/assume_ecs_task_exec.json") } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment resource "aws_iam_role_policy_attachment" "managed_task_exec" { role = aws_iam_role.task_exec.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group resource "aws_cloudwatch_log_group" "task" { name = "${var.prefix}-logs" } resource "aws_cloudwatch_log_group" "workload_agent" { name = "${var.prefix}-workload-agent-logs" } # https://registry.terraform.io/providers/sysdiglabs/sysdig/latest/docs/data-sources/fargate_workload_agent data "sysdig_fargate_workload_agent" "instrumented_envent_generator" { container_definitions = templatefile("${path.module}/task_definition/event_generator.json", { region = data.aws_region.current.name log_group_name = aws_cloudwatch_log_group.task.name log_stream_prefix = "${var.prefix}-event-generator" }) sysdig_access_key = var.sysdig_access_key workload_agent_image = "quay.io/sysdig/workload-agent:latest" orchestrator_host = module.fargate-orchestrator-agent.orchestrator_host orchestrator_port = module.fargate-orchestrator-agent.orchestrator_port log_configuration { region = data.aws_region.current.name group = aws_cloudwatch_log_group.workload_agent.name stream_prefix = "${var.prefix}-workload-agent" } } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition resource "aws_ecs_task_definition" "envent_generator" { family = "${var.prefix}-td-event-generator" requires_compatibilities = [ "FARGATE" ] network_mode = "awsvpc" cpu = "1024" memory = "2048" container_definitions = data.sysdig_fargate_workload_agent.instrumented_envent_generator.output_container_definitions execution_role_arn = aws_iam_role.task_exec.arn runtime_platform { operating_system_family = "LINUX" cpu_architecture = "X86_64" } } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster resource "aws_ecs_cluster" "cluster" { name = "${var.prefix}-cluster" setting { name = "containerInsights" value = "enabled" } } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group resource "aws_security_group" "ecs_service" { name = "${var.prefix}-ecs-service" description = "${var.prefix}-ecs-service" vpc_id = module.vpc.vpc_id } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule resource "aws_security_group_rule" "ecs_any_egress" { security_group_id = aws_security_group.ecs_service.id type = "egress" description = "Allow to Any" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service resource "aws_ecs_service" "service" { name = "${var.prefix}-service" cluster = aws_ecs_cluster.cluster.id launch_type = "FARGATE" task_definition = aws_ecs_task_definition.envent_generator.arn desired_count = 1 network_configuration { security_groups = [ aws_security_group.ecs_service.id ] subnets = module.vpc.private_subnets assign_public_ip = false } }
{ "Version": "2008-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Sysdig Secureで確認
Sysdig Secureで確認してみます。デフォルトでは重要度が「High」のルールのみ有効下されていたため、「Sysdig Runtime Notable Events
」と「Sysdig Runtime Activity Logs
」を有効にしてみます。
有効にするとルールで検知されたリソースがInshightに表示されていました。
Eventsタブでも、時系列順に検知されたルールが表示されるようになりました。
通信要件まとめ
Serverless Agentsの構成の場合、デフォルトでは以下の通信が必要でした。
どちらのポートも、orchestrator agent作成時に指定する値のため、ポート範囲に迷ったら、module "fargate-orchestrator-agent"
で探してみてください。
fargate-orchestrator-agent - inputs
IPアドレスベースで絞りたい場合は、再掲になりますがSysdigの地域別で利用しているIP範囲をご覧いただければと思います。
参考情報
教えてケイティ! - AWS ECSでサーバレスエージェントをデプロイする!
まとめ
以上、Serverless Agentsを利用して、ECS Fargate環境でデプロイされるコンテナのランタイム検知でした。
引き続きランタイム保護等のポリシーについて調べてみようと思います。この記事がどなたかの参考になれば幸いです。
AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!