1 //go:build go1.18
2 // +build go1.18
3 4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // Licensed under the MIT License.
6 7 package azidentity
8 9 import (
10 "context"
11 "fmt"
12 "strings"
13 14 "github.com/Azure/azure-sdk-for-go/sdk/azcore"
15 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
16 "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
17 )
18 19 const credNameManagedIdentity = "ManagedIdentityCredential"
20 21 type managedIdentityIDKind int
22 23 const (
24 miClientID managedIdentityIDKind = iota
25 miObjectID
26 miResourceID
27 )
28 29 // ManagedIDKind identifies the ID of a managed identity as either a client or resource ID
30 type ManagedIDKind interface {
31 fmt.Stringer
32 idKind() managedIdentityIDKind
33 }
34 35 // ClientID is the client ID of a user-assigned managed identity. [NewManagedIdentityCredential]
36 // returns an error when a ClientID is specified on the following platforms:
37 //
38 // - Azure Arc
39 // - Cloud Shell
40 // - Service Fabric
41 type ClientID string
42 43 func (ClientID) idKind() managedIdentityIDKind {
44 return miClientID
45 }
46 47 // String returns the string value of the ID.
48 func (c ClientID) String() string {
49 return string(c)
50 }
51 52 // ObjectID is the object ID of a user-assigned managed identity. [NewManagedIdentityCredential]
53 // returns an error when an ObjectID is specified on the following platforms:
54 //
55 // - Azure Arc
56 // - Azure ML
57 // - Cloud Shell
58 // - Service Fabric
59 type ObjectID string
60 61 func (ObjectID) idKind() managedIdentityIDKind {
62 return miObjectID
63 }
64 65 // String returns the string value of the ID.
66 func (o ObjectID) String() string {
67 return string(o)
68 }
69 70 // ResourceID is the resource ID of a user-assigned managed identity. [NewManagedIdentityCredential]
71 // returns an error when a ResourceID is specified on the following platforms:
72 //
73 // - Azure Arc
74 // - Azure ML
75 // - Cloud Shell
76 // - Service Fabric
77 type ResourceID string
78 79 func (ResourceID) idKind() managedIdentityIDKind {
80 return miResourceID
81 }
82 83 // String returns the string value of the ID.
84 func (r ResourceID) String() string {
85 return string(r)
86 }
87 88 // ManagedIdentityCredentialOptions contains optional parameters for ManagedIdentityCredential.
89 type ManagedIdentityCredentialOptions struct {
90 azcore.ClientOptions
91 92 // ID of a managed identity the credential should authenticate. Set this field to use a specific identity instead of
93 // the hosting environment's default. The value may be the identity's client, object, or resource ID.
94 // NewManagedIdentityCredential returns an error when the hosting environment doesn't support user-assigned managed
95 // identities, or the specified kind of ID.
96 ID ManagedIDKind
97 98 // dac indicates whether the credential is part of DefaultAzureCredential. When true, and the environment doesn't have
99 // configuration for a specific managed identity API, the credential tries to determine whether IMDS is available before
100 // sending its first token request. It does this by sending a malformed request with a short timeout. Any response to that
101 // request is taken to mean IMDS is available, in which case the credential will send ordinary token requests thereafter
102 // with no special timeout. The purpose of this behavior is to prevent a very long timeout when IMDS isn't available.
103 dac bool
104 }
105 106 // ManagedIdentityCredential authenticates an [Azure managed identity] in any hosting environment supporting managed identities.
107 // This credential authenticates a system-assigned identity by default. Use ManagedIdentityCredentialOptions.ID to specify a
108 // user-assigned identity.
109 //
110 // [Azure managed identity]: https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
111 type ManagedIdentityCredential struct {
112 mic *managedIdentityClient
113 }
114 115 // NewManagedIdentityCredential creates a ManagedIdentityCredential. Pass nil to accept default options.
116 func NewManagedIdentityCredential(options *ManagedIdentityCredentialOptions) (*ManagedIdentityCredential, error) {
117 if options == nil {
118 options = &ManagedIdentityCredentialOptions{}
119 }
120 mic, err := newManagedIdentityClient(options)
121 if err != nil {
122 return nil, err
123 }
124 return &ManagedIdentityCredential{mic: mic}, nil
125 }
126 127 // GetToken requests an access token from the hosting environment. This method is called automatically by Azure SDK clients.
128 func (c *ManagedIdentityCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
129 var err error
130 ctx, endSpan := runtime.StartSpan(ctx, credNameManagedIdentity+"."+traceOpGetToken, c.mic.azClient.Tracer(), nil)
131 defer func() { endSpan(err) }()
132 133 if len(opts.Scopes) != 1 {
134 err = fmt.Errorf("%s.GetToken() requires exactly one scope", credNameManagedIdentity)
135 return azcore.AccessToken{}, err
136 }
137 // managed identity endpoints require a v1 resource (i.e. token audience), not a v2 scope, so we remove "/.default" here
138 opts.Scopes = []string{strings.TrimSuffix(opts.Scopes[0], defaultSuffix)}
139 return c.mic.GetToken(ctx, opts)
140 }
141 142 var _ azcore.TokenCredential = (*ManagedIdentityCredential)(nil)
143