Closed MMollyy closed 2 weeks ago
Additionally I can confirm that it is related to the latest version:
vault write azure/roles/roletest application_object_id=### ttl=1h
Error writing data to azure/roles/roletest : Error making API request.
URL: PUT http://127.0.0.1:8200/v1/azure/roles/roletest
Code: 500. Errors:
* 1 error occurred:
* error loading Application: no application found
Vault version 1.14.8
vault write azure/roles/roletest application_object_id=### ttl=1h
Success! Data written to: azure/roles/roletest
I can confirm that it also still works in Vault version 1.15.6, where the secret engine runs on 0.16.3 So whatever got changed from 0.16.3 to 0.17.0 broke it.
I'm trying to find what might be the cause, what I can see is:
func (c *MSGraphClient) GetApplication(ctx context.Context, clientID string) (Application, error) {
filter := fmt.Sprintf("appId eq '%s'", clientID)
req := applications.ApplicationsRequestBuilderGetRequestConfiguration{
QueryParameters: &applications.ApplicationsRequestBuilderGetQueryParameters{
Filter: &filter,
},
}
resp, err := c.client.Applications().Get(ctx, &req)
if err != nil {
return Application{}, err
}
apps := resp.GetValue()
if len(apps) == 0 {
return Application{}, fmt.Errorf("no application found")
}
if len(apps) > 1 {
return Application{}, fmt.Errorf("multiple applications found - double check your client_id")
}
app := apps[0]
return getApplicationResponse(app), nil
}
In this code you are using the clientID, but in the previous code:
func (c *AppClient) GetApplication(ctx context.Context, applicationObjectID string) (ApplicationResult, error) {
The applicationObjectID is being used. The object_id and client_id for an application are not the same thing. If this change is a conscious choice it is definitely a breaking change.
So, I tried creating the role using the clientID instead of the application object ID. That results in a successfully created role, however, the subsequent API call to generate a token on the application doesn't work:
vault read azure/creds/role-name
Error reading azure/creds/role-name: Error making API request.
URL: GET http://127.0.0.1:8200/v1/azure/creds/role-name
Code: 500. Errors:
* 1 error occurred:
* error updating credentials: Resource '#SEA#$DF$%' does not exist or one of its queried reference-property objects are not present.
Which I am guessing is because here:
func (c *MSGraphClient) AddApplicationPassword(ctx context.Context, applicationObjectID string, displayName string, endDateTime time.Time) (PasswordCredential, error) {
The application object id is again being used? Which is a total mismatch with the client id.
I do not code in GO, but i asked chatgpt if it could write something. So maybe something like this:
func (c *MSGraphClient) GetApplication(ctx context.Context, applicationObjectID string) (Application, error) {
// Assuming object ID is identified by the 'id' field
filter := fmt.Sprintf("id eq '%s'", applicationObjectID)
req := applications.ApplicationsRequestBuilderGetRequestConfiguration{
QueryParameters: &applications.ApplicationsRequestBuilderGetQueryParameters{
Filter: &filter,
},
}
resp, err := c.client.Applications().Get(ctx, &req)
if err != nil {
return Application{}, err
}
apps := resp.GetValue()
if len(apps) == 0 {
return Application{}, fmt.Errorf("no application found")
}
if len(apps) > 1 {
return Application{}, fmt.Errorf("multiple applications found for the given object ID")
}
app := apps[0]
return getApplicationResponse(app), nil
}
??
So in summary:
When configuring a role in the engine static service principals are specified by setting the application_object_id:
application_object_id (string: "") - Application Object ID for an existing service principal that will be used instead of creating dynamic service principals. If present, azure_roles will be ignored. See roles docs for details on role definition.
The old code (0.16.3) did the following:
preparer := autorest.CreatePreparer(
autorest.AsContentType("application/json; charset=utf-8"),
autorest.AsGet(),
autorest.WithBaseURL(c.client.BaseURI),
autorest.WithPathParameters("/v1.0/applications/{applicationObjectId}", pathParameters),
c.client.WithAuthorization())
return preparer.Prepare((&http.Request{}).WithContext(ctx))
https://github.com/hashicorp/vault-plugin-secrets-azure/blob/v0.16.3/api/application_msgraph.go#L223
The new validation code for this attribute does an msgraph search:
filter := fmt.Sprintf("appId eq '%s'", clientID)
req := applications.ApplicationsRequestBuilderGetRequestConfiguration{
QueryParameters: &applications.ApplicationsRequestBuilderGetQueryParameters{
Filter: &filter,
},
}
https://github.com/hashicorp/vault-plugin-secrets-azure/blob/main/api/applications.go#L77
But this is a search for an application_id - not an application_object_id. As a result configuring new roles with static service principals is not possible with version 0.17+
I've attempted to fix the issue in PR #196
I think this was fixed in #200
Does this effect Vault dedicated? I am seeing the same issue.
Recently we upgraded the azure secrets engine from 0.16.1 to 0.17.0 when we upgraded our Vault from 1.14.8 to 1.16.1. It seems there is now an issue when creating new roles:
I checked the validity of the token that's in the config for the engine, it's valid and working. Since the error is 'no application found'; I tested it by using the application id, subscription id, tenant id and client secret in the config and putting it in my Postman, and performing a GET API call like so:
I also tested the creation of a new application, and a secret on the application, using Postman: Those also work. I tested the generation of a secret via the azure secrets engine: Works. So there is nothing wrong with permissions on the identity used in the config. The issue seems to be scoped to just the creation of roles into the secrets engine.
The InternalServerError seems to be coming from the engine itself, or from Vault maybe, since it fails on doing the PUT command, but then is giving an error that suggests the issue is on the AAD side.
I also looked into the Vault logs, however those do not provide any more relevant information then is already listed here.