본문 바로가기

블로그

LG CNS 기술블로그 DX Lounge에서 최신 IT 소식을 만나보세요!

AWS Ambassador

AWS CloudTrail과 CloudWatch를 활용한 로그 모니터링

2023.02.01

[ 머리말 ]

온프레미스, 프라이빗 클라우드, 퍼블릭 클라우드 등 모든 인프라의 형태와 그 위에 구현된 모든 아키텍처는 단일 계정 또는 다중 계정 등 특정 조건을 넘어 모두 보안을 고려해야 합니다. 그리고 그 보안의 첫걸음은 현 상태에 대한 모니터링에서 시작합니다. 


AWS를 활용한 아키텍처에서 가장 멋진 점 중 하나는, 각종 사용자의 Action을 CloudTrail을 통해 추적, 저장할 수 있다는 점이며, 발생한 로그를 기반으로 CloudWatch에서 메시지를 발생시켜 Alarm을 전달할 수 있다는 점입니다. 이 연계는 EventBridge를 통해 더욱 간단한 형태로 진화했습니다. 우선 이번 블로그에선 CloudTrail, CloudWatch 의 연계에 대해 소개해 보겠습니다! 

[ 아키텍처 ]

[ 핵심 요소 ] 

1. IAM – Role, Permission : CloudTrail의 로그가 CloudWatch logs로 저장될 수 있도록 권한 부여
2. KMS – CloudTrail log 및 S3를 암호화하기 위한 Key 생성
3. S3 – CloudTrail log의 저장을 위한 bucket 생성
4. CloudWatch logs , Alarm – CloudTrail의 로그 저장을 위한 logs, 알람 생성을 위한 Alarm 
5. CloudTrail의 Trail 설정 

CloudTrail의 구성을 위해선 연계되어야 할 서비스와 그에 필요한 각각의 설정을 잘 이해하는 것이 좋습니다.
하나하나 아래에서 확인해 보겠습니다. 

Tips! – CloudTrail 구현의 특이사항

CloudTrail 서비스 콘솔을 가보면, Event history에서 현재 발생하고 있는 log를 확인할 수 있습니다.
해당 값은 특별한 설정 없이도 AWS에서 기본으로 저장하는 것으로 90일간 로그의 검색이 가능합니다.
로그는 별도의 분석 및 저장이 필요한 만큼, 반드시 별도 설정을 통해 S3 및 CloudWatch logs로의 저장 설정을 추천합니다.

[ Contents ] 

1. KMS – Key creation
CloudTrail 로그 파일의 암호화 및 S3 bucket, Cloudwatch Logs의 암호화를 위한 키를 생성합니다. 
아래와 같이 Key Policy를 설정합니다

————————< Key Policy >———————————————————————————————

{
    “Version”: “2012-10-17”,
    “Id”: “Key policy created by CloudTrail”,
    “Statement”: [

        {
            “Sid”: “Enable IAM User Permissions”,
            “Effect”: “Allow”,
            “Principal”: {
                “AWS”: “arn:aws:iam::{Account ID}:root”
            },
            “Action”: “kms:”,            
“Resource”: “”
        },
        {
            “Sid”: “Allow CloudTrail to encrypt logs”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: [
                “kms:GenerateDataKey”,                
“kms:Decrypt”,
                “kms:DescribeKey”,
                “kms:Describe”,                
“kms:ReEncryptFrom”
            ],            
“Resource”: “arn:aws:kms:ap-northeast-2:{Account ID}:key/”,
            “Condition”: {
                “StringLike”: {
                    “kms:EncryptionContext:aws:cloudtrail:arn”: “arn:aws:cloudtrail::{Account ID}:trail/”
                }
            }
        },
        {
            “Sid”: “Enable CloudTrail log decrypt permissions”,    
            “Effect”: “Allow”,
            “Principal”: {
                “AWS”: “arn:aws:iam::{Account ID}:root”
            },
            “Action”: “kms:Decrypt”,
            “Resource”: “arn:aws:s3:::{S3 bucket name}”,
            “Condition”: {
                “Null”: {
                    “kms:EncryptionContext:aws:cloudtrail:arn”: “false”
                }
            }
        },
        {
            “Sid”: “Allow CloudTrail access”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “kms:DescribeKey”,
            “Resource”: “arn:aws:kms:ap-northeast-2:{Account ID}:key/”,            
“Condition”: {        
        “StringEquals”: {                    
“aws:SourceArn”: “arn:aws:cloudtrail:ap-northeast-2:{Account ID}:trail/”
                }
            }
        },
        {
            “Sid”: “Allow principals in the account to decrypt log files”,
            “Effect”: “Allow”,
            “Principal”: {
                “AWS”: “”            
},            
“Action”: [                
“kms:Decrypt”,                
“kms:ReEncryptFrom”
],             “Resource”: “arn:aws:kms:ap-northeast-2:{Account ID}:key/”,
            “Condition”: {
                “StringEquals”: {
                    “kms:CallerAccount”: “{Account ID}”
                },
                “StringLike”: {
                    “kms:EncryptionContext:aws:cloudtrail:arn”: “arn:aws:cloudtrail::{Account ID}:trail/”
                }
            }
        },
        {
            “Effect”: “Allow”,                              >> Cloudwatch logs를 위한 권한 
            “Principal”: {
                “Service”: “logs.ap-northeast-2.amazonaws.com”
            },
            “Action”: [
                “kms:Encrypt”,                
“kms:Decrypt”,
                “kms:ReEncrypt”,                
“kms:GenerateDataKey”,
                “kms:Describe”            
],            
“Resource”: “”,
            “Condition”: {
                “ArnEquals”: {
                    “kms:EncryptionContext:aws:logs:arn”: “arn:aws:logs:ap-northeast-2:{Account ID}:log-group:{CloudWatch logs name}”
                }
            }
        }
    ]
}


