Splunk Observability Kubernetes Auto-Instrumentation
Prerequisites
| Tool or access |
Purpose |
Verify |
| Bash and Python 3 |
Run bundled setup and validation helpers |
bash --version && python3 --version |
| Required product/platform access |
Inspect or configure the selected target |
Complete the documented preflight |
| Credential files for live modes |
Keep secrets out of chat |
Verify paths only |
Workflow Overview
┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐
│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │
└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘
When to Activate
- Wiring zero-code Java, Node.js, Python, .NET, Go, Apache, or Nginx instrumentation into Splunk Observability Cloud
APM, adding AlwaysOn Profiling, discovering workloads, or reverting operator-managed instrumentation.
- Preview and review the splunk observability k8s auto instrumentation setup workflow before any live apply phase.
- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.
Scope
Follow the documented read-only or render-first path whenever it is available.
This skill does not imply permission to mutate live systems. Require explicit
apply flags, protected credentials, and operator review for state changes.
Examples
Inspect the supported setup modes before selecting one:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh --help
Expected output: usage, supported modes, and required arguments are displayed
without changing the target environment.
Inspect validation modes before running completion checks:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh --help
Expected output: offline, live, and completion options are displayed when the
skill supports them; help exits without mutation.
Troubleshooting
| Issue |
Cause |
Resolution |
| Preflight fails |
A required tool or access path is missing |
Resolve it before rendering or applying |
| Rendered assets are incomplete |
Required non-secret inputs are absent |
Complete intake and render again |
| Apply is blocked |
Review, credentials, or explicit acceptance is missing |
Use the documented handoff |
| Validation is incomplete |
Live evidence is unavailable |
Record the gap and keep completion open |
This skill configures operator-driven, zero-code application auto-instrumentation for Kubernetes workloads that send traces, metrics, and profiling to Splunk Observability Cloud.
It is an overlay on top of splunk-observability-otel-collector-setup. That skill installs the Splunk OTel Collector chart, which in turn installs the OpenTelemetry Operator, the Instrumentation / OpenTelemetryCollector CRDs, and (optionally) a chart-managed default Instrumentation custom resource. This skill takes over from there: it renders one or more fully-configured Instrumentation custom resources per language, writes workload annotation patches that the operator mutating webhook reacts to, and drives the full lifecycle (apply, verify, uninstall).
What it renders
k8s-instrumentation/instrumentation-cr.yaml — one or more Instrumentation resources (multi-CR when the spec lists multiple).
k8s-instrumentation/workload-annotations.yaml — strategic-merge patches against spec.template.metadata.annotations (NEVER top-level metadata.annotations) for each target Deployment / StatefulSet / DaemonSet.
k8s-instrumentation/namespace-annotations.yaml — namespace-level inject-<lang> annotations for namespace-wide opt-in.
k8s-instrumentation/annotation-backup-configmap.yaml — owned template ConfigMap for versioned, managed-key-only rollback snapshots.
k8s-instrumentation/annotation-backup.py — reviewed transactional capture/verify/restore planner; it fails before workload mutation on kubectl, JSON, ownership, or completeness errors.
k8s-instrumentation/obi-daemonset.yaml — only when --enable-obi. Owned ServiceAccount plus digest-pinned Splunk OBI (eBPF) DaemonSet with namespace include/exclude selectors.
k8s-instrumentation/obi-lifecycle.py — exact OBI ownership/config, rollout, node/kernel coverage, bounded-log validation, and safe purge helper.
k8s-instrumentation/managed-resource-lifecycle.py — preflights every rendered Instrumentation/OBI/SCC identity before the first mutation, rejects foreign same-name objects, and uses UID/resourceVersion-bound replace/delete operations.
k8s-instrumentation/openshift-scc-obi.yaml — only when --distribution openshift and --enable-obi. SCC binding for the OBI service account.
k8s-instrumentation/apply-instrumentation.sh — CRD preflight, SCC then CR then DaemonSet apply, webhook readiness wait.
k8s-instrumentation/apply-annotations.sh — resolve and merge multi-language targets, transactionally snapshot every managed key, verify the committed backup, then strategic-merge-patch and restart.
k8s-instrumentation/uninstall.sh — refuse missing/corrupt/incomplete snapshots, restore only rendered managed keys, restart, and optionally purge owned OBI resources and CRs.
k8s-instrumentation/injection-audit.py — standalone fail-closed audit engine shared by rendered diagnostics.
k8s-instrumentation/verify-injection.sh — deep check for one or all rendered workloads (exact managed annotations, CR binding, init/sidecar evidence, OTLP env, and language hook).
k8s-instrumentation/status.sh — one-shot snapshot of CRs, MutatingWebhookConfiguration, operator pod.
k8s-instrumentation/list-instrumented.sh — runs the same deep drift audit for every rendered target before printing the inventory.
k8s-instrumentation/preflight-report.md — human-readable preflight verdict.
discovery/workloads.yaml and discovery/base-collector-probe.json — only when --discover-workloads.
runbook.md — ordered operator workflow from render through verify and optional uninstall.
handoff-collector.sh — guidance to run splunk-observability-otel-collector-setup first if CRDs are absent.
handoff-native-ops.spec.yaml — starter APM detectors spec for splunk-observability-native-ops.
handoff-dashboard-builder.spec.yaml — APM topology dashboard spec for splunk-observability-dashboard-builder.
metadata.json — spec digest, preflight verdicts, warning list, rendered file list, target workload list, and namespace-level injection contracts. Workload targets are consumed by --target-all on apply/uninstall; workload and namespace targets are consumed by the deep live auditor.
Safety Rules
- Never ask for a Splunk Observability access token or any other credential in conversation. This skill does not accept credentials on argv or render them. The OpenTelemetry Operator resolves ingest through the
$(SPLUNK_OTEL_AGENT) env var injected by the base chart. The optional APM API validation reads a separate mode-0600 User API access-token file through SPLUNK_O11Y_TOKEN_FILE; an ingest-only Org token is not sufficient for that read API.
- Reject direct token flags such as
--access-token, --token, --bearer-token, --api-token, --o11y-token, --sf-token, --hec-token, --platform-hec-token, --api-key. Ingest-token handling delegates to the base collector; the read-only APM probe accepts only the dedicated file path from SPLUNK_O11Y_TOKEN_FILE.
- Reject secret-like keys or values in specs,
--extra-env, resource attributes, headers, and endpoints (token, HEC, Bearer, Authorization, password, API-key, or Secret material). OTLP URLs must be credential-free HTTP(S) URLs with an explicit port and no userinfo, query, or fragment.
- Image-pull secrets for private registries mirroring
ghcr.io/signalfx/* are passed by name (--image-pull-secret <name>); the operator creates the Kubernetes Secret itself and this skill never touches that material.
- Mutating operations are gated:
--apply-instrumentation, --apply-annotations, and --uninstall-instrumentation require --accept-auto-instrumentation; CR changes can affect already-annotated workloads on their next restart, while annotation apply/uninstall forces restarts immediately. --apply-instrumentation with --enable-obi also requires --accept-obi-privileged.
- Every live validation or mutation requires
--kube-context <name>. Operators who intentionally use kubectl's current context must say so with --allow-current-context; the two flags are mutually exclusive. Non-mutating --dry-run previews do not require either acknowledgement.
- Cluster name is always explicit. This offline renderer never guesses an EKS/GKE/OpenShift identity.
- Operator installation controls (watch namespaces, certificate mode, installation job, or a purported multi-instrumentation feature gate) and vendor webhook detection are not implemented by this overlay. Supplying those legacy inputs fails closed; configure/audit them in the base collector workflow.
- Rendered mutations are repeatable and fail closed on missing preconditions (helm release, CRDs, or an owned complete backup). Annotation apply/uninstall intentionally triggers a new rollout on every invocation and is therefore operationally disruptive even when the annotation values are unchanged.
- Same-name Instrumentation, OBI ServiceAccount/DaemonSet, and OpenShift SCC objects are never adopted implicitly. Apply preflights the full set before its first write; existing objects must carry the exact skill ownership labels, and replacements/deletes are bound to the live UID and resourceVersion. Backup purge requires
--target-all, exact snapshot-key coverage, and a UID/resourceVersion-bound ConfigMap delete.
Primary Workflow
Confirm the base collector + operator are installed. If not, run splunk-observability-otel-collector-setup first. The rendered handoff-collector.sh carries the exact command.
(Optional) Discover candidate workloads. This is read-only; no cluster mutation:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \
--discover-workloads \
--realm us0 \
--cluster-name prod-cluster
Then edit splunk-observability-k8s-auto-instrumentation-rendered/discovery/workloads.yaml to mark each workload with its language.
Render the overlay assets:
The CLI-only path is the default; template.example is loaded only when
explicitly passed with --spec. This prevents example workloads or policy
settings from contaminating an operator's CLI render.
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \
--render \
--realm us0 \
--cluster-name prod-cluster \
--deployment-environment prod \
--languages java,nodejs,python \
--profiling-enabled \
--runtime-metrics-enabled \
--annotate-workload Deployment/prod/payments-api=java \
--annotate-workload Deployment/prod/checkout-web=nodejs \
--annotate-workload Deployment/prod/fraud-score=python
Review splunk-observability-k8s-auto-instrumentation-rendered/:
preflight-report.md — every fail / warn / advisory finding.
runbook.md — ordered operator steps.
k8s-instrumentation/instrumentation-cr.yaml — the CRs that will be applied.
k8s-instrumentation/workload-annotations.yaml — the strategic-merge patches.
Apply the Instrumentation CR(s) first:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \
--apply-instrumentation \
--accept-auto-instrumentation \
--kube-context prod-cluster-admin
Apply annotations + rollout restart:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \
--apply-annotations \
--accept-auto-instrumentation \
--kube-context prod-cluster-admin \
--target-all
Verify injection:
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh \
--check-injection \
--kube-context prod-cluster-admin
Annotation Model
The OpenTelemetry Operator reacts to pod annotations placed at spec.template.metadata.annotations on Deployment / StatefulSet / DaemonSet objects (or at the namespace level). This skill writes strategic-merge patches that target only spec.template.metadata.annotations; it never touches top-level metadata.annotations.
Supported annotations:
instrumentation.opentelemetry.io/inject-<lang>: "true" — inject using the chart-default Instrumentation CR.
instrumentation.opentelemetry.io/inject-<lang>: "<namespace>/<crname>" — inject using a specific CR (used for multi-CR / multi-env).
instrumentation.opentelemetry.io/inject-<lang>: "false" — explicit opt-out for a specific pod.
instrumentation.opentelemetry.io/container-names: "app,sidecar" — required in Istio-enabled namespaces to avoid instrumenting the istio-proxy sidecar.
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: linux-x64 | linux-musl-x64 — Alpine vs glibc for .NET.
instrumentation.opentelemetry.io/otel-go-auto-target-exe: /path/to/binary — mandatory for Go (eBPF needs the target binary path).
See references/annotation-catalog.md for the full surface, references/annotation-surgery.md for the patching mechanics, and references/instrumentation-cr-reference.md for CR field semantics.
Namespace-level live contract
For each rendered namespace target, live validation requires the Namespace's
managed annotations to match metadata exactly. Every non-terminating pod whose
phase is not Succeeded or Failed remains in scope and must be Running,
Ready, and carry the expected language evidence. A pod-level
inject-<language>: "false" is the only exclusion and is itself audited for
stale injection artifacts. A pod-level explicit CR value remains in scope and
is validated against that rendered CR. Terminal and deleting pods are reported
as excluded. A namespace with no active pods fails closed because it provides
no production evidence.
namespace-annotations.yaml is declarative input for GitOps or a separately
reviewed kubectl apply; the imperative apply-annotations.sh target selector
continues to mutate only explicitly rendered workloads.
OBI Behavior
--enable-obi emits an owned ServiceAccount and Splunk OpenTelemetry Zero-code (OBI) DaemonSet with privileged: true, hostPath mounts for /sys/kernel/security and /sys/fs/cgroup, Linux-node selection, and a kernel-≥5.8 requirement. OBI is eBPF-based and instruments compiled binaries (Go, C, Rust) without code or annotation changes. Apply requires --accept-obi-privileged. Because this repository has no audited default for the standalone OBI container contract, render also requires --obi-image ...@sha256:<digest>; tag-only --obi-version input fails closed. On OpenShift, openshift-scc-obi.yaml renders automatically. --check-obi proves the exact digest/config, controller rollout, one Ready OBI pod on every supported Ready schedulable Linux node, and a bounded 10-minute/200-line fatal-rule log window. uninstall.sh --purge-obi verifies exact ownership/config before deleting DaemonSet, optional SCC, then ServiceAccount.
See references/obi-ebpf.md.
Multi-CR / Multi-Environment
When the spec lists more than one Instrumentation CR (e.g. different samplers for dev vs prod), each workload annotation binds to a specific CR via cr=<ns>/<crname>. The OpenTelemetry Operator supports distinct named resources; this overlay does not claim or mutate a separate chart feature gate. Multiple language rows for one workload are intentionally merged into one manifest; duplicate workload/language rows or conflicting shared annotations fail closed.
This skill always renders an explicit <namespace>/<crname> value, including
for the default CR, so cross-namespace workloads never depend on the ambiguous
bare "true" lookup. --namespace overrides every rendered CR namespace;
--instrumentation-cr-name is accepted only for a single-CR render.
Instrumentation image policy
Java, Node.js, Python, .NET, Go, and Apache HTTPD defaults are immutable
@sha256 pins copied from the base Collector skill's chart-0.158.0 audited
image ledger. Custom image overrides must also be digest-pinned. This
repository has no audited Nginx default image, so Nginx fails closed until the
operator supplies a reviewed --nginx-image ...@sha256:<digest> override.
Hand-offs
Out of scope
- Installing the base collector, operator, CRDs, or cert-manager (handled by the base collector skill).
- Linux / systemd / preload instrumentation (handled by the base collector skill).
- HEC token creation for Splunk Platform logs (handled by splunk-hec-service-setup).
- Application-side SDK wiring (manual instrumentation). This skill is zero-code-only.
- .NET Framework (Windows) auto-instrumentation — not supported by Splunk; explicitly refused.
- Modifying application container images or Dockerfiles; all injection is via the operator init container pattern.
- Splunk On-Call routing and PagerDuty handoff (see splunk-oncall-setup and splunk-observability-native-ops).
Validation
bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh
Static checks cover:
- YAML well-formedness of every rendered manifest.
workload-annotations.yaml patches target spec.template.metadata.annotations (not top-level metadata.annotations).
- Go workloads include
otel-go-auto-target-exe=.
- No
.NET Framework references anywhere.
- Rendered scripts do not echo secrets.
- CR name uniqueness.
- Every Instrumentation language image is pinned by
@sha256 and the JSON
injection contract exactly matches instrumentation-cr.yaml.
- The rendered backup and OBI helpers byte-match their reviewed source; the OBI
metadata contract exactly matches the rendered ServiceAccount/DaemonSet/SCC.
--live --check-apm <service> runs the complete production gate. It enables
webhook, Instrumentation CR, injection, backup, optional OBI, and scoped APM checks. A caller
may explicitly omit only the APM or backup gate with --skip-apm-check or
--skip-backup-check; those named skips are valid only with --live. Individual
--check-* flags remain available as narrow diagnostics.
--check-webhook — exact pinned pod-admission webhook policy/route, CA bundle,
Service and ready 9443/TCP EndpointSlice (with a legacy Endpoints fallback
only when EndpointSlice is unavailable or empty), Ready Operator pods, and recent webhook
error log scan. This proves Kubernetes routing state but does not synthesize
an admission request or perform a separate TLS handshake.
--check-instrumentation — kubectl get otelinst -A shows the rendered CRs with expected fields.
--check-injection — iterate annotated workloads and namespace contracts. Workload controllers must have observed their current generation and completed rollout; all intended active pods must be Running and Ready with exact language injection evidence, the exact rendered @sha256 init/sidecar image, and expected OTEL_* env. Namespace opt-outs and terminal/deleting exclusions follow the contract above.
--check-obi — prove the owned OBI manifest contract, digest/config identity, DaemonSet rollout, supported kernel/architecture coverage, Ready pods, and bounded fatal-rule recent logs.
--check-apm <service> — allow only a service/realm pair bound to a rendered workload in metadata.json, then probe the scoped topology for that service, deployment environment, and Kubernetes cluster.
--check-backup — every rendered workload has a versioned, owned, structurally complete managed-key snapshot.
Every requested live check is fail-closed: a missing tool, credential,
resource, injected pod, backup, API response, or exact APM service is a
validation failure. The composed AWS/EKS/O11y staging gate is documented in
../../scripts/staging/README.md.
See reference.md for the full CLI flag reference and the thirteen references/*.md annexes for deep topical documentation.
1---2name: splunk-observability-k8s-auto-instrumentation-setup3description: Use when wiring zero-code Java, Node.js, Python, .NET, Go, Apache, or Nginx instrumentation into Splunk Observability Cloud APM, adding AlwaysOn Profiling, discovering workloads, or reverting operator-managed instrumentation. Render, apply, verify, and uninstall Splunk/OpenTelemetry Operator auto-instrumentation overlays for Kubernetes workloads after the base Splunk OTel Collector skill has installed the operator and CRDs. Emits language Instrumentation CRs, workload and namespace annotations, backup ConfigMaps, Splunk OBI eBPF assets, profiling/runtime metric env vars, sampler settings, Fargate gateway paths, GitOps YAML, transactional rollback snapshots, and clean uninstall scripts.4---56# Splunk Observability Kubernetes Auto-Instrumentation78## Prerequisites910| Tool or access | Purpose | Verify |11|---|---|---|12| Bash and Python 3 | Run bundled setup and validation helpers | `bash --version && python3 --version` |13| Required product/platform access | Inspect or configure the selected target | Complete the documented preflight |14| Credential files for live modes | Keep secrets out of chat | Verify paths only |1516## Workflow Overview1718```text19┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐20│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │21└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘22```2324## When to Activate2526- Wiring zero-code Java, Node.js, Python, .NET, Go, Apache, or Nginx instrumentation into Splunk Observability Cloud27 APM, adding AlwaysOn Profiling, discovering workloads, or reverting operator-managed instrumentation.28- Preview and review the splunk observability k8s auto instrumentation setup workflow before any live apply phase.29- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.3031## Scope3233Follow the documented read-only or render-first path whenever it is available.34This skill does not imply permission to mutate live systems. Require explicit35apply flags, protected credentials, and operator review for state changes.3637## Examples3839Inspect the supported setup modes before selecting one:4041```bash42bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh --help43```4445Expected output: usage, supported modes, and required arguments are displayed46without changing the target environment.4748Inspect validation modes before running completion checks:4950```bash51bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh --help52```5354Expected output: offline, live, and completion options are displayed when the55skill supports them; help exits without mutation.5657## Troubleshooting5859| Issue | Cause | Resolution |60|---|---|---|61| Preflight fails | A required tool or access path is missing | Resolve it before rendering or applying |62| Rendered assets are incomplete | Required non-secret inputs are absent | Complete intake and render again |63| Apply is blocked | Review, credentials, or explicit acceptance is missing | Use the documented handoff |64| Validation is incomplete | Live evidence is unavailable | Record the gap and keep completion open |6566This skill configures operator-driven, zero-code application auto-instrumentation for Kubernetes workloads that send traces, metrics, and profiling to Splunk Observability Cloud.6768It is an overlay on top of [splunk-observability-otel-collector-setup](../splunk-observability-otel-collector-setup/SKILL.md). That skill installs the Splunk OTel Collector chart, which in turn installs the OpenTelemetry Operator, the `Instrumentation` / `OpenTelemetryCollector` CRDs, and (optionally) a chart-managed default `Instrumentation` custom resource. This skill takes over from there: it renders one or more fully-configured `Instrumentation` custom resources per language, writes workload annotation patches that the operator mutating webhook reacts to, and drives the full lifecycle (apply, verify, uninstall).6970## What it renders7172- `k8s-instrumentation/instrumentation-cr.yaml` — one or more `Instrumentation` resources (multi-CR when the spec lists multiple).73- `k8s-instrumentation/workload-annotations.yaml` — strategic-merge patches against `spec.template.metadata.annotations` (NEVER top-level `metadata.annotations`) for each target `Deployment` / `StatefulSet` / `DaemonSet`.74- `k8s-instrumentation/namespace-annotations.yaml` — namespace-level `inject-<lang>` annotations for namespace-wide opt-in.75- `k8s-instrumentation/annotation-backup-configmap.yaml` — owned template ConfigMap for versioned, managed-key-only rollback snapshots.76- `k8s-instrumentation/annotation-backup.py` — reviewed transactional capture/verify/restore planner; it fails before workload mutation on kubectl, JSON, ownership, or completeness errors.77- `k8s-instrumentation/obi-daemonset.yaml` — only when `--enable-obi`. Owned ServiceAccount plus digest-pinned Splunk OBI (eBPF) DaemonSet with namespace include/exclude selectors.78- `k8s-instrumentation/obi-lifecycle.py` — exact OBI ownership/config, rollout, node/kernel coverage, bounded-log validation, and safe purge helper.79- `k8s-instrumentation/managed-resource-lifecycle.py` — preflights every rendered Instrumentation/OBI/SCC identity before the first mutation, rejects foreign same-name objects, and uses UID/resourceVersion-bound replace/delete operations.80- `k8s-instrumentation/openshift-scc-obi.yaml` — only when `--distribution openshift` and `--enable-obi`. SCC binding for the OBI service account.81- `k8s-instrumentation/apply-instrumentation.sh` — CRD preflight, SCC then CR then DaemonSet apply, webhook readiness wait.82- `k8s-instrumentation/apply-annotations.sh` — resolve and merge multi-language targets, transactionally snapshot every managed key, verify the committed backup, then strategic-merge-patch and restart.83- `k8s-instrumentation/uninstall.sh` — refuse missing/corrupt/incomplete snapshots, restore only rendered managed keys, restart, and optionally purge owned OBI resources and CRs.84- `k8s-instrumentation/injection-audit.py` — standalone fail-closed audit engine shared by rendered diagnostics.85- `k8s-instrumentation/verify-injection.sh` — deep check for one or all rendered workloads (exact managed annotations, CR binding, init/sidecar evidence, OTLP env, and language hook).86- `k8s-instrumentation/status.sh` — one-shot snapshot of CRs, MutatingWebhookConfiguration, operator pod.87- `k8s-instrumentation/list-instrumented.sh` — runs the same deep drift audit for every rendered target before printing the inventory.88- `k8s-instrumentation/preflight-report.md` — human-readable preflight verdict.89- `discovery/workloads.yaml` and `discovery/base-collector-probe.json` — only when `--discover-workloads`.90- `runbook.md` — ordered operator workflow from render through verify and optional uninstall.91- `handoff-collector.sh` — guidance to run `splunk-observability-otel-collector-setup` first if CRDs are absent.92- `handoff-native-ops.spec.yaml` — starter APM detectors spec for `splunk-observability-native-ops`.93- `handoff-dashboard-builder.spec.yaml` — APM topology dashboard spec for `splunk-observability-dashboard-builder`.94- `metadata.json` — spec digest, preflight verdicts, warning list, rendered file list, target workload list, and namespace-level injection contracts. Workload targets are consumed by `--target-all` on apply/uninstall; workload and namespace targets are consumed by the deep live auditor.9596## Safety Rules9798- Never ask for a Splunk Observability access token or any other credential in conversation. This skill does not accept credentials on argv or render them. The OpenTelemetry Operator resolves ingest through the `$(SPLUNK_OTEL_AGENT)` env var injected by the base chart. The optional APM API validation reads a separate mode-0600 User API access-token file through `SPLUNK_O11Y_TOKEN_FILE`; an ingest-only Org token is not sufficient for that read API.99- Reject direct token flags such as `--access-token`, `--token`, `--bearer-token`, `--api-token`, `--o11y-token`, `--sf-token`, `--hec-token`, `--platform-hec-token`, `--api-key`. Ingest-token handling delegates to the base collector; the read-only APM probe accepts only the dedicated file path from `SPLUNK_O11Y_TOKEN_FILE`.100- Reject secret-like keys or values in specs, `--extra-env`, resource attributes, headers, and endpoints (`token`, `HEC`, `Bearer`, `Authorization`, password, API-key, or Secret material). OTLP URLs must be credential-free HTTP(S) URLs with an explicit port and no userinfo, query, or fragment.101- Image-pull secrets for private registries mirroring `ghcr.io/signalfx/*` are passed by **name** (`--image-pull-secret <name>`); the operator creates the Kubernetes Secret itself and this skill never touches that material.102- Mutating operations are gated: `--apply-instrumentation`, `--apply-annotations`, and `--uninstall-instrumentation` require `--accept-auto-instrumentation`; CR changes can affect already-annotated workloads on their next restart, while annotation apply/uninstall forces restarts immediately. `--apply-instrumentation` with `--enable-obi` also requires `--accept-obi-privileged`.103- Every live validation or mutation requires `--kube-context <name>`. Operators who intentionally use kubectl's current context must say so with `--allow-current-context`; the two flags are mutually exclusive. Non-mutating `--dry-run` previews do not require either acknowledgement.104- Cluster name is always explicit. This offline renderer never guesses an EKS/GKE/OpenShift identity.105- Operator installation controls (watch namespaces, certificate mode, installation job, or a purported multi-instrumentation feature gate) and vendor webhook detection are not implemented by this overlay. Supplying those legacy inputs fails closed; configure/audit them in the base collector workflow.106- Rendered mutations are repeatable and fail closed on missing preconditions (helm release, CRDs, or an owned complete backup). Annotation apply/uninstall intentionally triggers a new rollout on every invocation and is therefore operationally disruptive even when the annotation values are unchanged.107- Same-name Instrumentation, OBI ServiceAccount/DaemonSet, and OpenShift SCC objects are never adopted implicitly. Apply preflights the full set before its first write; existing objects must carry the exact skill ownership labels, and replacements/deletes are bound to the live UID and resourceVersion. Backup purge requires `--target-all`, exact snapshot-key coverage, and a UID/resourceVersion-bound ConfigMap delete.108109## Primary Workflow1101111. Confirm the base collector + operator are installed. If not, run [splunk-observability-otel-collector-setup](../splunk-observability-otel-collector-setup/SKILL.md) first. The rendered `handoff-collector.sh` carries the exact command.1121132. (Optional) Discover candidate workloads. This is read-only; no cluster mutation:114115 ```bash116 bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \117 --discover-workloads \118 --realm us0 \119 --cluster-name prod-cluster120 ```121122 Then edit `splunk-observability-k8s-auto-instrumentation-rendered/discovery/workloads.yaml` to mark each workload with its language.1231243. Render the overlay assets:125126 The CLI-only path is the default; `template.example` is loaded only when127 explicitly passed with `--spec`. This prevents example workloads or policy128 settings from contaminating an operator's CLI render.129130 ```bash131 bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \132 --render \133 --realm us0 \134 --cluster-name prod-cluster \135 --deployment-environment prod \136 --languages java,nodejs,python \137 --profiling-enabled \138 --runtime-metrics-enabled \139 --annotate-workload Deployment/prod/payments-api=java \140 --annotate-workload Deployment/prod/checkout-web=nodejs \141 --annotate-workload Deployment/prod/fraud-score=python142 ```1431444. Review `splunk-observability-k8s-auto-instrumentation-rendered/`:145 - `preflight-report.md` — every fail / warn / advisory finding.146 - `runbook.md` — ordered operator steps.147 - `k8s-instrumentation/instrumentation-cr.yaml` — the CRs that will be applied.148 - `k8s-instrumentation/workload-annotations.yaml` — the strategic-merge patches.1491505. Apply the Instrumentation CR(s) first:151152 ```bash153 bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \154 --apply-instrumentation \155 --accept-auto-instrumentation \156 --kube-context prod-cluster-admin157 ```1581596. Apply annotations + rollout restart:160161 ```bash162 bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/setup.sh \163 --apply-annotations \164 --accept-auto-instrumentation \165 --kube-context prod-cluster-admin \166 --target-all167 ```1681697. Verify injection:170171 ```bash172 bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh \173 --check-injection \174 --kube-context prod-cluster-admin175 ```176177## Annotation Model178179The OpenTelemetry Operator reacts to pod annotations placed at `spec.template.metadata.annotations` on Deployment / StatefulSet / DaemonSet objects (or at the namespace level). This skill writes strategic-merge patches that target **only** `spec.template.metadata.annotations`; it never touches top-level `metadata.annotations`.180181Supported annotations:182183- `instrumentation.opentelemetry.io/inject-<lang>: "true"` — inject using the chart-default Instrumentation CR.184- `instrumentation.opentelemetry.io/inject-<lang>: "<namespace>/<crname>"` — inject using a specific CR (used for multi-CR / multi-env).185- `instrumentation.opentelemetry.io/inject-<lang>: "false"` — explicit opt-out for a specific pod.186- `instrumentation.opentelemetry.io/container-names: "app,sidecar"` — required in Istio-enabled namespaces to avoid instrumenting the `istio-proxy` sidecar.187- `instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: linux-x64 | linux-musl-x64` — Alpine vs glibc for .NET.188- `instrumentation.opentelemetry.io/otel-go-auto-target-exe: /path/to/binary` — mandatory for Go (eBPF needs the target binary path).189190See [references/annotation-catalog.md](references/annotation-catalog.md) for the full surface, [references/annotation-surgery.md](references/annotation-surgery.md) for the patching mechanics, and [references/instrumentation-cr-reference.md](references/instrumentation-cr-reference.md) for CR field semantics.191192### Namespace-level live contract193194For each rendered namespace target, live validation requires the Namespace's195managed annotations to match metadata exactly. Every non-terminating pod whose196phase is not `Succeeded` or `Failed` remains in scope and must be Running,197Ready, and carry the expected language evidence. A pod-level198`inject-<language>: "false"` is the only exclusion and is itself audited for199stale injection artifacts. A pod-level explicit CR value remains in scope and200is validated against that rendered CR. Terminal and deleting pods are reported201as excluded. A namespace with no active pods fails closed because it provides202no production evidence.203204`namespace-annotations.yaml` is declarative input for GitOps or a separately205reviewed `kubectl apply`; the imperative `apply-annotations.sh` target selector206continues to mutate only explicitly rendered workloads.207208## OBI Behavior209210`--enable-obi` emits an owned ServiceAccount and Splunk OpenTelemetry Zero-code (OBI) DaemonSet with `privileged: true`, `hostPath` mounts for `/sys/kernel/security` and `/sys/fs/cgroup`, Linux-node selection, and a kernel-≥5.8 requirement. OBI is eBPF-based and instruments compiled binaries (Go, C, Rust) without code or annotation changes. Apply requires `--accept-obi-privileged`. Because this repository has no audited default for the standalone OBI container contract, render also requires `--obi-image ...@sha256:<digest>`; tag-only `--obi-version` input fails closed. On OpenShift, `openshift-scc-obi.yaml` renders automatically. `--check-obi` proves the exact digest/config, controller rollout, one Ready OBI pod on every supported Ready schedulable Linux node, and a bounded 10-minute/200-line fatal-rule log window. `uninstall.sh --purge-obi` verifies exact ownership/config before deleting DaemonSet, optional SCC, then ServiceAccount.211212See [references/obi-ebpf.md](references/obi-ebpf.md).213214## Multi-CR / Multi-Environment215216When the spec lists more than one `Instrumentation` CR (e.g. different samplers for dev vs prod), each workload annotation binds to a specific CR via `cr=<ns>/<crname>`. The OpenTelemetry Operator supports distinct named resources; this overlay does not claim or mutate a separate chart feature gate. Multiple language rows for one workload are intentionally merged into one manifest; duplicate workload/language rows or conflicting shared annotations fail closed.217218This skill always renders an explicit `<namespace>/<crname>` value, including219for the default CR, so cross-namespace workloads never depend on the ambiguous220bare `"true"` lookup. `--namespace` overrides every rendered CR namespace;221`--instrumentation-cr-name` is accepted only for a single-CR render.222223## Instrumentation image policy224225Java, Node.js, Python, .NET, Go, and Apache HTTPD defaults are immutable226`@sha256` pins copied from the base Collector skill's chart-0.158.0 audited227image ledger. Custom image overrides must also be digest-pinned. This228repository has no audited Nginx default image, so Nginx fails closed until the229operator supplies a reviewed `--nginx-image ...@sha256:<digest>` override.230231## Hand-offs232233- Base collector + operator + CRDs: [splunk-observability-otel-collector-setup](../splunk-observability-otel-collector-setup/SKILL.md). Run first.234- Starter APM detectors: [splunk-observability-native-ops](../splunk-observability-native-ops/SKILL.md). Consume `handoff-native-ops.spec.yaml`.235- APM topology dashboards: [splunk-observability-dashboard-builder](../splunk-observability-dashboard-builder/SKILL.md). Consume `handoff-dashboard-builder.spec.yaml`.236237## Out of scope238239- Installing the base collector, operator, CRDs, or cert-manager (handled by the base collector skill).240- Linux / systemd / preload instrumentation (handled by the base collector skill).241- HEC token creation for Splunk Platform logs (handled by [splunk-hec-service-setup](../splunk-hec-service-setup/SKILL.md)).242- Application-side SDK wiring (manual instrumentation). This skill is zero-code-only.243- .NET Framework (Windows) auto-instrumentation — not supported by Splunk; explicitly refused.244- Modifying application container images or Dockerfiles; all injection is via the operator init container pattern.245- Splunk On-Call routing and PagerDuty handoff (see [splunk-oncall-setup](../splunk-oncall-setup/SKILL.md) and [splunk-observability-native-ops](../splunk-observability-native-ops/SKILL.md)).246247## Validation248249```bash250bash skills/splunk-observability-k8s-auto-instrumentation-setup/scripts/validate.sh251```252253Static checks cover:254255- YAML well-formedness of every rendered manifest.256- `workload-annotations.yaml` patches target `spec.template.metadata.annotations` (not top-level `metadata.annotations`).257- Go workloads include `otel-go-auto-target-exe=`.258- No `.NET Framework` references anywhere.259- Rendered scripts do not echo secrets.260- CR name uniqueness.261- Every Instrumentation language image is pinned by `@sha256` and the JSON262 injection contract exactly matches `instrumentation-cr.yaml`.263- The rendered backup and OBI helpers byte-match their reviewed source; the OBI264 metadata contract exactly matches the rendered ServiceAccount/DaemonSet/SCC.265266`--live --check-apm <service>` runs the complete production gate. It enables267webhook, Instrumentation CR, injection, backup, optional OBI, and scoped APM checks. A caller268may explicitly omit only the APM or backup gate with `--skip-apm-check` or269`--skip-backup-check`; those named skips are valid only with `--live`. Individual270`--check-*` flags remain available as narrow diagnostics.271272- `--check-webhook` — exact pinned pod-admission webhook policy/route, CA bundle,273 Service and ready 9443/TCP EndpointSlice (with a legacy Endpoints fallback274 only when EndpointSlice is unavailable or empty), Ready Operator pods, and recent webhook275 error log scan. This proves Kubernetes routing state but does not synthesize276 an admission request or perform a separate TLS handshake.277- `--check-instrumentation` — `kubectl get otelinst -A` shows the rendered CRs with expected fields.278- `--check-injection` — iterate annotated workloads and namespace contracts. Workload controllers must have observed their current generation and completed rollout; all intended active pods must be Running and Ready with exact language injection evidence, the exact rendered `@sha256` init/sidecar image, and expected `OTEL_*` env. Namespace opt-outs and terminal/deleting exclusions follow the contract above.279- `--check-obi` — prove the owned OBI manifest contract, digest/config identity, DaemonSet rollout, supported kernel/architecture coverage, Ready pods, and bounded fatal-rule recent logs.280- `--check-apm <service>` — allow only a service/realm pair bound to a rendered workload in `metadata.json`, then probe the scoped topology for that service, deployment environment, and Kubernetes cluster.281- `--check-backup` — every rendered workload has a versioned, owned, structurally complete managed-key snapshot.282283Every requested live check is fail-closed: a missing tool, credential,284resource, injected pod, backup, API response, or exact APM service is a285validation failure. The composed AWS/EKS/O11y staging gate is documented in286[`../../scripts/staging/README.md`](../../scripts/staging/README.md).287288See [reference.md](reference.md) for the full CLI flag reference and the thirteen `references/*.md` annexes for deep topical documentation.