Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ v1.10.0
- Add the `otelcol.receiver.faro` receiver to receive traces and logs from the Grafana Faro Web SDK. (@mar4uk)

- Add entropy support for `loki.secretfilter` (@romain-gaillard)
- Add htpasswd file based authentication for `otelcol.auth.basic` (@pkarakal)

### Enhancements

Expand Down
194 changes: 188 additions & 6 deletions docs/sources/reference/components/otelcol/otelcol.auth.basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,73 @@ otelcol.auth.basic "<LABEL>" {

## Arguments

{{< admonition type="caution" >}}
The top-level `username` and `password` arguments are deprecated and should not be used for new configurations. Use
the `client_auth` block for client authentication and the `htpasswd` block for server authentication instead.
{{< /admonition >}}

You can use the following arguments with `otelcol.auth.basic`:

| Name | Type | Description | Default | Required |
| ---------- | -------- | -------------------------------------------------- | ------- | -------- |
| `password` | `secret` | Password to use for basic authentication requests. | | yes |
| `username` | `string` | Username to use for basic authentication requests. | | yes |
| Name | Type | Description | Default | Required |
|------------|----------|-----------------------------------------------------------------|---------|----------|
| `password` | `secret` | (Deprecated) Password to use for basic authentication requests. | | no |
| `username` | `string` | (Deprecated) Username to use for basic authentication requests. | | no |


## Blocks

You can use the following block with `otelcol.auth.basic`:

| Block | Description | Required |
| -------------------------------- | -------------------------------------------------------------------------- | -------- |
|----------------------------------|----------------------------------------------------------------------------|----------|
| [`client_auth`][client_auth] | Configures client authentication credentials for exporters | no |
| [`debug_metrics`][debug_metrics] | Configures the metrics that this component generates to monitor its state. | no |
| [`htpasswd`][htpasswd] | Configures server authentication using htpasswd format for receivers | no |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
|----------------------------------|----------------------------------------------------------------------------|----------|
| [`client_auth`][client_auth] | Configures client authentication credentials for exporters | no |
| [`debug_metrics`][debug_metrics] | Configures the metrics that this component generates to monitor its state. | no |
| [`htpasswd`][htpasswd] | Configures server authentication using htpasswd format for receivers | no |
|----------------------------------|----------------------------------------------------------------------------|----------|
| [`client_auth`][client_auth] | Configures client authentication credentials for exporters. | no |
| [`debug_metrics`][debug_metrics] | Configures the metrics that this component generates to monitor its state. | no |
| [`htpasswd`][htpasswd] | Configures server authentication using htpasswd format for receivers. | no |


[client_auth]: #client_auth
[debug_metrics]: #debug_metrics
[htpasswd]: #htpasswd

### `client_auth`

The `client_auth` block configures credentials that client extensions (such as exporters) will use to authenticate to servers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `client_auth` block configures credentials that client extensions (such as exporters) will use to authenticate to servers.
The `client_auth` block configures credentials that client extensions (such as exporters) use to authenticate to servers.


| Name | Type | Description | Default | Required |
|------------|----------|-----------------------------------------------------|---------|----------|
| `password` | `string` | Password to use for basic authentication requests | | yes |
| `username` | `string` | Username to use for basic authentication requests | | yes |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Name | Type | Description | Default | Required |
|------------|----------|-----------------------------------------------------|---------|----------|
| `password` | `string` | Password to use for basic authentication requests | | yes |
| `username` | `string` | Username to use for basic authentication requests | | yes |
| Name | Type | Description | Default | Required |
| ---------- | -------- | -------------------------------------------------- | ------- | -------- |
| `password` | `string` | Password to use for basic authentication requests. | | yes |
| `username` | `string` | Username to use for basic authentication requests. | | yes |


{{< admonition type="note" >}}
If both the `client_auth` block and the deprecated top-level `username` and `password` attributes are specified, the
`client_auth` block takes precedence and the top-level attributes are ignored for client authentication.
{{< /admonition >}}

### `debug_metrics`

{{< docs/shared lookup="reference/components/otelcol-debug-metrics-block.md" source="alloy" version="<ALLOY_VERSION>" >}}

### `htpasswd`

The `htpasswd` block configures how the server extensions (such as receivers) will authenticate incoming requests using
the htpasswd format.

| Name | Type | Description | Default | Required |
|----------|----------|--------------------------------------------------------------------|---------|----------|
| `file` | `string` | Path to the htpasswd file to use for basic authentication requests | `""` | no |
| `inline` | `string` | The htpasswd file content in inline format | `""` | no |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Name | Type | Description | Default | Required |
|----------|----------|--------------------------------------------------------------------|---------|----------|
| `file` | `string` | Path to the htpasswd file to use for basic authentication requests | `""` | no |
| `inline` | `string` | The htpasswd file content in inline format | `""` | no |
| Name | Type | Description | Default | Required |
| -------- | -------- | --------------------------------------------------------------------- | ------- | -------- |
| `file` | `string` | Path to the `htpasswd` file to use for basic authentication requests. | `""` | no |
| `inline` | `string` | The `htpasswd` file content in inline format. | `""` | no |


You can specify either `file`, `inline`, or both. When using `inline`, the format should be `username:password` with
each user on a new line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You can specify either `file`, `inline`, or both. When using `inline`, the format should be `username:password` with
each user on a new line.
You can specify either `file`, `inline`, or both.
When you use `inline`, the format should be `username:password` with each user on a new line.


{{< admonition type="note" >}}
When both the `htpasswd` block and the deprecated top-level `username` and `password` attributes are specified, the
deprecated credentials are automatically appended to the `inline` content. This allows authentication using credentials
from both the htpasswd configuration and the deprecated attributes.

If the same username appears in both the `file` and `inline` content, including appended deprecated credentials,
the entry in the `inline` content takes precedence.
{{< /admonition >}}

## Exported fields

The following fields are exported and can be referenced by other components:
Expand All @@ -73,8 +119,9 @@ The following fields are exported and can be referenced by other components:

`otelcol.auth.basic` doesn't expose any component-specific debug information.

## Example
## Examples

### Forward signals to exporters
This example configures [`otelcol.exporter.otlp`][otelcol.exporter.otlp] to use basic authentication:

```alloy
Expand All @@ -91,4 +138,139 @@ otelcol.auth.basic "creds" {
}
```

### Authenticating requests for receivers

These examples show how to perform basic authentication using the `client_auth` block for exporters or the `htpasswd`
block for receivers.

#### Use client authentication
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between this example and the Forward signals to exporters example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that the first (forward signals to exporters uses the deprecated username and password top-level arguments whereas this uses the new client authentication block. Since I have split this into client and server authentication examples, I think I should just move this a below Forward signals to exporters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pairing them together would be better, but similar to the other thread I'm not a fan of showing deprecated fields in config examples in most cases. Let's see what our docs team says.


This example configures [`otelcol.exporter.otlp`][otelcol.exporter.otlp] to use basic authentication using a single
username and password combination

```alloy
otelcol.receiver.otlp "example" {
grpc {
endpoint = "127.0.0.1:4317"
}

output {
metrics = [otelcol.exporter.otlp.default.input]
logs = [otelcol.exporter.otlp.default.input]
traces = [otelcol.exporter.otlp.default.input]
}
}

otelcol.exporter.otlp "default" {
client {
endpoint = "my-otlp-grpc-server:4317"
auth = otelcol.auth.basic.creds.handler
}
}

otelcol.auth.basic "creds" {
client_auth {
username = "demo"
password = sys.env("API_KEY")
}
}
```

{{< admonition type="note" >}}
To migrate from the deprecated `username` and `password` attributes, move them into the `client_auth` block for client
authentication.
{{< /admonition >}}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To migrate from the deprecated `username` and `password` attributes, move them into the `client_auth` block for client
authentication.
{{< /admonition >}}
To migrate from the deprecated `username` and `password` attributes, move them into the `client_auth` block for client authentication.
{{< /admonition >}}

#### Use htpasswd file

This example configures [`otelcol.receiver.otlp`][otelcol.receiver.otlp] to use basic authentication using an htpasswd
file containing the users to use for basic auth:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This example configures [`otelcol.receiver.otlp`][otelcol.receiver.otlp] to use basic authentication using an htpasswd
file containing the users to use for basic auth:
This example configures [`otelcol.receiver.otlp`][otelcol.receiver.otlp] to use basic authentication using an `htpasswd` file containing the users to use for basic authentication:


```alloy
otelcol.receiver.otlp "example" {
grpc {
endpoint = "127.0.0.1:4317"

auth = otelcol.auth.basic.creds.handler
}

output {
metrics = [otelcol.exporter.debug.default.input]
logs = [otelcol.exporter.debug.default.input]
traces = [otelcol.exporter.debug.default.input]
}
}

otelcol.exporter.debug "default" {}

otelcol.auth.basic "creds" {
htpasswd {
file = "/etc/alloy/.htpasswd"
}
}
```

#### Use htpasswd inline content

This example shows how to specify htpasswd content directly in the configuration:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This example shows how to specify htpasswd content directly in the configuration:
This example shows how to specify `htpasswd` content directly in the configuration:


```alloy
otelcol.receiver.otlp "example" {
grpc {
endpoint = "127.0.0.1:4317"

auth = otelcol.auth.basic.creds.handler
}

output {
metrics = [otelcol.exporter.debug.default.input]
logs = [otelcol.exporter.debug.default.input]
traces = [otelcol.exporter.debug.default.input]
}
}

otelcol.exporter.debug "default" {}

otelcol.auth.basic "creds" {
htpasswd {
inline = "user1:password1\nuser2:password2"
}
}
```

{{< admonition type="note" >}}
To make the migration from the deprecated `username` and `password` attributes easier, you can specify both the
deprecated attributes and the `htpasswd` block in the same configuration. The deprecated attributes will be appended
to the `htpasswd` content.

```alloy
otelcol.receiver.otlp "example" {
grpc {
endpoint = "127.0.0.1:4317"

auth = otelcol.auth.basic.creds.handler
}

output {
metrics = [otelcol.exporter.debug.default.input]
logs = [otelcol.exporter.debug.default.input]
traces = [otelcol.exporter.debug.default.input]
}
}

otelcol.exporter.debug "default" {}

otelcol.auth.basic "creds" {
username = "demo"
password = sys.env("API_KEY")

htpasswd {
file = "/etc/alloy/.htpasswd"
}
}
```
{{< /admonition >}}

[otelcol.receiver.otlp]: ../otelcol.receiver.otlp/
[otelcol.exporter.otlp]: ../otelcol.exporter.otlp/
95 changes: 82 additions & 13 deletions internal/component/otelcol/auth/basic/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package basic

import (
"errors"
"fmt"

"github.com/grafana/alloy/internal/component"
Expand All @@ -15,6 +16,11 @@ import (
"go.opentelemetry.io/collector/pipeline"
)

var (
errNoCredentialSource = errors.New("no credential source provided")
errNoPasswordProvided = errors.New("no password provided")
)

func init() {
component.Register(component.Registration{
Name: "otelcol.auth.basic",
Expand All @@ -29,10 +35,41 @@ func init() {
})
}

type HtpasswdConfig struct {
File string `alloy:"file,attr,optional"`
Inline string `alloy:"inline,attr,optional"`
}

func (c HtpasswdConfig) convert() *basicauthextension.HtpasswdSettings {
return &basicauthextension.HtpasswdSettings{
File: c.File,
Inline: c.Inline,
}
}

type ClientAuthConfig struct {
Username string `alloy:"username,attr"`
Password string `alloy:"password,attr"`
}

func (c ClientAuthConfig) convert() *basicauthextension.ClientAuthSettings {
if c.Username == "" && c.Password == "" {
return nil
}
return &basicauthextension.ClientAuthSettings{
Username: c.Username,
Password: configopaque.String(c.Password),
}
}

// Arguments configures the otelcol.auth.basic component.
type Arguments struct {
Username string `alloy:"username,attr"`
Password alloytypes.Secret `alloy:"password,attr"`
Username string `alloy:"username,attr,optional"` // Deprecated: Use ClientAuth instead
Password alloytypes.Secret `alloy:"password,attr,optional"` // Deprecated: Use ClientAuth instead

ClientAuth *ClientAuthConfig `alloy:"client_auth,block,optional"`

Htpasswd *HtpasswdConfig `alloy:"htpasswd,block,optional"`

// DebugMetrics configures component internal metrics. Optional.
DebugMetrics otelcolCfg.DebugMetricsArguments `alloy:"debug_metrics,block,optional"`
Expand All @@ -45,23 +82,55 @@ func (args *Arguments) SetToDefault() {
args.DebugMetrics.SetToDefault()
}

// Validate implements syntax.Validator
func (args Arguments) Validate() error {
// check if no argument was provided
if args.Username == "" && args.Password == "" && args.Htpasswd == nil && args.ClientAuth == nil {
return errNoCredentialSource
}
// the downstream basicauthextension package supports having both inline
// and htpasswd files, so we should not error out in case both are
// provided

// check if password was not provided when username is provided
if args.Username != "" && args.Password == "" {
return errNoPasswordProvided
}

return nil
}

// ConvertClient implements auth.Arguments.
func (args Arguments) ConvertClient() (otelcomponent.Config, error) {
return &basicauthextension.Config{
ClientAuth: &basicauthextension.ClientAuthSettings{
Username: args.Username,
Password: configopaque.String(args.Password),
},
}, nil
c := &basicauthextension.Config{}
// If the client config is specified, ignore the deprecated
// username and password attributes.
if args.ClientAuth != nil {
c.ClientAuth = args.ClientAuth.convert()
return c, nil
}

c.ClientAuth = &basicauthextension.ClientAuthSettings{
Username: args.Username,
Password: configopaque.String(args.Password),
}
return c, nil
}

// ConvertServer implements auth.Arguments.
func (args Arguments) ConvertServer() (otelcomponent.Config, error) {
return &basicauthextension.Config{
Htpasswd: &basicauthextension.HtpasswdSettings{
Inline: fmt.Sprintf("%s:%s", args.Username, args.Password),
},
}, nil
c := &basicauthextension.Config{
Htpasswd: &basicauthextension.HtpasswdSettings{},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be better if this is only created if args.HtpasswdFile is not empty.

}
if args.Htpasswd != nil {
c.Htpasswd = args.Htpasswd.convert()
}
// Keeping this to avoid breaking existing use cases. Remove this for v2
if args.Username != "" && args.Password != "" {
c.Htpasswd.Inline += fmt.Sprintf("\n%s:%s", args.Username, args.Password)
}

return c, nil
}

// AuthFeatures implements auth.Arguments.
Expand Down
Loading