Edit

Add role assignment conditions for Key Vault secrets by using Azure CLI (preview)

Note

Azure ABAC for Key Vault is in preview. Some aspects might change before general availability. For preview terms, see the supplemental terms of use.

In most cases, an Azure role assignment grants the permissions you need to Azure resources. In some cases, you might want more granular access control by adding a role assignment condition.

This article shows how to use Azure CLI to add an Azure attribute-based access control (Azure ABAC) condition to a Key Vault role assignment so that a principal can only read secrets whose names start with a specific prefix.

For the full set of supported actions and attributes, see Actions and attributes for Azure Key Vault ABAC conditions (preview).

Important

ABAC conditions only work when the key vault's permission model is set to Azure role-based access control. Legacy vault access policies don't support conditions.

Prerequisites

  • For information about the prerequisites to add or edit role assignment conditions, see Conditions prerequisites.
  • The target key vault must have its permission model set to Azure role-based access control.
  • Azure CLI installed locally, or use Azure Cloud Shell.

Condition

In this article, you restrict access to secrets whose names begin with test-app. If the user tries to read a secret without the test-app name prefix, access isn't allowed.

Here's what the condition looks like:

(
  (
    !(ActionMatches{'Microsoft.KeyVault/vaults/secrets/getSecret/action'})
  )
  OR
  (
    @Resource[Microsoft.KeyVault/vaults/secrets:name] StringStartsWith 'test-app'
  )
)

Step 1: Sign in to Azure

  1. Use az login and follow the instructions to sign in as a User Access Administrator or Owner.

    az login
    
  2. Use az account show to get your subscription ID.

    az account show
    
  3. Initialize a variable with your subscription ID.

    subscriptionId="<subscriptionId>"
    

Step 2: Create a user

  1. Use az ad user create to create a user, or find an existing user. This article uses User1 as the example.

  2. Initialize a variable with the user's object ID.

    userObjectId="<userObjectId>"
    

Step 3: Set up the key vault

Note

The commands in this article use Bash syntax (variable="value" and $variable). If you run them from Windows PowerShell or PowerShell 7, use PowerShell variable syntax instead ($variable = "value") and ignore the Bash history-expansion note in Step 4. The az commands themselves are identical in both shells.

  1. Use az keyvault create to create a key vault that uses Azure RBAC as its permission model.

    az keyvault create --name "<keyVaultName>" --resource-group "<resourceGroup>" --location "<location>" --enable-rbac-authorization true
    
  2. Grant yourself a Key Vault data-plane role so you can create secrets. When a vault uses Azure RBAC, control-plane roles such as Owner or Contributor don't grant access to secret values. Without a data-plane role, az keyvault secret set fails with a (Forbidden) Caller is not authorized to perform action on resource error for the Microsoft.KeyVault/vaults/secrets/setSecret/action action.

    myObjectId=$(az ad signed-in-user show --query id -o tsv)
    vaultScope="/subscriptions/$subscriptionId/resourceGroups/<resourceGroup>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
    az role assignment create --assignee-object-id $myObjectId --assignee-principal-type User --role "Key Vault Secrets Officer" --scope $vaultScope
    

    Note

    Use Key Vault Secrets Officer to create and manage secret values, or Key Vault Administrator for full data-plane access. Key Vault Secrets User is read-only. After you assign a role, wait 1–5 minutes for propagation before you run the next command. A Forbidden error immediately after assignment usually means the role hasn't propagated yet.

  3. Use az keyvault secret set to create a secret named test-app-secret1.

    az keyvault secret set --vault-name "<keyVaultName>" --name "test-app-secret1" --value "<secretValue>"
    

    Note

    The secret name is the resource attribute evaluated by the condition. Choose names that reflect the prefix you plan to restrict access to.

  4. Create a second secret named test-db-password.

    az keyvault secret set --vault-name "<keyVaultName>" --name "test-db-password" --value "<secretValue>"
    
  5. Initialize variables with the names you used.

    resourceGroup="<resourceGroup>"
    keyVaultName="<keyVaultName>"
    secretNameAllowed="test-app-secret1"
    secretNameDenied="test-db-password"
    

