Skip to content
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

Getting InternalServerErrors returned when creating new roles in the engine #189

Open
MMollyy opened this issue Apr 16, 2024 · 5 comments
Open

Comments

@MMollyy
Copy link

MMollyy commented Apr 16, 2024

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:

vault write azure/engine/roles/role-name \
>     application_object_id=#### \
>     ttl=1h
Error writing data to azure/engine/roles/role-name: Error making API request.

URL: PUT https://****.vault.****.com/v1/azure/engine/roles/role-name
Code: 500. Errors:

* 1 error occurred:
        * error loading Application: no application found

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:

GET {{graphurl}}/applications/####

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.

@MMollyy
Copy link
Author

MMollyy commented Apr 17, 2024

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.

@MMollyy
Copy link
Author

MMollyy commented Apr 18, 2024

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.

@MMollyy
Copy link
Author

MMollyy commented Apr 18, 2024

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
}

??

sspans-sbp added a commit to sspans-sbp/vault-plugin-secrets-azure that referenced this issue Apr 24, 2024
sspans-sbp added a commit to sspans-sbp/vault-plugin-secrets-azure that referenced this issue Apr 24, 2024
@sspans-sbp
Copy link

sspans-sbp commented Apr 24, 2024

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

@sspans-sbp
Copy link

I think this was fixed in #200

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants