Skip to content
Open
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 sdk/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func NewAuthorizerFromCredentials(ctx context.Context, c Credentials, api enviro
ClientId: c.ClientID,
CustomManagedIdentityEndpoint: c.CustomManagedIdentityEndpoint,
CustomManagedIdentityAPIVersion: c.CustomManagedIdentityAPIVersion,
CustomManagedIdentityHeaders: c.CustomManagedIdentityHeaders,
}
a, err := NewManagedIdentityAuthorizer(ctx, opts)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions sdk/auth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type Credentials struct {
// CustomManagedIdentityAPIVersion specifies the API version to use for IMDS.
CustomManagedIdentityAPIVersion string

// CustomManagedIdentityHeaders specifies the headers when requesting token
CustomManagedIdentityHeaders map[string][]string

// Enables OIDC authentication (federated client credentials).
EnableAuthenticationUsingOIDC bool
// OIDCAssertionToken specifies the OIDC Assertion Token to authenticate using Client Credentials.
Expand Down
28 changes: 22 additions & 6 deletions sdk/auth/managed_identity_authorizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ type ManagedIdentityAuthorizerOptions struct {
// CustomManagedIdentityAPIVersion is an optional API version to use when requesting a token.
// This is required when using an endpoint that does not support the default API version such as Azure Container Apps.
CustomManagedIdentityAPIVersion string

// CustomManagedIdentityHeaders are optional HTTP headers to use when requesting a token
// This is required when requesting from Azure Container App or Service Fabric.
CustomManagedIdentityHeaders map[string][]string
}

// NewManagedIdentityAuthorizer returns an authorizer using a Managed Identity for authentication.
Expand All @@ -40,7 +44,7 @@ func NewManagedIdentityAuthorizer(ctx context.Context, options ManagedIdentityAu
if err != nil {
return nil, fmt.Errorf("determining resource for api %q: %+v", options.Api.Name(), err)
}
conf, err := newManagedIdentityConfig(*resource, options.ClientId, options.CustomManagedIdentityEndpoint, options.CustomManagedIdentityAPIVersion)
conf, err := newManagedIdentityConfig(*resource, options.ClientId, options.CustomManagedIdentityEndpoint, options.CustomManagedIdentityAPIVersion, options.CustomManagedIdentityHeaders)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -76,7 +80,7 @@ func (a *ManagedIdentityAuthorizer) Token(ctx context.Context, _ *http.Request)

u := fmt.Sprintf("%s?%s", a.conf.MsiEndpoint, query.Encode())

body, err := azureMetadata(ctx, u)
body, err := azureMetadata(ctx, u, a.conf.MsiHeaders)
if err != nil {
return nil, fmt.Errorf("ManagedIdentityAuthorizer: failed to request token from metadata endpoint: %v", err)
}
Expand Down Expand Up @@ -133,13 +137,16 @@ type managedIdentityConfig struct {
// MsiEndpoint is the endpoint where the metadata service can be found
MsiEndpoint string

// MsiHeaders are headers to add when requesting a token from the metadata service
MsiHeaders map[string][]string

// Resource is the service for which to request an access token
Resource string
}

// newManagedIdentityConfig returns a new managedIdentityConfig with a configured metadata endpoint and resource.
// clientId and objectId can be left blank when a single managed identity is available
func newManagedIdentityConfig(resource, clientId, customManagedIdentityEndpoint string, customManagedIdentityAPIVersion string) (*managedIdentityConfig, error) {
func newManagedIdentityConfig(resource, clientId, customManagedIdentityEndpoint string, customManagedIdentityAPIVersion string, customManagedIdentityHeaders map[string][]string) (*managedIdentityConfig, error) {
endpoint := msiDefaultEndpoint
if customManagedIdentityEndpoint != "" {
endpoint = customManagedIdentityEndpoint
Expand All @@ -155,6 +162,7 @@ func newManagedIdentityConfig(resource, clientId, customManagedIdentityEndpoint
Resource: resource,
MsiApiVersion: apiVersion,
MsiEndpoint: endpoint,
MsiHeaders: customManagedIdentityHeaders,
}, nil
}

Expand All @@ -165,14 +173,22 @@ func (c *managedIdentityConfig) TokenSource(_ context.Context) (Authorizer, erro
})
}

func azureMetadata(ctx context.Context, url string) (body []byte, err error) {
func azureMetadata(ctx context.Context, url string, headers map[string][]string) (body []byte, err error) {
var req *http.Request
req, err = http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
if err != nil {
return
}
req.Header = http.Header{
"Metadata": []string{"true"},

if headers != nil {
if _, ok := headers["Metadata"]; !ok {
headers["Metadata"] = []string{"true"}
}
req.Header = headers
} else {
req.Header = http.Header{
"Metadata": []string{"true"},
}
Copy link
Copy Markdown
Contributor

@wuxu92 wuxu92 Apr 7, 2026

Choose a reason for hiding this comment

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

Suggested change
if headers != nil {
if _, ok := headers["Metadata"]; !ok {
headers["Metadata"] = []string{"true"}
}
req.Header = headers
} else {
req.Header = http.Header{
"Metadata": []string{"true"},
}
req.Header = http.Header{
"Metadata": []string{"true"},
}
for k, v := range headers {
req.Header[k] = v
}

}

var resp *http.Response
Expand Down
Loading