# Automated Savings

> Let LevelFour apply an Azure saving you approved. You run one command per batch to grant a role on those resources alone, and LevelFour removes it once the change is done.

Source: https://docs.levelfour.ai/connectors/azure/automated-savings


Your Azure connection reads and never writes. When you want LevelFour to apply a saving for you, you grant write access for that one batch, on its resources and nothing wider, by running one command in Azure Cloud Shell. LevelFour applies the change and then removes the access it was given.

Ask your LevelFour contact to turn on Automated Savings for Azure for your organization. Until then, every Azure saving offers **Manual Setup**, which shows the change to make yourself.

## What LevelFour can apply

| Saving                                      | What LevelFour does                             | What the grant allows                                                                 |
| ------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------- |
| Unattached managed disk                     | Deletes the disk                                | `Microsoft.Compute/disks/read` and `delete`                                           |
| Unused public IP address                    | Deletes the address                             | `Microsoft.Network/publicIPAddresses/read` and `delete`                               |
| Snapshot older than 90 days                 | Deletes the snapshot                            | `Microsoft.Compute/snapshots/read` and `delete`                                       |
| Virtual machine stopped but still allocated | Deallocates it, which stops the compute charge  | `Microsoft.Compute/virtualMachines/read`, `instanceView/read` and `deallocate/action` |
| Idle virtual machine                        | Deallocates it                                  | The same as above                                                                     |
| Idle SQL database                           | Nothing: Manual Setup only                      | None                                                                                  |
| Reservation purchase or renewal             | Buys it, once an organization admin releases it | The built-in **Reservation Purchaser** role on the subscription it bills to           |
| Savings plan purchase or renewal            | Buys it, once an organization admin releases it | The built-in **Savings plan Purchaser** role on the subscription it bills to          |

An Azure SQL database cannot be stopped, so LevelFour leaves an idle one for you to decide on. [Commitments](/connectors/azure/commitments) covers buying and renewing.

## Approve and grant

### Approve the savings

Accept the savings in LevelFour and choose **Automated Savings** as the way to apply it. LevelFour shows a command for that batch.

### Run the command in Azure Cloud Shell

Run it in [Azure Cloud Shell](https://shell.azure.com) as someone who can assign roles on those resources, such as an Owner of their subscription. The command:

1. Creates or updates a custom role named `LevelFour Savings` followed by the kind of savings, holding only the actions the table above lists for it.
2. Assigns that role to the `LevelFour` service principal on each resource in the batch, and on nothing wider. For a purchase it assigns the built-in purchaser role on the subscription instead, since Azure buys only for a holder of that role.
3. Assigns **Role Based Access Control Administrator** on the same resources, with a condition that lets `LevelFour` delete only its own role assignments and create none. That is what lets LevelFour remove its access afterwards.
4. Reports what it assigned to LevelFour.

### LevelFour applies the change

LevelFour checks the permissions with Azure itself before acting, so a grant that did not land changes nothing. It reads each resource again first and skips any that no longer qualifies, such as a disk someone attached in the meantime. Then it makes the change, waits until Azure reports it done, and removes both of its role assignments on that resource.

For a purchase, LevelFour asks Azure for the price again first, and does not buy if it rose more than 2% above the price an admin accepted. LevelFour then removes both of its role assignments on the subscription.

> **Note**
>
> A grant for a saving expires 72 hours after LevelFour issues the command. [Commitments](/connectors/azure/commitments#delivery) covers how long a purchase or renewal grant lasts. An expired grant is never used. If a batch was not applied by then, LevelFour removes its role assignments at that point.

## Confirming it worked

The savings moves to **Optimized**, and its **Status & Logs** step lists each command LevelFour ran and what Azure reported, including the removal of its access. In the Azure portal, the resource's **Access control (IAM)**, or the subscription's for a purchase, no longer lists `LevelFour`.

## Removing access

LevelFour removes its own access, after the change and at the 72 hour deadline. You need to act in four cases:

* Azure refused the removal.
* The connection's secret no longer signs in, because it expired or was replaced.
* The removal kept failing for a week.
* The Azure connection was removed before the grant expired.

LevelFour then shows the command that deletes those role assignments and no others. It appears under the expired grant in the savings' **Implementation** step, and in its **Status & Logs** step when the removal right after a change failed. Run it in [Azure Cloud Shell](https://shell.azure.com).

If neither step shows the command any more, this lists and deletes every grant role assignment LevelFour still holds, in each subscription you can see. `--all` only reads the current subscription, so the loop names each one:

```bash
APP_ID="$(az ad app list --display-name LevelFour --query '[0].appId' -o tsv)"
for s in $(az account list --query '[].id' -o tsv); do
  az role assignment list --assignee "$APP_ID" --all --subscription "$s" \
    --query "[?starts_with(roleDefinitionName, 'LevelFour Savings') || roleDefinitionName == 'Role Based Access Control Administrator' || roleDefinitionName == 'Reservation Purchaser' || roleDefinitionName == 'Savings plan Purchaser'].id" -o tsv |
    xargs -r -n 1 az role assignment delete --ids
done
```

This leaves the read roles from the [connect command](/connectors/azure) in place.

## Troubleshooting

**The command reports a role it could not create or assign.**
The person who ran it cannot assign roles on those resources. Run it as an Owner of their subscription.

**LevelFour shows a command to remove its access.**
LevelFour could not remove the access itself. Run the command it shows, as [Removing access](#removing-access) describes.

**The savings waits on its grant after the command finished.**
Azure can take a few minutes to apply new role assignments. LevelFour keeps checking until the grant expires.

**The savings failed because the resource no longer qualifies.**
Someone changed the resource after LevelFour found it. LevelFour made no change. The next scan updates or retires the savings.

## Next

* [Connect Azure](/connectors/azure) covers the read-only service principal that every grant builds on
* [Commitments](/connectors/azure/commitments) covers buying a reservation or savings plan through LevelFour
