近年、IoT機器やエッジデバイスから収集したログをクラウドに転送し、分析や監視に活用するケースが増えています。しかし、デバイス上にAWSのアクセスキー(長期クレデンシャル)を直接保存することは、漏洩時のリスクが高くセキュリティ上の大きな課題となります。
本記事では、IoT機器やエッジデバイスのアクセスキー漏洩リスクを排除する、AWS IAM Roles Anywhereと国産のクラウド型認証・ID管理サービスSoliton OneGate(以下、OneGate)を活用したセキュアなログ転送の手順を解説します。
OneGateは、デジタル証明書を用いた強固なデバイス認証を簡単に実現できるクラウドサービスです。OneGateを利用することで、Wi-FiやVPNなどの社内ネットワーク認証だけでなく、今回のようなクラウド連携時のデバイス認証基盤としてもシームレスに証明書を統合でき、管理者の運用負荷を大きく軽減できます。
本記事では、一時クレデンシャルの自動失効からAWS LambdaによるCRL(証明書失効)運用の自動化まで、実運用に役立つ具体的な手順をご紹介します。
本来であれば専用のIoT機器で行いたいところですが、今回は手軽に検証できるよう、SyslogサーバーおよびSNMPマネージャーに見立てた仮想マシン(Ubuntu OS)を用意しました。この環境を用いて、デバイスに長期クレデンシャルを持たせずに、Amazon CloudWatch Logsへログを安全に転送する仕組みを試します。
IoT機器をターゲットとする場合、「AWS IoT Coreを使う方が良いのでは」と感じる方も多いと思います。確かにアーキテクチャとしてはIoT Coreが自然です。しかし、「証明書失効」の運用に目を向けると、それぞれ異なる特徴が見えてきます。
| サービス | 証明書の失効方法 | 特徴・懸念事項 |
|---|---|---|
| AWS IoT Core | デバイスレジストリ上で対象証明書のステータスをINACTIVEやREVOKEDに変更する。 | CRL(証明書失効リスト)ファイルをアップロードする形式ではなく、「このシリアルは失効している」と個別に記載(API実行等)する必要があります。一括管理には作り込みが必要です。 |
| IAM Roles Anywhere | CRLファイルをインポート(アップロード)する。 | OneGateなどの認証局から出力したCRLをそのまま適用できるため、既存のPKIインフラと親和性が高いです。ただしCRLの定期更新の仕組みが必要となります。 |
今回は、OneGateとの連携のしやすさや、エンタープライズPKIでの一般的な失効運用(CRL)に適合しやすい点から、IAM Roles Anywhereを採用しました。
本記事の検証構成・要件は次の通りです。

💡 なぜCloudWatch Agentを採用したのか?
RAMディスク(tmpfs)は電源断でデータが消失するリスクがありますが、CloudWatch Agentによる「ニアリアルタイムなストリーミング送信」を組み合わせることで、突然の電源喪失時でもログのロストを数秒〜数十秒の最小限に抑えつつ、SDカードの寿命を保護することが可能になります。
まずは認証局であるOneGateから仮想マシン用のクライアント証明書を発行します。
.p12形式)を発行し、ダウンロードします。
scp(セキュアコピー)コマンドを使います。ubuntu_user の部分は仮想マシン(Ubuntu OS)のログインユーザー名、192.168.x.x の部分は仮想マシンのIPアドレスに置き換えてください。scp AgentCert_SyslogServer01.p12 ubuntu_user@192.168.x.x:~/# クライアント証明書(client.crt)の抽出
openssl pkcs12 -in AgentCert_SyslogServer01.p12 -clcerts -nokeys -out client.crt -legacy# 秘密鍵(private.key)の抽出(パスフレーズなし)
openssl pkcs12 -in AgentCert_SyslogServer01.p12 -nocerts -nodes -out private.key -legacy# 配置用ディレクトリの作成
sudo mkdir -p /etc/ssl/private
# 転送した証明書と秘密鍵を移動
sudo mv ~/client.crt /etc/ssl/private/
sudo mv ~/private.key /etc/ssl/private/
# 所有者を root に変更し、パーミッションを 600 (所有者のみ読み書き可能)に設定
sudo chown root:root /etc/ssl/private/client.crt /etc/ssl/private/private.key
sudo chmod 600 /etc/ssl/private/client.crt /etc/ssl/private/private.key💡 セキュリティを高めるためのベストプラクティス
本記事では検証の手軽さを優先し、証明書の配置やエージェントの実行を root 権限で行う手順としていますが、本番環境で運用する際は「CloudWatch Agent用の専用ユーザー」を使用して実行することを推奨します。
本番運用を想定しSDカードの摩耗を防ぐため、SyslogやSNMPの受信ログをメモリ上のRAMディスク(tmpfs)に書き込むよう設定します。
# マウントポイントの作成
sudo mkdir -p /var/log/iot_ramdisk# fstabにtmpfsの設定を追記
echo "tmpfs /var/log/iot_ramdisk tmpfs defaults,size=50m,noatime,mode=0755,uid=syslog,gid=adm 0 0" | sudo tee -a /etc/fstab
# 設定を反映(今すぐマウントを実行)
sudo mount -a
# 正しくマウントされたか確認
df -h | grep iot_ramdiskAWS側のマネジメントコンソールで「Roles Anywhere」と検索し、IAMの機能として表示された「Roles Anywhere」の画面から設定を行います。
💡 重要:ARNをメモしておきましょう
作成した「信頼アンカー」「IAMロール」「プロファイル」それぞれの ARN をメモ帳などにコピーしておいてください。後の手順で使用します。


