auditdを用いてEC2内のファイル転送系コマンドをCloudWatch Logsに収集してみた

auditdを用いてEC2内のファイル転送系コマンドをCloudWatch Logsに収集してみた

2026.03.26

はじめに

みなさんこんにちは、クラウド事業本部コンサルティング部の浅野です。

EC2上で動作するシステムを運用していると、「このサーバーから外部にデータが持ち出されていないか?」という懸念が出てくることはありませんか?

特に、rsyncscpaws s3 cpといった転送系コマンドは、正当な運用で使われる一方、意図しないデータ持ち出しの手段にもなり得ます。¥

今回は、Linuxのカーネルレベル監査機能であるauditdを使って転送コマンドの実行を記録し、CloudWatch Logsに転送してログ収集する環境を構築してみました。

本記事では、実際にAmazon Linux 2023上でauditdを設定し、転送系コマンドが実行されたときにログに残す検証手順と結果を紹介します。

Linux Auditとauditd

Linux Auditとは

Linux Auditは、Linuxカーネルに組み込まれた監査フレームワークです。「誰が・いつ・何をしたか」をカーネルレベルで記録するソフトウェアであり、Red Hat、Ubuntu、Debianなど主要Linuxディストリビューションすべてに標準で含まれています。

auditdはそのフレームワークの中核となるデーモン(常駐プロセス)で、カーネルから設定した監査イベントを受け取り、ログファイルに書き出す役割を担っています。

よって「転送系コマンドを検知するためのツール」ではなくLinux OS内のシステムイベントを統合的に監視・収集できるツールとなります。今回は転送系コマンドのシステムイベント収集という役割で使用しています。

AWSでは、EC2 Linuxインスタンスからデフォルトで収集するログの一覧に/var/log/audit/audit.logが含まれており、AWSの運用基盤でもauditdのログ収集が標準的に組み込まれています。

https://docs.aws.amazon.com/managedservices/latest/userguide/access-to-logs-ec2.html

また、SUSEの公式ドキュメントUnderstanding Linux auditでは、Linux AuditフレームワークがCAPP(Controlled Access Protection Profiles)に準拠しており、Common Criteria(CC)認証の要件を満たす監査基盤であることが記載されており、セキュリティフレームワークやコンプライアンス要件が厳しい監査にも用いられるツールです。

公式のGithubもありますが、Red Hat Enterpriseドキュメントの方が詳しく解説されているので仕様を詳しく知りたい方はこちらを読むのがおすすめです。

構成

今回はEC2内にauditdとCloudWatch Agentを設定して転送系コマンド(scp, rsync, aws s3 cp)をCloudWatch Logsに収集する構成を試してみました。

2026-03-26-ec2-auditd-file-transfer-command-logging-01

