CloudTrail
AWS 리소스의 모든 읽기, 쓰기 작업의 상세 로그(작업 내역, 관련 리소스와 리전, 작업 수행자와 작업 시간 등)를 보관
API 작업과 비 API 작업을 모두 기록
-
API 작업 예: 인스턴스 시작, S3 버킷 생성, VPC 생성 등
-
비 API 작업 예: AWS Management Console에 로그인 등
이벤트(event) = AWS 계정의 활동 기록
-
관리 이벤트 = 제어 플레인 작업(Control Plane Operations)
-
보안 주체가 AWS 리소스에서 실행하는 작업를 포함
-
보안 구성 → IAM AttachRolePolicy API
-
디바이스 등록 → EC2 CreateDefaultVpc API
-
데이터 라우팅 규칙 구성 → EC2 CreateSubnet API
-
로깅 설정 → CloudTrail CreateTrail API
-
계정에서 발생하는 비 API 이벤트
-
사용자가 로그인하는 경우 ConsoleLogin 이벤트가 로깅
-
쓰기 전용과 읽기 전용으로 분류
-
쓰기 전용 이벤트: 리소스를 변경하거나 변경할 수 있는 API 작업
-
읽기 전용 이벤트: 리소스를 읽기만하고 변경하지 않는 API 작업
-
데이터 이벤트 = 데이터 플레인 작업(Data Plane Operations)
-
리소스 또는 리소스 내에서 수행되는 리소스 작업에 대한 정보를 제공
-
대량의 작업이 수행되는 S3 객체 수준 활동, Lambda 함수 실행
-
S3 객체 수준 활동 → GetObject, DeleteObject, PutObject API
-
Lambda 함수 실행 → Invoke API
-
추적을 생성할 때 데이터 이벤트는 기본적으로 기록되지 않음 → 데이터 이벤트를 기록하려면 활동을 수집할 리소스 또는 리소스 유형을 추적에 명시적으로 추가해야 함
-
인사이트 이벤트
-
AWS 계정의 비정상적인 활동을 캡쳐
-
계정 API 사용량 변화가 계정의 일반적인 사용 패턴과 크게 다를 때 로깅
-
S3 deleteBucket API 호출이 평균적으로 분당 20회 호출 → 분당 100회 호출이 감지 ⇒ 비정상적인 활동 ⇒ 비정상적인 활동이 시작될 때와 정상으로 돌아갔을 때를 기록
이벤트 기록(Event History)
-
CloudTrail 이벤트에 대한 지난 90일간의 기록
-
조회, 검색, 다운로드 등이 가능
-
각 리전별로 "이벤트 기록"을 작성하고 해당 리전에서의 활동만 기록
-
IAM, Route 53 등의 글로벌 서비스 이벤트는 모든 리전의 이벤트 기록에 포함
추적(trail)
-
90일이 경과한 이벤트 기록을 저장하거나 CloudTrail이 기록하는 이벤트 유형을 사용자 정의할 때 생성
-
특정 이벤트를 기록하고 지정한 S3 버킷에 CloudTrail 로그 파일을 전달. 로그 파일에는 JSON 형식의 로그 항목이 하나 이상 들어 있음
-
eventTime
-
userIdentity
-
eventSource
-
eventName
-
awsResion
-
sourceIPAddress
CloudWatch
-
AWS 리소스와 AWS에서 실시간으로 실행되는 애플리케이션을 모니터링
-
리소스와 애플리케이션에 대한 지표(= 측정할 수 있는 변수)를 수집하고 추적
-
CloudWatch 웹 사이트에는 사용 중인 모든 AWS 서비스에 한 지표가 자동으로 표시되고, 사용자 지정 대시보드 추가가 가능
-
지표를 감시해 알림을 보내거나 임계값을 위반한 경우 모니터링 중인 리소스를 자동으로 변경하는 경보를 생성
-
시스템 전체의 리소스 사용량, 애플리케이션 성능 및 운영 상태를 파악
Monitoring and Notifications with CloudWatch Events and SNS
EC2 인스턴스의 상태(state)가 변경되었을 때 이메일 통지(notification)를 발생

#1 EC2 인스턴스 확인

#2 SNS 주제(topic)와 이메일 구독(subscribe)을 생성



#3 SNS 주제를 트리거하는 CloudWatch 이벤트 규칙을 생성

#4 EC2 인스턴스의 상태를 변경했을 때 이메일 통지가 수신되는지 확인




실습: EC2 인스턴스가 중지(stopped)되었을 때 이메일과 함께 SMS 통지를 발생하도록 해 보세요.




