Amazon Web Services 한국 블로그

AWS 멀티 어카운트 환경을 위한 통합 로깅 방법

중앙 집중 로깅 기능은 규정 준수와 보안 및 분석, 애플리케이션 별 필요성과 같은 다양한 이유로 일정 규모 이상의 기업에서는 반드시 고려되는 기능입니다.

단일 부서에서 관리되거나 여러 부서에서 관리되는 멀티 어카운트 환경에서는, 중앙에서 로그정보를 수집하는 로깅 전담 어카운트가 있는 것이 모범사례입니다. 이를 통해 보안팀 입장에서는 실시간으로 위험한 행위를 탐지하고 침해에 대처하는데 도움을 받을 수 있게 됩니다. 또한 로그데이터가 사고나 혹은 의도적으로 지워질 경우도 방지할 수 있습니다. 애플리케이션 운영팀 입장에서도 여러 개의 애플리케이션 티어 상에서 로그 데이터를 분석하고 연관짓는 데 도움을 받을 수 있습니다.

본 포스팅에서는 멀티 어카운트 환경에서 Amazon CloudWatch Log 데이터를 다룰 수 있는 솔루션과 구현 방법을 제공합니다. 이것은 모든 어카운트들로 부터 관련있는 Amazon CloudWatch Log 데이터 전체를 중앙의 로깅 어카운트 쪽에 모을 수 있는 환경을 구성해 주는 재활용 가능한 솔루션입니다.

솔루션 개요

본 솔루션은 Amazon Kinesis Data Streams와 로깅 어카운트 상에서 로그 스트림을 수집하기 위한 엔드포인트로서, 로그 Destination을 이용하게 되며, S3 버킷으로 로그 데이터를 취합하기 위해 Amazon Kinesis Data Firehose 를 사용하게 됩니다. 애플리케이션 어카운트들은 Subscription Filter를 설정하여 로깅 어카운트의 지정된 타겟 쪽으로 CloudWatch Logs 의 전체 혹은 일부를 보내도록 구현됩니다.

아래 다이어그램에서 다양한 서비스들이 어떻게 상호 연계되는지 알 수 있습니다.

로깅 어카운트 내에, 로그 스트림을 받아 줄 하나의 Kinesis Data Stream이 생성되고, 원격지 로그 소스(애플리케이션 어카운트의 CloudWatch LogGroup)로부터 로그를 받기 위한 로그Destination이 생성되어  Kinesis Data Stream을 스트림 타겟으로 지정할 수 있도록 구성됩니다.

그리고 Kinesis Data Stream에서 S3쪽으로 로그 데이터를 공급하기 위해 Amazon Kinesis Data Firehose stream이 생성됩니다. 이때 공급되는 로그 데이터에 대한 검증과 변환을 위해 하나의 generic AWS Lambda Function이 사용됩니다.

각 애플리케이션 어카운트에서는, Amazon CloudWatch Log Group과 로깅 어카운트 내 로그 그룹별 Destination 간에 Subscription Filter 가 생성됩니다.

아래의 절차는 방금 설명드린 중앙 집중 로깅 솔루션을 위한 전체적인 구성 단계입니다:

  1. 중앙 집중 로깅을 위해 로깅 어카운트 내에 한 개의 Amazon S3 bucket 을 생성합니다.
  2. 로깅 어카운트 내에 로그 데이터 변환 등을 위한 AWS Lambda Function을 생성합니다.
  3. 공급되는 로그 스트림을 받아서 이를 다시 S3에 전달해 주기 위해, 로깅 어카운트 Destination역할을 할 중앙 로깅 스택을 생성합니다.
  4. 개별  CloudWatch Log Group으로 부터 로깅 어카운트의 Destination으로 로그를 배달해 주기 위해 각각의 애플리케이션 어카운트 별로 Subscription을 생성합니다.
  5. 로깅 어카운트 내에 로그데이터에 대한 쿼리와 분석을 위한 Amazon Athena 테이블을 구성합니다.

로깅 어카운트 내에 로그 Destination 생성하기

본 섹션에서는, 위에서 설명했던 과정 중 로깅 어카운트 에서 구성할 부분에 대해 살펴보겠습니다. 이 과정에서는 편의상 ‘us-east-1’ 리전을 사용하게 되지만 여러분들은 각 구성 요소 서비스가 모두 지원되는 다른 리전을 선택할 수 있습니다.