以下のリソースをCDKで用意しました。

  • VPC(プライベートサブネットのみ)
  • VPCエンドポイント(SSM, SSM Messages, CloudWatch Logs, S3)
  • EC2(Amazon Linux 2023 / t3.micro / SSM接続)
  • IAMロール(SSM + CloudWatchAgentServerPolicy + S3アクセス)
  • CloudWatch Logsロググループ(/ec2/auditd
  • S3バケット(aws s3 cp検証用)「auditd-transfer-test-demo-bucket」

検証環境

項目
OS Amazon Linux 2023
インスタンスタイプ t3.micro
auditdバージョン 3.1.5
CloudWatch Agentバージョン 1.300064.1
リージョン ap-northeast-1
CDKスタック
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as s3 from 'aws-cdk-lib/aws-s3';

export class DemoAuditdCloudwatchStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, 'AuditdVpc', {
      ipAddresses: ec2.IpAddresses.cidr('192.168.0.0/24'),
      maxAzs: 1,
      natGateways: 0,
      restrictDefaultSecurityGroup: false,
      subnetConfiguration: [
        {
          cidrMask: 26,
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });

    const vpcEndpointSg = new ec2.SecurityGroup(this, 'VpcEndpointSg', {
      vpc,
      description: 'Security group for VPC Endpoints',
      allowAllOutbound: true,
    });

    vpcEndpointSg.addIngressRule(
      ec2.Peer.ipv4(vpc.vpcCidrBlock),
      ec2.Port.tcp(443),
      'Allow HTTPS from VPC'
    );

    vpc.addInterfaceEndpoint('SsmEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.SSM,
      subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      securityGroups: [vpcEndpointSg],
    });

    vpc.addInterfaceEndpoint('SsmMessagesEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
      subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      securityGroups: [vpcEndpointSg],
    });

    vpc.addInterfaceEndpoint('CloudWatchLogsEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
      subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      securityGroups: [vpcEndpointSg],
    });

    vpc.addGatewayEndpoint('S3Endpoint', {
      service: ec2.GatewayVpcEndpointAwsService.S3,
      subnets: [{ subnetType: ec2.SubnetType.PRIVATE_ISOLATED }],
    });

    const ec2Sg = new ec2.SecurityGroup(this, 'Ec2Sg', {
      vpc,
      securityGroupName: 'auditd-cloudwatch-ec2-sg',
      description: 'Security group for auditd verification EC2',
      allowAllOutbound: true,
    });

    new logs.LogGroup(this, 'AuditdLogGroup', {
      logGroupName: '/ec2/auditd',
      retention: logs.RetentionDays.ONE_WEEK,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const transferTestBucket = new s3.Bucket(this, 'TransferTestBucket', {
      bucketName: 'auditd-transfer-test-demo-bucket',
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });

    const ec2Role = new iam.Role(this, 'Ec2Role', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
        iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchAgentServerPolicy'),
      ],
      inlinePolicies: {
        S3TransferTest: new iam.PolicyDocument({
          statements: [
            new iam.PolicyStatement({
              actions: ['s3:PutObject', 's3:GetObject', 's3:ListBucket'],
              resources: [
                transferTestBucket.bucketArn,
                `${transferTestBucket.bucketArn}/*`,
              ],
            }),
          ],
        }),
      },
    });

    new ec2.Instance(this, 'Ec2', {
      vpc,
      vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
      machineImage: ec2.MachineImage.latestAmazonLinux2023(),
      securityGroup: ec2Sg,
      role: ec2Role,
      blockDevices: [
        {
          deviceName: '/dev/xvda',
          volume: ec2.BlockDeviceVolume.ebs(20, {
            volumeType: ec2.EbsDeviceVolumeType.GP3,
          }),
        },
      ],
    });
  }
}

やってみた

CDKデプロイ後、SSM Session ManagerでEC2に接続して作業を進めます。

auditdの状態確認

Amazon Linux 2023にはauditdがデフォルトでインストール・有効化されています。

sh-5.2$ which auditd
/usr/sbin/auditd

