👁 Image
README
¶
Kubernetes Service Account Auth Extension
| Status | |
|---|---|
| Stability | development |
| Distributions | |
| Issues | 👁 Open issues 👁 Closed issues |
Overview
This extension implements server-side authentication for the OpenTelemetry Collector using Kubernetes service account tokens with RBAC (Role-Based Access Control) authorization. It validates incoming bearer tokens against the Kubernetes API and checks if the authenticated service account has permission to perform a specified action on a resource.
How It Works
The extension performs two-step authentication and authorization:
-
Token Validation: Uses the Kubernetes TokenReview API to validate that the bearer token is a legitimate Kubernetes service account token.
-
RBAC Authorization: Uses the Kubernetes SubjectAccessReview API to check if the authenticated service account has permission to perform the configured action on the specified resource.
Configuration
Parameters
-
auth_type(default:serviceAccount): How to authenticate to the Kubernetes API server. Options:serviceAccount: Use the service account token mounted in the podkubeConfig: Use credentials from~/.kube/confignone: No authentication (insecure, for testing only)
-
resource_attributes(required): Defines the Kubernetes resource and action to check for authorizationgroup(optional): API group of the resource (e.g.,"opentelemetry.io")version(optional): API version (e.g.,"v1")resource(required): Resource type to check (e.g.,"collector")verb(required): Action to authorize (e.g.,"export")namespace(optional): Namespace for namespaced resources. Empty means cluster-scoped.name(optional): Specific resource name. Empty means any resource of this type.
-
header(default:"Authorization"): HTTP header name containing the bearer token -
scheme(default:"Bearer"): Authentication scheme prefix -
audiences(default:["https://kubernetes.default.svc"]): The token must contain one of these audiences. The default works with standard Kubernetes service account. The recommended approach is to use a custom audience with a projected service account token with a defined audience.
Example Configuration
extensions:
k8ssaauth:
# Kubernetes API configuration
auth_type: serviceAccount
# RBAC check configuration
resource_attributes:
group: "telemetry.opentelemetry.io"
version: "v1"
resource: "telemetry"
verb: "export"
namespace: "observability" # Optional: check permissions in specific namespace
name: "mytelemetry" # Optional: check permissions for a specific resource
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
auth:
authenticator: k8ssaauth
http:
endpoint: 0.0.0.0:4318
auth:
authenticator: k8ssaauth
service:
extensions: [k8ssaauth]
pipelines:
traces:
receivers: [otlp]
exporters: [...]
metrics:
receivers: [otlp]
exporters: [...]
Kubernetes Setup
1. Create Custom Resource Definition (Optional)
If using a custom resource for semantic authorization:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: collectors.opentelemetry.io
spec:
group: opentelemetry.io
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
scope: Namespaced
names:
plural: collectors
singular: collector
kind: Collector
2. Create RBAC Resources
Create a Role (or ClusterRole for cluster-wide permissions):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: telemetry-exporter
namespace: observability
rules:
- apiGroups: ["opentelemetry.io"]
resources: ["collectors"]
verbs: ["export"] # Custom verb for semantic clarity
3. Create RoleBinding
Bind the role to service accounts that should be allowed to send telemetry:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-telemetry-exporter
namespace: observability
subjects:
- kind: ServiceAccount
name: my-app
namespace: default
roleRef:
kind: Role
name: telemetry-exporter
apiGroup: rbac.authorization.k8s.io
4. Collector Deployment
The collector needs permissions to perform TokenReview and SubjectAccessReview:
apiVersion: v1
kind: ServiceAccount
metadata:
name: otel-collector
namespace: observability
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: otel-collector-auth
rules:
- apiGroups: ["authentication.k8s.io"]
resources: ["tokenreviews"]
verbs: ["create"]
- apiGroups: ["authorization.k8s.io"]
resources: ["subjectaccessreviews"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: otel-collector-auth
subjects:
- kind: ServiceAccount
name: otel-collector
namespace: observability
roleRef:
kind: ClusterRole
name: otel-collector-auth
apiGroup: rbac.authorization.k8s.io
Client Configuration
Applications sending telemetry to the collector must include their service account token in the Authorization header:
Go Example
import (
"context"
"os"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
// Read service account token
token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
// handle error
}
// Create interceptor to add token to requests
authInterceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+string(token))
return invoker(ctx, method, req, reply, cc, opts...)
}
// Create exporter with auth
exporter, err := otlptracegrpc.New(
context.Background(),
otlptracegrpc.WithEndpoint("otel-collector.observability.svc.cluster.local:4317"),
otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")),
otlptracegrpc.WithDialOption(grpc.WithUnaryInterceptor(authInterceptor)),
)
Python Example
import os
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Read service account token
with open('/var/run/secrets/kubernetes.io/serviceaccount/token', 'r') as f:
token = f.read().strip()
# Create exporter with auth headers
exporter = OTLPSpanExporter(
endpoint="otel-collector.observability.svc.cluster.local:4317",
headers={"authorization": f"Bearer {token}"},
)
# Setup tracer
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(exporter))
Use Cases
- Multi-Tenant Observability - Ensure that applications can only send telemetry data if they have the appropriate RBAC permissions, preventing unauthorized data injection.
- Namespace Isolation - Configure different RBAC rules per namespace to isolate telemetry data between teams or environments.
- Audit Trail - Leverage Kubernetes audit logs to track which service accounts are sending telemetry data.
- Zero-Trust Security - Implement defense-in-depth by requiring both network policies and RBAC authorization for telemetry ingestion.
Security Considerations
-
Token Rotation: Service account tokens are automatically rotated by Kubernetes. Ensure your applications reload tokens periodically.
-
TLS: Always use TLS for the collector endpoints when using bearer token authentication.
-
Least Privilege: Grant only the minimum required permissions to service accounts.
-
Token audience: Use a projected service account token with a defined audience so that tokens used for authorizing export aren't trusted by the Kubernetes API to perform other actions.
Troubleshooting
Authentication Failures
Check collector logs for detailed error messages:
kubectl logs -n observability deployment/otel-collector | grep k8ssaauth
Common issues:
- "missing or empty authorization header": Client not sending token
- "token is not authenticated": Invalid or expired token
- "permission denied": Service account lacks required RBAC permissions
Verify RBAC Configuration
Test if a service account has the required permissions:
kubectl auth can-i export telemetries.telemetry.opentelemetry.io \
--as=system:serviceaccount:default:my-app \
-n observability
Debug Mode
Enable debug logging in the collector to see detailed authentication flow:
service:
telemetry:
logs:
level: debug
References
👁 Image
Documentation
¶
Overview ¶
Package k8ssaauthextension implements an extension that validates Kubernetes service account tokens and checks RBAC permissions for incoming requests.
This extension uses the Kubernetes TokenReview API to validate bearer tokens and the SubjectAccessReview API to verify that the authenticated service account has permission to perform a specified action on a resource.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewFactory ¶
NewFactory creates a factory for the Kubernetes service account authenticator extension.
Types ¶
type Config ¶
type Config struct {
k8sconfig.APIConfig `mapstructure:",squash"`
// ResourceAttributes defines what resource and action to check for authorization
ResourceAttributes ResourceAttributes `mapstructure:"resource_attributes"`
// Header specifies the auth-header for the token. Defaults to "Authorization"
Header string `mapstructure:"header,omitempty"`
// Scheme specifies the auth-scheme for the token. Defaults to "Bearer"
Scheme string `mapstructure:"scheme,omitempty"`
// Audiences specifies the expected audiences in the token.
// Defaults to ["https://kubernetes.default.svc"].
Audiences []string `mapstructure:"audiences,omitempty"`
}
Config specifies the configuration for the Kubernetes service account token authenticator
type ResourceAttributes ¶
type ResourceAttributes struct {
// Group is the API group of the resource (e.g., "telemetry.opentelemetry.io")
Group string `mapstructure:"group"`
// Version is the API version of the resource (e.g., "v1")
Version string `mapstructure:"version"`
// Resource is the resource type (e.g., "telemetry")
Resource string `mapstructure:"resource"`
// Verb is the action to check (e.g., "export", "create", "get")
Verb string `mapstructure:"verb"`
// Namespace is the namespace to check permissions in. Empty string means cluster-scoped.
Namespace string `mapstructure:"namespace,omitempty"`
// Name is the specific resource name to check. Empty string means any resource of this type.
Name string `mapstructure:"name,omitempty"`
}
ResourceAttributes defines the Kubernetes resource and action to check for authorization
