-
Notifications
You must be signed in to change notification settings - Fork 1
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 AuthN support using Nested Cred #30
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,19 +27,27 @@ var ( | |
// swagger.Credentials object can represent either system or user-assigned managed identity | ||
type CredentialsObject struct { | ||
swagger.CredentialsObject | ||
cloud string | ||
} | ||
|
||
type UserAssignedIdentities struct { | ||
CredentialsObject | ||
// NestedCredentialsObject is a wrapper around the swagger.NestedCredentialsObject to add additional functionality | ||
// swagger.NestedCredentials object can represent only user-assigned managed identity | ||
type NestedCredentialsObject struct { | ||
swagger.NestedCredentialsObject | ||
cloud string | ||
} | ||
|
||
// Constructor for UserAssignedIdentities object | ||
func NewUserAssignedIdentities(c CredentialsObject, cloud string) (*UserAssignedIdentities, error) { | ||
// Constructor for Credentials Object UserAssignedIdentities | ||
func NewCredentialsObjectUAIdentities(c CredentialsObject, cloud string) (*CredentialsObject, error) { | ||
if !c.IsUserAssigned() { | ||
return nil, errNoUserAssignedMSIs | ||
} | ||
return &UserAssignedIdentities{CredentialsObject: c, cloud: cloud}, nil | ||
return &CredentialsObject{CredentialsObject: c.CredentialsObject, cloud: cloud}, nil | ||
} | ||
|
||
// Constructor for Nested Credentials Object UserAssignedIdentities | ||
func NewNestedCredentialsObjectUAIdentities(c swagger.NestedCredentialsObject, cloud string) (*NestedCredentialsObject, error) { | ||
return &NestedCredentialsObject{NestedCredentialsObject: c, cloud: cloud}, nil | ||
} | ||
|
||
// This method may be used by clients to check if they can use the object as a user-assigned managed identity | ||
|
@@ -48,30 +56,52 @@ func (c CredentialsObject) IsUserAssigned() bool { | |
return len(c.ExplicitIdentities) > 0 | ||
} | ||
|
||
// Get an AzIdentity credential for the given user-assigned identity resource ID | ||
// Get an AzIdentity credential for the given credential object user-assigned identity resource ID | ||
// Clients can use the credential to get a token for the user-assigned identity | ||
func (u UserAssignedIdentities) GetCredential(requestedResourceID string) (*azidentity.ClientCertificateCredential, error) { | ||
func (c CredentialsObject) GetCredential(requestedResourceID string) (*azidentity.ClientCertificateCredential, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's go ahead and implement this interface instead:
We know that reloading the value from disk is critically important and every client will need to do it. A method off of a credentials object that returns a static There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (The higher-level construct should take a path as input and can use the code you have here as the implementation for loading the credential. Look at the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I already see an implementation of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We chatted about this out-of-band but just for posterity - no, it doesn't, since the code here is loading the credential once, and what clients will need is to refresh it from disk when it changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To recap requirements after talking with HyperShift and CS. It would be useful to have the following functions:
If you want to separate the implementation of these out into PRs that's fine, and if so I'd suggest working on the one for CS first as CS will leverage this functionality first. cc @miguelsorianod and @bryan-cox There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this PR implements the first of the two you listed, so we can merge it in and tackle the second next. @gouthamMN does that sound like a good plan to you? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stevekuznetsov - Yes, it's better to have the 2nd functionality implemented in a separate. |
||
requestedARMResourceID, err := arm.ParseResourceID(requestedResourceID) | ||
if err != nil { | ||
return nil, fmt.Errorf("%w for requested resource ID %s: %w", errParseResourceID, requestedResourceID, err) | ||
} | ||
requestedResourceID = requestedARMResourceID.String() | ||
|
||
for _, id := range u.ExplicitIdentities { | ||
for _, id := range c.ExplicitIdentities { | ||
if id != nil && id.ResourceID != nil { | ||
idARMResourceID, err := arm.ParseResourceID(*id.ResourceID) | ||
if err != nil { | ||
return nil, fmt.Errorf("%w for identity resource ID %s: %w", errParseResourceID, *id.ResourceID, err) | ||
} | ||
if requestedResourceID == idARMResourceID.String() { | ||
return getClientCertificateCredential(*id, u.cloud) | ||
return getClientCertificateCredential(*id, c.cloud) | ||
} | ||
} | ||
} | ||
|
||
return nil, errResourceIDNotFound | ||
} | ||
|
||
// Get an AzIdentity credential for the given nested credential object user-assigned identity resource ID | ||
// Clients can use the credential to get a token for the user-assigned identity | ||
func (n NestedCredentialsObject) GetCredential(requestedResourceID string) (*azidentity.ClientCertificateCredential, error) { | ||
requestedARMResourceID, err := arm.ParseResourceID(requestedResourceID) | ||
if err != nil { | ||
return nil, fmt.Errorf("%w for requested resource ID %s: %w", errParseResourceID, requestedResourceID, err) | ||
} | ||
requestedResourceID = requestedARMResourceID.String() | ||
|
||
if n.ResourceID != nil { | ||
idARMResourceID, err := arm.ParseResourceID(*n.ResourceID) | ||
if err != nil { | ||
return nil, fmt.Errorf("%w for identity resource ID %s: %w", errParseResourceID, *n.ResourceID, err) | ||
} | ||
if requestedResourceID == idARMResourceID.String() { | ||
return getClientCertificateCredential(n.NestedCredentialsObject, n.cloud) | ||
} | ||
} | ||
|
||
return nil, errResourceIDNotFound | ||
} | ||
|
||
func getAzCoreCloud(cloud string) azcloud.Configuration { | ||
switch cloud { | ||
case AzureUSGovCloud: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised to see an exported member field set by a constructor - either omit the constructor and export all the members or hide them and close over object initialization with the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to omit the constructor and export all the members.