sh-5.2$ sudo systemctl status auditd
 auditd.service - Security Auditing Service
     Loaded: loaded (/usr/lib/systemd/system/auditd.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-03-26 02:25:15 UTC; 1h 36min ago
       Docs: man:auditd(8)
             https://github.com/linux-audit/audit-documentation
   Main PID: 1267 (auditd)
      Tasks: 2 (limit: 1067)
     Memory: 2.6M
        CPU: 88ms
     CGroup: /system.slice/auditd.service
             └─1267 /sbin/auditd

auditdのディレクトリ構成

デフォルトのディレクトリ構成は以下の通りです。

sudo tree /etc/audit

/etc/audit
├── audit-stop.rules
├── audit.rules
├── auditd.conf
├── plugins.d
└── rules.d
    └── audit.rules

audit-stop.rulesはデーモン停止時に読み込まれるルール定義ファイルであり、初期では監査を無効にし全てのルールを削除するように組まれています。デーモン停止時にログに記録を残したい場合はここに設定すると良いかも知れません。

sudo cat /etc/audit/audit-stop.rules

# These rules are loaded when the audit daemon stops
# if configured to do so.

# Disable auditing
-e 0

# Delete all rules
-D

監査のためのルール設定はrules.d/配下にファイルを配置し、augenrules --loadコマンドで反映します。

ルート直下のaudit.rulesは、rules.d/に配置したルールファイルがAudit側で統合されて自動生成されるようになっています。

初期の監査ルールについてはrules.d/audit.rulesとして唯一のファイルがあり、初期の記載は以下となっています。

sudo cat /etc/audit/rules.d/audit.rules

## This set of rules is to suppress the performance effects of the
## audit system. The result is that you only get hardwired events.
-D

## This suppresses syscall auditing for all tasks started
## with this rule in effect.  Remove it if you need syscall
## auditing.
-a task,never

-a task,neverですべてのシステムコール監査が抑制されているのでシステムコール監査が必要な場合は、このルールを削除する必要があるようです。

auditd自体の設定ファイルはauditd.confに記述されています。
ログファイルの場所や制限などの設定が追加できます。

sh-5.2$ sudo cat /etc/audit/auditd.conf
local_events = yes
write_logs = yes
log_file = /var/log/audit/audit.log
log_group = root
log_format = ENRICHED
flush = INCREMENTAL_ASYNC
freq = 50
max_log_file = 8
num_logs = 5
priority_boost = 4
name_format = NONE
max_log_file_action = ROTATE
space_left = 75
space_left_action = SYSLOG
verify_email = yes
action_mail_acct = root
admin_space_left = 50
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
use_libwrap = yes
tcp_listen_queue = 5
tcp_max_per_addr = 1
tcp_client_max_idle = 0
transport = TCP
krb5_principal = auditd
distribute_network = no
q_depth = 2000
overflow_action = SYSLOG
max_restarts = 10
plugin_dir = /etc/audit/plugins.d
end_of_event_timeout = 2

参考:
https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/security_hardening/configuring-auditd-for-a-secure-environment_auditing-the-system

設定ファイルによるとログファイルの場所は/var/log/audit/audit.logに保存されていることがわかります。
plugins.d/はデフォルトで空です。

これにて一連のauditに関するファイルを確認しました。

デフォルトルールの修正

auditdによって現在読み込まれている設定ルールを以下のコマンドで確認します。

sh-5.2$ sudo auditctl -l
-a never,task

初期設定ルールファイル/etc/audit/rules.d/audit.rulesの通り全てのシステムコール監査が抑制されています。

デフォルトの-a task,neverが有効な状態では、後続のカスタムルールを追加してもシステムコールコマンドが記録されませんのでこの記述をコメントアウトしておきます。

sudo vi /etc/audit/rules.d/audit.rules
sh-5.2$ sudo cat /etc/audit/rules.d/audit.rules
## This set of rules is to suppress the performance effects of the
## audit system. The result is that you only get hardwired events.
-D

## This suppresses syscall auditing for all tasks started
## with this rule in effect.  Remove it if you need syscall
## auditing.
# -a task,never

転送コマンド監視ルールの作成

それではまず、ログ監視対象としたいコマンドのパスを確認します。
今回は以下の3つについて監視するルールを設定したいと思います。

sh-5.2$ which rsync
/usr/bin/rsync

sh-5.2$ which aws
/usr/bin/aws

sh-5.2$ which scp
/usr/bin/scp

rules.d/にルールファイルtransfer-commands.rulesという設定ファイルを作成します。

# 転送コマンド監視ルールを作成(syscallベース)
sudo tee /etc/audit/rules.d/transfer-commands.rules << 'EOF'
-a always,exit -F arch=b64 -F path=/usr/bin/rsync -F perm=x -k data_transfer
-a always,exit -F arch=b64 -F path=/usr/bin/scp -F perm=x -k data_transfer
-a always,exit -F arch=b64 -F path=/usr/bin/aws -F perm=x -k data_transfer
EOF

# 出力
-a always,exit -F arch=b64 -F path=/usr/bin/rsync -F perm=x -k data_transfer
-a always,exit -F arch=b64 -F path=/usr/bin/scp -F perm=x -k data_transfer
-a always,exit -F arch=b64 -F path=/usr/bin/aws -F perm=x -k data_transfer

各オプションの意味は以下のとおりです。

オプション 意味
-a always,exit syscall終了時に常にログを記録
-F arch=b64 64bitアーキテクチャを指定(省略すると32/64bit両方を監視しパフォーマンス低下)
-F path=/usr/bin/rsync 監視対象のファイルパス
-F perm=x 実行(execute)イベントのみ記録
-k data_transfer ログ検索用のキー名(ausearch -k data_transferでログ内を絞り込みやすくするために設定)

ルールの反映と確認

実際にルールを読み込んで設定されているか確認します。

# rules.d/のファイルを結合して読み込み
sh-5.2$ sudo augenrules --load
No rules

# 反映されたルールの確認
sh-5.2$ sudo auditctl -l
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/rsync -F perm=x -F key=data_transfer
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/scp -F perm=x -F key=data_transfer
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/aws -F perm=x -F key=data_transfer
sh-5.2$

このように3つのルールが反映されていることが確認できました。

CloudWatch Agentのインストール

CloudWatch Agentはプリインストールされていないため、別途インストールします。

which amazon-cloudwatch-agent-ctl
# 出力
which: no amazon-cloudwatch-agent-ctl in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)