OneGate-TrustAnchor)を入力し、認証機関(CA)ソースとして「外部証明書バンドル」を選択します。「外部証明書バンドル」のテキストボックスに、先ほど開いたOneGateの「CA証明書(PEM形式)」の中身を貼り付け、「信頼アンカーを作成する」 をクリックします。



{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "rolesanywhere.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession",
"sts:SetSourceIdentity"
],
"Condition": {
"StringEquals": {
"aws:PrincipalTag/x509Subject/CN": "SyslogServer01"
}
}
}
]
}

IoT-CloudWatch-Role)を入力し、設定を確認して 「ロールを作成」 をクリックします。



OneGate-IoT-Profile)を入力し、ロールの欄で「別のロールの追加」をクリックしてから「3-2. IAMロールの作成(CloudWatchへの書き込み権限付与)」で作成したIAMロール(例:IoT-CloudWatch-Role)を選択して 「プロファイルを作成」 をクリックします。

# 仮想マシン(AMD64) 用の署名ヘルパーをダウンロード
wget https://rolesanywhere.amazonaws.com/releases/1.8.0/X86_64/Linux/Amzn2023/aws_signing_helper
# 実行権限を付与し、パスが通った場所に移動
chmod +x aws_signing_helper
sudo mv aws_signing_helper /usr/local/bin/💡 CPUアーキテクチャについて
本記事の検証ではUbuntu(AMD64(x86_64))を想定したURLを記載していますが、お使いのOSがARM64(aarch64)の場合は、URLの X86_64 の部分を Aarch64 に置き換えてダウンロードしてください。
🚨 注意:CloudWatch Agentの仕様とワークアラウンド
現在のAWSの仕様上、オンプレミス環境のCloudWatch Agentは credential_process (動的なクレデンシャル取得機能)に対応しておらず、アクセスキーが見つからないというエラーが発生します。これを回避するため、「定期的に署名ヘルパーを実行し、取得した一時クレデンシャルを静的なファイルに書き込んでAgentに読み込ませる」という方式を採用しています。
# jqのインストール
sudo apt-get update
sudo apt-get install -y jq
# CloudWatch Agentのインストール
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i -E ./amazon-cloudwatch-agent.debsudo nano /usr/local/bin/update-aws-creds.sh#!/bin/bash
# IAM Roles Anywhereから一時クレデンシャルを取得
CRED_JSON=$(/usr/local/bin/aws_signing_helper credential-process \
--certificate /etc/ssl/private/client.crt \
--private-key /etc/ssl/private/private.key \
--trust-anchor-arn <作成した信頼アンカーのARN> \
--profile-arn <作成したプロファイルのARN> \
--role-arn <作成したロールのARN> \
--duration-seconds 900)
# エラーチェック
if [ -z "$CRED_JSON" ]; then
exit 1
fi
# jqコマンドでJSONから各キーを取り出す
ACCESS_KEY=$(echo "$CRED_JSON" | jq -r '.AccessKeyId')
SECRET_KEY=$(echo "$CRED_JSON" | jq -r '.SecretAccessKey')
SESSION_TOKEN=$(echo "$CRED_JSON" | jq -r '.SessionToken')
# 保存先のディレクトリ(.aws)が存在しない場合は作成する
mkdir -p /root/.aws
# /root/.aws/config を新規作成(または上書き)して静的な鍵として保存
cat <<EOF > /root/.aws/config
[profile iot-role]
region = ap-northeast-1
aws_access_key_id = $ACCESS_KEY
aws_secret_access_key = $SECRET_KEY
aws_session_token = $SESSION_TOKEN
EOFsudo chmod +x /usr/local/bin/update-aws-creds.sh
sudo /usr/local/bin/update-aws-creds.sh# 共通設定
sudo nano /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml[credentials]
shared_credential_profile = "profile iot-role"
shared_credential_file = "/root/.aws/config"# ログ収集設定
sudo nano /opt/aws/amazon-cloudwatch-agent/bin/config.json{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/iot_ramdisk/*.log",
"log_group_name": "/iot/raspberry-pi/syslog",
"log_stream_name": "{hostname}",
"timezone": "Local"
}
]
}
}
}
}各パラメーターの役割は以下の通りです。
| 項目 | 値 |
|---|---|
| file_path | CloudWatch Agentが収集対象とするログファイルのパス(場所)です。*(アスタリスク)を使ったワイルドカード指定が可能です。 |
| log_group_name | CloudWatch Logs 上に作成される「ロググループ」の名前です。ロググループは、関連するログをまとめる大きなフォルダのような役割をします。AWSの管理画面(マネジメントコンソール)でログを探すときは、まずこの名前を探すことになります。 |
| log_stream_name | ロググループの中に作成される「ログストリーム」の名前です。 ログストリームは、ロググループ内の小分けされたファイルのようなものです。{hostname} は特別な変数で、Agentが動いているマシンのホスト名(サーバー名やデバイス名)に自動で置き換わります。これにより、どの機器から送られてきたログなのかを一目で区別できます。 |
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m onPremise -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.jsonsudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m onPremise -a statusAgentを起動して数分待つと、AWSへログの送信が開始されます。AWSのマネジメントコンソールから無事にログが届いているか確認してみます。
/iot/raspberry-pi/syslog という名前のロググループが自動で作成されていることを確認し、クリックします。

sudo crontab -e*/10 * * * * /usr/local/bin/update-aws-creds.shlogrotateを使って古いログを自動削除するよう設定します。sudo nano /etc/logrotate.d/iot_ramdisk/var/log/iot_ramdisk/*.log
/var/log/iot_ramdisk/*/*.log
{
daily
maxsize 5M
rotate 3
missingok
notifempty
compress
delaycompress
create 0640 syslog adm
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}💡 CloudWatch Agentとlogrotateの相性
CloudWatch Agentは標準で logrotate に対応しており、ファイルが切り替わっても新しいファイルからログを読み取ります。
ここまでの構成でログの送信自体は完成ですが、本番運用に向けては「証明書の失効確認」が必須となります。
IAM Roles Anywhereで証明書の失効確認を有効にするには、OneGateのCRLファイル(証明書失効リスト)を定期的にAWSへアップロードする必要があります。今回の構成では、この作業をAWS LambdaとAmazon EventBridgeを使って完全自動化します。
現在、AWSのマネジメントコンソール上にはCRLファイルを画面から直接インポートする機能がないため、AWS CloudShellを利用して初期登録を行います。

openssl crl -inform DER -in download.crl -outform PEM -out crl_pem.crl>_)から CloudShell を起動します。右上の「アクション」から「ファイルのアップロード」を選択し、PEM形式のCRLファイル「 crl_pem.crl」 をアップロードします。
<信頼アンカーのARN> は「3-1. 信頼アンカー(Trust Anchor)の作成」でメモしたARNに置き換えてください)aws rolesanywhere import-crl \
--name "OneGate-CRL" \
--crl-data fileb://crl_pem.crl \
--trust-anchor-arn "<信頼アンカーのARN>" \
--enabled"crlId": "0123456789abcdef..." の値をメモしておきます。AWS Lambdaが「Roles AnywhereのCRLを更新する」ためのポリシーと、「実行ログを保存する」ためのロールを作成します。

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rolesanywhere:UpdateCrl"
],
"Resource": "*"
}
]
}
UpdateRolesAnywhereCRLPolicy)を入力し、右下の 「ポリシーの作成」 をクリックします。





