homepage
Menu
Open menu
  • Training
    Go one level top Back

    Training

    • Courses

      Build cyber prowess with training from renowned experts

    • Hands-On Simulations

      Hands-on learning exercises keep you at the top of your cyber game

    • Certifications

      Demonstrate cybersecurity expertise with GIAC certifications

    • Ways to Train

      Multiple training options to best fit your schedule and preferred learning style

    • Training Events & Summits

      Expert-led training at locations around the world

    • Free Training Events

      Upcoming workshops, webinars and local events

    • Security Awareness

      Harden enterprise security with end-user and role-based training

    Featured

    Get a Free Hour of SANS Training

    Free Course Demos

    Can't find what you are looking for?

    Let us help.
    Contact us
  • Learning Paths
    Go one level top Back

    Learning Paths

    • By Focus Area

      Chart your path to job-specific training courses

    • By NICE Framework

      Navigate cybersecurity training through NICE framework roles

    • DoDD 8140 Work Roles

      US DoD 8140 Directive Frameworks

    • By European Skills Framework

      Align your enterprise cyber skills with ECSF profiles

    • By Skills Roadmap

      Find the right training path based on critical skills

    • New to Cyber

      Give your cybersecurity career the right foundation for success

    • Leadership

      Training designed to help security leaders reduce organizational risk

    • Degree and Certificate Programs

      Gain the skills, certifications, and confidence to launch or advance your cybersecurity career.

    Featured: Solutions for Emerging Risks

    New to Cyber resources

    Start your career
  • Community Resources
    Go one level top Back

    Community Resources

    Watch & Listen

    • Webinars
    • Live Streams
    • Podcasts

    Read

    • Blog
    • Newsletters
    • White Papers
    • Internet Storm Center

    Download

    • Open Source Tools
    • Posters & Cheat Sheets
    • Policy Templates
    • Summit Presentations
    • SANS Community Benefits

      Connect, learn, and share with other cybersecurity professionals

    • CISO Network

      Engage, challenge, and network with fellow CISOs in this exclusive community of security leaders

  • For Organizations
    Go one level top Back

    For Organizations

    Team Development

    • Why Partner with SANS
    • Group Purchasing
    • Skills & Talent Assessments
    • Private & Custom Training

    Leadership Development

    • Leadership Courses & Accreditation
    • Executive Cybersecurity Exercises
    • CISO Network

    Security Awareness

    • End-User Training
    • Phishing Simulation
    • Specialized Role-Based Training
    • Risk Assessments
    • Public Sector Partnerships

      Explore industry-specific programming and customized training solutions

    • Sponsorship Opportunities

      Sponsor a SANS event or research paper

    Interested in developing a training plan to fit your organization’s needs?

    We're here to help.
    Contact us
  • Talk with an expert
  • Log In
  • Join - it's free
  • Account
    • Account Dashboard
    • Log Out
  1. Home >
  2. Blog >
  3. How to Automate in Azure Using PowerShell - Part 1
370x370_josh-johnson.jpg
Josh Johnson

How to Automate in Azure Using PowerShell - Part 1

In this post, we’ll cover how to automate the assessment and reporting of your cloud security configuration opportunities.

October 11, 2022

Welcome to the first in a series of blog posts about automating your Azure security worries away. In this post, we’ll cover how to automate the assessment and reporting of your cloud security configuration opportunities.

Cloud computing is a wonderful innovation, allowing organizations to quickly and efficiently build services to support their operations. In a DevOps world, it allows for maximizing creativity without the headache of building traditional infrastructure. However, since you’re visiting the SANS website, you probably already know that public cloud can also be a dangerous place. With all this wonderful automation and ease of use, it’s sometimes TOO easy to build something rife with vulnerabilities or misconfiguration. As a bonus, public clouds are inherently Internet-facing. We’ve all read stories about those misconfigured storage buckets with troves of data available to whoever brute forces the resource name.

Blue Teamers' jobs are hard enough; we shouldn’t also have to worry about self-inflicted mistakes leading to incidents. Fortunately, public cloud providers generally provide capabilities to quickly identify and correct these mistakes. Furthermore, with PowerShell automation we don’t need to browse to yet another portal to find this information. This post will cover PowerShell automation to centralize vulnerabilities and risks without opening yet another browser tab.

Setup Information

To follow along, you’ll need the following:

  • An Azure Tenant with resources deployed
  • Azure Defender for Cloud enabled
  • PowerShell
    • Az Module