sudo dnf install -y amazon-cloudwatch-agent
# 出力
Last metadata expiration check: 2:30:21 ago on Thu Mar 26 02:26:04 2026.
Dependencies resolved.
===========================================================================================================================================================================================
 Package                                             Architecture                       Version                                              Repository                               Size
===========================================================================================================================================================================================
Installing:
 amazon-cloudwatch-agent                             x86_64                             1.300064.1-1.amzn2023                                amazonlinux                              67 M

Transaction Summary
===========================================================================================================================================================================================
Install  1 Package

Total download size: 67 M
Installed size: 228 M
Downloading Packages:
amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64.rpm                                                                                                    71 MB/s |  67 MB     00:00
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                       68 MB/s |  67 MB     00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                                                   1/1
  Running scriptlet: amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64                                                                                                              1/1
create group cwagent, result: 0
create user cwagent, result: 0

  Installing       : amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64                                                                                                              1/1
  Running scriptlet: amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64                                                                                                              1/1
  Verifying        : amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64                                                                                                              1/1

Installed:
  amazon-cloudwatch-agent-1.300064.1-1.amzn2023.x86_64

Complete!

CloudWatch Agent設定ファイルの作成

インストールが完了したので、auditdのログファイルをCloudWatch Logsに転送する設定を作成します。
CloudWatch Agent設定ファイルとしてホームディレクトリ配下に data-transfer-auditd.jsonを作成しました。

run_as_userに関して設定しない場合は強制的にrootが使用されますが、明示的に指定しています。
regionに関しても設定しない場合はEC2が配置されているリージョンにログが収集されますが明示的に指定しています。

cat << 'EOF' > ~/data-transfer-auditd.json
{
  "agent": {
    "run_as_user": "root",
    "region": "ap-northeast-1"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/audit/audit.log",
            "log_group_name": "/ec2/auditd",
            "log_stream_name": "{instance_id}",
            "timezone": "Local"
          }
        ]
      }
    }
  }
}
EOF

/var/log/audit/audit.logの内容をCDKで作成したロググループに流す設定を記載しています。
CloudWatch Agentの設定方法に関しては公式ドキュメントを参考にしてください。

参考:
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html#Saving-Agent-Configuration-File

CloudWatch Agentの起動と確認

設定ファイルができたのでCloudWatch Agentを起動します。

# 設定を適用して起動
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config \
  -m ec2 \
  -s \
  -c file:$HOME/data-transfer-auditd.json

# 出力
****** processing amazon-cloudwatch-agent ******
Starting config-downloader, this will map back to a call to amazon-cloudwatch-agent
Executing /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent with arguments: [config-downloader -config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml -multi-config default -mode ec2 -download-source file:/home/ssm-user/data-transfer-auditd.json -output-dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d]I! Trying to detect region from ec2
D! [EC2] Found active network interface
I! imds retry client will retry 1 times
Start configuration validation...
2026/03/26 05:09:32 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_data-transfer-auditd.json.tmp ...
2026/03/26 05:09:32 I! Valid Json input schema.
2026/03/26 05:09:32 Configuration validation first phase succeeded
Starting config-translator, this will map back to a call to amazon-cloudwatch-agent
Executing /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent with arguments: [config-translator -multi-config default -input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -input-dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d -output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml -mode ec2 -config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml]D! [EC2] Found active network interface
I! imds retry client will retry 1 times
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
amazon-cloudwatch-agent has already been stopped
Created symlink /etc/systemd/system/multi-user.target.wants/amazon-cloudwatch-agent.service /etc/systemd/system/amazon-cloudwatch-agent.service.

# 起動ステータス確認
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a status
# 出力
{
  "status": "running",
  "starttime": "2026-03-26T05:09:31+00:00",
  "configstatus": "configured",
  "version": "1.300064.1"
}

fetch-configを実行すると、指定した設定ファイルが/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/配下にコピーされます。ここを確認すれば実際にCloudWatch Agentが読み込んでいる設定内容がわかるので確認してみます。

sudo ls /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/
# 出力
file_data-transfer-auditd.json

sudo cat /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_data-transfer-auditd.json

# 出力
{
  "agent": {
    "run_as_user": "root",
    "region": "ap-northeast-1"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/audit/audit.log",
            "log_group_name": "/ec2/auditd",
            "log_stream_name": "{instance_id}",
            "timezone": "Local"
          }
        ]
      }
    }
  }
}

意図した通りにCloudWatch Agentの設定が読み込まれていることが確認できました!

転送コマンドを実行して検知を確認

