Header menu logo FsCDK

CloudTrail AWS CloudTrail - Audit Logging

AWS CloudTrail provides governance, compliance, and audit capabilities for your AWS account. CloudTrail logs, continuously monitors, and retains account activity related to actions across your AWS infrastructure.

Security Best Practice: Per O'Reilly "Security as Code" - "Log all API calls with CloudTrail. This is non-negotiable for security monitoring."

Quick Start

#r "../src/bin/Release/net8.0/publish/Amazon.JSII.Runtime.dll"
#r "../src/bin/Release/net8.0/publish/Constructs.dll"
#r "../src/bin/Release/net8.0/publish/Amazon.CDK.Lib.dll"
#r "../src/bin/Release/net8.0/publish/FsCDK.dll"

open FsCDK
open Amazon.CDK
open Amazon.CDK.AWS.CloudTrail
open Amazon.CDK.AWS.Logs

Basic CloudTrail (Secure Defaults)

Create a CloudTrail with all security best practices enabled by default.

stack "BasicCloudTrail" {
    cloudTrail "SecurityAudit" {
        // All secure defaults are automatically applied:
        // - Multi-region trail (captures all regions)
        // - Global service events included (IAM, STS, CloudFront)
        // - Log file validation enabled (integrity checking)
        // - CloudWatch Logs integration enabled
        // - S3 bucket auto-created with encryption
        ()
    }
}

Production CloudTrail

Production-ready configuration with custom retention and monitoring.

stack "ProductionCloudTrail" {
    cloudTrail "ProductionAudit" {
        // Multi-region and global events (defaults)
        isMultiRegionTrail true
        includeGlobalServiceEvents true

        // Log integrity validation (detect tampering)
        enableFileValidation true

        // CloudWatch Logs for real-time monitoring
        sendToCloudWatchLogs true
        cloudWatchLogsRetention RetentionDays.THREE_MONTHS

        // Log all management events (default)
        managementEvents ReadWriteType.ALL
    }
}

Organization Trail

For AWS Organizations, create an organization-wide trail that logs events for all accounts.

stack "OrganizationCloudTrail" {
    cloudTrail "OrgSecurityAudit" {
        isOrganizationTrail true
        isMultiRegionTrail true
        includeGlobalServiceEvents true
        enableFileValidation true
        cloudWatchLogsRetention RetentionDays.SIX_MONTHS
    }
}

Custom S3 Bucket

Use a custom S3 bucket for CloudTrail logs (with lifecycle rules for cost optimization).

stack "CustomBucketCloudTrail" {
    // Create custom S3 bucket with lifecycle rules
    let! trailBucket =
        s3Bucket "CloudTrailLogs" {
            versioned true // Enable versioning for audit trail integrity

            lifecycleRule {
                transitions
                    [ transition {
                          storageClass Amazon.CDK.AWS.S3.StorageClass.GLACIER
                          transitionAfter (Duration.Days(90.0))
                      }
                      transition {
                          storageClass Amazon.CDK.AWS.S3.StorageClass.DEEP_ARCHIVE
                          transitionAfter (Duration.Days(365.0))
                      } ]
            }
        }

    cloudTrail "CustomBucketAudit" {
        s3Bucket trailBucket
        isMultiRegionTrail true
        includeGlobalServiceEvents true
    }
}

Compliance Trail (Long Retention)

For compliance requirements (HIPAA, PCI-DSS, SOC2), use longer retention periods.

stack "ComplianceCloudTrail" {
    cloudTrail "ComplianceAudit" {
        isMultiRegionTrail true
        includeGlobalServiceEvents true
        enableFileValidation true

        // Extended retention for compliance
        cloudWatchLogsRetention RetentionDays.ONE_YEAR

        // All management events
        managementEvents ReadWriteType.ALL
    }
}

Read-Only Trail (Cost Optimization)

For read-only monitoring, log only read operations (reduces volume and cost).

stack "ReadOnlyCloudTrail" {
    cloudTrail "ReadOnlyAudit" {
        isMultiRegionTrail true
        includeGlobalServiceEvents true

        // Only log read operations
        managementEvents ReadWriteType.READ_ONLY

        // Shorter retention for cost savings
        cloudWatchLogsRetention RetentionDays.ONE_WEEK
    }
}