Lambda-UpdateCRL-Role)を入力し、設定を確認してから画面右下の 「ロールを作成」 をクリックします。



UpdateRolesAnywhereCRL)Lambda-UpdateCRL-Role)を選択し「保存」をクリック


| キー | 値 |
|---|---|
CRL_URL | 「7-1. OneGateのCRL URLの確認と初期インポート」でメモしたOneGateのCRL配布ポイントURL ※PEM形式でのダウンロードが可能な場合は、末尾に「?type=pem」をつけたURL |
CRL_ID | 「7-1. OneGateのCRL URLの確認と初期インポート」でメモしたAWS上のCRL ID |




lambda_function.py のサンプルコードをすべて消去して、以下のPythonコードを貼り付けます。
import urllib.request
import boto3
import os
def lambda_handler(event, context):
crl_url = os.environ['CRL_URL']
crl_id = os.environ['CRL_ID']
# OneGateから最新のCRLをダウンロード
try:
req = urllib.request.Request(crl_url)
with urllib.request.urlopen(req) as response:
crl_data = response.read()
except Exception as e:
print(f"CRLのダウンロードに失敗しました: {e}")
raise e
# IAM Roles AnywhereのCRLを更新
try:
client = boto3.client('rolesanywhere')
response = client.update_crl(
crlId=crl_id,
crlData=crl_data
)
print("CRLの更新に成功しました。")
except Exception as e:
print(f"CRLの更新に失敗しました: {e}")
raise e
return {
'statusCode': 200,
'body': 'CRL updated successfully'
}💡 補足:CloudWatchでのログの見方について
コード内に記述されている print の出力内容は、実行時にCloudWatch Logsへ自動的に保存されます。AWSマネジメントコンソールの「CloudWatch」>「ロググループ」から /aws/lambda/(関数名) のロググループを開くことで、処理の正常終了やエラー発生時の詳細なメッセージを確認できます。