만들게 되는 로깅 어카운트 상의 Destination과 각 애플리케이션 어카운트의 Subscription 은 같은 리전 상에 있어야 한다는 점을 유념하시기 바라며, 만약 멀티 리전 환경을 위해서는 필요로 하는 리젼 별로 반복적으로 동일한 구성을 준비해야 합니다.

단계 1: S3 버킷 생성

로깅 어카운트 내, 한 개의 S3 버킷을 생성해 주는 다음 CloudFormation 템플릿을 사용하기 바랍니다. 본 템플릿은 또한 60일이 지난 로그 데이터를 버킷에서 Glacier쪽으로 저장 및 보존하도록 되어 있습니다.


{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Description": "CF Template to create S3 bucket for central logging",
  "Parameters":{

    "BucketName":{
      "Type":"String",
      "Default":"",
      "Description":"Central logging bucket name"
    }
  },
  "Resources":{
                        
   "CentralLoggingBucket" : {
      "Type" : "AWS::S3::Bucket",
      "Properties" : {
        "BucketName" : {"Ref": "BucketName"},
        "LifecycleConfiguration": {
            "Rules": [
                {
                  "Id": "ArchiveToGlacier",
                  "Prefix": "",
                  "Status": "Enabled",
                  "Transitions":[{
                      "TransitionInDays": "60",
                      "StorageClass": "GLACIER"
                  }]
                }
            ]
        }
      }
    }

  },
  "Outputs":{
    "CentralLogBucket":{
    	"Description" : "Central log bucket",
    	"Value" : {"Ref": "BucketName"} ,
    	"Export" : { "Name" : "CentralLogBucketName"}
    }
  }
} 

중앙 로깅 버킷을 만들기 위해 다음 작업을 수행하기 바랍니다:

  1. 여러분 PC 상에서 “central-log-bucket.json” 이름으로 위 템플릿 내용을 파일로 저장합니다.
  2. CloudFormation 콘솔에서, “create new stack”을 선택하고 “central-log-bucket.json” 파일을 Import하세요.
  3. 파라메터 란에 아래 그림처럼 중앙 로깅 버킷의 이름을 주고 스택 생성과정을 진행합니다.
  4. 최종적으로 버킷이 잘 생성되었는지 확인하고 버킷의 이름을 기록합니다.

단계 2: 로그를 변환하기 위한 Lambda Function 생성하기

로깅 어카운트 상에서S3로 로그 데이터들이 적재되는 과정에서 데이터의 변환을 책임 질 Lambda Function을 생성해 줄 아래에 있는 CloudFormation템플릿을 이용하기 바랍니다. 해당 함수는 Amazon Firehose에 의해 사용되게 되며, ‘AWS Lambda kinesis-firehose-cloudwatch-logs-processor’ Blueprint를 기반으로 합니다.

이 Lambda함수는 위 Blueprint를 이용하여 수작업으로 만들어도 되고, 아래의 CloudFormation 템플릿으로 만들어도 됩니다. 해당  Blueprint를 찾으려면, 다음 그림처럼, Lambda -> Create -> Function -> Blueprints 순서로 이동합니다.

이 Lambda 함수는 이벤트 메세지를 압축 해제하고, 파싱한 뒤, CloudWatch Logs 이벤트 인지를 검사합니다. 필요하다면 추가 작업을 덧붙일 수 있으며, 일반적인 함수이기 때문에, 모든 로그 수집용 스트림에 의해 사용될 수 있습니다.

