ECS FireLens 기반 OpenSearch 연동 테스트
Amazon ECS FireLens로 애플리케이션 로그를 OpenSearch에 전송하고 분석하여 효율적인 로그 관리 시스템을 구축합니다.
개요
본 문서는 Amazon ECS FireLens를 활용하여 애플리케이션 로그를 Amazon OpenSearch Service로 전송하고, OpenSearch Dashboards를 통해 로그를 분석 및 모니터링하는 기능을 검증하기 위한 테스트를 정의합니다. FireLens 설정, 로그 전송, OpenSearch 인덱싱 및 검색 기능을 테스트하여 안정적인 로그 관리 시스템 구축을 목표로 합니다.
테스트 환경
- AWS 서비스: Amazon ECS (Fargate 또는 EC2), Amazon OpenSearch Service, Amazon VPC, IAM
- 로그 수집 도구: FireLens (Fluent Bit)
- 로그 분석 도구: OpenSearch Dashboards
- 테스트 애플리케이션: Nginx
Process
Opensearch 생성
로그를 적재할 OpenSearch를 생성해야합니다.
OpenSearch 데이터 노드 생성


Opensearch 호스트는 다음과 같습니다.
OpenSearch 세분화된 엑세스를 통한 접근 제어
FGAC(Fine-Grained Access Control)를 사용하면 IAM 역할, 사용자 속성, 데이터 자체에 설정된 권한 등을 기반으로 접근 권한을 부여할 수 있습니다. 특히 필드 레벨, 문서 레벨까지 세분화된 접근 제어가 가능하여 특정 사용자에게 특정 필드 또는 문서에 대한 접근 권한만 부여할 수 있습니다. 이를 통해 로그를 적재하는 컨테이너에 최소 권한을 할당할 수 있고, 컨테이너가 수행하는 작업에 필요한 리소스에 대한 접근만 허용하여 보안을 강화할 수 있습니다
추가로 세분화된 엑세스 제어를 설정하였으므로, OpenSearch 내부에서 관련 권한을 추가로 설정해주어야합니다. Amazon OpenSearch Service는 데이터를 안전하게 보호하기 위해 3단계 계층으로 구성된 보안 모델을 제공합니다.
각 계층은 다음과 같은 역할을 수행합니다.
1. 네트워크 계층:
- OpenSearch Service 도메인에 대한 접근을 제어하는 첫 번째 관문입니다.
- 퍼블릭 액세스: 인터넷에 연결된 모든 클라이언트가 도메인에 접근할 수 있도록 허용합니다.
- VPC 액세스: Virtual Private Cloud(VPC) 내부의 클라이언트만 도메인에 접근할 수 있도록 제한합니다. VPC 및 보안 그룹 설정을 통해 접근을 더욱 세밀하게 제어할 수 있습니다.
2. 도메인 액세스 정책 계층:
- OpenSearch 도메인 자체에 대한 접근 권한을 제어합니다.
- 리소스 기반 액세스 정책을 사용하여 특정 사용자, 역할 또는 IP 주소가 도메인의 특정 리소스(예: 인덱스, 문서)에 접근할 수 있는지 여부를 정의합니다.
- OpenSearch에 요청이 도달하기 전에 "경계"에서 접근을 허용하거나 거부합니다.
3. 세분화된 액세스 제어 계층:
- OpenSearch 도메인 내에서 데이터에 대한 접근을 세밀하게 제어합니다.
- 사용자 자격 증명을 평가하여 인증하고, 사용자에게 할당된 역할에 따라 권한을 부여합니다.
- 역할 기반 액세스 제어를 통해 인덱스, 문서, 필드 수준까지 세분화된 접근 제어를 구현할 수 있습니다.
세 계층은 서로 연동하여 작동하며, OpenSearch Service 도메인에 대한 포괄적인 보안을 제공합니다.
예를 들어, VPC 액세스를 통해 특정 VPC 내의 클라이언트만 도메인에 접근하도록 제한하고, 도메인 액세스 정책을 통해 특정 IP 주소 범위의 접근을 차단하며, 세분화된 액세스 제어를 통해 특정 사용자에게 특정 문서에 대한 읽기 권한만 부여하는 등 다양한 보안 정책을 조합하여 적용할 수 있습니다.

OpenSearch 권한 설정
[Dashboard] → [Management] → [Security] → [Roles] → [Create Role] 이동합니다.
해당 권한에 아래 Cluster 정책을 추가합니다.
indices:data/write/bulk

인덱스 명은 CloudWatch FireLens에서 설정되는 설정과 동일해야합니다. 이때 없다면 자동으로 생성됩니다.

이후 역할을 생성합니다.

만약 인덱스를 미리 생성하지 않았더라면 아래 두 가지 index 권한을 추가해야합니다.
indices:admin/create
indices:admin/mapping/put
생성된 Role에 ECS TaskRole을 매핑하면 마무리입니다.


ECS Task 정의
ECS 인프라 요구 사항에 대한 기본적인 설정은 사용자의 애플리케이션에 따라 설정하며 현재 환경은 Fargate로 진행하였습니다. 정상적으로 ECS FireLens를 통해 로그를 전송하기 위해선 ECS TaskRole에 OpenSearch 접근 권한이 존재해야합니다. 또한 세분화된 엑세스 제어를 활성화하신 경우 OpenSearch에 대해서도 마찬가지로 Task Role이 OpenSearch에 작업할 수 있는 권한이 존재해야합니다.
Application 로그 수집 정의(OpenSearch 버전 1.x)
- Host → OpenSearch의 도메인을 입력합니다.
- Index → OpenSearch IndexPermission에서 추가한 인덱스와 동일한 인덱스명
ecs-nginx-demo
을 지정합니다. - Awsauth → Awsauth를 Off하는 경우 사용자 아이디, 비밀번호를 추가해야하지만 권장드리지 않습니다.
- TaskRole에 OpenSearch 접근 권한이 존재해야합니다.
- 세분화된 엑세스 제어를 활성화하신 경우 OpenSearch 권한이 존재해야합니다.

