
GitHub Enterprise Cloudの監査ログをS3にストリーミングして永続化しAthenaで検索してみた
GitHub Enterprise Cloudの監査ログ(Audit Log)は180日まで保持され、Gitイベントに関しては7日まで保持されます。
監査やトラブルシュートのために監査ログをAmazon S3に保存して永続化し、Amazon AthenaでSQL検索できるようにする方法を紹介します。

一度Amazon AthenaでS3監査ログのテーブル定義をしてしまえば、AWSにアクセスできるユーザーだれもが、SQLで監査ログを検索できるようになります。また、Athenaはフルマネージドのサーバーレスサービスのため、S3ストレージ以外に固定費も発生しません。
構築方法
1. AWS 側のデータ連携設定
データ連携のために、AWS側には以下の3リソースを作成します
- ログ・ファイル保存先のS3バケット
- GitHubとAWS間のOpenID Connect認証(AWS Identity Provider)
- GitHubがS3に書き込むためにassumeするIAMロール
以下の CloudFormationテンプレートを実行すると、これらリソースが作成されます。
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for GitHub Enterprise Audit Log streaming to S3 with OIDC authentication'
Parameters:
  BucketName:
    Type: String
    Description: Name of the S3 bucket to store GitHub Enterprise audit logs
    Default: github-enterprise-audit-logs
  GitHubAccount:
    Type: String
    Default: https://github.com/YOUR-ENTERPRISE-ACCOUNT
  LogRetentionDays:
    Type: Number
    Description: Number of days to retain logs
    Default: 365
    MinValue: 1
    MaxValue: 3653
Resources:
  # OIDC プロバイダーの作成
  GitHubAuditLogOIDCProvider:
    Type: AWS::IAM::OIDCProvider
    Properties:
      Url: https://oidc-configuration.audit-log.githubusercontent.com
      ClientIdList: 
        - sts.amazonaws.com
      ThumbprintList:
        - 6938fd4d98bab03faadb97b34396831e3780aea1
  # S3 バケットの作成
  AuditLogBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      VersioningConfiguration:
        Status: Suspended
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
            BucketKeyEnabled: true
      LifecycleConfiguration:
        Rules:
          - Id: ExpireOldLogs
            Status: Enabled
            ExpirationInDays: !Ref LogRetentionDays
  # GitHub OIDC 用の IAM ロール
  GitHubAuditLogRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: GitHubEnterpriseAuditLogRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Federated: !GetAtt GitHubAuditLogOIDCProvider.Arn
            Action: 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                "oidc-configuration.audit-log.githubusercontent.com:aud": "sts.amazonaws.com"
                "oidc-configuration.audit-log.githubusercontent.com:sub": !Ref GitHubAccount
      Policies:
        - PolicyName: GitHubAuditLogS3WritePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: VisualEditor0
                Effect: Allow
                Action:
                  - 's3:PutObject'
                Resource: !Sub 'arn:aws:s3:::${AuditLogBucket}/*'
Outputs:
  AuditLogBucketName:
    Description: Name of the S3 bucket storing GitHub Enterprise audit logs
    Value: !Ref AuditLogBucket
  AuditLogBucketArn:
    Description: ARN of the S3 bucket storing GitHub Enterprise audit logs
    Value: !GetAtt AuditLogBucket.Arn
  GitHubOIDCRoleArn:
    Description: ARN of the IAM role for GitHub OIDC authentication
    Value: !GetAtt GitHubAuditLogRole.Arn
  OIDCProviderArn:
    Description: ARN of the GitHub Audit Log OIDC provider
    Value: !GetAtt GitHubAuditLogOIDCProvider.Arn
2. GitHub 側のデータ連携設定
GitHub のエンタープライズアカウントの Settings → Log streaming から Amazon S3 連携を指定します。