{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Description": "Create cloudwatch data processing lambda function",
  "Resources":{
      
    "LambdaRole": {
        "Type": "AWS::IAM::Role",
        "Properties": {
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "lambda.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            },
            "Path": "/",
            "Policies": [
                {
                    "PolicyName": "firehoseCloudWatchDataProcessing",
                    "PolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "logs:CreateLogGroup",
                                    "logs:CreateLogStream",
                                    "logs:PutLogEvents"
                                ],
                                "Resource": "arn:aws:logs:*:*:*"
                            }
                        ]
                    }
                }
            ]
        }
    },
      
    "FirehoseDataProcessingFunction": {
        "Type": "AWS::Lambda::Function",
        "Properties": {
            "Handler": "index.handler",
            "Role": {"Fn::GetAtt": ["LambdaRole","Arn"]},
            "Description": "Firehose cloudwatch data processing",
            "Code": {
                "ZipFile" : { "Fn::Join" : ["\n", [
                  "'use strict';",
                  "const zlib = require('zlib');",
                  "function transformLogEvent(logEvent) {",
                  " return Promise.resolve(`${logEvent.message}\n`);",
                  "}",
                  "exports.handler = (event, context, callback) => {",
                  " Promise.all(event.records.map(r => {",
                  " const buffer = new Buffer(r.data, 'base64');",
                  " const decompressed = zlib.gunzipSync(buffer);",
                  " const data = JSON.parse(decompressed);",
                  " if (data.messageType !== 'DATA_MESSAGE') {",
                  " return Promise.resolve({",
                  " recordId: r.recordId,",
                  " result: 'ProcessingFailed',",
                  " });",
                  " } else {",
                  " const promises = data.logEvents.map(transformLogEvent);",
                  " return Promise.all(promises).then(transformed => {",
                  " const payload = transformed.reduce((a, v) => a + v, '');",
                  " const encoded = new Buffer(payload).toString('base64');",
                  " console.log('---------------payloadv2:'+JSON.stringify(payload, null, 2));",
                  " return {",
                  " recordId: r.recordId,",
                  " result: 'Ok',",
                  " data: encoded,",
                  " };",
                  " });",
                  " }",
                  " })).then(recs => callback(null, { records: recs }));",
                    "};"

                ]]}
            },
            "Runtime": "nodejs6.10",
            "Timeout": "60"
        }
    }

  },
  "Outputs":{
   "Function" : {
      "Description": "Function ARN",
      "Value": {"Fn::GetAtt": ["FirehoseDataProcessingFunction","Arn"]},
      "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Function" }}
    }
  }
}

다음 절차대로 해당 함수를 생성하기 바랍니다:

  1. 위 템플릿의 내용을 복사해서 “central-logging-lambda.json”라는 이름으로 파일로 저장하세요.
  2. 로깅 어카운트로 콘솔 로그인 후, CloudFormation 콘솔에서, “create new stack”을 선택합니다.
  3. “central-logging-lambda.json” 파일을 Import하고 next를 클릭합니다.
  4. 스택을 실행하기 위해 계속해서 단계를 진행하여 최종적으로 성공적으로 Lambda함수가 생성 되었는 지를 확인합니다.
  5. Output 탭에서 Lambda Function ARN을 확인하고 기록해 둡니다.

단계 3: 로깅 어카운트 상에 로그 Destination 생성하기

로그 Destination 은 각 애플리케이션 어카운트에서 Subscription의 타겟으로 사용되며 복수 개의 Subscription 간에 공유될 수 있습니다. 본 포스팅에서는 단일 S3버킷으로 취합하는 시나리오이기 때문에, 모든 로그 스트림이 한개의 Destination으로 들어오도록 되지만, 로그 데이터를 여러 개의 계층화된 구조에 담는 다거나 여러 개의 버킷 별로 받고자 하는 경우에는 개별적인 Destination을 생성하기 바랍니다.

앞에서 기술한 대로, 여러분의 Destination과 Subscription은 같은 리전 안에 있어야 합니다.

아래 템플릿을 이용하여 로깅 어카운트 내에 Destination Stack을 생성합니다.

