Creating AWS resources for GitHub audit log streaming with CloudFormation
Tags: aws, cloudformation, github, audit
Published: 2023-03-17 13:11:24

## Introduction

GitHub Enterprise Cloud audit logs support log streaming to various cloud providers.

https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/streaming-the-audit-log-for-your-enterprise

Streaming audit logs to Amazon S3 can be done via OpenID Connect. This requires the creation of an OIDC Provider and IAM role on the AWS side and an S3 bucket for log storage.

Please refer to the above document for detailed instructions.

It is not something that is created many times, but I have created a CloudFormation template and hope it will be helpful for those who want to create a new one quickly and easily.

## Resources to be created

| Logical ID | Type | Description |
| --- | --- | --- |
| AuditLogBucket | AWS::S3::Bucket | S3 bucket for audit log |
| AuditLogbucketPolicy | AWS::S3::BucketPolicy | S3 bucket policy for audit log |
| AccessLogBucket | AWS::S3::Bucket | S3 bucket for server access log |
| AccessLogBucketPolicy | AWS::S3::BucketPolicy | S3 bucket policy for server access log |
| AuditLogEncryptionKey | AWS::KMS::Key | Customer Managed Key for audit log encryption |
| AuditLogEncryptionKeyAlias | AWS::KMS::Alias | Customer Managed Key alias |
| AuditLogStremingPolicy | AWS::IAM::ManagedPolicy | IAM policy for audit log streaming |
| AuditLogStreamingRole | AWS::IAM::Role | IAM Role for audit log streaming |
| GithubAuditLogOIDCProvider | AWS::IAM::OIDCProvider | GitHub OIDC provider |

## CloudFormation template

Github repository is here

{% embed https://github.com/hayao-k/CFn-github-audit-log-streaming %}

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create AWS resources required for GitHub Enterprise Cloud audit log streaming

Parameters:
  RetainDays:
    Description: Number of days to keep audit log.
    Type: String
    Default: 365
  EnterpriseName:
    Description: Your GitHub Enterprise Name.
    Type: String
    Default: EXAPMLECORP
  AccessLogPrefix:
    Description: Server access log-prefix of audit log bucket.
    Type: String
    Default: logs/

Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      - Label: 
          default: GitHub Configuration
        Parameters: 
          - EnterpriseName
      - Label: 
          default: Audit Log Configuration
        Parameters: 
          - RetainDays
          - AccessLogPrefix

Resources:
  # Customer Managed Key for audit log encryption
  AuditLogEncryptionKey:
    Type: AWS::KMS::Key
    Properties: 
      Description: Customer Managed Key for audit log encryption
      Enabled: true
      EnableKeyRotation: True
      KeyPolicy:
        Version: '2012-10-17'
        Id: key-default-1
        Statement:
        - Sid: Allow administration of the key
          Effect: Allow
          Principal:
            AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
          Action:
          - kms:Create*
          - kms:Describe*
          - kms:Enable*
          - kms:List*
          - kms:Put*
          - kms:Update*
          - kms:Revoke*
          - kms:Disable*
          - kms:Get*
          - kms:Delete*
          - kms:ScheduleKeyDeletion
          - kms:CancelKeyDeletion
          Resource: '*'
        - Sid: Allow local use of the key
          Effect: Allow
          Principal:
            AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
          Action:
          - kms:Encrypt
          - kms:Decrypt
          - kms:ReEncrypt*
          - kms:GenerateDataKey*
          - kms:DescribeKey
          Resource: '*'

  # Customer Managed Key ALias
  AuditLogEncryptionKeyAlias:
    Type: AWS::KMS::Alias
    Properties: 
      AliasName: !Sub alias/${AWS::StackName}-key
      TargetKeyId: !Ref AuditLogEncryptionKey
  
  # S3 bucket for audit log
  AuditLogBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault: 
              SSEAlgorithm: aws:kms
              KMSMasterKeyID: !GetAtt AuditLogEncryptionKey.Arn
            BucketKeyEnabled: true    
      LifecycleConfiguration:
        Rules:
          - Id: Retain
            Status: Enabled
            ExpirationInDays: !Ref RetainDays
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      LoggingConfiguration:
        DestinationBucketName: !Ref AccessLogBucket
        LogFilePrefix: !Ref AccessLogPrefix
      VersioningConfiguration:
        Status: Enabled
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced

  # S3 bucket policy for audit log
  AudtiLogBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AuditLogBucket
      PolicyDocument:
        Statement:
        - Effect: Deny
          Principal: '*'
          Action: 's3:*'
          Resource: 
            - !Sub ${AuditLogBucket.Arn}/*
            - !GetAtt AuditLogBucket.Arn
          Condition:
            Bool: 
              aws:SecureTransport: false
  
  # S3 bucket for server access log
  AccessLogBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault: 
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - Id: Retain
            Status: Enabled
            ExpirationInDays: !Ref RetainDays
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced

  # S3 bucket policy for server access log
  AccessLogBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AccessLogBucket
      PolicyDocument:
        Statement:
          - Effect: Deny
            Principal: '*'
            Action: 's3:*'
            Resource: 
              - !Sub ${AccessLogBucket.Arn}/*
              - !GetAtt AccessLogBucket.Arn
            Condition:
              Bool: 
                aws:SecureTransport: false
          - Effect: Allow
            Principal:
              Service: logging.s3.amazonaws.com
            Action: s3:PutObject
            Resource:
              - !Sub ${AccessLogBucket.Arn}/${AccessLogPrefix}*
            Condition:
              ArnLike:
                aws:SourceArn: !GetAtt AuditLogBucket.Arn
              StringEquals: 
                aws:SourceAccount: !Ref AWS::AccountId

  # IAM policy for audit log streaming role
  AuditLogStremingPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Policy for GitHub Audit Log Streaming
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - s3:PutObject
            Resource:
              - !Sub ${AuditLogBucket.Arn}/*

  # IAM Role for audit log streaming role
  AuditLogStreamingRole:
    Type: AWS::IAM::Role
    Properties:
      ManagedPolicyArns: 
        - !Ref AuditLogStremingPolicy
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !Ref GithubAuditLogOIDCProvider
            Condition:
              StringEquals:
                oidc-configuration.audit-log.githubusercontent.com:sub: !Sub https://github.com/${EnterpriseName}
                oidc-configuration.audit-log.githubusercontent.com:aud: sts.amazonaws.com

  GithubAuditLogOIDCProvider:
    Type: AWS::IAM::OIDCProvider
    Properties:
      Url: https://oidc-configuration.audit-log.githubusercontent.com
      ClientIdList: 
        - sts.amazonaws.com
      ThumbprintList:
        - 7e6db7b7584d8cf2003e0931e6cfc41a3a62d3df

Outputs:
  IAMRole:
    Description: IAM role for audit log streaming role
    Value: !GetAtt AuditLogStreamingRole.Arn
  AuditLogBucket:
    Description: S3 bucket for audit log
    Value: !Ref AuditLogBucket
```

## Deploy

3 parameters are required.

* GitHub Enterprise Name (`EnterpriseName`)
    
* Number of days to keep audit log (`RetainDays`)
    
* Server access log-prefix of audit log bucket (`AccessLogPrefix`)
    

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u00pamlwiiixkrdcumrp.png)

After deploying the stack, set the output S3 bucket name and IAM Role ARN to GitHub Enterprise Cloud.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gb3svk1fppbi2h7ld81t.png)

If the endpoint connection check is successful, save the configuration.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nclnytxz2blk86eqpe4t.png)

You can see the audit log in the AuditLogBucket!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikms98l5e7chyg46eewi.png)


I hope this will be of help to someone else.