14.2 HTTP Event Collector (HEC) Architecture & Administration
Key Takeaways
- HEC listens on port 8088 by default and is disabled globally (disabled = 1) until enabled; tokens live in [http://<token_name>] stanzas, usually in the splunk_httpinput app.
- A token's indexes setting lists the indexes its events may use; if it is not set, any index can be used, and an event naming a disallowed index gets code 7, Incorrect index.
- The event endpoint takes JSON with an event key plus optional time, host, source, sourcetype, index, and fields; the raw endpoint takes plain text with metadata from the query string or token.
- Clients authenticate with Authorization: Splunk <token>, basic authentication, or ?token= when allowQueryStringAuth = true; codes include 4 Invalid token, 9 Server is busy, and 10 Data channel is missing.
- HEC indexer acknowledgment (useACK = true on the token) requires a channel GUID; a true ack status means the data was replicated at the desired replication factor, and it differs from forwarder useACK.
HTTP Event Collector (HEC)
Quick Summary: The HTTP Event Collector (HEC) lets applications send events to Splunk over HTTP or HTTPS with a token instead of a user name and password, so no forwarder is needed on the client. HEC listens on port 8088 by default, is disabled globally until you enable it, and is configured with a global
[http]stanza plus one[http://<token_name>]stanza per token. Know the JSON event endpoint versus the raw endpoint, how tokens restrict indexes, the status codes clients receive, and how HEC indexer acknowledgment uses channels.
What HEC Is and Where It Runs
HEC is an input built into splunkd. Any client that can make an HTTP POST can send data, for example applications, container logging drivers, serverless functions, and automation scripts.
- Token authentication: each token is a GUID. Clients present it in the
Authorizationheader, and tokens can be enabled, disabled, or restricted to specific indexes without sharing user credentials. - Where to run it: HEC can run on a standalone instance, on indexers, or on heavy forwarders. At scale it is common to place several HEC instances behind a load balancer.
- Where tokens are stored: tokens created in Splunk Web are written to
$SPLUNK_HOME/etc/apps/splunk_httpinput/local/inputs.conf. To manage tokens centrally,useDeploymentServer = 1writes the HEC configuration to the deployment server repository instead. - Enabling it: in Splunk Web, open Settings > Data inputs > HTTP Event Collector > Global Settings and enable all tokens. This sets
disabled = 0in the[http]stanza.
Global Settings: the [http] Stanza
| Setting | Default | Meaning |
|---|---|---|
disabled | 1 | HEC is off until you set 0 |
port | 8088 | Listening port |
enableSSL | true | Use TLS. HEC shares TLS settings with the management port and cannot use TLS if the management server has TLS turned off |
serverCert | $SPLUNK_HOME/etc/auth/server.pem | Server certificate |
dedicatedIoThreads | 0 | Dedicated I/O threads; 0 means the input uses a single thread |
maxSockets | 0 | Simultaneous connections; 0 = one third of the host's open-file limit (minimum 50) |
maxThreads | 0 | Threads for active HTTP transactions; 0 = one third of the host's thread limit (minimum 20) |
maxEventSize | 5MB | Larger events trigger a parsing error |
ackIdleCleanup / maxIdleTime | true / 600 | Remove ACK channels idle for 10 minutes |
channel_cookie | empty | Return the channel ID in a cookie, for load balancers that can only make sessions sticky on cookies |
A separate limit, max_content_length in the [http_input] stanza of limits.conf, caps the size of a request body (default 838,860,800 bytes, about 800 MB).
[http]
disabled = 0
port = 8088
enableSSL = 1
dedicatedIoThreads = 2
Token Stanzas: [http://<token_name>]
| Setting | Default | Meaning |
|---|---|---|
token | none | The GUID that clients send |
disabled | 0 | Disable one token without affecting the others |
index | the default index | Where events go when they do not name an index |
indexes | empty = any index | Comma-separated list of indexes that events for this token may use |
sourcetype | empty | Default source type when the event does not set one |
connection_host | not set | ip, dns, proxied_ip (use the X-Forwarded-For header), or none |
useACK | false | Enable HEC indexer acknowledgment for this token |
allowQueryStringAuth | false | Allow the token in the URL (?token=) |
queueSize / persistentQueueSize | 500KB / 0 | Input queue sizes |
Restricting Indexes with indexes
An event can name its own index in the JSON metadata. That index must be in the token's indexes list if the list is set; otherwise the request fails with status code 7, Incorrect index. The key trap: if indexes is not set, the list is empty and any index can be used. Set indexes on every token that untrusted or shared clients use.
[http://k8s_production_ingress]
disabled = 0
token = 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
index = prod_k8s
indexes = prod_k8s, prod_k8s_security
sourcetype = kube:ingress
useACK = 1
[http://cicd_build_runner]
disabled = 0
token = 99887766-5544-3322-1100-aabbccddeeff
index = cicd_events
indexes = cicd_events
sourcetype = gitlab:pipeline
Authentication Options
| Method | How the client sends the token |
|---|---|
| HTTP header (standard) | Authorization: Splunk <token> |
| Basic authentication | Any user name with the token as the password, e.g. curl -u "x:<token>" |
| Query string | ?token=<token>. Works only when the token has allowQueryStringAuth = true; tokens in URLs can be logged in clear text, so always use HTTPS |
If a token is sent in both the query string and the header, the query-string token takes precedence.
Event Endpoint vs. Raw Endpoint
/services/collector (also /services/collector/event): JSON Events
{
"time": 1727082400.451,
"host": "k8s-worker-node-04",
"source": "auth-svc",
"sourcetype": "auth:json",
"index": "prod_k8s",
"event": {"action": "login_attempt", "user": "jsmith", "status": "success"},
"fields": {"environment": "production", "region": "us-east-1"}
}
eventholds the data: a string, a number, or a JSON object. The metadata keystime,host,source,sourcetype,index, andfieldsare optional; anything left out takes the token's values.timeis epoch time in<sec>.<ms>format.fieldsdefines a flat set of indexed fields. It is accepted only by the event endpoint and does not apply to raw data.- Batching: put several event objects one after another, or in a JSON array, in one request to improve throughput.
/services/collector/raw: Raw Text
curl -H "Authorization: Splunk 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d" \
-H "X-Splunk-Request-Channel: 18654C68-B28B-4450-9CF0-6E7645CA60CA" \
"https://hec.corp.example:8088/services/collector/raw?index=net_fw&sourcetype=cisco:asa&host=edge-fw01" \
-d "Mar 23 03:00:00 edge-fw01 %ASA-6-302013: Built inbound TCP connection 10423"
- The body is plain text. HEC breaks it into events and sends them through the pipeline, which extracts timestamps and applies the source type's
props.confrules. - Metadata comes from the query string, the token, or the global settings, and applies to all events in the request.
- Splunk's examples for the raw endpoint include a channel identifier (
X-Splunk-Request-Channelheader or?channel=), and a channel is mandatory whenever the token uses indexer acknowledgment.
| Feature | Event endpoint | Raw endpoint |
|---|---|---|
| Body | JSON objects with an event key | Plain text |
| Per-event metadata | In the JSON | Query string, token, or global defaults |
Indexed fields (fields) | Supported | Not applicable |
| Event breaking | Each JSON object is an event | Line-breaking rules for the source type |
Status Codes Returned to Clients
HEC replies with an HTTP status and a JSON body containing a Splunk status code. The codes most worth knowing:
| Code | HTTP | Message |
|---|---|---|
| 0 | 200 | Success |
| 1 | 403 | Token disabled |
| 2 | 401 | Token is required |
| 3 | 401 | Invalid authorization |
| 4 | 403 | Invalid token |
| 5 | 400 | No data |
| 6 | 400 | Invalid data format |
| 7 | 400 | Incorrect index |
| 8 | 500 | Internal server error |
| 9 | 503 | Server is busy |
| 10 | 400 | Data channel is missing |
| 11 | 400 | Invalid data channel |
| 12 | 400 | Event field is required |
| 13 | 400 | Event field cannot be blank |
| 14 | 400 | ACK is disabled |
Newer codes cover the health endpoint (17–20, for example 18 "HEC is unhealthy, queues are full") and capacity warnings (24–27, including HTTP 429 when the queue or ACK channel is at capacity). Splunk cautions that clients must act on these codes, for example by retrying after 503 or 429, or data can be lost.
HEC Indexer Acknowledgment and Channels
By default, HEC returns HTTP 200 as soon as the request appears valid, before the data enters the processing pipeline. An outage after that point can lose the data. HEC indexer acknowledgment lets the client check what happened. It is a different feature from forwarder indexer acknowledgment (useACK in outputs.conf), even though the names are the same.
- Enable it per token with
useACK = true(or the Enable indexer acknowledgment checkbox when creating the token). - Send a channel with every request: a GUID in
X-Splunk-Request-Channelor?channel=. Without it, HEC returns code 10, Data channel is missing. One channel per client stops a fast client from slowing a slow one down. - Receive an ack ID: each request returns an identifier such as
{"ackId": 42}. - Query the status by posting
{"acks": [40, 41, 42]}to/services/collector/ackon the same channel. - Interpret the reply:
truemeans the events for that ID were replicated at the desired replication factor. It does not guarantee indexing, because the parsing pipeline can still drop events it cannot parse.falsemeans there is no status yet or no information for that ID. - Stop querying after
true: HEC deletes the status once it has returnedtrue, so asking again returnsfalse. Resend data whose ID never becomestruewithin a reasonable time.
Load Balancers
Acknowledgment status is kept by the HEC instance that received the request, so ACK queries must reach the same instance. Configure the load balancer for sticky sessions on the channel. For load balancers that can only stick on cookies (Splunk's example is AWS ELB), set channel_cookie so that HEC returns the channel in a cookie.
An administrator configures an HTTP Event Collector token stanza [http://payment_processor] in inputs.conf. To prevent the payment application team from mistakenly or maliciously writing events to the audit_compliance or financial_core indexes, which setting must be configured?
How do the HTTP Event Collector /services/collector and /services/collector/raw endpoints differ in how they process event payloads and metadata?
How does HEC indexer acknowledgment let a client confirm what happened to the events it sent?
A HEC token stanza sets index = app_logs but has no indexes setting. A client sends an event with "index": "security". What happens?