[アップデート]Amazon CloudWatchエージェントがSELinuxのサポートを追加しました
はじめに
皆様こんにちは、あかいけです。
AWSでは様々なアップデートがありワクワクな日々をお過ごしのことかと思いますが、
2025年4月16日に、CloudWatch エージェントに関するアップデートが発表されました。
具体的には、
CloudWatch エージェントにてSecurity-Enhanced Linux (SELinux) 環境のサポートがされるようになったとのことです。
SELinuxはお堅い環境では目にすることの多く、
特に金融関係システムの関係者には嬉しいアップデートではないでしょうか。
この記事では実際に試してみた結果をご紹介していきます。
アップデート内容
今回のアップデートでは、Amazon CloudWatch エージェントが Security-Enhanced Linux (SELinux) 環境を正式にサポートするようになりました。
具体的には、CloudWatch エージェントのSELinux ポリシーが提供され、SELinuxを有効化した環境においてCloudWatch エージェントが利用できるようになりました。
これまでSELinuxが有効な環境では、CloudWatchエージェントの導入には追加の設定が必要でしたが、
今回のアップデートによりそのような設定をすることなく、セキュリティを維持したままCloudWatchの機能を活用できるようになりました。
SELinux is 何?
そもそもSELinuxとはなんでしょうか?
多くの環境ではデフォルト設定から変更されていないか、設定の複雑さから無効化されることも多いため、詳細を知らない方もいるかもしれません。
SELinuxは、Linuxカーネルに組み込まれたセキュリティモジュールで、アクセス制御をより細かく強力に実装するためのシステムです。
従来のUNIX/Linuxのパーミッション管理を拡張し、「誰が」「何を」「どのように」アクセスできるかを詳細に制御します。
SELinuxは主に以下の特徴を持っています。
- 強制アクセス制御 (MAC)
- 管理者が定めたポリシーに基づき、プロセスやユーザーのアクセス権を制限
- 最小権限の原則
- プログラムやユーザーは必要最小限の権限のみを持つ
- コンテキストベースのセキュリティ
- ファイル、プロセス、ポートなどにセキュリティコンテキストを割り当て
Red Hat Enterprise Linux (RHEL)、CentOS、Fedoraなどの主要なディストリビューションでデフォルトで有効化されていることが多く、
特に政府機関や金融機関などのセキュリティ要件が厳しい環境で採用されています。
使ってみた
それでは実際に、SELinuxが有効な環境でCloudWatchエージェントを設定してみましょう。
1.環境構築
まずはTerraformで環境を構築します、
以下のコードはSSMセッションマネジャーから接続できるEC2を作成します。
main.tf
provider "aws" {
region = "ap-northeast-1"
}
# Amazon Linux 2023 AMI
data "aws_ami" "amazonlinux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-2023*-kernel-6.1-x86_64"]
}
}
data "http" "ipv4_icanhazip" {
url = "http://ipv4.icanhazip.com/"
}
locals {
region_code = "ap-northeast-1"
az = "ap-northeast-1a"
vpc_cidr = "10.0.0.0/16"
subnet_cidr = "10.0.1.0/24"
name_prefix = "CloudWatch-SELinux"
current-ip = chomp(data.http.ipv4_icanhazip.body)
allowed-cidr = "${local.current-ip}/32"
}
# VPC - 東京
resource "aws_vpc" "main" {
cidr_block = local.vpc_cidr
tags = {
Name = "${local.name_prefix}-VPC"
}
}
# パブリックサブネット
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = local.subnet_cidr
availability_zone = local.az
map_public_ip_on_launch = true
tags = {
Name = "${local.name_prefix}-Public-Subnet"
}
}
# インターネットゲートウェイ
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.name_prefix}-IGW"
}
}
# ルートテーブル
resource "aws_route_table" "main" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${local.name_prefix}-Route-Table"
}
}
# ルートテーブルの関連付け
resource "aws_route_table_association" "main" {
subnet_id = aws_subnet.main.id
route_table_id = aws_route_table.main.id
}
# SSMとCloudWatchのためのIAMロール
resource "aws_iam_role" "main" {
name = "SSMAndCloudWatchRoleForEC2"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
tags = {
Name = "SSMAndCloudWatchRoleForEC2"
}
}
# SSMポリシーのアタッチ
resource "aws_iam_role_policy_attachment" "ssm" {
role = aws_iam_role.main.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
# CloudWatch Agentポリシーのアタッチ
resource "aws_iam_role_policy_attachment" "cloudwatch_agent" {
role = aws_iam_role.main.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
}
# EC2インスタンスプロファイル
resource "aws_iam_instance_profile" "main" {
name = "SSMAndCloudWatchInstanceProfile"
role = aws_iam_role.main.name
}
# セキュリティグループ
resource "aws_security_group" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.name_prefix}-SG"
}
}
# セキュリティグループ 送信ルール
resource "aws_security_group_rule" "egress" {
security_group_id = aws_security_group.main.id
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
# EC2インスタンス
resource "aws_instance" "main" {
ami = data.aws_ami.amazonlinux_2023.id
instance_type = "t3.micro"
subnet_id = aws_subnet.main.id
vpc_security_group_ids = [aws_security_group.main.id]
iam_instance_profile = aws_iam_instance_profile.main.name
tags = {
Name = "${local.name_prefix}-EC2"
}
}
# インスタンス SSM接続コマンド
output "ssm_start_session" {
value = "aws ssm start-session --target ${aws_instance.main.id}"
}
# インスタンス IPアドレス
output "instance_global_ip" {
value = aws_instance.main.public_ip
}
EC2への接続コマンドは以下で確認できます。
terraform output
2.SELinuxとCloudWatchエージェントの設定
次にSELinuxとCloudWatchエージェントを設定しましょう。
SELinux
設定手順は以下ドキュメントの通りです。
まず SELinux ポリシー開発パッケージ をインストールします。
sudo yum update;
sudo yum install -y selinux-policy-devel policycoreutils-devel rpm-build git;
Amazon Linux2023においてはSELinuxはインストールされている状態ですが、
デフォルトで permissiveモード となっています。
※ permissiveモード = ポリシーに違反するアクセスをログに記録するが、実際にアクセスを拒否はしない
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2023"
ID="amzn"
ID_LIKE="fedora"
VERSION_ID="2023"
PLATFORM_ID="platform:al2023"
PRETTY_NAME="Amazon Linux 2023.7.20250414"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023"
HOME_URL="https://aws.amazon.com/linux/amazon-linux-2023/"
DOCUMENTATION_URL="https://docs.aws.amazon.com/linux/"
SUPPORT_URL="https://aws.amazon.com/premiumsupport/"
BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023"
VENDOR_NAME="AWS"
VENDOR_URL="https://aws.amazon.com/"
SUPPORT_END="2029-06-30"
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: permissive
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
これをenforcingモードに変更します。
sudo vi /etc/selinux/config
SELINUX=enforcing
へ変更して、再起動します。
SELINUX=enforcing
sudo reboot
再起動後、 enforcingモード となっていることが確認できます。
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
CloudWatchエージェント
CloudWatchエージェントは以下ドキュメントの通りインストールします。
sudo yum -y install amazon-cloudwatch-agent
CloudWatchエージェントはサンプルとして以下のような設定をしておきます。
CloudWatchエージェント 設定
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"metrics": {
"namespace": "CustomMetrics",
"metrics_collected": {
"cpu": {
"resources": [
"*"
],
"measurement": [
"usage_idle",
"usage_iowait",
"usage_user",
"usage_system"
],
"totalcpu": true,
"metrics_collection_interval": 60
},
"disk": {
"resources": [
"/",
"/tmp"
],
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 60
},
"diskio": {
"resources": [
"*"
],
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"metrics_collection_interval": 60
},
"mem": {
"measurement": [
"used_percent",
"total",
"available"
],
"metrics_collection_interval": 60
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_time_wait"
],
"metrics_collection_interval": 60
},
"swap": {
"measurement": [
"used_percent"
],
"metrics_collection_interval": 60
}
},
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
},
"aggregation_dimensions": [
["InstanceId"]
]
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/cloud-init.log",
"log_group_name": "cloud-init-logs",
"log_stream_name": "{instance_id}-cloud-init",
"retention_in_days": 7
},
{
"file_path": "/var/log/dnf.log",
"log_group_name": "dnf-logs",
"log_stream_name": "{instance_id}-dnf",
"retention_in_days": 7
},
{
"file_path": "/var/log/cloud-init-output.log",
"log_group_name": "cloud-init-output-logs",
"log_stream_name": "{instance_id}-cloud-init-output",
"retention_in_days": 7
}
]
}
},
"force_flush_interval": 15
}
}
この状態で実行しても、SELinux 制限ドメインで制御されておらず、
ドメインが unconfined_service_t となります。
sudo systemctl start amazon-cloudwatch-agent
ps -efZ | grep amazon-cloudwatch-agent
system_u:system_r:unconfined_service_t:s0 root 2331 1 1 02:26 ? 00:00:00 /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml -envconfig /opt/aws/amazon-cloudwatch-agent/etc/env-config.json -otelconfig /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.yaml -pidfile /opt/aws/amazon-cloudwatch-agent/var/amazon-cloudwatch-agent.pid
次にCloudWatch エージェントの SELinux ポリシーを取得して、スクリプトの実行権限を付与します。
sudo git clone https://github.com/aws/amazon-cloudwatch-agent-selinux.git;
cd amazon-cloudwatch-agent-selinux;
sudo chmod +x amazon_cloudwatch_agent.sh;
SELinuxポリシーインストールスクリプトを実行します。
sudo ./amazon_cloudwatch_agent.sh
CloudWatchエージェントを再起動するか聞かれるので、yで再起動します。
Would you like to restart the CloudWatch Agent now? (y/N): y
CloudWatchエージェントの再起動後、
以下コマンドでCloudWatchエージェント用のドメイン amazon_cloudwatch_agent_tで実行されていることを確認できます。
ps -efZ | grep amazon-cloudwatch-agent
system_u:system_r:amazon_cloudwatch_agent_t:s0 root 3365 1 0 02:43 ? 00:00:00 /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml -envconfig /opt/aws/amazon-cloudwatch-agent/etc/env-config.json -otelconfig /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.yaml -pidfile /opt/aws/amazon-cloudwatch-agent/var/amazon-cloudwatch-agent.pid
SELinuxとCloudWatchエージェントのセットアップはこれで完了です。
3.CloudWatch確認
最後はCloudWatchにて、メトリクスとログの出力状況を確認しましょう。
メトリクス
以下のAWS CLIでカスタムメトリクスの収集状況を確認します。
ここでは例として cpu_usage_system メトリクスを確認しています。
※ <インスタンスID> の部分は実機の値に置き換えてください
- メトリクスの一覧確認
aws cloudwatch list-metrics --namespace CustomMetrics
- メトリクスデータの確認
aws cloudwatch get-metric-data \
--metric-data-queries '[{"Id":"m1","MetricStat":{"Metric":{"Namespace":"CustomMetrics","MetricName":"cpu_usage_system","Dimensions":[{"Name":"InstanceId","Value":"<インスタンスID>"}]},"Period":60,"Stat":"Average"},"ReturnData":true}]' \
--start-time $(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
ログ
以下のAWS CLIでログ収集状況を確認します。
ここでは例として dnf-logs ロググループを確認しています。
※ <インスタンスID> の部分は実機の値に置き換えてください
- ロググループの確認
aws logs describe-log-groups
- ログストリームの確認
aws logs describe-log-streams \
--log-group-name dnf-logs
- ログイベントの確認
aws logs get-log-events \
--log-group-name dnf-logs \
--log-stream-name "<インスタンスID>-dnf" \
--limit 10
さいごに
以上、CloudWatch エージェントのアップデートのご紹介と、
SELinux環境でのCloudWatchエージェントのセットアップでした。
このアップデートにより、セキュリティを妥協することなくAWSの監視機能を活用できるようになり、特に金融機関や政府機関など厳格なセキュリティポリシーを持つ組織にとって大きなメリットがあります。
またSELinuxの複雑な設定作業なしにCloudWatchエージェントを導入できるため、導入コストもある程度抑えられると考えられます。
SELinux環境でのログやメトリクス監視を悩まれている方は、一度CloudWatch エージェントの利用を検討してみてはいかがでしょうか。