{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Description": "Create log destination and required resources",
  "Parameters":{

    "LogBucketName":{
      "Type":"String",
      "Default":"central-log-do-not-delete",
      "Description":"Destination logging bucket"
    },
    "LogS3Location":{
      "Type":"String",
      "Default":"<BU>/<ENV>/<SOURCE_ACCOUNT>/<LOG_TYPE>/",
      "Description":"S3 location for the logs streamed to this destination; example marketing/prod/999999999999/flow-logs/"
    },
    "ProcessingLambdaARN":{
      "Type":"String",
      "Default":"",
      "Description":"CloudWatch logs data processing function"
    },
    "SourceAccount":{
      "Type":"String",
      "Default":"",
      "Description":"Source application account number"
    }
  },
    
  "Resources":{
    "MyStream": {
      "Type": "AWS::Kinesis::Stream",
      "Properties": {
        "Name": {"Fn::Join" : [ "", [{ "Ref" : "AWS::StackName" },"-Stream"] ]},
        "RetentionPeriodHours" : 48,
        "ShardCount": 1,
        "Tags": [
          {
            "Key": "Solution",
            "Value": "CentralLogging"
          }
       ]
      }
    },
    "LogRole" : {
      "Type"  : "AWS::IAM::Role",
      "Properties" : {
          "AssumeRolePolicyDocument" : {
              "Statement" : [ {
                  "Effect" : "Allow",
                  "Principal" : {
                      "Service" : [ {"Fn::Join": [ "", [ "logs.", { "Ref": "AWS::Region" }, ".amazonaws.com" ] ]} ]
                  },
                  "Action" : [ "sts:AssumeRole" ]
              } ]
          },         
          "Path" : "/service-role/"
      }
    },
      
    "LogRolePolicy" : {
        "Type" : "AWS::IAM::Policy",
        "Properties" : {
            "PolicyName" : {"Fn::Join" : [ "", [{ "Ref" : "AWS::StackName" },"-LogPolicy"] ]},
            "PolicyDocument" : {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": ["kinesis:PutRecord"],
                  "Resource": [{ "Fn::GetAtt" : ["MyStream", "Arn"] }]
                },
                {
                  "Effect": "Allow",
                  "Action": ["iam:PassRole"],
                  "Resource": [{ "Fn::GetAtt" : ["LogRole", "Arn"] }]
                }
              ]
            },
            "Roles" : [ { "Ref" : "LogRole" } ]
        }
    },
      
    "LogDestination" : {
      "Type" : "AWS::Logs::Destination",
      "DependsOn" : ["MyStream","LogRole","LogRolePolicy"],
      "Properties" : {
        "DestinationName": {"Fn::Join" : [ "", [{ "Ref" : "AWS::StackName" },"-Destination"] ]},
        "RoleArn": { "Fn::GetAtt" : ["LogRole", "Arn"] },
        "TargetArn": { "Fn::GetAtt" : ["MyStream", "Arn"] },
        "DestinationPolicy": { "Fn::Join" : ["",[
		
				"{\"Version\" : \"2012-10-17\",\"Statement\" : [{\"Effect\" : \"Allow\",",
                " \"Principal\" : {\"AWS\" : \"", {"Ref":"SourceAccount"} ,"\"},",
                "\"Action\" : \"logs:PutSubscriptionFilter\",",
                " \"Resource\" : \"", 
                {"Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":" ,{ "Ref": "AWS::AccountId" }, ":destination:",{ "Ref" : "AWS::StackName" },"-Destination" ] ]}  ,"\"}]}"

			]]}
      }
    },
      
    "S3deliveryStream": {
      "DependsOn": ["S3deliveryRole", "S3deliveryPolicy"],
      "Type": "AWS::KinesisFirehose::DeliveryStream",
      "Properties": {
        "DeliveryStreamName": {"Fn::Join" : [ "", [{ "Ref" : "AWS::StackName" },"-DeliveryStream"] ]},
        "DeliveryStreamType": "KinesisStreamAsSource",
        "KinesisStreamSourceConfiguration": {
            "KinesisStreamARN": { "Fn::GetAtt" : ["MyStream", "Arn"] },
            "RoleARN": {"Fn::GetAtt" : ["S3deliveryRole", "Arn"] }
        },
        "ExtendedS3DestinationConfiguration": {
          "BucketARN": {"Fn::Join" : [ "", ["arn:aws:s3:::",{"Ref":"LogBucketName"}] ]},
          "BufferingHints": {
            "IntervalInSeconds": "60",
            "SizeInMBs": "50"
          },
          "CompressionFormat": "UNCOMPRESSED",
          "Prefix": {"Ref": "LogS3Location"},
          "RoleARN": {"Fn::GetAtt" : ["S3deliveryRole", "Arn"] },
          "ProcessingConfiguration" : {
              "Enabled": "true",
              "Processors": [
              {
                "Parameters": [ 
                { 
                    "ParameterName": "LambdaArn",
                    "ParameterValue": {"Ref":"ProcessingLambdaARN"}
                }],
                "Type": "Lambda"
              }]
          }
        }

      }
    },
      
    "S3deliveryRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "",
              "Effect": "Allow",
              "Principal": {
                "Service": "firehose.amazonaws.com"
              },
              "Action": "sts:AssumeRole",
              "Condition": {
                "StringEquals": {
                  "sts:ExternalId": {"Ref":"AWS::AccountId"}
                }
              }
            }
          ]
        }
      }
    },
      
    "S3deliveryPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": {"Fn::Join" : [ "", [{ "Ref" : "AWS::StackName" },"-FirehosePolicy"] ]},
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject"
              ],
              "Resource": [
                {"Fn::Join": ["", [ {"Fn::Join" : [ "", ["arn:aws:s3:::",{"Ref":"LogBucketName"}] ]}]]},
                {"Fn::Join": ["", [ {"Fn::Join" : [ "", ["arn:aws:s3:::",{"Ref":"LogBucketName"}] ]}, "*"]]}
              ]
            },
            {
              "Effect": "Allow",
              "Action": [
                "lambda:InvokeFunction",
                "lambda:GetFunctionConfiguration",
                "logs:PutLogEvents",
                "kinesis:DescribeStream",
                "kinesis:GetShardIterator",
                "kinesis:GetRecords",
                "kms:Decrypt"
              ],
              "Resource": "*"
            }
          ]
        },
        "Roles": [{"Ref": "S3deliveryRole"}]
      }
    }

  },
  "Outputs":{
      
   "Destination" : {
      "Description": "Destination",
      "Value": {"Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":" ,{ "Ref": "AWS::AccountId" }, ":destination:",{ "Ref" : "AWS::StackName" },"-Destination" ] ]},
      "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Destination" }}
    }

  }
} 