それではログ監査の準備が整ったので、実際にテストデータを作成し、3つの転送系コマンドを以下の操作で実行しました。

mkdir -p /tmp/test-data
echo "test data" > /tmp/test-data/sample.txt

rsyncの実行

sh-5.2$ rsync -av /tmp/test-data/ /tmp/rsync-dest/
sending incremental file list

sent 89 bytes  received 12 bytes  202.00 bytes/sec
total size is 10  speedup is 0.10

aws s3 cpの実行

aws s3 cp /tmp/test-data/sample.txt s3://auditd-transfer-test-demo-bucket/sample.txt
upload: ../../tmp/test-data/sample.txt to s3://auditd-transfer-test-demo-bucket/sample.txt

コマンド実行後テストファイルがS3バケットに格納されていることも確認できました。

2026-03-26-ec2-auditd-file-transfer-command-logging-02

scpの実行

sh-5.2$ mkdir -p /tmp/scp-data
scp /tmp/test-data/sample.txt /tmp/scp-data/sample.txt
cat /tmp/scp-data/sample.txt
test data

auditdログの確認

転送系コマンドがエラーなく終了したのでauditdのログを確認してみます。

ausearchコマンドで設定したdata_transferキーに該当するログを検索します。--interpretオプションでUID等を人が読める形式に変換します。

参考:ausearch(8) man page

sudo ausearch -k data_transfer --interpret

出力の全文は長いので折りたたんでおきます。この中から該当の監査コマンド毎に実行ログを抜粋しました。

出力全文
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:38:25.317:1213) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:38:25.317:1214) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:38:25.317:1215) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1322) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1323) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1324) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1326) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1327) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 04:44:26.908:1328) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2001) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2002) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2003) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=remove_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2004) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2005) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=CONFIG_CHANGE msg=audit(03/26/26 05:24:00.617:2006) : auid=unset ses=unset subj=system_u:system_r:unconfined_service_t:s0 op=add_rule key=data_transfer list=exit res=yes
----
type=PROCTITLE msg=audit(03/26/26 05:24:41.627:2058) : proctitle=rsync -av /tmp/test-data/ /tmp/rsync-dest/
type=PATH msg=audit(03/26/26 05:24:41.627:2058) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=8527157 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(03/26/26 05:24:41.627:2058) : item=0 name=/usr/bin/rsync inode=1035529 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:rsync_exec_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(03/26/26 05:24:41.627:2058) : cwd=/home/ssm-user
type=EXECVE msg=audit(03/26/26 05:24:41.627:2058) : argc=4 a0=rsync a1=-av a2=/tmp/test-data/ a3=/tmp/rsync-dest/
type=SYSCALL msg=audit(03/26/26 05:24:41.627:2058) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x563d53fed040 a1=0x563d53fc8ce0 a2=0x563d53faa4e0 a3=0x8 items=2 ppid=29595 pid=31362 auid=unset uid=ssm-user gid=ssm-user euid=ssm-user suid=ssm-user fsuid=ssm-user egid=ssm-user sgid=ssm-user fsgid=ssm-user tty=pts1 ses=unset comm=rsync exe=/usr/bin/rsync subj=system_u:system_r:unconfined_service_t:s0 key=data_transfer
----
type=PROCTITLE msg=audit(03/26/26 05:25:03.437:2059) : proctitle=/usr/bin/python3 -s /usr/bin/aws s3 cp /tmp/test-data/sample.txt s3://auditd-transfer-test-demo-bucket/sample.txt
type=PATH msg=audit(03/26/26 05:25:03.437:2059) : item=2 name=/lib64/ld-linux-x86-64.so.2 inode=8527157 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(03/26/26 05:25:03.437:2059) : item=1 name=/usr/bin/python3 inode=10589 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(03/26/26 05:25:03.437:2059) : item=0 name=/usr/bin/aws inode=821406 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(03/26/26 05:25:03.437:2059) : cwd=/home/ssm-user
type=EXECVE msg=audit(03/26/26 05:25:03.437:2059) : argc=7 a0=/usr/bin/python3 a1=-s a2=/usr/bin/aws a3=s3 a4=cp a5=/tmp/test-data/sample.txt a6=s3://auditd-transfer-test-demo-bucket/sample.txt
type=SYSCALL msg=audit(03/26/26 05:25:03.437:2059) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x563d53fed660 a1=0x563d53fed5c0 a2=0x563d53faa4e0 a3=0x8 items=3 ppid=29595 pid=31365 auid=unset uid=ssm-user gid=ssm-user euid=ssm-user suid=ssm-user fsuid=ssm-user egid=ssm-user sgid=ssm-user fsgid=ssm-user tty=pts1 ses=unset comm=aws exe=/usr/bin/python3.9 subj=system_u:system_r:unconfined_service_t:s0 key=data_transfer
----
type=PROCTITLE msg=audit(03/26/26 05:25:10.818:2060) : proctitle=scp /tmp/test-data/sample.txt /tmp/scp-data/sample.txt
type=PATH msg=audit(03/26/26 05:25:10.818:2060) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=8527157 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(03/26/26 05:25:10.818:2060) : item=0 name=/usr/bin/scp inode=976419 dev=103:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(03/26/26 05:25:10.818:2060) : cwd=/home/ssm-user
type=EXECVE msg=audit(03/26/26 05:25:10.818:2060) : argc=3 a0=scp a1=/tmp/test-data/sample.txt a2=/tmp/scp-data/sample.txt
type=SYSCALL msg=audit(03/26/26 05:25:10.818:2060) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x563d53fed720 a1=0x563d53fed440 a2=0x563d53faa4e0 a3=0x8 items=2 ppid=29595 pid=31374 auid=unset uid=ssm-user gid=ssm-user euid=ssm-user suid=ssm-user fsuid=ssm-user egid=ssm-user sgid=ssm-user fsgid=ssm-user tty=pts1 ses=unset comm=scp exe=/usr/bin/scp subj=system_u:system_r:unconfined_service_t:s0 key=data_transfer