Getting Started

First things first – if you have zero security recommendations, the following automation will produce…nothing… and we should be happy about that! That said, this automation can still be used to ensure that when a mistake happens, we’ll know quickly and can enact remediation plans. We’ll use a throwaway subscription with a vulnerable storage account to demonstrate how this can be used for lightning-fast, custom detection.

Digging In

Let’s go find some issues in an Azure Tenant. Using the Az.Accounts module’s `Connect-AzAccount` cmdlet, we can connect to an existing tenant/subscription. The cmdlet supports several types of authentication, and this example assumes the user is leveraging an interactive login with Multi-Factor Authentication. A browser window will open where the user can supply credentials and pass the MFA challenge.

Connect-AzAccount

The account is now connected, and one or more contexts may be available. In complex environments with multiple subscriptions, tenants, etc. it is important to ensure we’re working in the correct context.

Get-AzContext will list the current context of the session, and the -ListAvailable parameter can show available contexts. Note that this is limited to 25 which may be far less than the total possible. See this resource for more information on how to use Connect-AzAccount -MaxContextPopulation to be able to query against a larger set. Get-AzSubscription can also be used to find one’s bearings and set a new context if new to the Az PowerShell module.

Part_1_-_Picture1.png

Once oriented appropriately, as with all things PowerShell, there are multiple ways to achieve our goal.

Option 1 – Az cmdlets

The simplest is to leverage the Az module’s cmdlets to pull back basic vulnerability data. Get-AzSecurityAssessment can be run with no parameters to return security assessment results. The output object’s type can be examined via Get-Member to understand what properties exist.

Get-AzSecurityAssessment | Get-Member

Part_1_-_Picture2.png

Next, let’s take a look at a sample return object by selecting the first returned assessment:

Get-AzSecurityAssessment | Select-Object -First 1

Part_1_-_Picture3.png

You might be asking, “What is the status of this finding?” The Status property is another object and can be investigated using Select-Object with -ExpandProperty as well.

Get-AzSecurityAssessment | Select-Object -First 1 -ExpandProperty Status

Part_1_-_Picture4.png

This shows that we’re already configured correctly when it comes to KeyVault leveraging Defender. Let’s exclude any findings where the Status property has a code of Healthy. Unfortunately, there aren’t many parameters with this cmdlet to adopt the “Filter Left, Format Right” paradigm, and instead we can filter on the client-side, albeit less efficiently.

Get-AzSecurityAssessment | Where-Object {$_.Status.Code -ne "Healthy"} | Select-Object -First 1

Part_1_-_Picture5.png

We’re now working with return objects where the status is something other than “Healthy.” Let’s dig into the ResourceDetails property to understand which resource is misconfigured. Similar to the Status property, the ResourceDetails property is also an object. We can expand it to inspect its contents:

Get-AzSecurityAssessment | Where-Object {$_.Status.Code -ne "Healthy"} | Select-Object -First 1 -ExpandProperty ResourceDetails

Part_1_-_Picture6.png

So our ‘badstorageacct’ storage account is misconfigured. Let’s find out more about this resource:

Remember that the beauty of PowerShell’s pipeline is that we can pass output objects from a cmdlet as input objects to a separate cmdlet (assuming type compatibility). Get-AzResource accepts objects of type Microsoft.Azure.Commands.Security.Models.Assessments.PSSecurityAzureResourceDetails, so we can simply pipe the output of the previous command into Get-AzResource to understand more about our vulnerable resource.

Get-AzSecurityAssessment | Where-Object {$_.Status.Code -ne "Healthy"} | Select-Object -First 1 -ExpandProperty ResourceDetails | Get-AzResource

Part_1_-_Picture7.png

Notice we now have the context as to where this exists, including the resource group name and any tags that are applied to the resource.

Let’s now tie the two objects together, taking useful pieces of each and creating a custom object representing our finding as well as the affected resource. One way to do this is to leverage a Foreach-Object loop, where $PSItem or $_ represents the input object(s) and allows us to access properties of interest. Note that some findings may be associated with the overall subscription and Get-AzResource will throw an error. We can suppress those errors with the -ErrorAction SilentlyContinue parameter. We can take the output of each call to Get-AzResource and combine it with the finding by creating a PSCustomObject containing the properties in which we are interested.

