hashicorp / vault-plugin-secrets-azure

Vault Azure Secrets plugin
Mozilla Public License 2.0
26 stars 19 forks source link

Getting insufficient permission errors through Azure Secrets Engine, but not when using POSTMAN #124

Closed MMollyy closed 1 year ago

MMollyy commented 1 year ago

Hi there,

I am using an application X, which has permissions on application Y. This application X is configured on the Azure Secrets Engine in the configuration.

I am trying to add application Y (a pre-created application with SPN) to have its secrets managed by the secrets engine, using application X.

However, when doing the command:

vault write azure/testing/roles/application_Y_name \
    application_object_id=application_Y_object_id \
    ttl=1h

I receive the following error:

Error writing data to azure/testing/roles/application_Y_name : Error making API request.

URL: PUT https://vault.com/v1/azure/testing/roles/application_Y_name 
Code: 500. Errors:

* 1 error occurred:
        * error loading Application: provider#GetApplication: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="Authorization_RequestDenied" Message="Insufficient privileges to complete the operation." InnerError={"client-request-id":"97f21d95-03a5-4091-8809-84ae6505bb4f","date":"2023-01-27T07:57:26","request-id":"97f21d95-03a5-4091-8809-84ae6505bb4f"}

As if my application X is not allowed to do a GET command on the application Y, or even do a addPassword API POST command. However, I can verify from postman that it works when i do the following commands:

GET https://graph.microsoft.com/v1.0/applications(appId='34456-32r235346436')

and:

POST https://graph.microsoft.com/v1.0/applications/3456567-9495876674838393/addPassword

Both work just fine, so I am 100% certain permissions on application_X are not the issue.

The config I used for application_X:

vault write azure/testing/config \
    subscription_id=### \
    tenant_id=### \
    client_id=application_X_client_id \
    client_secret=application_X_client_secret \
    use_microsoft_graph_api=true

I believe being able to use the use_microsoft_Graph=true option in the config means I am using the latest version of the Azure Secrets Engine, but I haven't found anywhere on how to verify on the version. Does anyone have an idea why I am getting the insufficient permissions error through the engine, while it works in POSTMAN?

EDIT: So our Vault island uses 1.10.7 version, which means we use 0.12 version for the secrets-engine..

MMollyy commented 1 year ago

So, I went and looked a bit through the code in hopes to find something. I'm not a knower on GO, but this next code block looks like it would be the one taking care of which endpoint to use for the API:

// Reference: https://docs.microsoft.com/en-us/graph/deployments#microsoft-graph-and-graph-explorer-service-root-endpoints
func GetGraphURI(env string) (string, error) {
    switch env {
    case "AzurePublicCloud", "":
        return "https://graph.microsoft.com", nil
    case "AzureUSGovernmentCloud":
        return "https://graph.microsoft.us", nil
    case "AzureGermanCloud":
        return "https://graph.microsoft.de", nil
    case "AzureChinaCloud":
        return "https://microsoftgraph.chinacloudapi.cn", nil
    default:
        return "", fmt.Errorf("environment '%s' unknown", env)
    }
}

The v1.0 endpoint is not being used, is that intentional?

EDIT: So I tested the above two commands for GET and POST with the URL in the current code, from POSTMAN, and it results for me in:

{
    "error": {
        "code": "BadRequest",
        "message": "Invalid version.",
        "innerError": {
            "date": "2023-01-27T10:15:07",
            "request-id": "37a92048-3692-4acf-ad12-480d58e5a354",
            "client-request-id": "37a92048-3692-4acf-ad12-480d58e5a354"
        }
    }
}

Which is not the same outcome as insufficient permissions 😞

Fuco1 commented 1 year ago

I'm having the same issue. It is unclear to me what application permissions are required for the vault application to create a role. I never want to create dynamic principals, only refresh the secrets, so I only approved Application.ReadWrite.OwnedBy permission

Edit: I fixed it by assiging the "application X" as owner of itself. Seems like the provided needs to fetch some data about the "secret engine" application before being able to create a role.

MMollyy commented 1 year ago

It seems in my case the self managed Vault instances had some kind of environment variables configured which were being picked up instead of the config. If im not mistaken it also had something to do with a managed identity being used as it was running on Azure.

In any case, the API permissions assigned to the application used in the config of the engine needs 1 of 2 permissions: 1 Application: Application.ReadWrite.All or 2 Application: Application.ReadWrite.OwnedBy

In the first case, it is not least privilege, and if you want to let the engine create secrets on itself via a role you still need to make it an owner on itself. In the second case it is least privilege and you are required to make it an owner on itself, as well as on any other application you'd like it to manage. In the event you are creating application using the engine, there is nothing to worry about as ownership is inherently taken care of.