Write-Only Trail (Security Focus)

For security monitoring, focus on write operations (changes to infrastructure).

stack "SecurityFocusCloudTrail" {
    cloudTrail "SecurityMonitoring" {
        isMultiRegionTrail true
        includeGlobalServiceEvents true
        enableFileValidation true

        // Only log write/delete operations
        managementEvents ReadWriteType.WRITE_ONLY

        cloudWatchLogsRetention RetentionDays.ONE_MONTH
    }
}

Single Region Trail (Cost Optimization)

For single-region applications, save costs with a single-region trail.

stack "SingleRegionCloudTrail" {
    cloudTrail "RegionalAudit" {
        // Single region only (cost optimization)
        isMultiRegionTrail false

        // Still include global service events
        includeGlobalServiceEvents true
        enableFileValidation true

        cloudWatchLogsRetention RetentionDays.TWO_WEEKS
    }
}

Disabling CloudWatch Logs (S3 Only)

For cost-conscious deployments, disable CloudWatch Logs and use S3 only.

stack "S3OnlyCloudTrail" {
    cloudTrail "S3OnlyAudit" {
        isMultiRegionTrail true
        includeGlobalServiceEvents true
        enableFileValidation true

        // Disable CloudWatch Logs (S3 only)
        sendToCloudWatchLogs false
    }
}

Best Practices

Security

Compliance

CloudTrail is required for most compliance frameworks:

Cost Optimization

Cost Reduction Strategies: 1. Use read-only or write-only trails if appropriate 2. Disable CloudWatch Logs for low-priority environments 3. Use S3 lifecycle policies to transition to Glacier 4. Use single-region trails for region-specific applications 5. Filter out high-volume, low-value events

Monitoring & Alerting

Set up CloudWatch alarms for:

Incident Investigation

CloudTrail is essential for security incident response:

  1. Who - Identity of the caller (IAM user, role, federated user)
  2. What - The action that was attempted
  3. When - Date and time of the request
  4. Where - Source IP address and region
  5. Why - Event outcome (success or failure)

Data Events (Advanced)

For S3 and Lambda, you can enable data event logging (additional cost):

// Note: Data events require additional configuration
// and are not included in the free tier

Default Settings

FsCDK CloudTrail applies these security best practices by default:

What is Logged?

Management Events (Always Logged)

Global Service Events

NOT Logged by Default

Log Format Example

{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDAI...",
    "arn": "arn:aws:iam::123456789012:user/alice",
    "accountId": "123456789012",
    "userName": "alice"
  },
  "eventTime": "2025-11-08T10:30:00Z",
  "eventSource": "ec2.amazonaws.com",
  "eventName": "RunInstances",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "203.0.113.1",
  "requestParameters": {
    "instanceType": "t3.micro",
    "imageId": "ami-12345678"
  },
  "responseElements": {
    "instancesSet": [...]
  }
}

Integration with Other Services

CloudWatch Logs Insights

Query CloudTrail logs using CloudWatch Logs Insights:

fields @timestamp, userIdentity.userName, eventName, sourceIPAddress
| filter eventName = "RunInstances"
| sort @timestamp desc
| limit 20

AWS Config

CloudTrail + AWS Config = Complete compliance solution: - CloudTrail - Who did what, when - AWS Config - Current and historical configuration state

Amazon Athena

Query CloudTrail logs in S3 using SQL:

SELECT useridentity.username, eventname, count(*) as count
FROM cloudtrail_logs
WHERE eventtime > '2025-11-01'
GROUP BY useridentity.username, eventname
ORDER BY count DESC

AWS Security Hub

CloudTrail findings are automatically sent to Security Hub for centralized security management.

Resources

Summary

CloudTrail is non-negotiable for: - ✅ Security incident investigation - ✅ Compliance requirements - ✅ Operational troubleshooting - ✅ Detecting unauthorized access - ✅ Audit trails for regulated industries

FsCDK makes it easy with secure-by-default settings. Simply add cloudTrail "name" { } to your stack!

namespace FsCDK
namespace Amazon
namespace Amazon.CDK
namespace Amazon.CDK.AWS
namespace Amazon.CDK.AWS.CloudTrail
namespace Amazon.CDK.AWS.Logs
val stack: name: string -> StackBuilder
<summary>Creates an AWS CDK Stack construct.</summary>
<param name="name">The name of the stack.</param>
<code lang="fsharp"> stack "MyStack" { lambda myFunction bucket myBucket } </code>
val cloudTrail: name: string -> CloudTrailBuilder
<summary> Creates a CloudTrail configuration with AWS security best practices. CloudTrail logs all AWS API calls for security monitoring and compliance. </summary>
<param name="name">The trail name.</param>
<code lang="fsharp"> cloudTrail "SecurityAuditTrail" { isMultiRegionTrail true includeGlobalServiceEvents true enableFileValidation true } </code>
custom operation: isMultiRegionTrail (bool) Calls CloudTrailBuilder.IsMultiRegionTrail
<summary> Sets whether this is a multi-region trail. **Security Best Practice:** Multi-region trails are enabled by default to capture events from all AWS regions. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="enabled">Whether to enable multi-region (default: true).</param>
<code lang="fsharp"> cloudTrail "MyTrail" { isMultiRegionTrail false // Only if single-region monitoring is acceptable } </code>
custom operation: includeGlobalServiceEvents (bool) Calls CloudTrailBuilder.IncludeGlobalServiceEvents
<summary> Sets whether to include global service events (IAM, STS, CloudFront, etc.). **Security Best Practice:** Enabled by default to capture critical security events. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="enabled">Whether to include global events (default: true).</param>
custom operation: enableFileValidation (bool) Calls CloudTrailBuilder.EnableFileValidation
<summary> Sets whether to enable log file validation. **Security Best Practice:** Enabled by default for log integrity verification. This allows you to detect if log files were tampered with after delivery. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="enabled">Whether to enable validation (default: true).</param>
custom operation: sendToCloudWatchLogs (bool) Calls CloudTrailBuilder.SendToCloudWatchLogs
<summary> Sets whether to send trail logs to CloudWatch Logs. **Note:** CloudWatch Logs integration enables real-time monitoring but adds cost. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="enabled">Whether to send to CloudWatch (default: true).</param>
custom operation: cloudWatchLogsRetention (RetentionDays) Calls CloudTrailBuilder.CloudWatchLogsRetention
<summary> Sets the CloudWatch Logs retention period for the trail. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="retention">The retention period (default: ONE_MONTH).</param>
<code lang="fsharp"> cloudTrail "MyTrail" { cloudWatchLogsRetention RetentionDays.THREE_MONTHS } </code>
[<Struct>] type RetentionDays = | ONE_DAY = 0 | THREE_DAYS = 1 | FIVE_DAYS = 2 | ONE_WEEK = 3 | TWO_WEEKS = 4 | ONE_MONTH = 5 | TWO_MONTHS = 6 | THREE_MONTHS = 7 | FOUR_MONTHS = 8 | FIVE_MONTHS = 9 ...
field RetentionDays.THREE_MONTHS: RetentionDays = 7
custom operation: managementEvents (ReadWriteType) Calls CloudTrailBuilder.ManagementEvents
<summary> Sets the management event logging type. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="readWriteType">The type of events to log (default: ReadWriteType.ALL).</param>
<code lang="fsharp"> cloudTrail "MyTrail" { managementEvents ReadWriteType.WRITE_ONLY // Only log write events } </code>
[<Struct>] type ReadWriteType = | READ_ONLY = 0 | WRITE_ONLY = 1 | ALL = 2 | NONE = 3
field ReadWriteType.ALL: ReadWriteType = 2
custom operation: isOrganizationTrail (bool) Calls CloudTrailBuilder.IsOrganizationTrail
<summary> Sets whether this is an organization trail (requires AWS Organizations). Organization trails log events for all accounts in the organization. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="enabled">Whether this is an organization trail.</param>
<code lang="fsharp"> cloudTrail "OrgTrail" { isOrganizationTrail true } </code>
field RetentionDays.SIX_MONTHS: RetentionDays = 10
val trailBucket: AWS.S3.IBucket
val s3Bucket: name: string -> BucketBuilder
<summary> Creates a new S3 bucket builder with secure defaults. Example: s3Bucket "my-bucket" { versioned true } Alias for bucket builder. </summary>
custom operation: versioned (bool) Calls BucketBuilder.Versioned
<summary> Enables or disables versioning for the S3 bucket. **Security Best Practice:** Enable versioning for: - Critical data that requires audit trails - Data subject to compliance requirements (HIPAA, SOC2, etc.) - Production buckets storing business data **Cost Consideration:** Versioning stores all versions of objects, increasing storage costs. Only disable for: - Temporary/cache buckets - Build artifacts with short lifecycle - Development/testing buckets **Default:** false (opt-in for cost optimization) </summary>
<param name="value">True to enable versioning, false to disable.</param>
<param name="config">The current bucket configuration.</param>
<code lang="fsharp"> bucket "production-data" { versioned true // Enable for production } bucket "cache-bucket" { versioned false // Disable for temp data } </code>
val lifecycleRule: LifecycleRuleBuilder
custom operation: transitions (AWS.S3.ITransition list) Calls LifecycleRuleBuilder.Transitions
val transition: TransitionBuilder
<summary> Creates an S3 lifecycle transition rule for moving objects to different storage classes. Transitions reduce storage costs by automatically moving objects to cheaper storage tiers. </summary>
<code lang="fsharp"> transition { storageClass StorageClass.GLACIER transitionAfter (Duration.Days(90.0)) } </code>
custom operation: storageClass (AWS.S3.StorageClass) Calls TransitionBuilder.StorageClass
<summary> Sets the storage class to transition to. Common classes: GLACIER (low-cost archival), DEEP_ARCHIVE (lowest cost, rare access), INTELLIGENT_TIERING (automatic cost optimization), GLACIER_IR (instant retrieval). </summary>
<param name="storageClass">The target storage class.</param>
namespace Amazon.CDK.AWS.S3
Multiple items
type StorageClass = inherit DeputyBase new: value: string -> unit member ToString: unit -> string member Value: string static member DEEP_ARCHIVE: StorageClass static member GLACIER: StorageClass static member GLACIER_INSTANT_RETRIEVAL: StorageClass static member INFREQUENT_ACCESS: StorageClass static member INTELLIGENT_TIERING: StorageClass static member ONE_ZONE_INFREQUENT_ACCESS: StorageClass

--------------------
AWS.S3.StorageClass(value: string) : AWS.S3.StorageClass
property AWS.S3.StorageClass.GLACIER: AWS.S3.StorageClass with get
custom operation: transitionAfter (Duration) Calls TransitionBuilder.TransitionAfter
<summary> Sets when objects transition after creation (use Duration.Days()). Example: transitionAfter (Duration.Days(90.0)) moves objects after 90 days. </summary>
<param name="duration">Time after object creation to transition.</param>
type Duration = inherit DeputyBase member FormatTokenToNumber: unit -> string member IsUnresolved: unit -> bool member Minus: rhs: Duration -> Duration member Plus: rhs: Duration -> Duration member ToDays: ?opts: ITimeConversionOptions -> float member ToHours: ?opts: ITimeConversionOptions -> float member ToHumanString: unit -> string member ToIsoString: unit -> string member ToMilliseconds: ?opts: ITimeConversionOptions -> float ...
Duration.Days(amount: float) : Duration
property AWS.S3.StorageClass.DEEP_ARCHIVE: AWS.S3.StorageClass with get
custom operation: s3Bucket (AWS.S3.IBucket) Calls CloudTrailBuilder.S3Bucket
<summary> Sets a custom S3 bucket for CloudTrail logs. If not specified, CDK will create a bucket with appropriate security settings. </summary>
<param name="config">The current CloudTrail configuration.</param>
<param name="bucket">The S3 bucket interface.</param>
field RetentionDays.ONE_YEAR: RetentionDays = 11
field ReadWriteType.READ_ONLY: ReadWriteType = 0
field RetentionDays.ONE_WEEK: RetentionDays = 3
field ReadWriteType.WRITE_ONLY: ReadWriteType = 1
field RetentionDays.ONE_MONTH: RetentionDays = 5
field RetentionDays.TWO_WEEKS: RetentionDays = 4

Type something to start searching.