Application 로그 수집 정의(OpenSearch 버전 2.x)
Opensearch 2.x 버전의 경우 콘솔에서 지원하는 템플릿으로 생성할 수 없습니다.
따라서 JSON 포맷을 구성해서 직접 options를 수정해야하며 이때 Type
을 제거하고 Suppress_Type_Name
을 추가하여 생성합니다. 예제 포맷은 다음과 같습니다.
{
"containerDefinitions": [
{
"name": "nginx",
"image": "nginxdemos/hello",
"cpu": 512,
"memory": 2048,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Aws_region": "ap-northeast-2",
"Suppress_Type_Name": "On",
"Port": "443",
"Host": "search-bjchoi-log-test2-55k3wkmjq37egj3dku5oblwnia.ap-northeast-2.es.amazonaws.com",
"Index": "ecs-nginx-demo",
"tls": "On",
"Aws_auth": "On",
"Name": "es",
}
}
},
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
"cpu": 1024,
"memory": 2048,
"essential": true,
"user": "0",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/test-bjchoi-nginx-task",
"awslogs-create-group": "true",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
},
"firelensConfiguration": {
"type": "fluentbit"
}
}
],
"family": "test-bjchoi-nginx-task",
"taskRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "2048",
"memory": "4096",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
}
}
이후 서비스를 배포하여 로그를 확인합니다.

- 컨테이너 정상 배포 확인

- 서비스도 정상적으로 실행 중인 것을 확인할 수 있습니다.
Opensearch 확인
정상적으로 배포가 수행되었고 로그가 정상적으로 배포되는 경우 로그를 확인할 수 있습니다.

트러블 슈팅
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Action/metadata line [1] contains an unknown parameter [_type]"
}
],
"type": "illegal_argument_exception",
"reason": "Action/metadata line [1] contains an unknown parameter [_type]"
},
"status": 400
}
OpenSearch에 데이터를 인덱싱할 때 발생하는 오류입니다. 오류 메시지를 분석해보면 "Action/metadata line [1] contains an unknown parameter [_type]" 라고 되어 있는데, 이는 OpenSearch가 인식할 수 없는 파라미터 _type
이 요청에 포함되어 있다는 것을 의미합니다.
OpenSearch의 2.x 버전부터는 해당 타입을 지원하지 않습니다. 따라서 제거해야하지만, 콘솔에서 FireLens → OpenSearch 포맷으로 작성하는 경우 해당 값을 변경하는게 불가능합니다. 따라서 ECS Task를 JSON으로 생성해서 Type을 제거하고 생성해야 바람직합니다.
{
"containerDefinitions": [
{
"name": "nginx",
"image": "nginxdemos/hello",
"cpu": 512,
"memory": 2048,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Aws_region": "ap-northeast-2",
"Suppress_Type_Name": "On",
"Port": "443",
"Host": "search-bjchoi-log-test2-55k3wkmjq37egj3dku5oblwnia.ap-northeast-2.es.amazonaws.com",
"Index": "ecs-nginx-demo",
"tls": "On",
"Aws_auth": "On",
"Name": "es",
}
}
},
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
"cpu": 1024,
"memory": 2048,
"essential": true,
"user": "0",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/test-bjchoi-nginx-task",
"awslogs-create-group": "true",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
},
"firelensConfiguration": {
"type": "fluentbit"
}
}
],
"family": "test-bjchoi-nginx-task",
"taskRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "2048",
"memory": "4096",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
}
}
Chunk cannot be retried, failed to flush chunk
인덱스가 없는 경우, Replace_Dots
가 없는 경우 발생하는 오류로, 해당 파라미터를 추가합니다.
{
"containerDefinitions": [
{
"name": "nginx",
"image": "nginxdemos/hello",
"cpu": 512,
"memory": 2048,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Aws_region": "ap-northeast-2",
"Suppress_Type_Name": "On",
"Port": "443",
"Host": "search-bjchoi-log-test2-55k3wkmjq37egj3dku5oblwnia.ap-northeast-2.es.amazonaws.com",
"Index": "ecs-nginx-demo",
"tls": "On",
"Aws_auth": "On",
"Name": "es",
"Replace_Dots": "On"
}
}
},
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
"cpu": 1024,
"memory": 2048,
"essential": true,
"user": "0",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/test-bjchoi-nginx-task",
"awslogs-create-group": "true",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
},
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "true"
}
}
}
],
"family": "test-bjchoi-nginx-task",
"taskRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::759320821027:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "2048",
"memory": "4096",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
}
}
References
- https://blog.bespinglobal.com/post/firelens-opensearch-%EC%97%B0%EB%8F%99-%EC%84%A4%EC%A0%95/
- https://repost.aws/knowledge-center/ecs-pull-container-error
- https://discuss.openobserve.ai/2J2485f
- https://github.com/fluent/fluent-bit/issues/5916
- https://github.com/aws-samples/amazon-ecs-firelens-examples
- https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/firelens-concatanate-multiline.html