로그 Destination 과 모든 필요한 리소스들을 생성하려면, 다음 절차들을 수행하기 바랍니다:

  1. 위 CloudFormation템플릿을 복사하여 “central-logging-destination.json”이름으로 파일로 저장합니다.
  2. 로깅 어카운트로 콘솔 로그인 후, CloudFormation 콘솔에서, “create new stack”을 선택합니다.
  3. “central-logging-destination.json” 파일을 선택하고 Next를 클릭합니다.
  4. 아래 그림처럼 각 파라메터들을 설정하고 Next를 클릭합니다
  5. 디폴트 단계들을 진행하여 완료하고 최종적으로 생성되었는지 점검합니다.
    1. “중앙 로깅 버킷 생성하기” 부분에서 진행했던 버킷 이름과 동일한 버킷
    2. LogS3Location에는 해당  Destination으로 전달되는 로그 데이터를 저장하기 위한 디렉토리 계층구조 입니다.
    3. ProcessingLambdaARN 은 “데이터 처리를 위한 Lambda Function생성하기” 단계에서 생성했던 Lambda Function의 ARN입니다.
    4. SourceAccount는 subscription을 생성할 애플리케이션 어카운트 입니다.
  6. 템플릿의 실행 결과에 표시되는 Destination ARN정보를 기록해 주시기 바랍니다

단계 4: 애플리케이션 어카운트에서 로그 Subscription 생성하기

본 섹션에서는, 애플리케이션 어카운트들 중 한 개에 Subscription Filter를 생성하게 되며, 이를 통해 CloudWatch Log Group 으로 부터, 로깅 어카운트에 생성했던 Log Destination으로 로그 데이터를 공급하게 됩니다.

Subscription Filter는 CloudWatch Log Group과  Destination Endpoint 간에 생성됩니다. Subscription을 통해 로그 그룹내 로그 데이터의 전부 혹은 일부만 필터링 할 수 있습니다. 예를 들면, 여러분들은 상태가 ‘REJECT’ 인 VPC Flow Log만을 로그 스트림으로 공급하는 Subscription Filter를 생성할 수 있습니다.

다음 CloudFormation 템플릿을 사용하여 Subscription Filter를 만들기 바랍니다. Subscription Filter와 로그 Destination은 같은 리전 내에 있어야 합니다.

