mirror of
https://github.com/prometheus/prometheus.git
synced 2026-06-09 00:22:19 -04:00
Merge pull request #18217 from bragi92/main
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests for 32-bit x86 (push) Waiting to run
CI / Go tests for Prometheus upgrades and downgrades (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Compliance testing (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
govulncheck / Run govulncheck (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests for 32-bit x86 (push) Waiting to run
CI / Go tests for Prometheus upgrades and downgrades (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Compliance testing (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
govulncheck / Run govulncheck (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
remote_write : Add Certificate support for ingesting data into an Azure Monitor Workspace
This commit is contained in:
commit
d0db9b693c
11 changed files with 200 additions and 2 deletions
|
|
@ -3831,6 +3831,18 @@ azuread:
|
|||
[ client_secret: <string> ]
|
||||
[ tenant_id: <string> ] ]
|
||||
|
||||
# Azure Certificate-based authentication.
|
||||
[ certificate:
|
||||
client_id: <string>
|
||||
tenant_id: <string>
|
||||
certificate_path: <file_name>
|
||||
# Optional path to private key file if separate from certificate
|
||||
[ certificate_key_path: <file_name> ]
|
||||
# Optional password for password-protected certificate files (PFX/PKCS12)
|
||||
[ certificate_password: <secret> ]
|
||||
# Whether to send the certificate chain in the x5c header
|
||||
[ send_certificate_chain: <boolean> | default = false ] ]
|
||||
|
||||
# Azure SDK auth.
|
||||
# See https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication
|
||||
[ sdk:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -88,6 +89,30 @@ type SDKConfig struct {
|
|||
TenantID string `yaml:"tenant_id,omitempty"`
|
||||
}
|
||||
|
||||
// CertificateConfig is used to store azure certificate-based authentication config values.
|
||||
type CertificateConfig struct {
|
||||
// ClientID is the clientId of the azure active directory application that is being used to authenticate.
|
||||
ClientID string `yaml:"client_id,omitempty"`
|
||||
|
||||
// TenantID is the tenantId of the azure active directory application that is being used to authenticate.
|
||||
TenantID string `yaml:"tenant_id,omitempty"`
|
||||
|
||||
// CertificatePath is the path to the certificate file (PEM or PFX format).
|
||||
CertificatePath string `yaml:"certificate_path,omitempty"`
|
||||
|
||||
// CertificateKeyPath is the path to the private key file (PEM format).
|
||||
// This is optional and only needed if the certificate and key are in separate files.
|
||||
CertificateKeyPath string `yaml:"certificate_key_path,omitempty"`
|
||||
|
||||
// CertificatePassword is the password for the certificate file (for PFX files).
|
||||
// This is optional and only needed if the certificate file is password-protected.
|
||||
CertificatePassword config_util.Secret `yaml:"certificate_password,omitempty"`
|
||||
|
||||
// SendCertificateChain controls whether to include x5c header in assertion to support
|
||||
// subject name / issuer-based authentication.
|
||||
SendCertificateChain bool `yaml:"send_certificate_chain,omitempty"`
|
||||
}
|
||||
|
||||
// AzureADConfig is used to store the config values.
|
||||
type AzureADConfig struct { //nolint:revive // exported.
|
||||
// ManagedIdentity is the managed identity that is being used to authenticate.
|
||||
|
|
@ -102,6 +127,9 @@ type AzureADConfig struct { //nolint:revive // exported.
|
|||
// SDK is the SDK config that is being used to authenticate.
|
||||
SDK *SDKConfig `yaml:"sdk,omitempty"`
|
||||
|
||||
// Certificate is the certificate config that is being used to authenticate.
|
||||
Certificate *CertificateConfig `yaml:"certificate,omitempty"`
|
||||
|
||||
// Cloud is the Azure cloud in which the service is running. Example: AzurePublic/AzureGovernment/AzureChina.
|
||||
Cloud string `yaml:"cloud,omitempty"`
|
||||
|
||||
|
|
@ -151,9 +179,12 @@ func (c *AzureADConfig) Validate() error {
|
|||
if c.SDK != nil {
|
||||
authenticators++
|
||||
}
|
||||
if c.Certificate != nil {
|
||||
authenticators++
|
||||
}
|
||||
|
||||
if authenticators == 0 {
|
||||
return errors.New("must provide an Azure Managed Identity, Azure Workload Identity, Azure OAuth or Azure SDK in the Azure AD config")
|
||||
return errors.New("must provide an Azure Managed Identity, Azure Workload Identity, Azure OAuth, Azure Certificate or Azure SDK in the Azure AD config")
|
||||
}
|
||||
if authenticators > 1 {
|
||||
return errors.New("cannot provide multiple authentication methods in the Azure AD config")
|
||||
|
|
@ -215,6 +246,25 @@ func (c *AzureADConfig) Validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if c.Certificate != nil {
|
||||
if c.Certificate.ClientID == "" {
|
||||
return errors.New("must provide an Azure Certificate client_id in the Azure AD config")
|
||||
}
|
||||
if c.Certificate.TenantID == "" {
|
||||
return errors.New("must provide an Azure Certificate tenant_id in the Azure AD config")
|
||||
}
|
||||
if c.Certificate.CertificatePath == "" {
|
||||
return errors.New("must provide an Azure Certificate certificate_path in the Azure AD config")
|
||||
}
|
||||
|
||||
if _, err := uuid.Parse(c.Certificate.ClientID); err != nil {
|
||||
return errors.New("the provided Azure Certificate client_id is invalid")
|
||||
}
|
||||
if _, err := regexp.MatchString("^[0-9a-zA-Z-.]+$", c.Certificate.TenantID); err != nil {
|
||||
return errors.New("the provided Azure Certificate tenant_id is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
if c.Scope != "" {
|
||||
if matched, err := regexp.MatchString("^[\\w\\s:/.\\-]+$", c.Scope); err != nil || !matched {
|
||||
return errors.New("the provided scope contains invalid characters")
|
||||
|
|
@ -325,6 +375,21 @@ func newTokenCredential(cfg *AzureADConfig) (azcore.TokenCredential, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if cfg.Certificate != nil {
|
||||
certificateConfig := &CertificateConfig{
|
||||
ClientID: cfg.Certificate.ClientID,
|
||||
TenantID: cfg.Certificate.TenantID,
|
||||
CertificatePath: cfg.Certificate.CertificatePath,
|
||||
CertificateKeyPath: cfg.Certificate.CertificateKeyPath,
|
||||
CertificatePassword: cfg.Certificate.CertificatePassword,
|
||||
SendCertificateChain: cfg.Certificate.SendCertificateChain,
|
||||
}
|
||||
cred, err = newCertificateTokenCredential(clientOpts, certificateConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return cred, nil
|
||||
}
|
||||
|
||||
|
|
@ -367,6 +432,46 @@ func newSDKTokenCredential(clientOpts *azcore.ClientOptions, sdkConfig *SDKConfi
|
|||
return azidentity.NewDefaultAzureCredential(opts)
|
||||
}
|
||||
|
||||
// newCertificateTokenCredential returns new certificate-based token credential.
|
||||
func newCertificateTokenCredential(clientOpts *azcore.ClientOptions, certConfig *CertificateConfig) (azcore.TokenCredential, error) {
|
||||
certData, err := os.ReadFile(certConfig.CertificatePath)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read certificate file " + certConfig.CertificatePath + ": " + err.Error())
|
||||
}
|
||||
|
||||
// If a separate key file is provided, append it to the cert data so ParseCertificates can find the private key.
|
||||
if certConfig.CertificateKeyPath != "" {
|
||||
keyData, err := os.ReadFile(certConfig.CertificateKeyPath)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read private key file " + certConfig.CertificateKeyPath + ": " + err.Error())
|
||||
}
|
||||
certData = append(append(certData, '\n'), keyData...)
|
||||
}
|
||||
|
||||
var password []byte
|
||||
if certConfig.CertificatePassword != "" {
|
||||
password = []byte(certConfig.CertificatePassword)
|
||||
}
|
||||
|
||||
certs, key, err := azidentity.ParseCertificates(certData, password)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to parse certificate data: " + err.Error())
|
||||
}
|
||||
|
||||
opts := &azidentity.ClientCertificateCredentialOptions{
|
||||
ClientOptions: *clientOpts,
|
||||
SendCertificateChain: certConfig.SendCertificateChain,
|
||||
}
|
||||
|
||||
return azidentity.NewClientCertificateCredential(
|
||||
certConfig.TenantID,
|
||||
certConfig.ClientID,
|
||||
certs,
|
||||
key,
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
||||
// newTokenProvider helps to fetch accessToken for different types of credential. This also takes care of
|
||||
// refreshing the accessToken before expiry. This accessToken is attached to the Authorization header while making requests.
|
||||
func newTokenProvider(cfg *AzureADConfig, cred azcore.TokenCredential) (*tokenProvider, error) {
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ func TestAzureAdConfig(t *testing.T) {
|
|||
// Missing managedidentity or oauth field.
|
||||
{
|
||||
filename: "testdata/azuread_bad_configmissing.yaml",
|
||||
err: "must provide an Azure Managed Identity, Azure Workload Identity, Azure OAuth or Azure SDK in the Azure AD config",
|
||||
err: "must provide an Azure Managed Identity, Azure Workload Identity, Azure OAuth, Azure Certificate or Azure SDK in the Azure AD config",
|
||||
},
|
||||
// Invalid managedidentity client id.
|
||||
{
|
||||
|
|
@ -232,6 +232,43 @@ func TestAzureAdConfig(t *testing.T) {
|
|||
{
|
||||
filename: "testdata/azuread_good_oauth_customscope.yaml",
|
||||
},
|
||||
// Valid certificate config.
|
||||
{
|
||||
filename: "testdata/azuread_good_certificate.yaml",
|
||||
},
|
||||
// Valid certificate config with separate key file.
|
||||
{
|
||||
filename: "testdata/azuread_good_certificate_with_key.yaml",
|
||||
},
|
||||
// Valid certificate config with PFX.
|
||||
{
|
||||
filename: "testdata/azuread_good_certificate_pfx.yaml",
|
||||
},
|
||||
// Missing certificate client id.
|
||||
{
|
||||
filename: "testdata/azuread_bad_certificate_missingclientid.yaml",
|
||||
err: "must provide an Azure Certificate client_id in the Azure AD config",
|
||||
},
|
||||
// Missing certificate tenant id.
|
||||
{
|
||||
filename: "testdata/azuread_bad_certificate_missingtenantid.yaml",
|
||||
err: "must provide an Azure Certificate tenant_id in the Azure AD config",
|
||||
},
|
||||
// Missing certificate path.
|
||||
{
|
||||
filename: "testdata/azuread_bad_certificate_missingpath.yaml",
|
||||
err: "must provide an Azure Certificate certificate_path in the Azure AD config",
|
||||
},
|
||||
// Invalid certificate client id.
|
||||
{
|
||||
filename: "testdata/azuread_bad_certificate_invalidclientid.yaml",
|
||||
err: "the provided Azure Certificate client_id is invalid",
|
||||
},
|
||||
// Invalid config when both certificate and oauth is provided.
|
||||
{
|
||||
filename: "testdata/azuread_bad_certificate_oauth.yaml",
|
||||
err: "cannot provide multiple authentication methods in the Azure AD config",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
_, err := loadAzureAdConfig(c.filename)
|
||||
|
|
|
|||
5
storage/remote/azuread/testdata/azuread_bad_certificate_invalidclientid.yaml
vendored
Normal file
5
storage/remote/azuread/testdata/azuread_bad_certificate_invalidclientid.yaml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: invalid-client-id
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingclientid.yaml
vendored
Normal file
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingclientid.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingpath.yaml
vendored
Normal file
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingpath.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingtenantid.yaml
vendored
Normal file
4
storage/remote/azuread/testdata/azuread_bad_certificate_missingtenantid.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
9
storage/remote/azuread/testdata/azuread_bad_certificate_oauth.yaml
vendored
Normal file
9
storage/remote/azuread/testdata/azuread_bad_certificate_oauth.yaml
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
oauth:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
client_secret: Cl1ent$ecret!
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
5
storage/remote/azuread/testdata/azuread_good_certificate.yaml
vendored
Normal file
5
storage/remote/azuread/testdata/azuread_good_certificate.yaml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
6
storage/remote/azuread/testdata/azuread_good_certificate_pfx.yaml
vendored
Normal file
6
storage/remote/azuread/testdata/azuread_good_certificate_pfx.yaml
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pfx
|
||||
certificate_password: P@ssw0rd!
|
||||
7
storage/remote/azuread/testdata/azuread_good_certificate_with_key.yaml
vendored
Normal file
7
storage/remote/azuread/testdata/azuread_good_certificate_with_key.yaml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
cloud: AzurePublic
|
||||
certificate:
|
||||
client_id: 00000000-0000-0000-0000-000000000000
|
||||
tenant_id: 00000000-a12b-3cd4-e56f-000000000000
|
||||
certificate_path: /path/to/certificate.pem
|
||||
certificate_key_path: /path/to/key.pem
|
||||
send_certificate_chain: true
|
||||
Loading…
Reference in a new issue