Get-AzSecurityAssessment | Where-Object {$_.Status.Code -ne "Healthy"} | Foreach-Object {    
$vuln = $_
$_ | Select-Object -First 1 -ExpandProperty ResourceDetails |
ForEach-Object {
$affectedResource = $_ | Get-AzResource -ErrorAction
SilentlyContinue
[PSCustomObject]@{
Vulnerability = $vuln.DisplayName
ResourceID = $affectedResource.ResourceId
Name = $affectedResource.Name
Tags = $affectedResource.Tags
}
}
}

Part_1_-_Picture8.png

We can also add logic such that if the resource is defined at a subscription level, return subscription details instead of resource details. However, the current technique is requiring significant client-side filtering and multiple requests from the client. Let’s take a look at an alternative technique to gather similar data.

Option 2 – Azure Resource Graph

Azure Resource Graph is a powerful utility that allows for quick and efficient queries against subscriptions, resources, and even security recommendations. Resource Graph leverages the Kusto Query Language (KQL) which provides a full-featured syntax meant for querying databases. With Resource Graph, Azure provides several prebuilt and prepopulated tables with useful data. See the Microsoft docs for more information on KQL Syntax. 

Compared to our first approach towards aggregating resource and assessment data, Resource Graph queries allow us to offload all compute and aggregation tasks to the Azure cloud and simplifies the PowerShell we need to write. Furthermore, when initiating the queries via PowerShell, we are returned objects with the properties we’re requesting. The difference in our technique means that or KQL Query logic must perform the queries and aggregations, and we will use the Az module’s Search-AzGraph cmdlet to execute the query and handle the results. To learn how to build queries and ensure we’re capturing the correct data for automation, the Azure Resource Graph Explorer is a fantastic tool to build queries.

First things first, we need to connect to Azure. Connect-AzAccount is still the cmdlet here, even though we’re using a different mechanism to query for our data.

Once connected, we can craft a simple KQL query to ensure things are working properly. Security assessments are contained within the SecurityResources table, with columns and nested properties providing context as to the finding, affected resource and more. KQL queries are often several lines, and in many PowerShell examples, look like one long string. To help with readability, the here-string can allow for a multi-line string to be supplied as the KQL query. Let’s start with a simple query to return assessment results, like the output of Get-AzSecurityAssessment.

$query = @"
SecurityResources
| where type == 'microsoft.security/assessments'
"@

Search-AzGraph -Query $query

Part_1_-_Picture9.png

Several results are returned. Instead of filtering output with Where-Object, instead we can now leverage KQL to offload that filtering to Resource Graph using the where operator.

Let’s filter on the subscription of interest (if you’re following along with copy/paste make sure you update the subscriptionId field to match a subscription you can access!) and on the status code to ensure we’re not returning resources that are already healthy/applicable.

$query = @"
SecurityResources
| where type == 'microsoft.security/assessments'
| where subscriptionId == "40a48b56-e4b2-4fda-a655-8948290f2e40"
| where properties.status.code !in ("Healthy","NotApplicable")
"@

Search-AzGraph -Query $query

Part_1_-_Picture10.png

Now that we have known issues, let’s use the project operator to return only fields of interest and produce a summary report, leveraging the summarize and order operators. Note that when we use dot notation to dig into nested properties, the returned object includes properties replacing the dots with underscores, making it straightforward to keep track of where data originated.

$query = @"
SecurityResources
| where type == 'microsoft.security/assessments'
| where subscriptionId == "40a48b56-e4b2-4fda-a655-8948290f2e40"
| where properties.status.code !in ("Healthy","NotApplicable")
| project properties.status.firstEvaluationDate,properties.status.code,properties.displayName,properties.metadata.severity,properties.resourceDetails.Id,properties.links.azurePortal
| summarize count() by tostring(properties_metadata_severity),tostring(properties_displayName)
| order by ['count_'] desc
"@

$results = Search-AzGraph -Query $query

Part_1_-_Picture11.png

This can be useful for high-level reporting, but it still doesn’t show us details of affected resources. We can re-run that query and store the results in a variable to leverage the findings and identify resources needing changes:

$results = Search-AzGraph -Query $query

With findings stored in the $results variable, we can iterate through each finding using a ForEach-Object loop, identifying affected resources. We can use string substitution in order to update our query each pass through the loop, such that each pass looks for a different finding. A nested ForEach-Object loop can then inspect, for each finding, affected resources. A PSCustomObject can be created to capture relevant finding data, combined with details for each specific resource. Here is the full code snippet:

$reportObj = @()
#iterate through each finding, projecting details including the affected resource ID
$results | ForEach-Object {
#Query is updated to look at a different finding each pass through the loop
$findingQuery = @"
SecurityResources
| where type == 'microsoft.security/assessments'
| where subscriptionId == "40a48b56-e4b2-4fda-a655-8948290f2e40"
| where properties.status.code !in ("Healthy","NotApplicable")
| where properties.displayName == `"$($_.properties_displayName)`"
| project properties.displayName,properties.status.code,properties.status.firstEvaluationDate,properties.resourceDetails.Id,properties.links.azurePortal
"@
#Search-AzGraph will only return the top 100 results by default. A maximum of 1000 results can be specified
$findingResults = Search-AzGraph -Query $findingQuery -First 1000
#Now iterate through each affected resource
$findingResults | Foreach-Object {
#Query is updated to look at each affected resource for each finding
$resourceQuery = @"
Resources
| where id =~ `"$($_.properties_resourceDetails_Id)`"
| mv-expand tags=tags
| project tags
"@
$resourceDetails = Search-AzGraph -query $resourceQuery
#Custom object captures all relevant data about the finding and affected resource
$resultObj = [PSCustomObject]@{
AllTags = $resourceDetails.Tags
Type = $resourceDetails.Tags.'type' | Where-Object {$_ -ne $null}
Team = $resourceDetails.Tags.'team' | Where-Object {$_ -ne $null}
Contact = $resourceDetails.Tags.'adminContact' | Where-Object {$_ -ne $null}
ResourceId = $_.properties_resourceDetails_Id
Finding = $_.properties_displayName
FindingLink = $_.properties_links_azurePortal
DateIdentified = $_.properties_status_firstEvaluationDate
}
$reportObj += $resultObj
}
}

Inspecting the $reportObj variable, we see that we now have specific details about the findings and affected resources. Tags can be crucial for cloud inventories as they can be used to correlate resources to business purpose, environments and even personnel/groups who can be contacted about findings.

Part_1_-_Picture12.png

Wrapping Up

Cloud risks don’t have to be difficult to identify and triage. With PowerShell, we have a capable automation framework that can be used to identify and even (stay tuned to this blog series) remediate known issues. While we were running these commands manually and stepping through the output, identification and reporting can be fully automated. Leveraging cloud-native technology like Function Apps, the above PowerShell can be scheduled to run regularly, and reporting of new issues can be automated as well. If Blue Teams are leveraging Teams or Slack as messaging tools, we can use techniques like web hooks to automatically format findings and post to channels for immediate notification of new risks.

For part 2 of the series, go here: https://www.sans.org/blog/how-to-automate-in-azure-using-powershell-part-2/