- Authentication : OpenID Connect
- Bucket : 先ほどのS3バケット
- ARN Role : 先ほど作成したIAMロールのARN
特に、GitHubとAWS間はOpenID Connectでの認証し、永続的なアクセスキーは利用しません。
3. S3監査ログとAmazon Athenaの連携
本セクションでは、サイボウズ様の次の記事を大いに参考にしています。
GitHub の 監査ログを Amazon Athena でクエリできるようにした
正しく監査ログがストリーム連携されると、S3バケットのルートに _check ファイルが作成され、 yyyy/MM/dd/HH の階層で gzip ファイルが作成されます。
$ tree .
.
├── 2025
│   ├── 02
│   ├── 02
│   │   ├── 27
│   │   │   └── 23
│   │   │       ├── 26
│   │   │       │   ├── aaa-bbb-ccc-ddd-eee.json.log.gz
│   │   │       │   └── aaa-bbb-ccc-ddd-eee.json.log.gz
...
└── _check
スキャン範囲を限定することで検索時間、及び、利用費を削減できるように、'yyyy/MM/dd/HH' のディレクトリ階層でパーティション化して、テーブル作成します。
様々な操作に対するログが JSON 形式でストリーミングされるため、次のログイベントのドキュメントのように、フィールドも様々です
Audit log events for your enterprise - GitHub Enterprise Cloud Docs
そのため、以下の2種類のAthena用テーブルを定義することをおすすめします
- ログ横断型汎用テーブル
- 用途特化型テーブル
どちらも射影(projection)でパーティション化しています。
ログ横断型汎用テーブル
汎用型テーブルでは、レコード全体をJSON文字列(org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe)として1カラム(json_objects)で管理します。
任意のJSONに対応できる一方で、クエリー時に json_extract_scalar 等を使ったJSON文字列のパースが必要です。
CREATE EXTERNAL TABLE `default`.`github_audit_logs` (
  `json_objects` string
)
PARTITIONED BY (
  `date` string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
LOCATION 's3://YOUR-BUCKET-NAME/'
TBLPROPERTIES (
  'projection.enabled' = 'true',
  'projection.date.type' = 'date',
  'projection.date.format' = 'yyyy/MM/dd/HH',
  'projection.date.range' = '2025/01/01/01,NOW',
  'projection.date.interval' = '1',
  'projection.date.interval.unit' = 'HOURS',
  'storage.location.template' = 's3://YOUR-BUCKET-NAME/${date}/'
);
用途特化型テーブル(ワークフローの例)
特化型テーブルでは、検索対象のログ(操作)に対応するJSONのキーをテーブルのカラムとして構造化して管理します。実際のデータ型は、実データを参考にしましょう。
テーブル定義時に一手間かける一方で、SQLで素直にクエリーできます。
CREATE EXTERNAL TABLE github_workflow_logs (
	`@timestamp` BIGINT,
	`_document_id` STRING,
	`action` STRING,
	`actor` STRING,
	`actor_id` BIGINT,
	`actor_is_bot` BOOLEAN,
	`business` STRING,
	`business_id` BIGINT,
	`created_at` BIGINT,
	`event` STRING,
	`hashed_token` STRING,
	`head_branch` STRING,
	`head_sha` STRING,
	`name` STRING,
	`operation_type` STRING,
	`org` STRING,
	`org_id` BIGINT,
	`programmatic_access_type` STRING,
	`public_repo` BOOLEAN,
	`repo` STRING,
	`repo_id` BIGINT,
	`request_access_security_header` STRING,
	`run_number` INT,
	`started_at` STRING,
	`token_id` BIGINT,
	`trigger_id` BIGINT,
	`user_agent` STRING,
	`workflow_id` BIGINT,
	`workflow_run_id` BIGINT,
	`completed_at` STRING,
	`conclusion` STRING,
	`run_attempt` INT,
	`topic` STRING
)
PARTITIONED BY (
  `date` string
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
	'ignore.malformed.json' = 'FALSE',
	'dots.in.keys' = 'FALSE',
	'case.insensitive' = 'TRUE',
	'mapping' = 'TRUE'
)
LOCATION 's3://YOUR-BUCKET-NAME/'
TBLPROPERTIES (
	'projection.enabled' = 'true',
	'projection.date.type' = 'date',
	'projection.date.format' = 'yyyy/MM/dd/HH',
	'projection.date.range' = '2025/01/01/01,NOW',
	'projection.date.interval' = '1',
	'projection.date.interval.unit' = 'HOURS',
	'storage.location.template' = 's3://YOUR-BUCKET-NAME//${date}/',
	'classification' = 'json'
);
検索
以降では
- GitHub のSettings → Audit log → Events 検索画面
- Athena 汎用テーブル
- Athena 特化型テーブル
から具体的にログを検索してみます。
Athenaの場合、スキャン範囲を限定するために、明示的にフルスキャンするケースを除いて日付を指定しましょう。
action をざっと把握したい
操作(action)をトリガーにイベントログが生成されます。
Athena 汎用テーブル
どのような操作が存在するか、ざっと把握するためには、Athenaの汎用テーブルに対して、以下のクエリでaction x 件数の一覧を抽出します。
select json_extract_scalar(json_objects, '$.action') as action,
	count(*) as cnt
from default.github_audit_logs
where date between '2025/03/01' AND '2025/04/01'
group by json_extract_scalar(json_objects, '$.action')
order by cnt desc
リポジトリの削除ログを調査
リポジトリを削除すると、repo.destroy という action で記録されます。
GitHub
GitHubコンソールで、以下の条件で検索しましょう。
action:repo.destroy repo:ORG_NAME/REPO_NAME

Athena 汎用テーブル
select *
from default.github_audit_logs
where date between '2025/03/01' AND '2025/04/01'
	and json_extract_scalar(json_objects, '$.action') = 'repo.destroy'
	and json_extract_scalar(json_objects, '$.repo') = 'ORG_NAME/REPO_NAME'
GitHub Actionsの実行数を知りたい
GitHub Actionsのワークフローが実行完了すると、 workflows.completed_workflow_run というアクションが記録されます。
汎用型テーブルに対して json_extract_scalar を用いて複雑なクエリーを組み立てると、汎用的にデータ探索できる一方で、特化型テーブルはクエリーがシンプルになります。
Athena 汎用テーブル
select json_extract_scalar(json_objects, '$.repo') as repo,
	count(*) as cnt
from default.github_audit_logs
where date between '2025/03/01' AND '2025/03/05'
	and json_extract_scalar(json_objects, '$.action') = 'workflows.completed_workflow_run'
group by json_extract_scalar(json_objects, '$.repo')
order by cnt desc
Athena 特化テーブル
select repo,
	count(*) as cnt
from github_workflow_logs
where action = 'workflows.completed_workflow_run'
	and date between '2025/03/01' AND '2025/03/05'
group by repo
order by cnt desc
最後に
GitHub Enterprise Cloudで監査ログをAmazon S3にストリーミングし、Amazon Athenaで検索する方法を紹介しました。
- 監査ログの永続化を設定
- イベントログをJSON文字列としてAthenaテーブル定義し、汎用的に探索
- 頻出する運用オペレーションに対応するイベント特化型のAthenaテーブルを定義
というような流れで段階的に運用を強化するとよいと思います。