{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Description": "Create log subscription filter for a specific Log Group",
  "Parameters":{

    "DestinationARN":{
      "Type":"String",
      "Default":"",
      "Description":"ARN of logs destination"
    },
    "LogGroupName":{
      "Type":"String",
      "Default":"",
      "Description":"Name of LogGroup to forward logs from"
    },
    "FilterPattern":{
      "Type":"String",
      "Default":"",
      "Description":"Filter pattern to filter events to be sent to log destination; Leave empty to send all logs"
    }
  },
    
  "Resources":{
    "SubscriptionFilter" : {
      "Type" : "AWS::Logs::SubscriptionFilter",
      "Properties" : {
        "LogGroupName" : { "Ref" : "LogGroupName" },
        "FilterPattern" : { "Ref" : "FilterPattern" },
        "DestinationArn" : { "Ref" : "DestinationARN" }
      }
    }
  }
}

애플리케이션 어카운트의 CloudWatch Log Group 중 한 개에 Subscription Filter를 생성하려면 다음 단계를 수행하기 바랍니다:

  1. 위 CloudFormation템플릿 내용을 복사해서 “central-logging-subscription.json” 이름으로 파일로 저장합니다.
  2. 애플리케이션 어카운트로 로그인하고, CloudFormation 콘솔로 가서 “create new stack”을 선택합니다.
  3. “central-logging-subscription.json”파일을 선택하고 Next를 클릭합니다.
  4. 위에서 진행했던 다음 내역들을 각각 파라메터 입력으로 설정합니다.
    a.  DestinationARN 은 “로깅 어카운트 내 로그 Destination생성하기” 단계에서 진행했던 것을 설정합니다.
    b.  FilterPatterns 는 로깅 어카운트로 로그 데이터를 전달할 때 적용할 필터 조건입니다.(모든 로그들을 수집하려면 공란으로 두셔도 됩니다.)
    c.  LogGroupName 은 CloudWatch Logs 에 표시되는 로그 그룹입니다.
  5. Subscription의 생성을 최종적으로 확인합니다.

이것으로 로깅 및 애플리케이션 어카운트 간, 설정 구성 부분을 마쳤습니다. 몇 분 뒤, 로깅 어카운트 상의 중앙 로깅 Destination에 로그들이 수집되기 시작합니다.

단계 5:  로그 데이터 분석

일단 로그 데이터가 중앙에 모이기 시작하면, 수집된 데이터들을 비지니스 및 보안 요건을 위해 분석할 준비가 됩니다. 이 때 사용할 수 있는 강력한 AWS 서비스가 바로 Amazon Athena입니다.

Amazon Athena는 표준 SQL을 이용하여 S3에 적재된 데이터에 쿼리를 실행할 수 있게 해줍니다.

다음 절차를 따라서 간단한 테이블을 생성하고, 애플리케이션 어카운트에서 수집된 VPC Flow log 데이터에 대해 쿼리를 실행해 보기 바랍니다.

  1. 로깅 어카운트로 로그인 하고, Amazon Athena 콘솔로 가서, 새로운 테이블을 생성하기 위한 다음 DDL을 Query  Editor에서 실행합니다.
    CREATE EXTERNAL TABLE IF NOT EXISTS prod_vpc_flow_logs (
    Version INT,
    Account STRING,
    InterfaceId STRING,
    SourceAddress STRING,
    DestinationAddress STRING,
    SourcePort INT,
    DestinationPort INT,
    Protocol INT,
    Packets INT,
    Bytes INT,
    StartTime INT,
    EndTime INT,
    Action STRING,
    LogStatus STRING
    )
    
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
    WITH SERDEPROPERTIES (
    "input.regex" = "^([^ ]+)\\s+([0-9]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([^ ]+)\\s+([^ ]+)$")
    
    LOCATION 's3://central-logging-company-do-not-delete/';
  2. ‘run query’를 클릭하고, 성공적으로 실행되었는지 확인합니다. 그 결과로 “prod_vpc_flow_logs”이라는 테이블이 만들어 집니다.
  3. 그 다음, 아래 그림 처럼 해당 테이블에 대해 쿼리를 실행할 수 있습니다.:

결론

지금까지 설명드린 대로, 여러분들은 하나의 애플리케이션 어카운트에서 중앙의 로깅 어카운트로 CloudWatch Log를 취합하는 환경을 만들어 주는 솔루션을 만들었습니다. 이 솔루션은 복수 개의 어카운트와 로깅 요건에 맞추어 반복적으로 적용 가능합니다.

이 글은 AWS Architecture Blog의 Central Logging in Multi-Account Environments를 AWS 코리아의 임기성 보안 솔루션즈 아키텍트께서 번역해 주셨습니다.