With strong organization and design for our development teams, cloud infrastructure and security considerations, we’ll now extract Azure cost information that we can share with our organization. In addition, we will see that we can retain this information if needed to track growth (or reduction) in costs. This step is important as it will allow our teams to have an insight into their development and it will also be another audit we can use on the security side to catch unusual growth (or significant reductions) in resource costs that may be the result of an attacker. Our ultimate goal with tracking these costs and sharing them with teams is to improve our development and possibly re-organize it as needed, giving us the ability to further reduce our spending.
By querying Azure cost information, we can share with development and improve to reduce costs.
Basic Queries to Get Costs Information with PowerShell
We’ll begin querying cost information by logging into AzureRm. To confirm the version that we’re using as well, we’ll import the AzureRm module and check for the version. These scripts were executed with version 6.13.1.
1 2 3 |
Login-AzureRmAccount | Out-Null Import-Module AzureRm Get-Module | Where-Object {$_.Name -eq "AzureRm" } | Select-Object Name, Version |
PowerShell will output the version and these scripts may require a higher version if below the one shown.
In the below PowerShell call, we get the full Azure cost information of our logged in account. This will return everything for our Azure profile, which we’ll be filtering for details later. It’s worth seeing a view of the information that we’ll have access to and in some cases, we may want to see all the Azure information for a profile since some environments may demarcate assets by profile instead of other methods, such as subscriptions, resource groups, etc. We can wrap the PowerShell call in parenthesis and get specific properties, such as the InstanceName, Currency, BillingPeriodName, etc. If we are not logged in, we will not get any output – as long as we’re logged in in our current session, we’ll get information.
1 |
Get-AzureRmConsumptionUsageDetail | ft |
An example of the output we’ll get when we querying for Azure costs with this function.
For security purposes, the below scripts will not come with images, but calls will return information as long as the parameters we use (such as billing period) have data from usage (ie: if we didn’t use resources in February of this year, we would get nothing in our query).
If we had a resource named OurServer (such as an Azure SQL database), we could get Azure cost information from the below query by specifying the resource name OurServer. This query returns information about this Azure SQL Server (in this example). We can use the InstanceName parameter to specify the object. If we need to see the InstanceName of an object, we can always call the query Get-AzureRmConsumptionUsageDetail to see the full list of InstanceNames.
1 |
Get-AzureRmConsumptionUsageDetail -InstanceName "OurServer" |
One of the most common queries for Azure cost information involves periodic billing information, such as the spend for a month. In the below query, we query the spend information for the month of February (March is the billing month for the usage in February). This query along with additional parameters provides an example of what we may want to send development teams – the monthly cost of Azure resource usage so they can have insight into how resources are being used and where we can optimize these resources.
1 |
Get-AzureRmConsumptionUsageDetail -BillingPeriodName 201903 |
For smaller time ranges, we can specify the start and end times using the parameters StartDate and EndDate. In the below query, we’re looking at Azure cost information between February 1st and 4th. This query can be helpful for both security in detection of rapid cost increases or drops on a day-to-day basis or to assist development teams testing performance on a shorter time cadence. For an example, if a development team changes code to improve performance of cloud resources, they may want to see the comparison between the two days – the day before and the day after the code changed. This will help the team discover if the performance improved or didn’t improve so they can make the appropriate adjustments if they discover the latter. This can be helpful for teams as it provides constant feedback to teams so they can make improvements to reduce the likelihood of poor performing code with cloud resources.
1 |
Get-AzureRmConsumptionUsageDetail -StartDate 2019-02-01 -EndDate 2019-02-04 |
We can get specific details when querying Azure cost information – in the below query, we select a subset of the full amount of data. We return the InstanceName, Currency, PretaxCost and IsEstimated properties for the usage in February (billed in March). Generally, we’ll want to share a subset of information with our development teams.
1 |
Get-AzureRmConsumptionUsageDetail -BillingPeriodName 201903 | Select-Object InstanceName, Currency, PretaxCost, IsEstimated |
In the below query, we get the top ten Azure cost information details and expand on the details of this information. The top parameter can be helpful for developers when teams have multiple areas where improvements need to be made and the initial focus should be on the top areas where optimizations should be made. As teams make improvements, the top query will continue to adapt showing the next expensive resources.
1 |
Get-AzureRmConsumptionUsageDetail -Expand MeterDetails -Top 10 |
In our final example, we combine some of the parameters we’ve already used with additional logic to drill into the Azure cost information for the InstanceName of OurServer. We return the top ten details of OurServer only returning the InstanceName, BillingPeriod, and UsageQuantity. We may require more or less information than the below query returns and this shows us how we can drill into information that we find useful for our development teams or for auditing information for security.
1 |
Get-AzureRmConsumptionUsageDetail -Expand MeterDetails -Top 10 | Where-Object {$_.InstanceName -eq "OurServer"} | Select-Object InstanceName, BillingPeriod, UsageQuantity |
We’ve seen that we can query information and we can save this information with PowerShell using the variety of command to export data to CSVs or write custom scripts to save this to storage (like storage accounts or SQL databases). Depending on what we want to do with this information, we may want to manage the data in one of the following ways, depending on our need:
- Direct calls with PowerShell and submitting results. Getting current data or comparing one recent time period to another time period, such as comparing February 1st to February 2nd and sending the data through communication channels (email, Slack, etc)
- Worksheets or SQL databases. Securely give users access to the data through demarcated access (indirectly) and allow them to query the data as needed. This secures the asset by not providing direct access, but access through a separate resource where the information is saved
- Storage accounts. Store Azure cost information over time for possible querying in the future (a basic Azure SQL database will also suffice for this)
Security of Cost Information
Querying Azure cost information with PowerShell for tracking can also give us another tool for auditing these costs, such as identifying if a resource was mis-scaled by an attacker. We will want to be extremely careful with who has access to get this information. Allowing developers to access appropriate resources will help us move forward in development, but getting cost information should be restricted. We can and will distribute the appropriate cost information to teams in larger or medium size organizations – startups are an exception here since they tend to involve small teams and may already have access to this information in their profile. One reason why I recommend saving this information to worksheets or SQL databases (when required) is that developers can access these files or databases without having too much permissions to Azure resources.
Conclusion
As we’ve seen, we can extract Azure cost information easily with PowerShell and retain this information for sharing with teams how we see fit. On the organization side, we’ve seen how we can group information by the tags we’ve set up or by the resources we’ve named – if we followed organized naming conventions that allow us to track this by resources instead of tags. While we looked at resources under one subscription, keep in mind we can also scale by subscription – especially if we do subscription level scaling for application types, environments, etc. Finally, we looked at using this information for security as another audit to possibly detect inappropriate activity, even if the activity occurred by a legitimate user who may have had credentials compromised or made a mistake in scaling resources.
Table of contents
- Data Masking or Altering Behavioral Information - June 26, 2020
- Security Testing with extreme data volume ranges - June 19, 2020
- SQL Server performance tuning – RESOURCE_SEMAPHORE waits - June 16, 2020