TODO. EC2 인스턴스가 중지(stopped)되었을 때 포맷팅된 알림 메시지를 전송하시오.
AWS EC2 Custom Logging with CloudWatch
EC2 인스턴스에서 생성되는 로그 정보를 CloudWatch로 전송해서 로그를 통합 ⇒ EC2 인스턴스에 CloudWatch Logs 에이전트를 설치하고, 로그 서비스를 켜고, 메시지를 수신하도록 CloudWatch를 구성
#1 EC2 인스턴스 생성




#2 작업을 위해 EC2 인스턴스에 SSH 접속


#3 EC2 인스턴스에 awslogs 서비스를 추가
[ec2-user@ip-10-0-0-134 ~]$ sudo yum update -y
[ec2-user@ip-10-0-0-134 ~]$ sudo yum install -y awslogs
[ec2-user@ip-10-0-0-134 ~]$ cd /etc/awslogs
[ec2-user@ip-10-0-0-134 awslogs]$ ls -l
total 20
-rw------- 1 root root 55 Mar 5 02:14 awscli.conf ⇐ 자격증명과 지역정보를 포함
-rw-r--r-- 1 root root 8355 Jul 25 2018 awslogs.conf ⇐ CloudWatch 로깅에 대한 설정 정보를 포함
drwxr-xr-x 2 root root 6 Jul 25 2018 config
-rw-r--r-- 1 root root 147 Jul 25 2018 proxy.conf
[ec2-user@ip-10-0-0-134 awslogs]$ sudo systemctl start awslogsd ⇐ awslogs 서비스를 시작
[ec2-user@ip-10-0-0-134 awslogs]$ tail -f /var/log/awslogs.log ⇐ awslogs 에이전트가 생성하는 로그를 확인
2021-03-05 02:18:18,404 - cwlogs.push - INFO - 3448 - MainThread - Missing or invalid value for use_gzip_http_content_encoding config. Defaulting to use gzip encoding.
2021-03-05 02:18:18,404 - cwlogs.push - INFO - 3448 - MainThread - Missing or invalid value for queue_size config. Defaulting to use 10
2021-03-05 02:18:18,404 - cwlogs.push - INFO - 3448 - MainThread - Using default logging configuration.
2021-03-05 02:18:18,425 - cwlogs.push.stream - INFO - 3448 - Thread-1 - Starting publisher for [1538ea66cfd1d4424de78dedc63516f8, /var/log/messages]
2021-03-05 02:18:18,431 - cwlogs.push.stream - INFO - 3448 - Thread-1 - Starting reader for [1538ea66cfd1d4424de78dedc63516f8, /var/log/messages]
2021-03-05 02:18:18,432 - cwlogs.push.reader - INFO - 3448 - Thread-4 - Start reading file from 0.
2021-03-05 02:18:24,519 - cwlogs.push.publisher - WARNING - 3448 - Thread-3 - Caught exception: An error occurred (ResourceNotFoundException) when calling the PutLogEvents operation: The specified log group does not exist.
2021-03-05 02:18:24,520 - cwlogs.push.batch - INFO - 3448 - Thread-3 - Creating log group /var/log/messages.
2021-03-05 02:18:24,582 - cwlogs.push.batch - INFO - 3448 - Thread-3 - Creating log stream i-04545e7d208a38d21.
2021-03-05 02:18:24,675 - cwlogs.push.publisher - INFO - 3448 - Thread-3 - Log group: /var/log/messages, log stream: i-04545e7d208a38d21, queue size: 0, Publish batch: {'skipped_events_count': 0, 'first_event': {'timestamp': 1614910316000, 'start_position': 0L, 'end_position': 162L}, 'fallback_events_count': 0, 'last_event': {'timestamp': 1614910698000, 'start_position': 68477L, 'end_position': 68564L}, 'source_id': '1538ea66cfd1d4424de78dedc63516f8', 'num_of_events': 789, 'batch_size_in_bytes': 88289}
[ec2-user@ip-10-0-0-134 awslogs]$ sudo systemctl enable awslogsd.service ⇐ 부팅 시 awslogs 서비스를 자동 실행
#4 EC2에서 보낸 CloudWatch Logs 확인 (수집된 로그를 확인)
EC2 인스턴스의 /var/log/message 파일의 내용과 CloudWatch의 /var/log/messages 로그그룹에 수집된 내용이 일치


참고: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
AWS Access Control Alerts with CloudWatch and CloudTrail
#1 중요 정보를 담을 S3 버킷을 생성 ← 모니터링이 필요

#2 CloudTrail 서비스에 추적(trail)을 생성



#3 CloudWatch 로그 그룹을 생성