Step 4: Assign a role with a condition

  1. Initialize the Key Vault Secrets User role variables.

    roleDefinitionName="Key Vault Secrets User"
    roleDefinitionId="4633458b-17de-408a-b874-0445c86b69e6"
    
  2. Initialize the scope for the resource group.

    scope="/subscriptions/$subscriptionId/resourceGroups/$resourceGroup"
    
  3. Initialize the condition.

    condition="((!(ActionMatches{'Microsoft.KeyVault/vaults/secrets/getSecret/action'})) OR (@Resource[Microsoft.KeyVault/vaults/secrets:name] StringStartsWith 'test-app'))"
    

    For the Get secret action, this condition allows reading a secret only if its name starts with test-app. All other actions (non-getSecret) are unaffected.

    Note

    The condition must be a single-line string. Multi-line conditions are rejected. If you build the condition across multiple lines, flatten it first. For example:

    condition=$(echo "$condition" | tr -s ' \n' ' ')
    

    In Bash, if history expansion is enabled, you might see bash: !: event not found because of the exclamation point (!) in the condition. Disable history expansion with set +H, then re-enable it later with set -H.

  4. Initialize the condition version and description.

    conditionVersion="2.0"
    description="Read access to secrets whose names start with test-app"
    
  5. Use az role assignment create to assign the Key Vault Secrets User role with a condition to the user at resource group scope.

    az role assignment create --assignee-object-id $userObjectId --scope $scope --role $roleDefinitionId --description "$description" --condition "$condition" --condition-version $conditionVersion
    

    Example output:

    {
      "canDelegate": null,
      "condition": "((!(ActionMatches{'Microsoft.KeyVault/vaults/secrets/getSecret/action'})) OR (@Resource[Microsoft.KeyVault/vaults/secrets:name] StringStartsWith 'test-app'))",
      "conditionVersion": "2.0",
      "description": "Read access to secrets whose names start with test-app",
      "id": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Authorization/roleAssignments/{roleAssignmentId}",
      "name": "{roleAssignmentId}",
      "principalId": "{userObjectId}",
      "principalType": "User",
      "resourceGroup": "{resourceGroup}",
      "roleDefinitionId": "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
      "scope": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}",
      "type": "Microsoft.Authorization/roleAssignments"
    }
    

Step 5: Test the condition

  1. Open a new command window.

  2. Use az login to sign in as User1.

    az login
    
  3. Initialize the variables you used earlier.

    keyVaultName="<keyVaultName>"
    secretNameAllowed="test-app-secret1"
    secretNameDenied="test-db-password"
    
  4. Use az keyvault secret show to try to read the denied secret.

    az keyvault secret show --vault-name $keyVaultName --name $secretNameDenied
    

    Example output. Notice that the read fails because of the condition:

    (Forbidden) Caller is not authorized to perform action on resource.
    If role assignments, deny assignments or role definitions changed
    recently, please observe propagation time.
    ...
    Code: ForbiddenByRbac
    
  5. Read the secret whose name starts with test-app.

    az keyvault secret show --vault-name $keyVaultName --name $secretNameAllowed
    

    Example output. Notice that you can read the secret because its name starts with test-app:

    {
      "attributes": { },
      "contentType": null,
      "id": "https://<keyVaultName>.vault.azure.net/secrets/test-app-secret1/<version>",
      "name": "test-app-secret1",
      "tags": {},
      "value": "<secretValue>"
    }
    

Step 6: (Optional) Edit the condition

  1. In the original command window, use az role assignment list to get the role assignment you added.

    az role assignment list --assignee $userObjectId --resource-group $resourceGroup
    
  2. Create a JSON file with the following format and update the condition and description properties to also allow secrets whose names start with api-.

    {
      "canDelegate": null,
      "condition": "((!(ActionMatches{'Microsoft.KeyVault/vaults/secrets/getSecret/action'})) OR (@Resource[Microsoft.KeyVault/vaults/secrets:name] StringStartsWith 'test-app' OR @Resource[Microsoft.KeyVault/vaults/secrets:name] StringStartsWith 'api-'))",
      "conditionVersion": "2.0",
      "description": "Read access to secrets whose names start with test-app or api-",
      "id": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Authorization/roleAssignments/{roleAssignmentId}",
      "name": "{roleAssignmentId}",
      "principalId": "{userObjectId}",
      "principalName": "user1@contoso.com",
      "principalType": "User",
      "resourceGroup": "{resourceGroup}",
      "roleDefinitionId": "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
      "roleDefinitionName": "Key Vault Secrets User",
      "scope": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}",
      "type": "Microsoft.Authorization/roleAssignments"
    }
    
  3. Use az role assignment update to update the condition.

    az role assignment update --role-assignment "./path/roleassignment.json"
    

Step 7: Clean up resources

  1. Use az role assignment delete to remove the role assignment and condition.

    az role assignment delete --assignee $userObjectId --role "$roleDefinitionName" --resource-group $resourceGroup
    
  2. Delete the key vault you created.

  3. Delete the user you created.