discovery: add support for Managed Identity authentication in Azure SD (#4590)

Signed-off-by: Marcel Juhnke <marrat@marrat.de>
This commit is contained in:
Marcel D. Juhnke 2018-12-19 11:03:33 +01:00 committed by Brian Brazil
parent fb8479a677
commit c7d83b2b6a
5 changed files with 83 additions and 40 deletions

View File

@ -444,13 +444,14 @@ var expectedConf = &Config{
ServiceDiscoveryConfig: sd_config.ServiceDiscoveryConfig{ ServiceDiscoveryConfig: sd_config.ServiceDiscoveryConfig{
AzureSDConfigs: []*azure.SDConfig{ AzureSDConfigs: []*azure.SDConfig{
{ {
Environment: "AzurePublicCloud", Environment: "AzurePublicCloud",
SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11", SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
TenantID: "BBBB222B-B2B2-2B22-B222-2BB2222BB2B2", TenantID: "BBBB222B-B2B2-2B22-B222-2BB2222BB2B2",
ClientID: "333333CC-3C33-3333-CCC3-33C3CCCCC33C", ClientID: "333333CC-3C33-3333-CCC3-33C3CCCCC33C",
ClientSecret: "mysecret", ClientSecret: "mysecret",
RefreshInterval: model.Duration(5 * time.Minute), AuthenticationMethod: "OAuth",
Port: 9100, RefreshInterval: model.Duration(5 * time.Minute),
Port: 9100,
}, },
}, },
}, },
@ -769,6 +770,10 @@ var expectedErrors = []struct {
filename: "azure_tenant_id_missing.bad.yml", filename: "azure_tenant_id_missing.bad.yml",
errMsg: "Azure SD configuration requires a tenant_id", errMsg: "Azure SD configuration requires a tenant_id",
}, },
{
filename: "azure_authentication_method.bad.yml",
errMsg: "Unknown authentication_type \"invalid\". Supported types are \"OAuth\" or \"ManagedIdentity\"",
},
{ {
filename: "empty_scrape_config.bad.yml", filename: "empty_scrape_config.bad.yml",
errMsg: "empty or null scrape config section", errMsg: "empty or null scrape config section",

View File

@ -0,0 +1,4 @@
scrape_configs:
- azure_sd_configs:
- authentication_method: invalid
subscription_id: 11AAAA11-A11A-111A-A111-1111A1111A11

View File

@ -196,6 +196,7 @@ scrape_configs:
- job_name: service-azure - job_name: service-azure
azure_sd_configs: azure_sd_configs:
- environment: AzurePublicCloud - environment: AzurePublicCloud
authentication_method: OAuth
subscription_id: 11AAAA11-A11A-111A-A111-1111A1111A11 subscription_id: 11AAAA11-A11A-111A-A111-1111A1111A11
tenant_id: BBBB222B-B2B2-2B22-B222-2BB2222BB2B2 tenant_id: BBBB222B-B2B2-2B22-B222-2BB2222BB2B2
client_id: 333333CC-3C33-3333-CCC3-33C3CCCCC33C client_id: 333333CC-3C33-3333-CCC3-33C3CCCCC33C

View File

@ -26,13 +26,11 @@ import (
"github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/azure"
"github.com/go-kit/kit/log" "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level" "github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/util/strutil" "github.com/prometheus/prometheus/util/strutil"
) )
@ -47,6 +45,9 @@ const (
azureLabelMachinePrivateIP = azureLabel + "machine_private_ip" azureLabelMachinePrivateIP = azureLabel + "machine_private_ip"
azureLabelMachineTag = azureLabel + "machine_tag_" azureLabelMachineTag = azureLabel + "machine_tag_"
azureLabelMachineScaleSet = azureLabel + "machine_scale_set" azureLabelMachineScaleSet = azureLabel + "machine_scale_set"
authMethodOAuth = "OAuth"
authMethodManagedIdentity = "ManagedIdentity"
) )
var ( var (
@ -63,21 +64,23 @@ var (
// DefaultSDConfig is the default Azure SD configuration. // DefaultSDConfig is the default Azure SD configuration.
DefaultSDConfig = SDConfig{ DefaultSDConfig = SDConfig{
Port: 80, Port: 80,
RefreshInterval: model.Duration(5 * time.Minute), RefreshInterval: model.Duration(5 * time.Minute),
Environment: azure.PublicCloud.Name, Environment: azure.PublicCloud.Name,
AuthenticationMethod: authMethodOAuth,
} }
) )
// SDConfig is the configuration for Azure based service discovery. // SDConfig is the configuration for Azure based service discovery.
type SDConfig struct { type SDConfig struct {
Environment string `yaml:"environment,omitempty"` Environment string `yaml:"environment,omitempty"`
Port int `yaml:"port"` Port int `yaml:"port"`
SubscriptionID string `yaml:"subscription_id"` SubscriptionID string `yaml:"subscription_id"`
TenantID string `yaml:"tenant_id,omitempty"` TenantID string `yaml:"tenant_id,omitempty"`
ClientID string `yaml:"client_id,omitempty"` ClientID string `yaml:"client_id,omitempty"`
ClientSecret config_util.Secret `yaml:"client_secret,omitempty"` ClientSecret config_util.Secret `yaml:"client_secret,omitempty"`
RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"`
AuthenticationMethod string `yaml:"authentication_method,omitempty"`
} }
func validateAuthParam(param, name string) error { func validateAuthParam(param, name string) error {
@ -95,18 +98,27 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
if err != nil { if err != nil {
return err return err
} }
if err = validateAuthParam(c.SubscriptionID, "subscription_id"); err != nil { if err = validateAuthParam(c.SubscriptionID, "subscription_id"); err != nil {
return err return err
} }
if err = validateAuthParam(c.TenantID, "tenant_id"); err != nil {
return err if c.AuthenticationMethod == authMethodOAuth {
if err = validateAuthParam(c.TenantID, "tenant_id"); err != nil {
return err
}
if err = validateAuthParam(c.ClientID, "client_id"); err != nil {
return err
}
if err = validateAuthParam(string(c.ClientSecret), "client_secret"); err != nil {
return err
}
} }
if err = validateAuthParam(c.ClientID, "client_id"); err != nil {
return err if c.AuthenticationMethod != authMethodOAuth && c.AuthenticationMethod != authMethodManagedIdentity {
} return fmt.Errorf("Unknown authentication_type %q. Supported types are %q or %q", c.AuthenticationMethod, authMethodOAuth, authMethodManagedIdentity)
if err = validateAuthParam(string(c.ClientSecret), "client_secret"); err != nil {
return err
} }
return nil return nil
} }
@ -186,13 +198,30 @@ func createAzureClient(cfg SDConfig) (azureClient, error) {
resourceManagerEndpoint := env.ResourceManagerEndpoint resourceManagerEndpoint := env.ResourceManagerEndpoint
var c azureClient var c azureClient
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, cfg.TenantID)
if err != nil { var spt *adal.ServicePrincipalToken
return azureClient{}, err
} switch cfg.AuthenticationMethod {
spt, err := adal.NewServicePrincipalToken(*oauthConfig, cfg.ClientID, string(cfg.ClientSecret), resourceManagerEndpoint) case authMethodManagedIdentity:
if err != nil { msiEndpoint, err := adal.GetMSIVMEndpoint()
return azureClient{}, err if err != nil {
return azureClient{}, err
}
spt, err = adal.NewServicePrincipalTokenFromMSI(msiEndpoint, resourceManagerEndpoint)
if err != nil {
return azureClient{}, err
}
case authMethodOAuth:
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, cfg.TenantID)
if err != nil {
return azureClient{}, err
}
spt, err = adal.NewServicePrincipalToken(*oauthConfig, cfg.ClientID, string(cfg.ClientSecret), resourceManagerEndpoint)
if err != nil {
return azureClient{}, err
}
} }
bearerAuthorizer := autorest.NewBearerAuthorizer(spt) bearerAuthorizer := autorest.NewBearerAuthorizer(spt)

View File

@ -274,14 +274,18 @@ See below for the configuration options for Azure discovery:
# The information to access the Azure API. # The information to access the Azure API.
# The Azure environment. # The Azure environment.
[ environment: <string> | default = AzurePublicCloud ] [ environment: <string> | default = AzurePublicCloud ]
# The subscription ID.
# The authentication method, either OAuth or ManagedIdentity.
# See https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
[ authentication_method: <string> | default = OAuth]
# The subscription ID. Always required.
subscription_id: <string> subscription_id: <string>
# The tenant ID. # Optional tenant ID. Only required with authentication_method OAuth.
tenant_id: <string> [ tenant_id: <string> ]
# The client ID. # Optional client ID. Only required with authentication_method OAuth.
client_id: <string> [ client_id: <string> ]
# The client secret. # Optional client secret. Only required with authentication_method OAuth.
client_secret: <secret> [ client_secret: <secret> ]
# Refresh interval to re-read the instance list. # Refresh interval to re-read the instance list.
[ refresh_interval: <duration> | default = 300s ] [ refresh_interval: <duration> | default = 300s ]