2. S3 bucket creation

S3 bucket을 생성합니다.  아래 특이사항은 꼭 반영해 주십시오

(1) Encryption : 1에서 생성한 KMS Key를 통한 bucket 암호화 
(2) Bucket Policy : 

———————————-< Bucket Policy >—————————————————————————————————————–

{
    “Version”: “2012-10-17”,
    “Statement”: [
        {
            “Sid”: “AWSCloudTrailAclCheck”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “s3:GetBucketAcl”,
            “Resource”: “arn:aws:s3:::{S3 Bucket Name}”
        },
        {
            “Sid”: “AWSCloudTrailWrite20150319”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “s3:PutObject”,
            “Resource”: “arn:aws:s3:::{S3 Bucket Name}/AWSLogs/{Account ID}/”,            
“Condition”: {                
“StringEquals”: {                    
“s3:x-amz-acl”: “bucket-owner-full-control”
          },                
“StringLike”: {
             “AWS:SourceArn”: “arn:aws:cloudtrail:ap-northeast-2:{Account ID}:trail/”
                }
            }
        },
        {
            “Sid”: “Require SSL”,
            “Effect”: “Deny”,
            “Principal”: {
                “AWS”: “”
        },            
“Action”: “s3:”,
      “Resource”: “arn:aws:s3:::{S3 Bucket Name}/”,            
“Condition”: {                
“Bool”: {                    
“aws:SecureTransport”: “false”                
}
        }
      },        
{            
“Sid”: “ReadAccess”,            
“Effect”: “Allow”,            
“Principal”: {
          “AWS”: “arn:aws:iam::{Account ID}:root”
        },            
“Action”: “s3:GetObject”,            
“Resource”: “arn:aws:s3:::{S3 Bucket Name}/”
        },
        {
            “Sid”: “ListAccess”,
            “Effect”: “Allow”,
            “Principal”: {
                “AWS”: “arn:aws:iam::{Account ID}:root”
            },
            “Action”: “s3:ListBucket”,
            “Resource”: “arn:aws:s3:::{S3 Bucket Name}”
        },
        {
            “Sid”: “AWSCloudTrailAclCheck20150319”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “s3:GetBucketAcl”,
            “Resource”: “arn:aws:s3:::{S3 Bucket Name}”,
            “Condition”: {
                “StringEquals”: {
                    “AWS:SourceArn”: “arn:aws:cloudtrail:ap-northeast-2:{Account ID}:trail/{CloudTrail Name}”   TIPS! – {CloudTrail Name} 영역은 현재 trail의 설정이 되어 있지 않은 상태에서 입력 시 에러 발생 가능. 
                }                                                                                                                                                                 
1차로 trail:/* 로 전체 적용 후, Trail 을 설정한 다음 , name 정의 하는 순서로 진행 가능
            }
        },
        {
            “Sid”: “AWSCloudTrailWrite20150319”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “s3:PutObject”,
            “Resource”: “arn:aws:s3:::{S3 Bucket Name}/AWSLogs/{Account ID}/*”,
            “Condition”: {
                “StringEquals”: {
                    “AWS:SourceArn”: “arn:aws:cloudtrail:ap-northeast-2:{Account ID}:trail/{CloudTrail Name}”,
                    “s3:x-amz-acl”: “bucket-owner-full-control”
                }
            }
        }
    ]
}


3. IAM Role Creation 

CloudTrail의 저장 위치에 CloudWatch logs를 선택하는 경우 IAM Role이 필요합니다.
여기서 Create a Role을 선택하는 경우, IAM의 service role이 생성됩니다. 

Tips! IAM의 Role

IAM의 Role의 종류를 명확히 이해하고 있어야 합니다. 다른 blog에서 설명드린 바 있지만, 표면적으로 IAM에서 Role을 생성하고 권한을 부여하는 것은 콘솔 상에서 쉽게 작업이 가능합니다. 하지만, 권한을 철저하게 통제하는 환경에서, Terraform과 같은 IaC 로 Role을 생성하게 된다면,
어떻게 만들어야 하는지 쉽게 떠오르지 않을 수 있습니다. 특정한 경우엔 동일한 권한을 부여한 경우라도 service role이 아니면 서비스가 정상 작동을 하지 않는 경우도 있습니다. Role에 대한 명확한 이해! 매우 중요합니다.

CloudWatch logs를 위한 Role은 Service Role 또는 직접 생성한 일반 Role도 모두 정상 작동합니다. Trail 설정 시 직접 생성한 IAM Role을 선택할 경우,  자동으로 Policy가 생성되어 추가됩니다. 

위의 policy-trail-cwlg-test-1이 직접 생성한 정책, 아래가 AWS에서 자동으로 추가한 정책 IAM Role 생성 시 2 가지가 중요합니다. 

(1) Trust Relationship      –  콘솔에서 Create a Role을 선택하면 아래 값은 자동으로 동일하게 입력됩니다. 

{
    “Version”: “2012-10-17”,
    “Statement”: [
        {
            “Sid”: “Statement1”,
            “Effect”: “Allow”,
            “Principal”: {
                “Service”: “cloudtrail.amazonaws.com”
            },
            “Action”: “sts:AssumeRole”
        }
    ]
}

(2) Policy 

———————————————-< IAM Policy >——————————————————————————————————————————

{
    “Version”: “2012-10-17”,
    “Statement”: [
        {
            “Sid”: “AWSCloudTrailCreateLogStream2014110”,
            “Effect”: “Allow”,
            “Action”: [
                “logs:CreateLogStream”
            ],
            “Resource”: [
                “arn:aws:logs:ap-northeast-2:{ACCOUNT ID}:log-group:{CloudWatch Logs Name}:log-stream:
{ACCOUNT ID}_CloudTrail_ap-northeast-2″  
          ]        
},    
    {            
“Sid”: “AWSCloudTrailPutLogEvents20141101”,            
“Effect”: “Allow”,            
“Action”: [                
“logs:PutLogEvents”            
],            
“Resource”: [                
“arn:aws:logs:ap-northeast-2:{ACCOUNT ID}:log-group:{CloudWatch Logs Name}:log-stream:
{ACCOUNT ID}_CloudTrail_ap-northeast-2″
            ]
        }
    ]
}


4. CloudWatch logs group Creation 

생성은 복잡하지 않습니다. 단, KMS의 암호화를 추천드리며, Retention setting은 보안 요건에 맞춰 설정되어야 합니다.

5. CloudTrail 설정

(1)  Storage location : 기 생성한 S3 bucket 지정 
 (2)  Log file SSE-KMS encryption Enabled 선택  – CloudTrail 로그 파일의 암호화 
 (3)  Customer Managed AWS KMS Key – Existing 선택, 위에서 생성한 Key 선택 
 (4)  CloudWatch Logs Enabled 선택, Log group – 위에서 생성한 Log Group 선택
                                                                          IAM Role , 위에서 생성한 Role 선택 
 (5) Event type – Management events : AWS resource에 대한 로그 
                            Data events : DynamoDB, Lambda, S3, Glue 등 Data와 관련된 API 로그 

참조 – https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html

참조 – https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-insights-events-with-cloudtrail.html

(6) API Activity – Read / Write는 당연히 logging을 하실 것이라는 예상과 함께,
                            Exclude AWS KMS events는 정말 특별한 이유가 있지 않다면 선택을 추천 드립니다. 
                            ebs / s3 / cloudtrail 등 다양한 저장매체의 암호화가 진행되고 따라서 cloudtrail에 kms 관련 많은 로그가 생성됩니다.
                            다른 로그의 검색에 영향을 줄 수 있음을 고려해 주십시오. 

자, 이제 CloudTrail의 설정이 완료되었습니다. 이제 로그는 받게 되었으니, 알람을 받기 위하여 하나의 상황을 가정해 보겠습니다.
대부분의 상황에서 중요하게 고려되는 AWS Console의 user 로그인 발생 시, Email 알람을 받아보자! 가 목표입니다. 

Tips! – Global Service의 CloudTrail log

AWS의 서비스 중 특정 리전이 아닌 Global service가 있습니다. IAM이 대표적입니다. 이런 Global service는 CloudTrail이 설정된 리전이 아닌, US-East-1에 저장됩니다. 즉, CloudTrail 콘솔의 Event history에서 로그를 보기 위해선 US-East-1로 이동해야 합니다. 단, Trails 설정을 통해 S3, Cloudwatch로 저장 위치를 지정한 경우, 해당 저장 공간의 region으로 이동하여 통합 저장됩니다. 자, 이제 CloudTrail의 설정이 완료되었습니다. 이제 로그는 받게 되었으니, 알람을 받기 위하여 하나의 상황을 가정해 보겠습니다대부분의 상황에서 중요하게 고려되는 AWS Console의 user 로그인 발생 시 , Email 알람을 받아보자! 가 목표입니다. 

6. Metric filters 생성
5번의 설정을 통해 CloudTrail의 로그가 CloudWatch logs로 저장되고 있습니다.

위 그림의 중간 옵션에서 “Metric filters”를 선택해주십시오. 
Metric filters를 만든다는 의미는, log로 떨어지는 데이터 중 특정 조건 / 패턴에 맞는 로그가 생성되는 것을 하나의 측정, 알람 기준으로 만드는 과정입니다. 

(1) “Create metric filter”를 선택해주십시오.  먼저 pattern을 정해야 합니다.

여기서 정의하는 Pattern은 Cloudwatch logs에서 사용할 수 있는 패턴을 사용해야 하며, 아래 내용을 참고해 주십시오.

참고 : https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html#matching-terms-events
우리의 목표는 AWS Console의 로그인을 추출하는 것으로, 패턴은 아래와 같습니다.
{ $.eventName = “ConsoleLogin” } 

Tips! 패턴의 형태와 내용 

위 문구의 { $. = ” ” }의 패턴은 CloudWatch Logs의 것이나, eventName, ConsoleLogin 은 CloudTrail에 저장되는 로그 형태입니다. 
따라서 특정 상황에 대한 로그를 추출하려는 경우 CloudTrail의 Event history에서 해당 로그의 형태를 먼저 확인한 후, CloudWatch logs의 패턴 형태로 작성하여 사용하면 됩니다. 

예시 ) Security group modification  – {($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup)}

(2) Filter namespace 및 name 정의 

Namespace 및 Name은 CloudWatch metric에서 주로 확인하게 될 항목입니다.
Namespace : 다수의 metric이 등록 가능한 그룹의 이름
Name : ConsoleLogin을 확인할 metric의 이름
Metric value : 로그 중 ConsoleLogin이 감지될 경우 입력할 값입니다. case 별로 count 해야 하니 1로 정해야 합니다.

위와 같이 생성이 완료되면 아래 그림과 같이 등록된 Metric을 볼 수 있습니다.

(3) Alarm 등록

위 화면의 상단 우측 버튼에서 “Create alarm”이 보이실 것입니다. Metric을 만들어 로그 발생 시 카운트 되도록 만들었으니, 조건이 맞으면 Alarm이 발생하도록 만들어야 합니다

Statistics : Metric을 통해 수집된 value를 sum (더하기), average (평균) 할 것인지 선택
Period : statistics 작업을 반복할 시간의 turn 
Conditions : Alarm으로 만들기 위한 조건을 정의합니다. 로그인이 일어날 때마다 1로 값을 정의했고, 5분 간격으로 sum하는 상태입니다.
따라서 0 (로그인 없음)에서 1 (로그인 발생)을 기준으로 삼아야 하니, Greater than 0로 지정하면 됩니다.
Datapoints to alarm : 위 Conditions에 맞는 값이 1로 올라갔을 때 바로 alarm 상태로 변경됩니다. 2 out of 3 은 5분 간격의 점검이 3회 진행되었을 때 conditions에 부합하는 값이 2회 발생하면 alarm 상태로 지정된다는 의미입니다.

위와 같이 Alarms이 생성된 것을 볼 수 있습니다. 이제 로그인을 하면?! 
아래와 같이 Email이 발송되고 Console login event가 발생했다는 것을 전달 받을 수 있습니다.


[ 결론 ]

위의 순서와 설정, 값들이 단순했나요?
“AWS 콘솔에 로그인이 발생 시 담당자 notice 필요”라는 요구사항에 있어,  CloudTrail 을 활용하여 로그를 받고 CloudWatch를 통해 모니터링할 수 있습니다. 라는 답변이 실제 구현 시엔 많은 고려 사항이 필요하고 그 점을 전달하고자 이번 블로그를 작성했습니다. 항상 적절한 권한의 부여, 암호화는 필수 적이며, 로그는 별도 저장을 꼭 고려해 주십시오. 그리고 모니터링의 설정에 있어 어떤 값을 어떤 value로 지정할 것이고, 이를 기반으로 어떤 조건이 전달을 받아야 하는 수준인가?!를 정하는 것은 운영의 묘미이며 중요한 정책이라는 것을 꼭 유념해 주십시오!

챗봇과 대화를 할 수 있어요