各ログのtypeについては以下のRed Hatドキュメントを参考にしてください。

参考:
https://access.redhat.com/articles/4409591?extIdCarryOver=true&sc_cid=RHCTG0250000454097#audit-record-types-2

rsyncの実行ログ記録

type=PROCTITLE : proctitle=rsync -av /tmp/test-data/ /tmp/rsync-dest/
type=PATH      : item=0 name=/usr/bin/rsync inode=1035529 ...
type=CWD       : cwd=/home/ssm-user
type=EXECVE    : argc=4 a0=rsync a1=-av a2=/tmp/test-data/ a3=/tmp/rsync-dest/
type=SYSCALL   : arch=x86_64 syscall=execve success=yes ... uid=ssm-user ... exe=/usr/bin/rsync ... key=data_transfer

aws s3 cpの実行ログ記録

type=PROCTITLE : proctitle=/usr/bin/python3 -s /usr/bin/aws s3 cp /tmp/test-data/sample.txt s3://auditd-transfer-test-demo-bucket/sample.txt
type=EXECVE    : argc=7 a0=/usr/bin/python3 a1=-s a2=/usr/bin/aws a3=s3 a4=cp a5=/tmp/test-data/sample.txt a6=s3://auditd-transfer-test-demo-bucket/sample.txt
type=SYSCALL   : ... comm=aws exe=/usr/bin/python3.9 ... key=data_transfer

scpの実行ログ記録

type=PROCTITLE : proctitle=scp /tmp/test-data/sample.txt /tmp/scp-data/sample.txt
type=EXECVE    : argc=3 a0=scp a1=/tmp/test-data/sample.txt a2=/tmp/scp-data/sample.txt
type=SYSCALL   : ... comm=scp exe=/usr/bin/scp ... key=data_transfer

少し読みづらい形式ですが、3つのコマンド実行すべてがkey=data_transferで記録されていることが確認できました。

CloudWatch Logsで確認

CloudWatch Logsコンソールでも確認してみます。ロググループ/ec2/auditdを開き、type=EXECVEでフィルタすると転送コマンドの実行ログが以下のように確認できました。

2026-03-26-ec2-auditd-file-transfer-command-logging-03

CloudWatch Agentにはバッファがあるため、コマンド実行後ログが反映されるまで数分~数十分程度かかる場合があります。

最後に

今回はLinuxの監査フレームワークであるauditdを使って、EC2上の転送系コマンド(rsync、scp、aws s3 cp)の実行をログ収集し、CloudWatch Logsに転送する構成を試しました。

Linux OSにおいてauditdを用いればエージェント型のセキュリティツールを別途導入することもなくファイル転送の監査ログを取得できる点が利点です。CloudWatch Agentと組み合わせることで、ログの一元管理やアラート設定にもつなげられるので組み合わせやすいです。

この記事がどなたかの参考になれば幸いです。今回は以上です。

この記事をシェアする

FacebookHatena blogX

関連記事