作成したLambda関数を高頻度で自動実行し、OneGateで証明書を失効させた際にいち早くAWS側のCRLを最新化するため、「Amazon EventBridge Scheduler」を使ってスケジュールを設定します。

Daily-CRL-Update-Schedule)を入力します。


UpdateRolesAnywhereCRL)を選択し、「次へ」をクリックします。



これで、証明書失効運用も自動化することができました。
ここまでの設定により、OneGateで証明書を失効させると、最大で「EventBridgeの実行間隔(15分)+クレデンシャルの有効期限(15分)」という短い時間でアクセスが自動的に遮断されるようになります。
しかし、端末の紛失などの緊急事態が発生した場合には、CRLの更新を待たずにAWS側でアクセスを即時遮断することも可能です。
その場合は、「3-2. IAMロールの作成(CloudWatchへの書き込み権限付与)」で作成したIAMロールのカスタム信頼ポリシーに「特定のデバイス(証明書のCN)からのアクセスをすべて拒否する」ルールを追加します。
対象のロールに以下のインラインポリシーを追加することで、一時クレデンシャルが有効であっても即座にAWSへのアクセスが弾かれます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/x509Subject/CN": "SyslogServer01"
}
}
}
]
}※ "SyslogServer01" の部分は、失効させたい対象証明書のCNに置き換えてください。
緊急時にはAWSマネジメントコンソールから直接特定のデバイス(証明書のCN)からのアクセスをすべて拒否する運用ルールにすることで、より強固なセキュリティを担保できます。
本記事では、AWSのIAM Roles AnywhereとSoliton OneGateを組み合わせ、エッジデバイスからAWS環境へセキュアにアクセスするための検証をご紹介しました。デバイスに長期クレデンシャル(アクセスキー)を直接持たせないことで、情報漏洩リスクを根本から排除した安全なログ転送が実現できます。
また、今回は仮想マシン(Ubuntu OS)を用いた検証として、ログをRAMディスク(tmpfs)へ書き込むことで本番運用を想定したSDカードの寿命問題をクリアしつつ、CloudWatch Agentによるストリーミング送信で、ニアリアルタイムな監視とデータ保護を両立させました。
さらに、実運用において課題となりやすい「証明書の失効(CRL)運用」についても、AWS LambdaとAmazon EventBridgeを連携させて完全自動化しました。クレデンシャルの有効期間を最小化することで失効からアクセス遮断までのタイムラグを極小化しつつ、緊急時用の明示的なDeny運用も備えることで、高いセキュリティ水準を保ちながら、管理者の運用負荷を最小限に抑える仕組みが構築できたかと思います。
IoT・エッジコンピューティング環境におけるセキュリティ強化の一環として、「AWS × Soliton OneGate」の組み合わせをぜひご検討いただければ幸いです。