以前に以下の記事でCloudTrailの取得をCloudFormationで有効化しました。 S3にCloudTrailログがどんどん溜まってきているところまで作成しています。
AWSのCloudFormationでIaCを実践(6) – CloudTrail
https://syachiku.net/awscloudformationiac6-trail/
今回はCloudTrailログを溜めるだけではなく、せっかくなのでグラフィカルに可視化をしていきたいと思います。
可視化する方法としてはEC2インスタンスに可視化ツールをインストールすることもできますが、今回はAWSのマネジメントサービスである「Amazon Elasticsearch Service」を使います。
さらに、できる限り(全部ではないです)CloudFormationによるコード化をするようにしたいと思います。
1. 前提条件
- AWSアカウントが取得できていること
- 適切な権限(=Admin相当)をもったIAMユーザーを作成していること
- ルーティングなどの最低限のネットワークの知識があること
- YAMLの書きかたを知っていること(CloudFormationはjsonもしくはyamlで書けますが、今回はyamlで書いていきます。)
- kibanaレポート(ElasticSeachのクラスタ)がVPCのプライベートサブネットに配置されるので、ブラウザでアクセスできる環境があること(WindowsのEC2などでもOK)
- 今回は自宅からVPNで接続してProxyを経由してアクセスします。
※今回実施するElasticseachについては無料枠の範囲ではないため、少なからず利用料金が発生します、あくまで自己責任でお願いします。
2. 構成図
構成図としては以下の様な感じになるかと思います。CloudWatchLogsのリソースはCroudTrailと同じスタックにしました。
3. 今回作成するAWS環境と作業手順
大阪リージョンの場合にはElasticSeachの最小インスタンスが結構大きいものしか選択できなかったことと、CWLogSubscriptionでElasticseachの選択肢がなかったので、オレゴンリージョンで構築しています。
それでは、以下の手順で構築を行っていきます。
- ElasticSearchのドメイン作成時に必要となる「EsServiceLinkedRole」を作成
- CloudTrailのログをS3バケットへ保管するのに追加し、Cloudwach Loggroupにも転送するように設定(以下は前回との変更点です)
- CloudTrailログ保管するCWLogGroupを新規作成
- LogGroupのSubscription Filterで利用するロールを作成
- ElasticSeachドメインを作成
- 2台のクラスタ構成(PrivateSubnet)でドメイン構成
- Elasticsearch用のSecurityGroupを作成
ここまではCloufFormationで構築しますが、以下の作業は手動でマネジメントコンソールで構築しました。 マネジメントコンソール経由だと自動でLambdaなどを作成してくれるのでこっちにしてます。
- LogGroupへサブスクリプションフィルター作成(+Lambda関数も自動で作成)
- kibanaのレポートを手動で作成
4. CloudFormation Template
最初にEsServiceLinkedRoleの構築です。 ES以外も想定してsystem-roleとしてスタックを分離して構築してます。
AWSTemplateFormatVersion: "2010-09-09"
Description:
system role
Resources:
EsServiceLinkedRole:
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: es.amazonaws.com
Description: "Service Linked Role for Amazon Elasticsearch Service"
Outputs:
EsServiceLinkedRole:
Value: !Ref EsServiceLinkedRole
Export:
Name: es-service-linked-role
次にCloudTrailのテンプレートとなります。
AWSTemplateFormatVersion: 2010-09-09
Description: CloudTrail
Parameters:
LogGroupName:
Type: String
Description: Enter LogGroupName
Default: "aws-infra-croudtrail-loggroup"
LogStreamName:
Type: String
Description: Enter LogStreamName
Default: "aws-infra-croudtrail-logstream"
Resources:
CloudTrailLogsBucket:
Type: AWS::S3::Bucket
# DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
BucketName: !Sub ${AWS::Region}-cloudtrail-logs
AccessControl: LogDeliveryWrite
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
LifecycleConfiguration:
Rules:
- Id: AutoDelete
Status: Enabled
ExpirationInDays: 14
- Id: NoncurrentVersionExpiration
Status: Enabled
NoncurrentVersionExpirationInDays: 7
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
# CloudTrailログ格納用バケットポリシー
CloudTrailLogsBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref CloudTrailLogsBucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: CloudTrailAclCheck
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:GetBucketAcl
Resource: !Sub arn:aws:s3:::${CloudTrailLogsBucket}
- Sid: CloudTrailWrite
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:PutObject
Resource: !Sub arn:aws:s3:::${CloudTrailLogsBucket}/AWSLogs/${AWS::AccountId}/*
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
# Create CWLog group
CloudTrailLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Ref LogGroupName
RetentionInDays: 3
# Create CloudWTrailRole for CWLogs and ElasticSearch
CloudTrailLogRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- !Sub "cloudtrail.${AWS::URLSuffix}"
- !Sub "lambda.${AWS::URLSuffix}"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: aws-infra-policy-cloudtrail-es
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'es:ESHttpPost'
Resource: "arn:aws:es:*:*:*"
- Effect: Allow
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:DescribeLogStreams"
- "logs:PutLogEvents"
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
Resource: "*"
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource: "arn:aws:logs:*:*:*"
# CloudTrailから配信されるログの暗号化キー
# https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/create-kms-key-policy-for-cloudtrail.html
KmsKey:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Version: 2012-10-17
Id: DefaultKeyPolicy
Statement:
- Sid: EnableIAMUserPermissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: kms:*
Resource: '*'
- Sid: AllowCloudTrailToEncryptLogs
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: kms:GenerateDataKey*
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:cloudtrail:arn:
- !Sub arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*
- Sid: AllowCloudTrailToDescribeKey
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: kms:DescribeKey
Resource: '*'
KeyUsage: ENCRYPT_DECRYPT
CloudTrail:
Type: AWS::CloudTrail::Trail
Properties:
CloudWatchLogsLogGroupArn: !GetAtt CloudTrailLogGroup.Arn
CloudWatchLogsRoleArn: !GetAtt CloudTrailLogRole.Arn
S3BucketName: !Ref CloudTrailLogsBucket
KMSKeyId: !Ref KmsKey
TrailName: CloudTrailLog
IncludeGlobalServiceEvents: true
IsLogging: true
IsMultiRegionTrail: true
EnableLogFileValidation: true
EventSelectors:
- DataResources:
- Type: AWS::S3::Object
Values:
- arn:aws:s3
ElasticSearchを構築するテンプレートです。
AWSTemplateFormatVersion: "2010-09-09"
Description:
elastic search
Parameters:
ESDomainName:
Description: "Your Elasticsearch Domain Name"
Type: String
MinLength: 3
MaxLength: 28
AllowedPattern: "^[a-z0-9+-]*$"
Default: "aws-infra-es-domain"
MyVpcId:
Type: String
Default: "vpc-id"
MyVpcCidrBlock:
Type: String
Default: "10.1.0.0/16"
MyEsSubnetId01:
Type: String
Default: "subnet-private01"
MyEsSubnetId02:
Type: String
Default: "subnet-private02"
InstanceType:
Type: String
Default: "t3.small.elasticsearch"
AllowedValues:
- t3.small.elasticsearch
- t3.medium.elasticsearch
- r5.large.elasticsearch
Resources:
# Security Group
# For Amazon Elasticsearch Service
ElasticsearchSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: elasticsearch-sg
VpcId: !Ref MyVpcId
Tags:
- Key: Name
Value: aws-infra-elasticsearch-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: !Ref MyVpcCidrBlock
# Elasticsearch on VPC
MyElasticsearch:
Type: AWS::Elasticsearch::Domain
Properties:
AccessPolicies:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: 'es:*'
Resource: !Sub arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ESDomainName}/*
DomainName: !Ref ESDomainName
EBSOptions:
EBSEnabled: true
VolumeSize: 10
VolumeType: gp2
ElasticsearchClusterConfig:
InstanceCount: 2
InstanceType: !Ref InstanceType
ZoneAwarenessEnabled: true
ElasticsearchVersion: 7.4
SnapshotOptions:
AutomatedSnapshotStartHour: 17
VPCOptions:
SubnetIds:
- !Ref MyEsSubnetId01
- !Ref MyEsSubnetId02
SecurityGroupIds:
- !Ref ElasticsearchSecurityGroup
UpdatePolicy:
EnableVersionUpgrade: true
5. スタックの作成
それでは先ほど作成したコードを使って、リソース(CloudFormationで作成できる部分)を作成していきます。
マネージメントコンソールにログオンして、リージョンをオレゴンに切り替えたのち、CloudFormationを開きます。
「スタックの作成」→「新しいリソースを使用」を選択します。
「テンプレートファイルをアップロード」からコードのファイルを選択してアップします。
スタックの名称やネットワーク設定値を入力(デフォルトから変更したい場合には変更してください)してスタック作成をしてください。
※「今回作成するAWS環境と作業手順」に記載している順番通りにスタックを作成してください。
5.1. IAM Role
5.2. セキュリティグループ
5.3. CloudWatchロググループ
5.4. Elasticsearchドメイン
Elasticsearchドメイン構築はかなり時間がかかります。20分くらいかかりました。
6. ロググループのサブスクリプションフィルター作成
次に手動操作になります。マネコン経由でロググループのサブスクリプションフィルター作成をします。
Elasticsearch 用のsubscription Filterのメニューが存在します(大阪リージョンでは存在しませんでした2021年8月時点)
送信先に先ほど作成したElasticsearchを選択します。
ログ形式としてCloudTrailの項目が用意されています。これを選択するだけでLambdaも自動的に作成してくれるようです。なんて便利なんだ・・・
7. kibanaレポートの作成
最後にkibanaのレポート作成です。
プライベートサブネットにアクセスできるマシンのブラウザ経由で実施してください。
まずはkibanaのURLをElasticsearchのドメインの概要から確認します。
kibanaのURLへアクセスします。
インデックスを作成します。cloudtrailのログインデックスがcwl-xxxxという日付単位の形式なので、cws-20*とかで作成します。
timestampを指定するだけですね。
これだけです。簡単に可視化レポートができました。
あとは左側の項目でフィルタかければ項目単位で検索することができますね。
8. まとめ
CloudTrailのログをCWLogsのサブスクリプションフィルター経由でElasticsearchに流してkibanaでのレポート表示までをおこないました。
ログを可視化する流れとしては「CWLogsのサブスクリプションフィルター→Elasticsearch」というのは一番使われている気がします。
他のログなども応用できるかと思います。
できれば全てCloudFormationで行いたかったのですが、思ったよりもマネコン経由での手間がなかったので一部手動での作業手順となりました。
時間がある時(もしくは機会があれば)全てのリソースのCloudFormation化を行いたいと考えています。
AWSを効率的に学習する方法
私が効率的にAWSを学習するために実施した方法は以下の通りです。
①最初に書籍(ハンズオンができる)を購入、座学でAWSの基礎を学習
②AWS資格試験を取得ための学習
※私の場合は①と②を合わせて2か月でソリューションアーキテクトを取得できました。
①AWS基礎学習
最初に購入した書籍は「Amazon Web Services 基礎からのネットワーク&サーバー構築」です。
Amazon Web Services 基礎からのネットワーク&サーバー構築
この本では、AWSの基本サービスを利用したハンズオンを通じて、AWSの基礎を学習することができます。
また、タイトル通りAWSのネットワークやインフラに関しても網羅しているため、もともとインフラ系の技術者ではない人たちにとっても分かりやすい内容だと思います。
とりあえずAWS上にサーバーを設定して開発を行うための準備までするには最良の一冊です。
Amazon Web Services 基礎からのネットワーク&サーバー構築
②AWS資格取得
AWSの基礎をある程度学習することができたら、次はAWS資格を取得しましょう。まずはAWSソリューションアーキテクトを目指しましょう。
資格勉強のための問題集をひたすら解きながら、AWSの知識を積み重ねて習得していきましょう!
苦行ではありますが、この問題集を3周ほどすればAWS用語や構成に関しても習得できているはずです。
今回は以上となります。
コメント