#4 CloudWatch에서 지표를 설정



#5 CloudWatch에서 경보를 설정



경보를 알릴 데이터 포인트가 3/3으로 설정된 경우

지표 경보 상태
-
OK ⇒ 지표 또는 표현식이 정의된 임계값 내에 있음
-
ALARM ⇒ 지표 또는 표현식이 정의된 임계값을 벗어났음
-
INSUFFICIENT_DATA ⇒ 경보가 방금 시작되었거나, 지표를 사용할 수 없거나, 지표를 통해 경보 상태를 결정하는데 충분한 데이터가 없는 경우

#6 S3 버킷에 파일을 업로드 후 경보 발생 여부 확인


Creating a Simple AWS Lambda Function
적절한 권한이 부여되고 있는지 확인



작성한 함수를 테스트 (테스트 탭에서)


⇒ event 인자값에 message 이름의 키가 존재하지 않으므로 오류가 발생


(1) 소스코드 8번 라인의 return event['message'] 코드의 결과
(2) 소스코드 6번 라인의 print("message --> " + event['message']) 코드의 결과 ⇐ CloudWatch에 저장된 로그 내용

배포한 람다 함수를 호출
Using the AWS CLI to Create an AWS Lambda Function
클라이언트에서 작성 람다 함수를 ASW CLI를 이용해서 배포 및 실행

#1 실습환경을 확인 - S3 버킷, IAM 역할, EC2 인스턴스 확인



#2 EC2 인스턴스로 SSH 접속

#3 AWS CLI 설치 여부 확인
[cloud_user@ip-10-99-1-75 ~]$ aws --version
aws-cli/1.16.113 Python/2.7.16 Linux/4.14.173-106.229.amzn1.x86_64 botocore/1.12.103
#4 해당 지역(버지니아 북부)의 람다 함수를 조회
[cloud_user@ip-10-99-1-75 ~]$ aws lambda list-functions --region us-east-1
{
"Functions": []
}
list-functions ⇒ https://docs.aws.amazon.com/cli/latest/reference/lambda/list-functions.html
--region ⇒ https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/cli-configure-options.html
#5 S3 버킷 목록을 반환하는 람다 함수를 작성
[cloud_user@ip-10-99-1-75 ~]$ vim lambda_function.js
const AWS = require('aws-sdk'); AWS.config.update({ region: 'us-east-1' }); const s3 = new AWS.S3({ apiVersion: '2006-03-01' }); exports.handler = (event, context, callback) => { s3.listBuckets( (err, data) => { if (err) { console.log("Error: ", err); } else { console.log("List of S3 Buckets", data.Buckets); } } ); }; |
#6 작성한 람다 함수를 배포 후 확인
[cloud_user@ip-10-99-1-75 ~]$ zip lambda_function.zip lambda_function.js
adding: lambda_function.js (deflated 33%)
[cloud_user@ip-10-99-1-75 ~]$ ll
total 8
-rw-rw-r-- 1 cloud_user cloud_user 347 Mar 5 06:58 lambda_function.js
-rw-rw-r-- 1 cloud_user cloud_user 418 Mar 5 06:59 lambda_function.zip
[cloud_user@ip-10-99-1-75 ~]$ aws lambda create-function \
> --region us-east-1 \
> --function-name "ListS3Buckets" \
> --runtime "nodejs12.x" \
> --role "arn:aws:iam::436502908608:role/lambda_exec_role_LA" \
> --handler "lambda_function.handler" \
> --zip-file fileb:///home/cloud_user/lambda_function.zip
{
"TracingConfig": {
"Mode": "PassThrough"
},
"CodeSha256": "Fr0Pm6jmV41kxdA/p0bcSFp5/WoOqmxdaU7pgAdAFRw=",
"FunctionName": "ListS3Buckets",
"CodeSize": 418,
"RevisionId": "4e92b5d0-7891-4724-9a18-b212de8e4ef4",
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:us-east-1:436502908608:function:ListS3Buckets",
"Version": "$LATEST",
"Role": "arn:aws:iam::436502908608:role/lambda_exec_role_LA",
"Timeout": 3,
"LastModified": "2021-03-05T07:02:25.147+0000",
"Handler": "lambda_function.handler",
"Runtime": "nodejs12.x",
"Description": ""
}
[cloud_user@ip-10-99-1-75 ~]$ aws lambda list-functions --region us-east-1
{
"Functions": [
{
"TracingConfig": {
"Mode": "PassThrough"
},
"Version": "$LATEST",
"CodeSha256": "Fr0Pm6jmV41kxdA/p0bcSFp5/WoOqmxdaU7pgAdAFRw=",
"FunctionName": "ListS3Buckets",
"MemorySize": 128,
"RevisionId": "4e92b5d0-7891-4724-9a18-b212de8e4ef4",
"CodeSize": 418,
"FunctionArn": "arn:aws:lambda:us-east-1:436502908608:function:ListS3Buckets",
"Handler": "lambda_function.handler",
"Role": "arn:aws:iam::436502908608:role/lambda_exec_role_LA",
"Timeout": 3,
"LastModified": "2021-03-05T07:02:25.147+0000",
"Runtime": "nodejs12.x",
"Description": ""
}
]
}

