Collect Terraform Enterprise logs

Supported in:

This document explains how to ingest Terraform Enterprise logs to Google Security Operations using Google Cloud Storage V2.

Terraform Enterprise (TFE) is a self-hosted infrastructure as code platform that generates application logs containing audit events for workspace operations, policy checks, state changes, and user activity. Audit events are embedded within the TFE application logs and marked with the [Audit Log] tag. Because TFE stores these logs locally on the application server, you must export them to a Google Cloud Storage (GCS) bucket and then configure a Google SecOps feed to ingest them.

Before you begin

Make sure you have the following prerequisites:

  • A Google SecOps instance
  • A Google Cloud project with Cloud Storage API enabled
  • Permissions to create and manage GCS buckets
  • Permissions to manage IAM policies on GCS buckets
  • Administrative access to the Terraform Enterprise server (SSH or console access)
  • Access to TFE application logs on the server file system (typically at /var/log/terraform-enterprise/ or accessible via replicatedctl app logs )

Create a Google Cloud Storage bucket

  1. Go to the Google Cloud Console .
  2. Select your project or create a new one.
  3. In the navigation menu, go to Cloud Storage > Buckets.
  4. Click Create bucket.
  5. Provide the following configuration details:

    Setting Value
    Name your bucket Enter a globally unique name (for example, terraform-enterprise-logs )
    Location type Choose based on your needs (Region, Dual-region, Multi-region)
    Location Select the location closest to your Google SecOps instance (for example, us-central1 )
    Storage class Standard (recommended for frequently accessed logs)
    Access control Uniform (recommended)
    Protection tools Optional: Enable object versioning or retention policy
  6. Click Create.

Configure automated export of TFE application logs to GCS

Terraform Enterprise embeds audit log entries within its application logs. Audit events are marked with the [Audit Log] string and can be filtered from the application log output. Choose one of the following approaches to automate the export.

Terraform Enterprise supports external log forwarding using a built-in Fluent Bit-based mechanism. You can configure TFE to forward application logs to a GCS bucket.

  1. Access the TFE administration console.
  2. Go to Settings > Logging.
  3. Enable External Logging.
  4. Configure the Fluent Bit output to use the GCS plugin:

     [OUTPUT]
        Name                       gcs
        Match                      *
        Bucket                     terraform-enterprise-logs
        Object_key_format          audit-logs/tfe_logs_%Y%m%d_%H%M%S.json
        Content_Type               application/json 
    
  5. Save the configuration and restart the TFE services if prompted.

Option 2: Compute Engine VM with cron (for direct log collection)

