Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AzureAD oauth for application registrations #2152

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Main (unreleased)

### Features

- Add `azuread.oauth` to `prometheus.remote_write` to support Azure AD authentication applicaion. (@callumau)

- Add `add_cloudwatch_timestamp` to `prometheus.exporter.cloudwatch` metrics. (@captncraig)

- Add support to `prometheus.operator.servicemonitors` to allow `endpointslice` role. (@yoyosir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ endpoint > oauth2 | [oauth2][] | Configure OAuth2 for authenticating to the endp
endpoint > oauth2 > tls_config | [tls_config][] | Configure TLS settings for connecting to the endpoint. | no
endpoint > sigv4 | [sigv4][] | Configure AWS Signature Verification 4 for authenticating to the endpoint. | no
endpoint > azuread | [azuread][] | Configure AzureAD for authenticating to the endpoint. | no
endpoint > azuread > managed_identity | [managed_identity][] | Configure Azure user-assigned managed identity. | yes
endpoint > azuread > managed_identity | [managed_identity][] | Configure Azure user-assigned managed identity. | no
endpoint > azuread > oauth | [oauth][] | Configure Azure application authenication. | no
endpoint > tls_config | [tls_config][] | Configure TLS settings for connecting to the endpoint. | no
endpoint > queue_config | [queue_config][] | Configuration for how metrics are batched before sending. | no
endpoint > metadata_config | [metadata_config][] | Configuration for how metric metadata is sent. | no
Expand All @@ -72,6 +73,7 @@ basic_auth` refers to a `basic_auth` block defined inside an
[sigv4]: #sigv4-block
[azuread]: #azuread-block
[managed_identity]: #managed_identity-block
[oauth]: #oauth-block
[tls_config]: #tls_config-block
[queue_config]: #queue_config-block
[metadata_config]: #metadata_config-block
Expand Down Expand Up @@ -151,6 +153,10 @@ metrics fails.

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

### oauth block

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

### tls_config block

{{< docs/shared lookup="reference/components/tls-config-block.md" source="alloy" version="<ALLOY_VERSION>" >}}
Expand Down
25 changes: 25 additions & 0 deletions docs/sources/shared/reference/components/oauth-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
canonical: https://grafana.com/docs/alloy/latest/shared/reference/components/oauth-block/
description: Shared content, oauth block
headless: true
---

Name | Type | Description | Default | Required
------------|----------|---------------------------------------------------------|---------|---------
`client_id` | `string` | Client ID of the Microsoft authenication application used to authenticate. | | yes
`client_secret` | `string` | Client secret of the Microsoft authenication application used to authenticate. | | yes
`tenant_id` | `string` | Tenant ID of the Microsoft authenication application used to authenticate. | | yes
callumau marked this conversation as resolved.
Show resolved Hide resolved

`client_id` should be a valid [UUID][] in one of the supported formats:
* `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
* `urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
* Microsoft encoding: `{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`
* Raw hex encoding: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

`tenant_id` should be a valid [UUID][] in one of the supported formats:
* `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
* `urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
* Microsoft encoding: `{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`
* Raw hex encoding: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

[UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier
66 changes: 62 additions & 4 deletions internal/component/prometheus/remotewrite/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,41 @@ type ManagedIdentityConfig struct {
ClientID string `alloy:"client_id,attr"`
}

func (m ManagedIdentityConfig) toPrometheusType() azuread.ManagedIdentityConfig {
return azuread.ManagedIdentityConfig{
func (m ManagedIdentityConfig) toPrometheusType() *azuread.ManagedIdentityConfig {
if m.ClientID == "" {
return nil
}

return &azuread.ManagedIdentityConfig{
ClientID: m.ClientID,
}
}

// Azure AD oauth
type AzureOAuthConfig struct {
// AzureADOAuth is the OAuth configuration that is being used to authenticate.
ClientID string `alloy:"client_id,attr"`
ClientSecret string `alloy:"client_secret,attr"`
TenantID string `alloy:"tenant_id,attr"`
}

func (m AzureOAuthConfig) toPrometheusType() *azuread.OAuthConfig {
if m.ClientID == "" && m.ClientSecret == "" && m.TenantID == "" {
return nil
}

return &azuread.OAuthConfig{
ClientID: m.ClientID,
ClientSecret: m.ClientSecret,
TenantID: m.TenantID,
}
}

type AzureADConfig struct {
// ManagedIdentity is the managed identity that is being used to authenticate.
ManagedIdentity ManagedIdentityConfig `alloy:"managed_identity,block"`
ManagedIdentity ManagedIdentityConfig `alloy:"managed_identity,block,optional"`
// OAuth is the OAuth configuration that is being used to authenticate.
OAuth AzureOAuthConfig `alloy:"oauth,block,optional"`

// Cloud is the Azure cloud in which the service is running. Example: AzurePublic/AzureGovernment/AzureChina.
Cloud string `alloy:"cloud,attr,optional"`
Expand All @@ -298,6 +324,36 @@ func (a *AzureADConfig) Validate() error {
return fmt.Errorf("the provided Azure Managed Identity client_id provided is invalid")
}

// Validate OAuth if it is provided
callumau marked this conversation as resolved.
Show resolved Hide resolved
// if a.OAuth != "" {
// if a.OAuth.TenantID == "" {
// return fmt.Errorf("OAuth TenantID must not be empty")
// }
// if a.OAuth.ClientSecret == "" {
// return fmt.Errorf("OAuth ClientSecret must not be empty")
// }
// }

// // Validate ManagedIdentity if it is provided
// if a.ManagedIdentity != nil {
// if a.ManagedIdentity.ClientID == "" {
// return fmt.Errorf("ManagedIdentity ClientID must not be empty")
// }
// }

// // Validate OAuth if it is provided
// if a.OAuth != nil {
// if a.OAuth.ClientID == "" {
// return fmt.Errorf("OAuth ClientID must not be empty")
// }
// if a.OAuth.TenantID == "" {
// return fmt.Errorf("OAuth TenantID must not be empty")
// }
// if a.OAuth.ClientSecret == "" {
// return fmt.Errorf("OAuth ClientSecret must not be empty")
// }
// }

return nil
}

Expand All @@ -314,8 +370,10 @@ func (a *AzureADConfig) toPrometheusType() *azuread.AzureADConfig {
}

mangedIdentity := a.ManagedIdentity.toPrometheusType()
oauth := a.OAuth.toPrometheusType()
return &azuread.AzureADConfig{
ManagedIdentity: &mangedIdentity,
OAuth: oauth,
ManagedIdentity: mangedIdentity,
Cloud: a.Cloud,
}
}
Expand Down
44 changes: 44 additions & 0 deletions internal/component/prometheus/remotewrite/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,32 @@ func TestAlloyConfig(t *testing.T) {
}
}),
},
{
testName: "AzureAD_Oauth",
cfg: `
endpoint {
url = "http://0.0.0.0:11111/api/v1/write"

azuread {
cloud = "AzureChina"
oauth {
client_id = "00000000-0000-0000-0000-000000000000"
tenant_id = "00000000-0000-0000-0000-000000000001"
client_secret = "00000000-0000-0000-0000-000000000002"
}
}
}`,
expectedCfg: expectedCfg(func(c *config.Config) {
c.RemoteWriteConfigs[0].AzureADConfig = &azuread.AzureADConfig{
Cloud: "AzureChina",
OAuth: &azuread.OAuthConfig{
ClientID: "00000000-0000-0000-0000-000000000000",
ClientSecret: "00000000-0000-0000-0000-000000000002",
TenantID: "00000000-0000-0000-0000-000000000001",
},
}
}),
},
{
testName: "SigV4_Defaults",
cfg: `
Expand Down Expand Up @@ -223,6 +249,24 @@ func TestAlloyConfig(t *testing.T) {
}`,
errorMsg: "at most one of sigv4, azuread, basic_auth, oauth2, bearer_token & bearer_token_file must be configured",
},
{
testName: "TooManyAuthAzureAD",
cfg: `
endpoint {
url = "http://0.0.0.0:11111/api/v1/write"

sigv4 {}
azuread {
managed_identity {
client_id = "00000000-0000-0000-0000-000000000000"
}
oauth {
client_id = "00000000-0000-0000-0000-000000000000"
}
}
}`,
errorMsg: "at most oauth or managed identity must be configured for azuread",
},
{
testName: "BadAzureClientId",
cfg: `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,26 @@ func toAzureAD(azureADConfig *azuread.AzureADConfig) *remotewrite.AzureADConfig
return nil
}

return &remotewrite.AzureADConfig{
Cloud: azureADConfig.Cloud,
ManagedIdentity: remotewrite.ManagedIdentityConfig{
var oauth remotewrite.AzureOAuthConfig
var managedIdentity remotewrite.ManagedIdentityConfig

if azureADConfig.OAuth != nil {
oauth = remotewrite.AzureOAuthConfig{
ClientID: azureADConfig.OAuth.ClientID,
ClientSecret: azureADConfig.OAuth.ClientSecret,
TenantID: azureADConfig.OAuth.TenantID,
}
}

if azureADConfig.ManagedIdentity != nil {
managedIdentity = remotewrite.ManagedIdentityConfig{
ClientID: azureADConfig.ManagedIdentity.ClientID,
},
}
}

return &remotewrite.AzureADConfig{
Cloud: azureADConfig.Cloud,
ManagedIdentity: managedIdentity,
OAuth: oauth,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,23 @@ prometheus.remote_write "metrics_test7_azuread_explicit" {
}
}
}

prometheus.remote_write "metrics_test8_azuread_appauth" {
endpoint {
name = "test8_azuread_appauth-1654c7"
url = "http://localhost:9012/api/prom/push"

queue_config { }

metadata_config { }

azuread {
oauth {
client_id = "00000000-0000-0000-0000-000000000000"
client_secret = "fake_client_secret"
tenant_id = "00000000-0000-0000-0000-000000000000"
}
cloud = "AzureGovernment"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ metrics:
cloud: AzureGovernment
managed_identity:
client_id: 00000000-0000-0000-0000-000000000000
- name: "test8_azuread_appauth"
remote_write:
- url: http://localhost:9012/api/prom/push
azuread:
cloud: AzureGovernment
oauth:
client_id: 00000000-0000-0000-0000-000000000000
client_secret: fake_client_secret
tenant_id: 00000000-0000-0000-0000-000000000000

Loading