Share:
TwitterLinkedInFacebook
Copy url Url was copied to clipboard
Subscribe to SANS Newsletters
Receive curated news, vulnerabilities, & security awareness tips
United States
Canada
United Kingdom
Spain
Belgium
Denmark
Norway
Netherlands
Australia
India
Japan
Singapore
Afghanistan
Aland Islands
Albania
Algeria
American Samoa
Andorra
Angola
Anguilla
Antarctica
Antigua and Barbuda
Argentina
Armenia
Aruba
Austria
Azerbaijan
Bahamas
Bahrain
Bangladesh
Barbados
Belarus
Belize
Benin
Bermuda
Bhutan
Bolivia
Bonaire, Sint Eustatius, and Saba
Bosnia And Herzegovina
Botswana
Bouvet Island
Brazil
British Indian Ocean Territory
Brunei Darussalam
Bulgaria
Burkina Faso
Burundi
Cambodia
Cameroon
Cape Verde
Cayman Islands
Central African Republic
Chad
Chile
China
Christmas Island
Cocos (Keeling) Islands
Colombia
Comoros
Cook Islands
Costa Rica
Cote D'ivoire
Croatia (Local Name: Hrvatska)
Curacao
Cyprus
Czech Republic
Democratic Republic of the Congo
Djibouti
Dominica
Dominican Republic
East Timor
Ecuador
Egypt
El Salvador
Equatorial Guinea
Eritrea
Estonia
Eswatini
Ethiopia
Falkland Islands (Malvinas)
Faroe Islands
Fiji
Finland
France
French Guiana
French Polynesia
French Southern Territories
Gabon
Gambia
Georgia
Germany
Ghana
Gibraltar
Greece
Greenland
Grenada
Guadeloupe
Guam
Guatemala
Guernsey
Guinea
Guinea-Bissau
Guyana
Haiti
Heard And McDonald Islands
Honduras
Hong Kong
Hungary
Iceland
Indonesia
Iraq
Ireland
Isle of Man
Israel
Italy
Jamaica
Jersey
Jordan
Kazakhstan
Kenya
Kiribati
Korea, Republic Of
Kosovo
Kuwait
Kyrgyzstan
Lao People's Democratic Republic
Latvia
Lebanon
Lesotho
Liberia
Liechtenstein
Lithuania
Luxembourg
Macau
Madagascar
Malawi
Malaysia
Maldives
Mali
Malta
Marshall Islands
Martinique
Mauritania
Mauritius
Mayotte
Mexico
Micronesia, Federated States Of
Moldova, Republic Of
Monaco
Mongolia
Montenegro
Montserrat
Morocco
Mozambique
Myanmar
Namibia
Nauru
Nepal
Netherlands Antilles
New Caledonia
New Zealand
Nicaragua
Niger
Nigeria
Niue
Norfolk Island
North Macedonia
Northern Mariana Islands
Oman
Pakistan
Palau
Palestine
Panama
Papua New Guinea
Paraguay
Peru
Philippines
Pitcairn
Poland
Portugal
Puerto Rico
Qatar
Reunion
Romania
Russian Federation
Rwanda
Saint Bartholemy
Saint Kitts And Nevis
Saint Lucia
Saint Martin
Saint Vincent And The Grenadines
Samoa
San Marino
Sao Tome And Principe
Saudi Arabia
Senegal
Serbia
Seychelles
Sierra Leone
Sint Maarten
Slovakia
Slovenia
Solomon Islands
South Africa
South Georgia and the South Sandwich Islands
South Sudan
Sri Lanka
St. Helena
St. Pierre And Miquelon
Suriname
Svalbard And Jan Mayen Islands
Sweden
Switzerland
Taiwan
Tajikistan
Tanzania, United Republic Of
Thailand
Togo
Tokelau
Tonga
Trinidad And Tobago
Tunisia
Turkey
Turkmenistan
Turks And Caicos Islands
Tuvalu
Uganda
Ukraine
United Arab Emirates
United States Minor Outlying Islands
Uruguay
Uzbekistan
Vanuatu
Vatican City State
Venezuela
Vietnam
Virgin Islands (British)
Virgin Islands (U.S.)
Wallis And Futuna Islands
Western Sahara
Yemen
Zambia
Zimbabwe

By providing this information, you agree to the processing of your personal data by SANS as described in our Privacy Policy.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Recommended Training

  • SEC450: Blue Team Fundamentals: Security Operations and Analysis™
  • SEC580: Metasploit for Enterprise Penetration Testing™
  • SEC401J: Security Essentials - Network, Endpoint, and Cloud™ (Japanese)

Tags:
  • Cloud Security
  • Cyber Defense

Related Content

Blog
SANS_Cloud_Security_340x340.png
Cloud Security
December 11, 2024
SANS Cloud Security Curriculum
The SANS Cloud Security Curriculum is growing fast – like the Cloud itself.
370x370_Frank-Kim.jpg
Frank Kim
read more
Blog
340x340.png
Cloud Security
September 30, 2024
A Visual Summary of SANS CloudSecNext Summit 2024
Check out these graphic recordings created in real-time throughout the event for SANS CloudSecNext Summit 2024
No Headshot Available
Alison Kim
read more
Blog
SEC540_Updated_340x340.png
Cloud Security
December 29, 2023
What is the SANS Cloud Flight Simulator?
Get ready for takeoff into the NEW SEC540!
Eric_Johnson_370x370.png
Eric Johnson
read more
  • Company
  • Mission
  • Instructors
  • About
  • FAQ
  • Press
  • Contact Us
  • Careers
  • Policies
  • Training Programs
  • Work Study
  • Academies & Scholarships
  • Public Sector Partnerships
  • Law Enforcement
  • SkillsFuture Singapore
  • Degree Programs
  • Get Involved
  • Join the Community
  • Become an Instructor
  • Become a Sponsor
  • Speak at a Summit
  • Join the CISO Network
  • Award Programs
  • Partner Portal
