Collect HashiCorp audit logs
This parser processes HashiCorp audit logs in JSON, Syslog, or combined formats. It extracts fields, performs Grok and KV parsing for both standard and "runner" type messages, handles JSON payloads, and maps the extracted data to the UDM. The parser also includes error handling and dropping malformed logs.
Before you begin
- Ensure that you have a Google Security Operations instance.
- Ensure that you have a Windows 2016 or later or a Linux host with systemd.
- If running behind a proxy, ensure firewall ports are open.
- Ensure that you have privileged access to HCP.
Get Google SecOps ingestion authentication file
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Collection Agents.
- Download the Ingestion Authentication File.
Get Google SecOps customer ID
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Profile.
- Copy and save the Customer ID from the Organization Details section.
Install Bindplane Agent
- For Windows installation, run the following script:
 msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
- For Linux installation, run the following script:
 sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
- Additional installation options can be found in this installation guide.
Configure Bindplane Agent to ingest Syslog and send to Google SecOps
- Access the machine where Bindplane Agent is installed.
- Edit the - config.yamlfile as follows:- receivers: udplog: # Replace the below port <54525> and IP <0.0.0.0> with your specific values listen_address: "0.0.0.0:54525" exporters: chronicle/chronicle_w_labels: compression: gzip # Adjust the creds location below according the placement of the credentials file you downloaded creds: '{ json file for creds }' # Replace <customer_id> below with your actual ID that you copied customer_id: <customer_id> endpoint: malachiteingestion-pa.googleapis.com # You can apply ingestion labels below as preferred ingestion_labels: log_type: SYSLOG namespace: auditd raw_log_field: body service: pipelines: logs/source0__chronicle_w_labels-0: receivers: - udplog exporters: - chronicle/chronicle_w_labels
- Restart the Bindplane Agent to apply the changes: - sudo systemctl restart bindplane
Enable Syslog for HCP Vault
- Sign in to the HCP Portal.
- Go to Vault Clusters.
- Select your Vault cluster from the list of deployed clusters.
- In the Cluster Overview, locate and copy the Vault Address (for example, https://vault-cluster-name.hashicorpcloud.com:8200).
- Go to the Access Details section, and copy the Root Token.
Install the Vault CLI
- For Linux: - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install vault
- For macOS (using Homebrew): - brew tap hashicorp/tap brew install hashicorp/tap/vault
- For Windows: - Download the executable file. Extract it and add the Vault binary to your system's PATH.
- Verify the Vault CLI installation by running: - vault --version
Configure HCP Vault using CLI to send audit logs to Bindplane
- Open the terminal or the command prompt.
- Set the Vault server address using the environment variable: - export VAULT_ADDR="https://vault-cluster-name.hashicorpcloud.com:8200"
- Log in to Vault using the root token: - vault login <root-token>
Configure the Syslog Path to an External Syslog Socket
- Run the following command to enable syslog and send to Bindplane Agent: - vault audit enable socket address="udp://<bindplane-ip>:<bindplane-port>" socket_type="udp" tag="vault"
- Confirm the new configuration: - vault audit list
- The output should display the new socket configuration. 
- Optional: Automate the setup using Terraform: - Create a Terraform configuration file (audit.tf):
 - resource "vault_audit" "syslog" { type = "syslog" description = "Syslog audit logs" options = { tag = "vault" facility = "LOCAL0" } } resource "vault_audit" "socket" { type = "socket" description = "Remote syslog socket" options = { address = "udp://<syslog-server-ip>:514" socket_type = "udp" tag = "vault" } }- Apply the configuration:
 - terraform init terraform apply
Troubleshooting logs not received
- Verify the syslog server is reachable: - ping <syslog-server-ip>
UDM Mapping Table
| Log Field | UDM Mapping | Logic | 
|---|---|---|
| auth.accessor | security_result.about.resource.attribute.labels.value | The value of auth.accessorfrom the raw log is mapped to a label with key "auth_accessor" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| auth.client_token | security_result.about.resource.attribute.labels.value | The value of auth.client_tokenfrom the raw log is mapped to a label with key "auth_client_token" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| auth.display_name | target.user.user_display_name | The value of auth.display_namefrom the raw log is mapped totarget.user.user_display_namein the UDM. | 
| auth.entity_id | target.resource.product_object_id | The value of auth.entity_idfrom the raw log is mapped totarget.resource.product_object_idin the UDM. | 
| auth.metadata.account_id | target.user.userid | The value of auth.metadata.account_idfrom the raw log is mapped totarget.user.useridin the UDM. | 
| auth.metadata.auth_type | security_result.about.resource.attribute.labels.value | The value of auth.metadata.auth_typefrom the raw log is mapped to a label with key "auth_type" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| auth.metadata.role_id | security_result.about.resource.attribute.labels.value | The value of auth.metadata.role_idfrom the raw log is mapped to a label with key "role_id" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| auth.metadata.role_name | target.resource.attribute.roles.name | The value of auth.metadata.role_namefrom the raw log is mapped totarget.resource.attribute.roles.namein the UDM. | 
| auth.token_ttl | security_result.about.resource.attribute.labels.value | The value of auth.token_ttlfrom the raw log is mapped to a label with key "auth_token_ttl" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| auth.token_type | security_result.about.resource.attribute.labels.value | The value of auth.token_typefrom the raw log is mapped to a label with key "auth_token_type" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| cluster | observer.resource.name | The value of clusterfrom the raw log is mapped toobserver.resource.namein the UDM. | 
| error | security_result.description | The value of errorfrom the raw log is mapped tosecurity_result.descriptionin the UDM. | 
| headers.accept | security_result.about.resource.attribute.labels.value | The value of headers.acceptfrom the raw log is mapped to a label with key "httpHeaders accept" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| headers.httpHeaders.cache-control | additional.fields.value.string_value | The value of headers.httpHeaders.cache-controlfrom the raw log is mapped to a field with key "httpHeaders cache control" underadditional.fieldsin the UDM. | 
| headers.snyk-acting-org-public-id | principal.resource.attribute.labels.value | The value of headers.snyk-acting-org-public-idfrom the raw log is mapped to a label with key "snyk-acting-org-public-id" underprincipal.resource.attribute.labelsin the UDM. | 
| headers.snyk-flow-name | principal.resource.attribute.labels.value | The value of headers.snyk-flow-namefrom the raw log is mapped to a label with key "snyk-flow-name" underprincipal.resource.attribute.labelsin the UDM. | 
| headers.snyk-request-id | principal.resource.attribute.labels.value | The value of headers.snyk-request-idfrom the raw log is mapped to a label with key "snyk-request-id" underprincipal.resource.attribute.labelsin the UDM. | 
| headers.user-agent | network.http.parsed_user_agent | The value of headers.user-agentfrom the raw log is parsed as a user agent and mapped tonetwork.http.parsed_user_agentin the UDM. | 
| headers.x-forwarded-host | principal.hostname | The value of headers.x-forwarded-hostfrom the raw log is mapped toprincipal.hostnamein the UDM. | 
| headers.x-forwarded-port | principal.port | The value of headers.x-forwarded-portfrom the raw log is mapped toprincipal.portin the UDM. | 
| headers.x-real-ip | principal.ip | The value of headers.x-real-ipfrom the raw log is mapped toprincipal.ipin the UDM. | 
| hostname | observer.hostname | The value of hostnamefrom the raw log is mapped toobserver.hostnamein the UDM. | 
| httpHeaders.cf-cache-status | target.resource.attribute.labels.value | The value of httpHeaders.cf-cache-statusfrom the raw log is mapped to a label with key "cf-cache-status" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.cf-ray | target.resource.attribute.labels.value | The value of httpHeaders.cf-rayfrom the raw log is mapped to a label with key "cf-ray" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.content-length | security_result.about.resource.attribute.labels.value | The value of httpHeaders.content-lengthfrom the raw log is mapped to a label with key "httpHeaders Content-Length" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| httpHeaders.content-type | security_result.about.resource.attribute.labels.value | The value of httpHeaders.content-typefrom the raw log is mapped to a label with key "httpHeaders Content-Type" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| httpHeaders.gitlab-lb | target.resource.attribute.labels.value | The value of httpHeaders.gitlab-lbfrom the raw log is mapped to a label with key "gitlab-lb" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.gitlab-sv | target.resource.attribute.labels.value | The value of httpHeaders.gitlab-svfrom the raw log is mapped to a label with key "gitlab-sv" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.ratelimit-limit | target.resource.attribute.labels.value | The value of httpHeaders.ratelimit-limitfrom the raw log is mapped to a label with key "ratelimit-limit" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.ratelimit-observed | target.resource.attribute.labels.value | The value of httpHeaders.ratelimit-observedfrom the raw log is mapped to a label with key "ratelimit-observed" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.ratelimit-remaining | target.resource.attribute.labels.value | The value of httpHeaders.ratelimit-remainingfrom the raw log is mapped to a label with key "ratelimit-remaining" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.ratelimit-reset | target.resource.attribute.labels.value | The value of httpHeaders.ratelimit-resetfrom the raw log is mapped to a label with key "ratelimit-reset" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.ratelimit-resettime | target.resource.attribute.labels.value | The value of httpHeaders.ratelimit-resettimefrom the raw log is mapped to a label with key "ratelimit-resettime" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.referrer-policy | target.resource.attribute.labels.value | The value of httpHeaders.referrer-policyfrom the raw log is mapped to a label with key "referrer-policy" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.server | target.resource.attribute.labels.value | The value of httpHeaders.serverfrom the raw log is mapped to a label with key "server" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.x-content-type-options | target.resource.attribute.labels.value | The value of httpHeaders.x-content-type-optionsfrom the raw log is mapped to a label with key "x-content-type-options" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.x-frame-options | target.resource.attribute.labels.value | The value of httpHeaders.x-frame-optionsfrom the raw log is mapped to a label with key "x-frame-options" undertarget.resource.attribute.labelsin the UDM. | 
| httpHeaders.x-request-id | target.resource.attribute.labels.value | The value of httpHeaders.x-request-idfrom the raw log is mapped to a label with key "x-request-id" undertarget.resource.attribute.labelsin the UDM. | 
| httpStatus | network.http.response_code | The value of httpStatusfrom the raw log is mapped tonetwork.http.response_codein the UDM. | 
| httpUrl | target.url | The value of httpUrlfrom the raw log is mapped totarget.urlin the UDM. | 
| insertId | metadata.product_log_id | The value of insertIdfrom the raw log is mapped tometadata.product_log_idin the UDM. | 
| job | additional.fields.value.string_value | The value of jobfrom the raw log is mapped to a field with key "job id" underadditional.fieldsin the UDM. | 
| job_status | additional.fields.value.string_value | The value of job_statusfrom the raw log is mapped to a field with key "job_status" underadditional.fieldsin the UDM. | 
| labels.compute.googleapis.com/resource_name | target.resource.name | The value of labels.compute.googleapis.com/resource_namefrom the raw log is mapped totarget.resource.namein the UDM. | 
| labels.k8s-pod/app_kubernetes_io/instance | target.resource.attribute.labels.value | The value of labels.k8s-pod/app_kubernetes_io/instancefrom the raw log is mapped to a label with key "Kubernetes IO Instance" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/app_kubernetes_io/name | target.resource.attribute.labels.value | The value of labels.k8s-pod/app_kubernetes_io/namefrom the raw log is mapped to a label with key "Kubernetes IO Instance Name" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/component | target.resource.attribute.labels.value | The value of labels.k8s-pod/componentfrom the raw log is mapped to a label with key "component" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/controller-revision-hash | target.resource.attribute.labels.value | The value of labels.k8s-pod/controller-revision-hashfrom the raw log is mapped to a label with key "Controller Revision Hash" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/helm_sh/chart | target.resource.attribute.labels.value | The value of labels.k8s-pod/helm_sh/chartfrom the raw log is mapped to a label with key "Kubernetes IO Instance Manager SH" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/vault-active | target.resource.attribute.labels.value | The value of labels.k8s-pod/vault-activefrom the raw log is mapped to a label with key "Vault active" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/vault-initialized | target.resource.attribute.labels.value | The value of labels.k8s-pod/vault-initializedfrom the raw log is mapped to a label with key "Vault initialized" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/vault-perf-standby | target.resource.attribute.labels.value | The value of labels.k8s-pod/vault-perf-standbyfrom the raw log is mapped to a label with key "vault perf standby" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/vault-sealed | target.resource.attribute.labels.value | The value of labels.k8s-pod/vault-sealedfrom the raw log is mapped to a label with key "Vault sealed" undertarget.resource.attribute.labelsin the UDM. | 
| labels.k8s-pod/vault-version | target.resource.attribute.labels.value | The value of labels.k8s-pod/vault-versionfrom the raw log is mapped to a label with key "Vault version" undertarget.resource.attribute.labelsin the UDM. | 
| maskedToken | security_result.about.resource.attribute.labels.value | The value of maskedTokenfrom the raw log is mapped to a label with key "maskedToken" undersecurity_result.about.resource.attribute.labelsin the UDM. | 
| method | network.http.method,operation | The value of methodfrom the raw log is mapped tooperation. Ifoperationis not empty, thennetwork.application_protocolis set to "HTTP". Based on the value ofoperation,network.http.methodis derived. | 
| msg | metadata.description | The value of msgfrom the raw log is mapped tometadata.descriptionin the UDM. | 
| pid | target.process.pid | The value of pidfrom the raw log is mapped totarget.process.pidin the UDM. | 
| request.client_token | target.resource.attribute.labels.value | The value of request.client_tokenfrom the raw log is mapped to a label with key "request_client_token" undertarget.resource.attribute.labelsin the UDM. | 
| request.client_token_accessor | target.resource.attribute.labels.value | The value of request.client_token_accessorfrom the raw log is mapped to a label with key "request_client_token_accessor" undertarget.resource.attribute.labelsin the UDM. | 
| request.data.role_id | target.resource.attribute.labels.value | The value of request.data.role_idfrom the raw log is mapped to a label with key "request_data_role_id" undertarget.resource.attribute.labelsin the UDM. | 
| request.data.secret_id | target.resource.attribute.labels.value | The value of request.data.secret_idfrom the raw log is mapped to a label with key "request_data_secret_id" undertarget.resource.attribute.labelsin the UDM. | 
| request.id | network.session_id | The value of request.idfrom the raw log is mapped tonetwork.session_idin the UDM. | 
| request.mount_accessor | target.resource.attribute.labels.value | The value of request.mount_accessorfrom the raw log is mapped to a label with key "request_mount_accessor" undertarget.resource.attribute.labelsin the UDM. | 
| request.mount_type | target.resource.attribute.labels.value | The value of request.mount_typefrom the raw log is mapped to a label with key "request_mount_type" undertarget.resource.attribute.labelsin the UDM. | 
| request.namespace.id | target.namespace | The value of request.namespace.idfrom the raw log is mapped totarget.namespacein the UDM. | 
| request.operation | target.resource.attribute.labels.value,network.http.method,operation | The value of request.operationfrom the raw log is mapped tooperation. Ifoperationis not empty, thennetwork.application_protocolis set to "HTTP". Based on the value ofoperation,network.http.methodis derived.  The value ofrequest.operationis also mapped to a label with key "capabilities" undertarget.resource.attribute.labelsin the UDM. | 
| request.path | target.url | The value of request.pathfrom the raw log is mapped totarget.urlin the UDM. | 
| request.remote_address | principal.ip | The value of request.remote_addressfrom the raw log is mapped toprincipal.ipin the UDM. | 
| request.remote_port | principal.port | The value of request.remote_portfrom the raw log is mapped toprincipal.portin the UDM. | 
| request.wrap_ttl | target.resource.attribute.labels.value | The value of request.wrap_ttlfrom the raw log is mapped to a label with key "request_wrap_ttl" undertarget.resource.attribute.labelsin the UDM. | 
| resource.labels.container_name | additional.fields.value.string_value | The value of resource.labels.container_namefrom the raw log is mapped to a field with key "container name" underadditional.fieldsin the UDM. | 
| resource.labels.location | target.location.name | The value of resource.labels.locationfrom the raw log is mapped totarget.location.namein the UDM. | 
| resource.labels.namespace_name | target.namespace | The value of resource.labels.namespace_namefrom the raw log is mapped totarget.namespacein the UDM. | 
| resource.labels.pod_name | additional.fields.value.string_value | The value of resource.labels.pod_namefrom the raw log is mapped to a field with key "pod_name" underadditional.fieldsin the UDM. | 
| resource.labels.project_id | target.cloud.project.name | The value of resource.labels.project_idfrom the raw log is mapped totarget.cloud.project.namein the UDM. | 
| response.data.num_uses | target.resource.attribute.labels.value | The value of response.data.num_usesfrom the raw log is mapped to a label with key "response_data_num_uses" undertarget.resource.attribute.labelsin the UDM. | 
| response.data.orphan | target.resource.attribute.labels.value | The value of response.data.orphanfrom the raw log is mapped to a label with key "response_data_orphan" undertarget.resource.attribute.labelsin the UDM. | 
| response.data.renewable | target.resource.attribute.labels.value | The value of response.data.renewablefrom the raw log is mapped to a label with key "response_data_renewable" undertarget.resource.attribute.labelsin the UDM. | 
| response.data.ttl | target.resource.attribute.labels.value | The value of response.data.ttlfrom the raw log is mapped to a label with key "response_data_ttl" undertarget.resource.attribute.labelsin the UDM. | 
| response.wrap_info.accessor | target.resource.attribute.labels.value | The value of response.wrap_info.accessorfrom the raw log is mapped to a label with key "response_wrap_info_accessor" undertarget.resource.attribute.labelsin the UDM. | 
| response.wrap_info.token | target.resource.attribute.labels.value | The value of response.wrap_info.tokenfrom the raw log is mapped to a label with key "response_wrap_info_token" undertarget.resource.attribute.labelsin the UDM. | 
| response.wrap_info.ttl | target.resource.attribute.labels.value | The value of response.wrap_info.ttlfrom the raw log is mapped to a label with key "response_wrap_info_ttl" undertarget.resource.attribute.labelsin the UDM. | 
| response.wrap_info.wrapped_accessor | target.resource.attribute.labels.value | The value of response.wrap_info.wrapped_accessorfrom the raw log is mapped to a label with key "response_wrap_info_wrapped_accessor" undertarget.resource.attribute.labelsin the UDM. | 
| runner | principal.user.userid | The value of runnerfrom the raw log is mapped toprincipal.user.useridin the UDM. | 
| status | network.http.response_code | The value of statusfrom the raw log is mapped tonetwork.http.response_codein the UDM. | 
| streamingID | target.resource.attribute.labels.value | The value of streamingIDfrom the raw log is mapped to a label with key "streamingID" undertarget.resource.attribute.labelsin the UDM. | 
| time | metadata.event_timestamp.seconds,metadata.event_timestamp.nanos | The value of timefrom the raw log is parsed and used to populate themetadata.event_timestampfield in the UDM. | 
| type | metadata.product_event_type | The value of typefrom the raw log is mapped tometadata.product_event_typein the UDM. | 
| url | principal.url | The value of urlfrom the raw log is mapped toprincipal.urlin the UDM.  The value "MACHINE" is assigned toextensions.auth.typein the UDM. The value "USER_LOGIN" is assigned tometadata.event_typein the UDM. The value "HASHICORP" is assigned tometadata.log_typein the UDM. The value "HASHICORP" is assigned tometadata.product_namein the UDM. The value "HASHICORP" is assigned tometadata.vendor_namein the UDM. The value "SERVICE_ACCOUNT" is assigned totarget.resource.attribute.roles.typein the UDM. | 
Need more help? Get answers from Community members and Google SecOps professionals.