If the TFE server runs on Google Compute Engine or has network connectivity to GCP, configure a cron job on the TFE server to export filtered audit logs to GCS.

  1. Install the Google Cloud CLI on the TFE server.
  2. Create a service account for the export:

    1. In the GCP Console, go to IAM & Admin > Service Accounts.
    2. Click Create Service Account.
    3. Provide the following configuration details:
      • Service account name: Enter tfe-log-export-sa
      • Service account description: Enter Service account for TFE log export to GCS
    4. Click Create and Continue.
    5. Add the Storage Object Adminrole.
    6. Click Done.
    7. Download a JSON key for the service account and copy it to the TFE server.
  3. Create an export script on the TFE server ( /opt/tfe-export/export_logs.sh ):

      #!/usr/bin/env bash 
     set 
      
    -euo  
    pipefail BUCKET 
     = 
     "terraform-enterprise-logs" 
     PREFIX 
     = 
     "audit-logs" 
     LOG_DIR 
     = 
     "/var/log/terraform-enterprise" 
     EXPORT_DIR 
     = 
     "/tmp/tfe-export" 
     TIMESTAMP 
     = 
     $( 
    date  
    -u  
    +%Y%m%d_%H%M%S ) 
    mkdir  
    -p  
     " 
     $EXPORT_DIR 
     " 
     # Filter audit log entries from TFE application logs 
    grep  
     '\[Audit Log\]' 
      
     " 
     $LOG_DIR 
     " 
    /*.log > 
     " 
     $EXPORT_DIR 
     /tfe_audit_ 
     ${ 
     TIMESTAMP 
     } 
     .json" 
      
     2 
    >/dev/null  
     || 
      
     true 
     if 
      
     [ 
      
    -s  
     " 
     $EXPORT_DIR 
     /tfe_audit_ 
     ${ 
     TIMESTAMP 
     } 
     .json" 
      
     ] 
     ; 
      
     then 
      
    gcloud  
    storage  
    cp  
     " 
     $EXPORT_DIR 
     /tfe_audit_ 
     ${ 
     TIMESTAMP 
     } 
     .json" 
      
     \ 
      
     "gs:// 
     ${ 
     BUCKET 
     } 
     / 
     ${ 
     PREFIX 
     } 
     /" 
      
     echo 
      
     "Uploaded tfe_audit_ 
     ${ 
     TIMESTAMP 
     } 
     .json to gs:// 
     ${ 
     BUCKET 
     } 
     / 
     ${ 
     PREFIX 
     } 
     /" 
     else 
      
     echo 
      
     "No audit log entries found." 
     fi 
    rm  
    -rf  
     " 
     $EXPORT_DIR 
     " 
     
    
  4. Make the script executable and schedule it with cron:

     chmod  
    +x  
    /opt/tfe-export/export_logs.sh ( 
    crontab  
    -l  
     ; 
      
     echo 
      
     "0 * * * * /opt/tfe-export/export_logs.sh >> /var/log/tfe-export.log 2>&1" 
     ) 
      
     | 
      
    crontab  
    - 
    

Option 3: Storage Transfer Service (for file-based log collection)

If TFE logs are written to a file system accessible via a Storage Transfer Agent, use Storage Transfer Service to move them to GCS.

  1. In the GCP Console, go to Storage Transfer Service.
  2. Click Create transfer job.
  3. Select POSIX filesystemas the source.
  4. Follow the instructions to install the Storage Transfer Agent on the TFE server or a machine with access to the TFE log directory.
  5. Configure the transfer job:

    Setting Value
    Source directory Path to TFE log directory (for example, /var/log/terraform-enterprise/ )
    Destination bucket terraform-enterprise-logs
    Destination path audit-logs/
    Schedule Set a recurring schedule (for example, every hour)
  6. Click Create.

  1. Go to SIEM Settings > Feeds.
  2. Click Add New Feed.
  3. Click Configure a single feed.
  4. In the Feed namefield, enter a name for the feed (for example, Terraform Enterprise Logs ).
  5. Select Google Cloud Storage V2as the Source type.
  6. Select Terraform Enterprise Auditas the Log type.
  7. Click Get Service Account. A unique service account email will be displayed, for example:

     chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com 
    
  8. Copy this email address for use in the next step.

The Google SecOps service account needs Storage Object Viewerrole on your GCS bucket.

  1. Go to Cloud Storage > Buckets.
  2. Click on your bucket name (for example, terraform-enterprise-logs ).
  3. Go to the Permissionstab.
  4. Click Grant access.
  5. Provide the following configuration details:
    • Add principals: Paste the Google SecOps service account email (for example, chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com ).
    • Assign roles: Select Storage Object Viewer.
  6. Click Save.

Configure the Google SecOps feed

  1. Go to SIEM Settings > Feeds.
  2. Click Add New Feed.
  3. Click Configure a single feed.
  4. In the Feed namefield, enter a name for the feed (for example, Terraform Enterprise Logs ).
  5. Select Google Cloud Storage V2as the Source type.
  6. Select Terraform Enterprise Auditas the Log type.
  7. Click Next.
  8. Specify values for the following input parameters:

    • Storage bucket URL: Enter the GCS bucket URI:

       gs://terraform-enterprise-logs/audit-logs/ 
      
      • Replace terraform-enterprise-logs with your GCS bucket name.
      • Replace audit-logs with your configured prefix path.
    • Source deletion option: Select the deletion option according to your preference:

      • Never: Never deletes any files after transfers (recommended for testing).
      • Delete transferred files and empty directories: Deletes files and empty directories after successful transfer.

    • Maximum File Age: Include files modified in the last number of days (default is 180 days).

    • Asset namespace: The asset namespace .

    • Ingestion labels: The label to be applied to the events from this feed.

  9. Click Next.

  10. Review your new feed configuration in the Finalizescreen, and then click Submit.

UDM mapping table

Log Field UDM Mapping Logic
action_label
additional.fields Merged
allow_config_generation_label
additional.fields Merged
allow_empty_apply_label
additional.fields Merged
auto_apply_label
additional.fields Merged
can_apply_label
additional.fields Merged
can_cancel_label
additional.fields Merged
can_comment_label
additional.fields Merged
can_discard_label
additional.fields Merged
can_force_cancel_label
additional.fields Merged
can_force_execute_label
additional.fields Merged
can_override_policy_check_label
additional.fields Merged
comments_label
additional.fields Merged
cost_estimated_at_label
additional.fields Merged
cost_estimating_at_label
additional.fields Merged
dd_span_id_label
additional.fields Merged
dd_trace_id_label
additional.fields Merged
has_changes_label
additional.fields Merged
is_cancelable_label
additional.fields Merged
is_confirmable_label
additional.fields Merged
is_destroy_label
additional.fields Merged
is_discardable_label
additional.fields Merged
is_force_cancelable_label
additional.fields Merged
jsonPayload_auth_source_label
additional.fields Merged
jsonPayload_db_label
additional.fields Merged
jsonPayload_dd_env_label
additional.fields Merged
jsonPayload_dd_service_label
additional.fields Merged
jsonPayload_dd_span_id_label
additional.fields Merged
jsonPayload_dd_trace_id_label
additional.fields Merged
jsonPayload_dd_version_label
additional.fields Merged
jsonPayload_ddsource_label
additional.fields Merged
jsonPayload_duration_label
additional.fields Merged
jsonPayload_format_label
additional.fields Merged
jsonPayload_node_id_label
additional.fields Merged
jsonPayload_selinux_context_label
additional.fields Merged
jsonPayload_systemd_cgroup_label
additional.fields Merged
jsonPayload_systemd_slice_label
additional.fields Merged
jsonPayload_view_label
additional.fields Merged
json_image_name_label
additional.fields Merged
json_syslog_identifier_label
additional.fields Merged
json_transport_label
additional.fields Merged
json_uid_label
additional.fields Merged
msg_label
additional.fields Merged
plan_only_label
additional.fields Merged
plan_queueable_at_label
additional.fields Merged
plan_queued_at_label
additional.fields Merged
planned_and_finished_at_label
additional.fields Merged
planned_at_label
additional.fields Merged
planning_at_label
additional.fields Merged
policychecks_label
additional.fields Merged
post_plan_completed_at_label
additional.fields Merged
post_plan_running_at_label
additional.fields Merged
queuing_at_label
additional.fields Merged
refresh_label
additional.fields Merged
refresh_only_label
additional.fields Merged
resource_label
additional.fields Merged
runevents_label
additional.fields Merged
save_plan_label
additional.fields Merged
source_label
additional.fields Merged
source_realtime_timestamp_label
additional.fields Merged
taskstages_label
additional.fields Merged
trigger_reason_label
additional.fields Merged
updated_at_label
additional.fields Merged
uuid_label
additional.fields Merged
data.attributes.created-at
metadata.event_timestamp Parsed as ISO8601
receiveTimestamp
metadata.event_timestamp Parsed as ISO8601
time
metadata.event_timestamp Parsed as MMM dd HH:mm:ss
time_stamp
metadata.event_timestamp Parsed as yyyy-MM-dd HH:mm:ss
time_zone
metadata.event_timestamp Parsed as yyyy-MM-dd HH:mm:ss
timestamp
metadata.event_timestamp Parsed as yyyy-MM-dd HH:mm:ss.SSSSSS+Z.Z
event_type
metadata.event_type Directly mapped
has_principal
metadata.event_type Mapped: true STATUS_UPDATE , true NETWORK_HTTP , true NETWORK_CONNECTION
has_principal_user
metadata.event_type Mapped: true USER_UNCATEGORIZED
has_user
metadata.event_type Mapped: true USER_RESOURCE_ACCESS , true USER_UNCATEGORIZED
type
metadata.product_event_type Directly mapped
id
metadata.product_log_id Directly mapped
insertId
metadata.product_log_id Directly mapped
data.attributes.terraform-version
metadata.product_version Directly mapped
vault_version
metadata.product_version Directly mapped
logName
metadata.url_back_to_product Directly mapped
method
network.http.method Directly mapped
status
network.http.response_code Renamed/mapped
user_agent
network.http.user_agent Directly mapped
request_id
network.session_id Directly mapped
jsonPayload.machine_id
principal.asset.asset_id Directly mapped
dd_service
principal.asset.hostname Directly mapped
hostname
principal.asset.hostname Directly mapped
actor_ip
principal.asset.ip Merged
sha
principal.file.sha1 Directly mapped
dd_service
principal.hostname Directly mapped
hostname
principal.hostname Directly mapped
jsonPayload.hostname
principal.hostname Directly mapped
src_host
principal.hostname Directly mapped
actor_ip
principal.ip Merged
remote_ip
principal.ip Merged
port
principal.port Renamed/mapped
src_port
principal.port Renamed/mapped
jsonPayload.cap_effective
principal.process.access_mask Renamed/mapped
jsonPayload.cmdline
principal.process.command_line Directly mapped
jsonPayload.exe
principal.process.file.full_path Directly mapped
jsonPayload.comm
principal.process.file.names Merged
jsonPayload.pid
principal.process.pid Directly mapped
jsonPayload_container_tag_label
principal.resource.attribute.labels Merged
jsonPayload.container_id_full
principal.resource.product_object_id Directly mapped
resource_id
principal.resource.product_object_id Directly mapped
resource.type
principal.resource.resource_subtype Directly mapped
auth_impersonator_id_label
principal.user.attribute.labels Merged
client_token_accessor_label
principal.user.attribute.labels Merged
client_token_label
principal.user.attribute.labels Merged
mount_accessor_label
principal.user.attribute.labels Merged
mount_point_label
principal.user.attribute.labels Merged
namespace_id_label
principal.user.attribute.labels Merged
organization_id_label
principal.user.attribute.labels Merged
request_id_label
principal.user.attribute.labels Merged
write_timestamp_label
principal.user.attribute.labels Merged
role
principal.user.attribute.roles Merged
organization
principal.user.department Merged
jsonPayload.gid
principal.user.group_identifiers Merged
auth.entity_id
principal.user.product_object_id Directly mapped
auth.display_name
principal.user.user_display_name Directly mapped
actor
principal.user.userid Directly mapped
auth.accessor_id
principal.user.userid Directly mapped
auth.entity_id
principal.user.userid Directly mapped
request.client_id
principal.user.userid Directly mapped
user
principal.user.userid Directly mapped
record.resource.action
security_result.action_details Directly mapped
request.operation
security_result.action_details Directly mapped
data.attributes.status
security_result.category_details Merged
apply_detection_field_id
security_result.detection_fields Merged
apply_detection_field_related
security_result.detection_fields Merged
auth_accessor_label
security_result.detection_fields Merged
auth_client_token_label
security_result.detection_fields Merged
auth_metadata_role_label
security_result.detection_fields Merged
auth_policy_results_allowed_label
security_result.detection_fields Merged
auth_token_type_label
security_result.detection_fields Merged
comments_related_label
security_result.detection_fields Merged
configuration_version_detection_field_id
security_result.detection_fields Merged
configuration_version_detection_field_related
security_result.detection_fields Merged
cost_estimate_detection_field_id
security_result.detection_fields Merged
cost_estimate_detection_field_related
security_result.detection_fields Merged
data_id_label
security_result.detection_fields Merged
data_links_self_label
security_result.detection_fields Merged
detection_fields_organization_id
security_result.detection_fields Merged
id_label
security_result.detection_fields Merged
plan_detection_field_id
security_result.detection_fields Merged
plan_detection_field_related
security_result.detection_fields Merged
policy_checks_related_label
security_result.detection_fields Merged
run_events_related_label
security_result.detection_fields Merged
task_stages_related_label
security_result.detection_fields Merged
token_ttl_label
security_result.detection_fields Merged
workspace_detection_field_id
security_result.detection_fields Merged
jsonPayload.priority
security_result.priority_details Directly mapped
severity
security_result.severity Mapped: INFO INFORMATIONAL
severity_detail
security_result.severity Mapped: (?i)Info INFORMATIONAL , (?i)Error ERROR , (?i)Warning MEDIUM
request.remote_address
target.asset.ip Merged
target_ip
target.asset.ip Merged
request.remote_address
target.ip Merged
target_ip
target.ip Merged
labels_namespace
target.namespace Directly mapped
request.remote_port
target.port Renamed/mapped
labels_location
target.resource.attribute.cloud.availability_zone Directly mapped
region
target.resource.attribute.cloud.availability_zone Directly mapped
provider
target.resource.attribute.cloud.environment Mapped: aws AMAZON_WEB_SERVICES
cluster_size_label
target.resource.attribute.labels Merged
cluster_tier_label
target.resource.attribute.labels Merged
hcp_product_label
target.resource.attribute.labels Merged
image_tag_label
target.resource.attribute.labels Merged
instance-id_label
target.resource.attribute.labels Merged
organization_id_label
target.resource.attribute.labels Merged
cluster_id
target.resource.name Directly mapped
jsonPayload.container_name
target.resource.name Directly mapped
name
target.resource.name Directly mapped
record.resource.id
target.resource.name Directly mapped
project_id
target.resource.product_object_id Directly mapped
resource.meta.project_id
target.resource.product_object_id Directly mapped
record.resource.type
target.resource.resource_subtype Directly mapped
target_resource_ancestors
target.resource_ancestors Merged
path
target.url Directly mapped
request.path
target.url Directly mapped
mount_accessor_label
target.user.attribute.labels Merged
mount_class_label
target.user.attribute.labels Merged
mount_point_label
target.user.attribute.labels Merged
mount_running_plugin_version_label
target.user.attribute.labels Merged
mount_type_label
target.user.attribute.labels Merged
replication_cluster_label
target.user.attribute.labels Merged
N/A
metadata.event_type Constant: USER_RESOURCE_ACCESS
N/A
metadata.product_name Constant: TERRAFORM_ENTERPRISE
N/A
metadata.vendor_name Constant: TERRAFORM_ENTERPRISE
N/A
security_result.severity Constant: INFORMATIONAL
N/A
target.resource.attribute.cloud.environment Constant: AMAZON_WEB_SERVICES

Need more help? Get answers from Community members and Google SecOps professionals.

Create a Mobile Website
View Site in Mobile | Classic
Share by: