Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/otelcontribcol/builder-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extensions:
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/asapauthextension v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsproxy v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/azureauthextension v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/awssecretsmanagerauthextension v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.152.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/datadogextension v0.152.0
Expand Down
153 changes: 153 additions & 0 deletions extension/awssecretsmanagerauthextension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# AWS Secrets Manager Auth Extension

| Status | |
| ------------- |-----------|
| Stability | [development] |
| Distributions | [contrib] |

[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib

This extension implements both `extensionauth.Server` and `extensionauth.Client` to authenticate receivers and exporters using HTTP Basic Auth, with credentials sourced from [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) and automatically rotated at a configurable interval.

The extension uses the default AWS credential chain (environment variables, `~/.aws/credentials`, EC2/ECS/EKS IAM roles). No explicit AWS credentials are required in the collector config.

When a new secret version is detected, credentials are swapped atomically with no restart required. If a fetch fails, the extension logs a warning and continues using the last known credentials.

When used as a server authenticator, a successful authentication exposes the following attributes on `client.Info.Auth`:

- `username`: The authenticated username.
- `raw`: Raw base64-encoded credentials.

## Modes

Exactly one of `htpasswd` or `client_auth` must be set.

### Server authentication (`htpasswd`)

The secret value is treated as [htpasswd](https://httpd.apache.org/docs/current/programs/htpasswd.html) file content. All hash formats supported by the [`go-htpasswd`](https://github.com/tg123/go-htpasswd) library are accepted (bcrypt, SHA, MD5, APR1, etc.).

If `value_key` is set, the secret must be a JSON object and the value at that key is used as the htpasswd content. If `value_key` is empty, the entire secret string is used as-is.

### Client authentication (`client_auth`)

The secret must be a JSON object. `username_key` and `password_key` identify which fields to use (both default to `"username"` and `"password"`).

## Configuration

| Field | Required | Default | Description |
|---|---|---|---|
| `secret_arn` | yes | | ARN or name of the secret in AWS Secrets Manager |
| `refresh_interval` | yes | `30s` | How often to poll for a new secret version |
| `htpasswd.value_key` | no | `""` | JSON key holding htpasswd content; if empty the raw secret string is used |
| `client_auth.username_key` | no | `"username"` | JSON key for the username |
| `client_auth.password_key` | no | `"password"` | JSON key for the password |

## Examples

### Client authenticator — outbound requests

Secret value in AWS Secrets Manager:
```json
{"username": "alice", "password": "s3cr3t"}
```

Collector config:
```yaml
extensions:
awssecretsmanagerauth/client:
secret_arn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-exporter-creds"
refresh_interval: 30s
client_auth: {} # uses "username" and "password" keys by default

exporters:
otlp:
endpoint: https://my-collector.example.com:4317
auth:
authenticator: awssecretsmanagerauth/client

service:
extensions: [awssecretsmanagerauth/client]
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [otlp]
```

### Client authenticator — custom JSON key names

Secret value:
```json
{"user": "alice", "pass": "s3cr3t"}
```

```yaml
extensions:
awssecretsmanagerauth/client:
secret_arn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-creds"
refresh_interval: 60s
client_auth:
username_key: user
password_key: pass
```

### Server authenticator — inbound requests (raw htpasswd)

Secret value (raw htpasswd content):
```
alice:$2y$05$abcdefghijklmnopqrstuuVGnzYyZ1mBkYHpURsB7L9J2jl5Rp2Cy
bob:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
```

```yaml
extensions:
awssecretsmanagerauth/server:
secret_arn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-htpasswd"
refresh_interval: 30s
htpasswd: {} # uses the entire secret string as htpasswd content

receivers:
otlp:
protocols:
http:
auth:
authenticator: awssecretsmanagerauth/server

service:
extensions: [awssecretsmanagerauth/server]
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [debug]
```

### Server authenticator — htpasswd stored as a JSON field

Secret value:
```json
{"htpasswd": "alice:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g="}
```

```yaml
extensions:
awssecretsmanagerauth/server:
secret_arn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-htpasswd-json"
refresh_interval: 30s
htpasswd:
value_key: htpasswd
```

## Rotation

The extension polls AWS Secrets Manager every `refresh_interval`. AWS rotates secrets by publishing a new secret version; the extension detects the new `VersionId` and swaps credentials atomically without restarting the collector.

To rotate manually:
```bash
aws secretsmanager put-secret-value \
--secret-id "my-exporter-creds" \
--secret-string '{"username":"alice","password":"newpassword"}'
```

The collector will pick up the new credentials within one `refresh_interval`.
75 changes: 75 additions & 0 deletions extension/awssecretsmanagerauthextension/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package awssecretsmanagerauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awssecretsmanagerauthextension"

import (
"errors"
"fmt"
"time"
)

var (
errNoCredentialSource = errors.New("no credential source provided")
errMultipleAuthenticators = errors.New("only one of `htpasswd` or `client_auth` can be specified")
)

// HtpasswdSettings configures server-side authentication. The secret value is
// treated as htpasswd file content. If ValueKey is set, the secret must be a
// JSON object and the value at that key is used as the htpasswd content.
type HtpasswdSettings struct {
// ValueKey is the JSON key in the secret whose value contains the htpasswd content.
// If empty, the entire secret string is used as-is.
ValueKey string `mapstructure:"value_key"`
// prevent unkeyed literal initialization
_ struct{}
}

// ClientAuthSettings configures client-side authentication. The secret must be
// a JSON object. UsernameKey and PasswordKey identify which fields to use.
type ClientAuthSettings struct {
// UsernameKey is the JSON key whose value is used as the username.
// Defaults to "username".
UsernameKey string `mapstructure:"username_key"`
// PasswordKey is the JSON key whose value is used as the password.
// Defaults to "password".
PasswordKey string `mapstructure:"password_key"`
// prevent unkeyed literal initialization
_ struct{}
}

// Config defines the configuration for the awssecretsmanagerauth extension.
type Config struct {
// SecretARN is the ARN or name of the secret in AWS Secrets Manager.
SecretARN string `mapstructure:"secret_arn"`
// RefreshInterval controls how often the extension polls for a new secret version.
RefreshInterval time.Duration `mapstructure:"refresh_interval"`
// Htpasswd configures server-side (inbound) authentication.
// Exactly one of Htpasswd or ClientAuth must be set.
Htpasswd *HtpasswdSettings `mapstructure:"htpasswd,omitempty"`
// ClientAuth configures client-side (outbound) authentication.
// Exactly one of Htpasswd or ClientAuth must be set.
ClientAuth *ClientAuthSettings `mapstructure:"client_auth,omitempty"`
// prevent unkeyed literal initialization
_ struct{}
}

func (cfg *Config) Validate() error {
if cfg.SecretARN == "" {
return errors.New("secret_arn must not be empty")
}
if cfg.RefreshInterval <= 0 {
return fmt.Errorf("refresh_interval must be positive, got %s", cfg.RefreshInterval)
}

serverSet := cfg.Htpasswd != nil
clientSet := cfg.ClientAuth != nil

if serverSet && clientSet {
return errMultipleAuthenticators
}
if !serverSet && !clientSet {
return errNoCredentialSource
}
return nil
}
7 changes: 7 additions & 0 deletions extension/awssecretsmanagerauthextension/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// Package awssecretsmanagerauthextension provides an authenticator extension
// that sources HTTP Basic Auth credentials from AWS Secrets Manager and
// periodically rotates them at a configurable interval.
package awssecretsmanagerauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awssecretsmanagerauthextension"
Loading
Loading