Subscribe to SANS Newsletters
Receive curated news, vulnerabilities, & security awareness tips
United States
Canada
United Kingdom
Spain
Belgium
Denmark
Norway
Netherlands
Australia
India
Japan
Singapore
Afghanistan
Aland Islands
Albania
Algeria
American Samoa
Andorra
Angola
Anguilla
Antarctica
Antigua and Barbuda
Argentina
Armenia
Aruba
Austria
Azerbaijan
Bahamas
Bahrain
Bangladesh
Barbados
Belarus
Belize
Benin
Bermuda
Bhutan
Bolivia
Bonaire, Sint Eustatius, and Saba
Bosnia And Herzegovina
Botswana
Bouvet Island
Brazil
British Indian Ocean Territory
Brunei Darussalam
Bulgaria
Burkina Faso
Burundi
Cambodia
Cameroon
Cape Verde
Cayman Islands
Central African Republic
Chad
Chile
China
Christmas Island
Cocos (Keeling) Islands
Colombia
Comoros
Cook Islands
Costa Rica
Cote D'ivoire
Croatia (Local Name: Hrvatska)
Curacao
Cyprus
Czech Republic
Democratic Republic of the Congo
Djibouti
Dominica
Dominican Republic
East Timor
Ecuador
Egypt
El Salvador
Equatorial Guinea
Eritrea
Estonia
Eswatini
Ethiopia
Falkland Islands (Malvinas)
Faroe Islands
Fiji
Finland
France
French Guiana
French Polynesia
French Southern Territories
Gabon
Gambia
Georgia
Germany
Ghana
Gibraltar
Greece
Greenland
Grenada
Guadeloupe
Guam
Guatemala
Guernsey
Guinea
Guinea-Bissau
Guyana
Haiti
Heard And McDonald Islands
Honduras
Hong Kong
Hungary
Iceland
Indonesia
Iraq
Ireland
Isle of Man
Israel
Italy
Jamaica
Jersey
Jordan
Kazakhstan
Kenya
Kiribati
Korea, Republic Of
Kosovo
Kuwait
Kyrgyzstan
Lao People's Democratic Republic
Latvia
Lebanon
Lesotho
Liberia
Liechtenstein
Lithuania
Luxembourg
Macau
Madagascar
Malawi
Malaysia
Maldives
Mali
Malta
Marshall Islands
Martinique
Mauritania
Mauritius
Mayotte
Mexico
Micronesia, Federated States Of
Moldova, Republic Of
Monaco
Mongolia
Montenegro
Montserrat
Morocco
Mozambique
Myanmar
Namibia
Nauru
Nepal
Netherlands Antilles
New Caledonia
New Zealand
Nicaragua
Niger
Nigeria
Niue
Norfolk Island
North Macedonia
Northern Mariana Islands
Oman
Pakistan
Palau
Palestine
Panama
Papua New Guinea
Paraguay
Peru
Philippines
Pitcairn
Poland
Portugal
Puerto Rico
Qatar
Reunion
Romania
Russian Federation
Rwanda
Saint Bartholemy
Saint Kitts And Nevis
Saint Lucia
Saint Martin
Saint Vincent And The Grenadines
Samoa
San Marino
Sao Tome And Principe
Saudi Arabia
Senegal
Serbia
Seychelles
Sierra Leone
Sint Maarten
Slovakia
Slovenia
Solomon Islands
South Africa
South Georgia and the South Sandwich Islands
South Sudan
Sri Lanka
St. Helena
St. Pierre And Miquelon
Suriname
Svalbard And Jan Mayen Islands
Sweden
Switzerland
Taiwan
Tajikistan
Tanzania, United Republic Of
Thailand
Togo
Tokelau
Tonga
Trinidad And Tobago
Tunisia
Turkey
Turkmenistan
Turks And Caicos Islands
Tuvalu
Uganda
Ukraine
United Arab Emirates
United States Minor Outlying Islands
Uruguay
Uzbekistan
Vanuatu
Vatican City State
Venezuela
Vietnam
Virgin Islands (British)
Virgin Islands (U.S.)
Wallis And Futuna Islands
Western Sahara
Yemen
Zambia
Zimbabwe

By providing this information, you agree to the processing of your personal data by SANS as described in our Privacy Policy.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
  • Privacy Policy
  • Terms and Conditions
  • Do Not Sell/Share My Personal Information
  • Contact
  • Careers
© 2025 The Escal Institute of Advanced Technologies, Inc. d/b/a SANS Institute. Our Terms and Conditions detail our trademark and copyright rights. Any unauthorized use is expressly prohibited.
  • Twitter
  • Facebook
  • Youtube
  • LinkedIn