#7 람다 함수를 호출
[cloud_user@ip-10-99-1-75 ~]$ aws lambda invoke --region us-east-1 --function-name "ListS3Buckets" OUTPUT.log
{ ~~~~~~~~~~
"ExecutedVersion": "$LATEST", 함수의 실행 결과를 파일로 저장
"StatusCode": 200
}
#8 CloudWatch에서 로그 그룹을 확인

⇒ 소스 코드의 "console.log("List of S3 Buckets", data.Buckets);" 부분의 출력
[cloud_user@ip-10-99-1-75 ~]$ cat OUTPUT.log
null ⇐ 아무 내용이 없음 → 반환하는 값이 없기 때문
DONE >>> #9 소스코드를 수정
[cloud_user@ip-10-99-1-75 ~]$ vim lambda_function.js
const AWS = require('aws-sdk'); AWS.config.update({ region: 'us-east-1' }); const s3 = new AWS.S3({ apiVersion: '2006-03-01' }); exports.handler = (event, context, callback) => { s3.listBuckets( (err, data) => { if (err) { console.log("Error: ", err); } else { console.log("List of S3 Buckets", data.Buckets); callback(null, data.Buckets); // ⇐ 호출한 곳으로 값을 전달(반환) } } ); }; |
#10 소스코드 압축 및 배포
[cloud_user@ip-10-99-1-75 ~]$ zip lambda_function.zip lambda_function.js
updating: lambda_function.js (deflated 35%)
[cloud_user@ip-10-99-1-75 ~]$ aws lambda update-function-code --region us-east-1 --function-name "ListS3Buckets" --zip-file fileb:///home/cloud_user/lambda_function.zip
{
"TracingConfig": {
"Mode": "PassThrough"
},
"CodeSha256": "hWTdjE1+m73H0/Vs8axhG7fUT8dqr1AMDfbPltyra+o=",
"FunctionName": "ListS3Buckets",
"CodeSize": 427,
"RevisionId": "1ddd4d10-0b4a-46b8-9e8d-4a88d19540d5",
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:us-east-1:436502908608:function:ListS3Buckets",
"Version": "$LATEST",
"Role": "arn:aws:iam::436502908608:role/lambda_exec_role_LA",
"Timeout": 3,
"LastModified": "2021-03-05T07:15:47.256+0000",
"Handler": "lambda_function.handler",
"Runtime": "nodejs12.x",
"Description": ""
}
update-funct

ion-code ⇒ https://docs.aws.amazon.com/cli/latest/reference/lambda/update-function-code.html
#11 람다 함수 호출 및 결과 확인
[cloud_user@ip-10-99-1-91 ~]$ aws lambda invoke --region us-east-1 --function-name "ListS3Buckets" OUTPUT.log
{
"ExecutedVersion": "$LATEST",
"StatusCode": 200
}

[cloud_user@ip-10-99-1-91 ~]$ cat OUTPUT.log
[{"Name":"cfst-660-55ac64441487ca639f4246c37a1-labs3bucketa-qvucgewc53hq","CreationDate":"2021-03-07T09:24:11.000Z"},{"Name":"cfst-660-55ac64441487ca639f4246c37a1-labs3bucketb-fzdcyzm5mnas","CreationDate":"2021-03-07T09:24:11.000Z"}]
참고: Serverless Framework
https://myanjini.tistory.com/entry/Serverless-Framework-1
https://myanjini.tistory.com/entry/Serverless-Framework-2
DONE >>> Triggering Lambda from Amazon SQS
SQS를 사용해서 람다 함수를 트리거 하는 방법
~~~~~~~~~
SQS 대기열의 메시지를 처리하고 메시지 데이터를 DynamoDB 테이블에 삽입

#1 IAM 정책을 생성


#2 IAM 역할을 생성



#3 람다 함수 생성

함수 코드
from datetime import datetime import json import os import boto3 QUEUE_NAME = os.environ['QUEUE_NAME'] # 환경 변수의 값을 가져오는 부분 MAX_QUEUE_MESSAGES = os.environ['MAX_QUEUE_MESSAGES'] DYNAMODB_TABLE = os.environ['DYNAMODB_TABLE'] sqs = boto3.resource('sqs') dynamodb = boto3.resource('dynamodb') def lambda_handler(event, context): # Receive messages from SQS queue queue = sqs.get_queue_by_name(QueueName=QUEUE_NAME) print("ApproximateNumberOfMessages:", queue.attributes.get('ApproximateNumberOfMessages')) for message in queue.receive_messages( MaxNumberOfMessages=int(MAX_QUEUE_MESSAGES)): print(message) # Write message to DynamoDB table = dynamodb.Table(DYNAMODB_TABLE) response = table.put_item( Item={ 'MessageId': message.message_id, 'Body': message.body, 'Timestamp': datetime.now().isoformat() } ) print("Wrote message to DynamoDB:", json.dumps(response)) # Delete SQS message message.delete() print("Deleted message:", message.message_id) |
#4 함수 실행에 필요한 환경 변수의 값을 설정



QUEUE_NAME

DYNAMODB_TABLE

#5 람다 함수의 트리거를 설정


#6 EC2 인스턴스에 SSH 접속


#7 send_message.py 실행을 위한 python3.7 및 필요 모듈 설치
[cloud_user@ip-10-1-10-107 ~]$ sudo yum install gcc openssl-devel bzip2-devel libffi-devel
[cloud_user@ip-10-1-10-107 ~]$ cd /opt
[cloud_user@ip-10-1-10-107 ~]$ sudo wget https://www.python.org/ftp/python/3.7.9/Python-3.7.9.tgz
[cloud_user@ip-10-1-10-107 ~]$ sudo tar xzf Python-3.7.9.tgz
[cloud_user@ip-10-1-10-107 ~]$ cd Python-3.7.9/
[cloud_user@ip-10-1-10-107 Python-3.7.9]$ sudo ./configure --enable-optimizations
[cloud_user@ip-10-1-10-107 Python-3.7.9]$ sudo make altinstall
[cloud_user@ip-10-1-10-107 Python-3.7.9]$ sudo rm /usr/src/Python-3.7.9.tgz
[cloud_user@ip-10-1-10-107 Python-3.7.9]$ cd
[cloud_user@ip-10-1-10-107 ~]$ python3.7 -V
Python 3.7.9
[cloud_user@ip-10-1-10-107 ~]$ pip3.7 install boto3
[cloud_user@ip-10-1-10-107 ~]$ pip3.7 install Faker
#8 메시지를 생성
[cloud_user@ip-10-1-10-109 ~]$ ls
send_message.py
[cloud_user@ip-10-1-10-109 ~]$ cat send_message.py
#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-
import argparse
import logging
import sys
from time import sleep
import boto3
from faker import Faker
parser = argparse.ArgumentParser()
parser.add_argument("--queue-name", "-q", required=True,
help="SQS queue name")
parser.add_argument("--interval", "-i", required=True,
help="timer interval", type=float)
parser.add_argument("--message", "-m", help="message to send")
parser.add_argument("--log", "-l", default="INFO",
help="logging level")
args = parser.parse_args()
if args.log:
logging.basicConfig(
format='[%(levelname)s] %(message)s', level=args.log)
else:
parser.print_help(sys.stderr)
sqs = boto3.client('sqs')
response = sqs.get_queue_url(QueueName=args.queue_name)
queue_url = response['QueueUrl']
logging.info(queue_url)
while True:
message = args.message
if not args.message:
fake = Faker()
message = fake.text()
logging.info('Sending message: ' + message)
response = sqs.send_message(
QueueUrl=queue_url, MessageBody=message)
logging.info('MessageId: ' + response['MessageId'])
sleep(args.interval)
[cloud_user@ip-10-1-10-109 ~]$ ./send_message.py -q Messages -i 0.1
~~~~~~~~~~~ ~~~~~~
큐 이름 실행 주기
#9 CloudWatch 로그 확인

#10 DynamoDB 항목 확인

'CLOUD > AWS' 카테고리의 다른 글
3/9 - AWS 8차시 (0) | 2021.03.09 |
---|---|
3/8 - AWS 7차시 (0) | 2021.03.08 |
3/4 - A Cloud Guru를 이용한 AWS 5차시 (0) | 2021.03.04 |
3/3 - A Cloud Guru를 이용한 AWS 4차시 (0) | 2021.03.03 |
3/2 - A Cloud Guru를 이용한 AWS 3차시 (0) | 2021.03.02 |