diff --git a/.github/actions/get_aprl/entrypoint.py b/.github/actions/get_aprl/entrypoint.py index 8d57333b1..f0608103c 100644 --- a/.github/actions/get_aprl/entrypoint.py +++ b/.github/actions/get_aprl/entrypoint.py @@ -93,6 +93,7 @@ def get_aprl_recos(): github_file_extension = '.yaml' github_branch = 'master' retrieved_recos = [] + timestamp = datetime.date.today().strftime("%B %d, %Y") # Get last commit to APRL reco if (verbose): print("DEBUG: Scanning GitHub repository {0} for {1} files...".format(github_repo, github_file_extension)) r = requests.get(f'https://api.github.com/repos/{github_org}/{github_repo}/commits') @@ -131,7 +132,9 @@ def get_aprl_recos(): item['severity'] = item['recommendationImpact'] item['category'] = item['recommendationControl'] item['guid'] = item['aprlGuid'] - item['source'] = file_path + item['sourceFile'] = file_path + item['sourceType'] = 'aprl' + item['timestamp'] = timestamp retrieved_recos += aprl_recos if verbose: print("DEBUG: {0} recommendations found in file {1}".format(len(aprl_recos), file_path)) else: diff --git a/.github/actions/get_service_guides/entrypoint.py b/.github/actions/get_service_guides/entrypoint.py index db5d5b8f1..8a38be748 100644 --- a/.github/actions/get_service_guides/entrypoint.py +++ b/.github/actions/get_service_guides/entrypoint.py @@ -75,6 +75,11 @@ args_verbose = (sys.argv[3].lower() == 'true') except: args_verbose = True +try: + args_overwrite = (sys.argv[4].lower() == 'true') +except: + args_overwrite = False + # These parameters haven't been implemented in the github action args_print_json = False args_extract_key_phrases_checklist = False @@ -197,10 +202,11 @@ def short_pillar(pillar): else: return pillar # Function to parse markdown -def parse_markdown(markdown, service, verbose=False): +def parse_markdown(markdown, service, source=None, verbose=False): recos = [] waf_pillars = ['cost optimization', 'operational excellence', 'performance efficiency', 'reliability', 'security'] processing_pillar = '' + timestamp = datetime.date.today().strftime("%B %d, %Y") if (verbose): print("DEBUG: Processing markdown file...") line_count = 0 for line in markdown.split('\n'): @@ -211,7 +217,10 @@ def parse_markdown(markdown, service, verbose=False): if (verbose): print("DEBUG: Processing pillar '{0}'".format(processing_pillar)) if (line[0:4] == '> - ') and (processing_pillar != ''): reco = line[4:] - recos.append({'waf': processing_pillar, 'service': service, 'text': remove_markdown(reco), 'description': '', 'type': 'checklist'}) + reco_object = {'waf': processing_pillar, 'service': service, 'text': remove_markdown(reco), 'description': '', 'type': 'checklist', 'sourceType': 'wafsg', 'timestamp': timestamp} + if source: + reco_object['sourceFile'] = source + recos.append(reco_object) # If line matches a pattern that starts with "|" then comes a text, then "|" and a description and a closing "|" if (line[0:1] == '|'): line_table_items = line.split('|') @@ -258,7 +267,7 @@ def get_waf_service_guide_recos(): if r.status_code == 200: svcguide = r.text if (args_verbose): print("DEBUG: Parsing service guide '{0}', {1} characters retrieved...".format(file_path, len(svcguide))) - svc_recos = parse_markdown(svcguide, service, verbose=False) + svc_recos = parse_markdown(svcguide, service, source=file_path, verbose=False) if (len(svc_recos) > 0): retrieved_recos += svc_recos if args_verbose: print("DEBUG: {0} recommendations found for service '{1}'".format(len(svc_recos), service)) @@ -315,24 +324,33 @@ def get_waf_service_guide_recos(): # If file exists, try to match the recos in the file by the text field and update the GUIDs # If file doesn't exist, generate random GUIDs for each reco def update_guids(checklist, filename): - # If file exists + # If file exists, we can either overwrite it and generate new GUIDs or try to match the recos by text + # Note that if matching the recos by GUID, the old recos that do not exactly match the text of the new ones will be lost if os.path.isfile(filename): - if (args_verbose): print("DEBUG: Retrieving checklist GUIDs from file {0}...".format(filename)) - existing_checklist = load_json(filename) - for reco in checklist['items']: - # Find a reco in the existing checklist that matches the text - existing_reco = [x for x in existing_checklist['items'] if x['text'] == reco['text']] - if len(existing_reco) > 0: - # Verify that the existing reco has a GUID - if 'guid' in existing_reco[0]: - reco['guid'] = existing_reco[0]['guid'] + if args_overwrite: + if (args_verbose): print("DEBUG: File {0} not found, generating new GUIDs...".format(filename)) + for reco in checklist['items']: + reco['guid'] = str(uuid.uuid4()) + if 'checklist_match' in reco: + reco['checklist_match_guid'] = str(uuid.uuid4()) + return checklist + else: + if (args_verbose): print("DEBUG: Retrieving checklist GUIDs from file {0}...".format(filename)) + existing_checklist = load_json(filename) + for reco in checklist['items']: + # Find a reco in the existing checklist that matches the text + existing_reco = [x for x in existing_checklist['items'] if x['text'] == reco['text']] + if len(existing_reco) > 0: + # Verify that the existing reco has a GUID + if 'guid' in existing_reco[0]: + reco['guid'] = existing_reco[0]['guid'] + else: + if (args_verbose): print("DEBUG: reco {0} not found in file {1}, generating new GUID...".format(reco['text'], filename)) + reco['guid'] = str(uuid.uuid4()) + # If no reco was found, generate a new GUID else: - if (args_verbose): print("DEBUG: reco {0} not found in file {1}, generating new GUID...".format(reco['text'], filename)) reco['guid'] = str(uuid.uuid4()) - # If no reco was found, generate a new GUID - else: - reco['guid'] = str(uuid.uuid4()) - return checklist + return checklist # If file doesn't exist, generate GUIDs for each reco else: if (args_verbose): print("DEBUG: File {0} not found, generating new GUIDs...".format(filename)) diff --git a/.github/actions/get_the_aks_checklist/entrypoint.py b/.github/actions/get_the_aks_checklist/entrypoint.py index 9af53e424..fd320798c 100644 --- a/.github/actions/get_the_aks_checklist/entrypoint.py +++ b/.github/actions/get_the_aks_checklist/entrypoint.py @@ -79,6 +79,8 @@ def get_theaks_recos(): item['waf'] = 'Resiliency' elif 'operations' in item['category'].lower() or 'management' in item['category'].lower(): item['waf'] = 'Operational Excellence' + item['sourceType'] = 'theakscl' + item['sourceFile'] = file_url retrieved_recos += theaks_recos if verbose: print("DEBUG: {0} recommendations found in file {1}".format(len(theaks_recos), file_path)) else: diff --git a/.github/actions/recov2lint/Dockerfile b/.github/actions/recov2lint/Dockerfile new file mode 100644 index 000000000..7f50a89b5 --- /dev/null +++ b/.github/actions/recov2lint/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.8-slim-buster +WORKDIR /app +COPY requirements.txt requirements.txt +COPY entrypoint.py entrypoint.py +RUN pip3 install -r requirements.txt +ENTRYPOINT ["python3", "/app/entrypoint.py"] \ No newline at end of file diff --git a/.github/actions/recov2lint/README.md b/.github/actions/recov2lint/README.md new file mode 100644 index 000000000..4047d343f --- /dev/null +++ b/.github/actions/recov2lint/README.md @@ -0,0 +1,26 @@ +# Retrieve recommendations from Well Architected service guides + +This action retrieves the recommendations described in [Well-Architected Service Guides](https://learn.microsoft.com/azure/well-architected/service-guides/?product=popular) and stores it as a new checklist. + +## Inputs + +## `services` + +**Optional** Service(s) whose service guide will be downloaded (leave blank for all service guides). You can specify multiple comma-separated values. Default `""`. + +## `output_folder` + +**Optional** Folder where the new checklists will be stored. Default `"./checklists-ext"`. + +## `verbose` + +**Optional** Whether script output is verbose or not. Default `"true"`. + +## Example usage + +``` +uses: ./.github/actions/get_service_guides +with: + output_file: './checklists' + service: 'Azure Kubernetes Service' +``` diff --git a/.github/actions/recov2lint/action.yml b/.github/actions/recov2lint/action.yml new file mode 100644 index 000000000..e7108a043 --- /dev/null +++ b/.github/actions/recov2lint/action.yml @@ -0,0 +1,18 @@ +# action.yml +name: 'Validate PRs for v2 recommendations and checklists.' +description: 'Verify that no duplicate names exist and that all YAML files conform to the schemas.' +inputs: + folder: + description: 'Folder where the recommendations are stored' + required: false + default: './v2 (string)' + verbose: + description: 'Verbose output, true/false (string)' + required: false + default: 'true' +runs: + using: 'docker' + image: 'Dockerfile' + args: + - '${{ inputs.folder }}' + - '${{ inputs.verbose }}' diff --git a/.github/actions/recov2lint/entrypoint.py b/.github/actions/recov2lint/entrypoint.py new file mode 100644 index 000000000..f55421dc4 --- /dev/null +++ b/.github/actions/recov2lint/entrypoint.py @@ -0,0 +1,139 @@ +# This scripts runs checks on the v2 recommendations and checklists +import jsonschema +import sys +import yaml +import json +import os +from pathlib import Path +from collections import Counter + + +# The script has been modified to be run from a github action with positional parameters +# 1. Root Folder where the v2 recommendations, checklists and schemas are stored +# 2. Verbose +try: + root_folder = sys.argv[1] +except: + root_folder = './v2' +try: + verbose = (sys.argv[2].lower() == 'true') +except: + verbose = True + +# Print the parameters +if verbose: print("INFO: Running recov2lint with parameters: root_folder='{0}', verbose={1}".format(root_folder, verbose)) + +# Constants +checklist_subfolder = os.path.join(root_folder, 'checklists') +reco_subfolder = os.path.join(root_folder, 'recos') +schema_subfolder = os.path.join(root_folder, 'schema') +reco_schema_file = os.path.join(schema_subfolder, 'recommendation.schema.json') +checklist_schema_file = os.path.join(schema_subfolder, 'checklist.schema.json') + +# Verify that the root folder and the subfolders exist +if not os.path.exists(root_folder): + print(f"ERROR: Root folder '{root_folder}' does not exist.") + sys.exit(1) +if not os.path.exists(checklist_subfolder): + print(f"ERROR: Checklist subfolder '{checklist_subfolder}' does not exist.") + sys.exit(1) +if not os.path.exists(reco_subfolder): + print(f"ERROR: Reco subfolder '{reco_subfolder}' does not exist.") + sys.exit(1) +if not os.path.exists(schema_subfolder): + print(f"ERROR: Schema subfolder '{schema_subfolder}' does not exist.") + sys.exit(1) +if not os.path.exists(reco_schema_file): + print(f"ERROR: Reco schema file '{reco_schema_file}' does not exist.") + sys.exit(1) +if not os.path.exists(checklist_schema_file): + print(f"ERROR: Checklist schema file '{checklist_schema_file}' does not exist.") + sys.exit(1) + +# Gets all YAML files in a folder and parses them into a list of objects, adding the filepath for reference +def get_yml_objects(folder, verbose=False): + files = list(Path(folder).rglob( '*.*' )) + if verbose: print("DEBUG: Found {0} files in folder {1}".format(len(files), folder)) + objects = [] + for file in files: + if (file.suffix == '.yaml') or (file.suffix == '.yml'): + try: + with open(file.resolve()) as f: + object = yaml.safe_load(f) + except Exception as e: + print("ERROR: Error when loading YAML file {0} - {1}". format(file, str(e))) + item = { + 'filepath': str(file.resolve()), + 'object': object + } + objects.append(item) + if verbose: print("DEBUG: Loaded {0} objects from folder {1}".format(len(objects), folder)) + return objects + +# Given a list of objects, compares them with a JSON schema +def get_invalid_objects(items, schema_file, verbose=False): + # Retrieve checklists schema + if verbose: print("DEBUG: Loading schema from", schema_file) + with open(schema_file, 'r') as stream: + try: + schema = json.load(stream) + except: + print("ERROR: Error loading JSON schema from", schema_file) + return None + # Start validation + if verbose: print("DEBUG: Starting validation with schema {0}...".format(schema_file)) + object_counter = 0 + finding_counter = 0 + for item in items: + object = item['object'] + object_counter +=1 + if 'name' in object: + object_name = object['name'] + else: + object_name = 'unnamed' + try: + jsonschema.validate(object, schema) + if verbose: print("DEBUG: Checklist '{0}' in '{1}' validates correctly against the schema.".format(object_name, item['filepath'])) + except jsonschema.exceptions.ValidationError as e: + print("ERROR: Object '{0}' in '{1}' does not validate against the schema.".format(object_name, item['filepath'])) + print("DEBUG: -", str(e)) + finding_counter += 1 + except jsonschema.exceptions.SchemaError as e: + print("ERROR: Schema", schema_file, "does not seem to be valid.") + if verbose: print("DEBUG: -", str(e)) + sys.exit(1) + except Exception as e: + print("ERROR: Unknown error validating checklist '{0}' against the schema {1}: {2}".format(cl['name'], schema_file,str(e))) + return finding_counter + + +# Get all recos +v2recos = get_yml_objects(reco_subfolder) +# Look for duplicate names +name_list = [reco['object']['name'] for reco in v2recos if 'name' in reco['object']] +name_counts = Counter(name_list) +duplicate_names = [item for item, count in name_counts.items() if count > 1] +if len(duplicate_names) > 0: + print("ERROR: Duplicate reco names found: {0}".format(duplicate_names)) + sys.exit(1) +else: + print("INFO: No duplicate reco names found in {0} recommendations.".format(len(v2recos))) +# Validate recos +reco_errors = get_invalid_objects(v2recos, reco_schema_file, verbose=verbose) +if reco_errors > 0: + print("ERROR: {0} recos did not validate against the schema.".format(reco_errors)) + sys.exit(1) +else: + print("INFO: {0} recommendations validated from folder {2}, {1} non-compliances found.".format(len(v2recos), reco_errors, reco_subfolder)) + +# Get all checklists +v2checklists = get_yml_objects(checklist_subfolder) +# Validate checklists +checklist_errors = get_invalid_objects(v2checklists, checklist_schema_file, verbose=verbose) +if checklist_errors > 0: + print("ERROR: {0} checklists did not validate against the schema.".format(checklist_errors)) + sys.exit(1) +else: + print("INFO: {0} checklists validated from folder {2}, {1} non-compliances found.".format(len(v2checklists), checklist_errors, checklist_subfolder)) + + diff --git a/.github/actions/recov2lint/requirements.txt b/.github/actions/recov2lint/requirements.txt new file mode 100644 index 000000000..da9426234 --- /dev/null +++ b/.github/actions/recov2lint/requirements.txt @@ -0,0 +1,2 @@ +pyyaml +jsonschema \ No newline at end of file diff --git a/.github/workflows/autotagv2.yml b/.github/workflows/autotagv2.yml new file mode 100644 index 000000000..80e9daf2b --- /dev/null +++ b/.github/workflows/autotagv2.yml @@ -0,0 +1,46 @@ +name: Autotag + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +on: + pull_request: + branches: [v2] + paths: + - '**.yml' + - '**.yaml' + +jobs: + autotag: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - id: files + uses: masesgroup/retrieve-changed-files@v2 + - id: alzimpact + name: Verify whether the modified files have an impact on the ALZ checklist + run: | + echo "DEBUG: Running on $SHELL" + pip install -r ./scripts/requirements.txt + alz_files=$(python3 ./scripts/cl.py list-recos --input-folder ./v2/recos --checklist-file ./v2/checklists/alz.yaml --only-filenames) + alz_files_count=$(echo "$alz_files" | wc -l) + echo "$alz_files_count reco files found in the ALZ checklist:" + echo "$alz_files" | head -2 + echo "..." + echo "$alz_files" | tail -2 + for input_file in ${{ steps.files.outputs.all }}; do + echo "Processing '$input_file'..." + if [[ "$alz_files" == *"$input_file"* ]]; then + echo "Modification to file '$input_file' detected, which seems to be a reco leveraged by the ALZ checklist" + echo "alz_impact=yes" >> $GITHUB_OUTPUT + else + echo "'$input_file' has no ALZ impact" + fi + done + - name: add ALZ label + if: ${{ steps.alzimpact.outputs.alz_impact == 'yes' }} + uses: actions-ecosystem/action-add-labels@v1 + id: addalzlabel + with: + labels: 'landingzone' + github_token: ${{ secrets.WORKFLOW_PAT }} \ No newline at end of file diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 5f30701b5..e9e6bc5df 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -26,7 +26,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check that GUIDs are unique id: checklistlint - uses: ./.github/actions/get_the_aks_checklist + uses: ./.github/actions/review-checklists-lint with: file_extension: 'en.json' key_name: 'guid' diff --git a/.github/workflows/linterv2.yml b/.github/workflows/linterv2.yml new file mode 100644 index 000000000..c364036ec --- /dev/null +++ b/.github/workflows/linterv2.yml @@ -0,0 +1,21 @@ +--- +name: Lint v2 recommendations and checklists +on: + # push: + # branches-ignore: [main] + pull_request: + branches: [v2] + +jobs: + build: + name: Lint v2 recommendations and checklists + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v2 + - name: Check unique names and schema conformity + id: checklistlint + uses: ./.github/actions/recov2lint + with: + folder: './v2' + verbose: 'false' diff --git a/.github/workflows/translatev2.yml b/.github/workflows/translatev2.yml new file mode 100644 index 000000000..ffc9b00a7 --- /dev/null +++ b/.github/workflows/translatev2.yml @@ -0,0 +1,159 @@ +name: Translation + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +on: + push: + branches: [ v2 ] + paths: + - '**.yaml' + - '**.yml' + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + translate: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + # Get list of files that have been changed in the push + - id: files + uses: masesgroup/retrieve-changed-files@v2 + # Set variables that indicate whether XLSX files have been modified, which would indicate that + - name: Set variables + id: variables + run: | + echo "v1_output_folder=v2/checklists" >> $GITHUB_OUTPUT + echo "clv2_file_list=('./v2/checklists/alz.yaml' './v2/checklists/waf.yaml' './v2/checklists/app_delivery.yaml')" >> $GITHUB_OUTPUT + # this action has been triggered by an automated action + - id: automationresult + name: Verify whether this action is a result of another action + run: | + for input_file in ${{ steps.files.outputs.all }}; do + if [[ "$input_file" == *"xlsx" ]]; then + echo "Modification to XLSX file $input_file detected, this seems to be the output of an automated PR" + echo "excel_file_changed=yes" >> $GITHUB_OUTPUT + else + echo "$input_file is not an XLSX file" + fi + done + + # Find out the impacted checklists + - id: climpact + if: ${{ steps.automationresult.outputs.excel_file_changed != 'yes' }} + name: Verify whether the modified files have an impact on the defined v2 checklists + run: | + # Install Python dependencies to run the checklist CLI + pip install -r ./scripts/requirements.txt + # The list of impacted checklists will be passed as an array + impacted_cl_files=() + done_something=no + clv2_file_list=${{ steps.variables.outputs.clv2_file_list }} + echo "Checking impact of changes in files ${{ steps.files.outputs.all }} to the following ${#clv2_file_list[@]} v2 checklists: ${clv2_file_list[@]}..." + for cl_file in "${clv2_file_list[@]}"; do + echo "Processing v2 checklist '${cl_file}'..." + cl_name=$(echo $cl_file | cut -d/ -f4 | cut -d. -f1) + cl_reco_files=$(python3 ./scripts/cl.py list-recos --input-folder ./v2/recos --checklist-file ./v2/checklists/alz.yaml --only-filenames) + cl_reco_files_count=$(echo "$cl_reco_files" | wc -l) + echo "$cl_reco_files_count reco files found referenced in the checklist $cl_file" + for input_file in ${{ steps.files.outputs.all }}; do + echo "- Processing changed file '$input_file'..." + if [[ "$cl_reco_files" == *"$input_file"* ]]; then + echo " * Modification to file '$input_file' detected, which seems to be a reco leveraged by the checklist $cl_name in $cl_file" + impacted_cl_files+="$cl_file" + done_something=yes + else + echo " * '$input_file' has no impact to the checklist $cl_name in $cl_file" + fi + done + done + echo "impacted_cl_files=(${impacted_cl_files[@]})" >> $GITHUB_OUTPUT + echo "done_something=$done_something" >> $GITHUB_OUTPUT + # Process the impacted checklists and generate v1 versions + - name: Generate v1 JSON checklists and translate them + id: clv1 + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + env: + AZURE_TRANSLATOR_SUBSCRIPTION_KEY: ${{ secrets.AZURE_TRANSLATOR_SUBSCRIPTION_KEY }} + AZURE_TRANSLATOR_ENDPOINT: ${{ secrets.AZURE_TRANSLATOR_ENDPOINT }} + AZURE_TRANSLATOR_REGION: ${{ secrets.AZURE_TRANSLATOR_REGION }} + run: | + # First we put the GH variable into a local one. Doing a loop against the GH variable directly doesn't work. + cl_v2_files=${{ steps.climpact.outputs.impacted_cl_files }} + # We will pass the list of generated v1 checklists as an array + cl_v1_files=() + echo "Generating v1 checklists for the following v2 files: $cl_v2_files..." + # We run now through the list of impacted checklists + for cl_file in "${cl_v2_files[@]}"; do + cl_name=$(echo $cl_file | cut -d/ -f4 | cut -d. -f1) + cl_v1_file="./${{ steps.variables.outputs.v1_output_folder }}/${cl_name}_checklist.en.json" + cl_v1_files+="$cl_v1_file" + # Generate v1 JSON for the checklist + echo "Generating v1 JSON for checklist $cl_name in $cl_file into $cl_v1_file..." + python3 ./scripts/cl.py export-checklist --input-folder ./v2/recos --service-dictionary ./scripts/service_dictionary.json --checklist-file $cl_file --output-file $cl_v1_file --verbose + # Sort modified file + # python3 ./scripts/sort_checklist.py --input-file $input_file + # Update the timestamp in the modified file + # python3 ./scripts/timestamp_checklist.py --input-file $input_file + # Translate the checklist + echo "Translating $cl_v1_file (this can take a few minutes)..." + python3 ./scripts/translate.py --input-file $cl_v1_file + done + echo "cl_v1_files=(${cl_v1_files[@]})" >> $GITHUB_OUTPUT + + # Generate macro-free spreadsheets and Azure Monitor workbooks + - name: Setup python + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + uses: actions/setup-python@v2 + with: + python-version: 3.8 #install the python needed + - name: Install dependencies + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + run: | + python -m pip install --upgrade pip + pip install requests openpyxl + # Create Excel spreadsheets + - name: Execute excel python script # run file + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + run: | + # First we put the GH variable into a local one. Doing a loop against the GH variable directly doesn't work. + cl_v1_files="${{ steps.clv1.outputs.cl_v1_files }}" + # For each file we will generate a macro-free Excel file + for cl_file in "${cl_v1_files[@]}"; do + echo "Generating macro-free Excel file for $cl_file..." + python3 ./scripts/update_excel_openpyxl.py --checklist-file="$cl_v1_file" --find-all --excel-file="./spreadsheet/macrofree/review_checklist_empty.xlsx" --output-name-is-input-name --output-path="./spreadsheet/macrofree/" --verbose + done + + # Create Azure Monitor workbooks + # Note that workbook creation might not work with some of the v1 checklists generated from v2, since categories and subcategories might be missing. + # The workbook creation script should instead pick service names instead of categories for the tabs. + - name: Execute workbook python script # run file + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + run: | + # First we put the GH variable into a local one. Doing a loop against the GH variable directly doesn't work. + cl_v1_files="${{ steps.clv1.outputs.cl_v1_files }}" + # For each file we will generate a macro-free Excel file + for cl_file in "${cl_v1_files[@]}"; do + # Create workbooks for the modified file, both with and without reco counters + echo "Generating workbooks for the v1 checklist file: $cl_file..." + python3 ./scripts/workbook_create.py --checklist-file="$cl_file" --output-path="./workbooks/" --blocks-path="./workbooks/blocks/" + python3 ./scripts/workbook_create.py --checklist-file="$cl_file" --output-path="./workbooks/" --blocks-path="./workbooks/blocks/" --counters + # Extra static commands to generate a network-specific ALZ workbook + # python3 ./scripts/workbook_create.py --checklist-file ./checklists/alz_checklist.en.json --output-path ./workbooks --blocks-path ./workbooks/blocks --create-arm-template --category=network --query-size medium + # python3 ./scripts/workbook_create.py --checklist-file ./checklists/alz_checklist.en.json --output-file ./workbooks/alz_checklist.en_network_counters.json --blocks-path ./workbooks/blocks --create-arm-template --category=network --query-size tiny --counters + # python3 ./scripts/workbook_create.py --checklist-file ./checklists/alz_checklist.en.json --output-file ./workbooks/alz_checklist.en_network_tabcounters.json --blocks-path ./workbooks/blocks --create-arm-template --category=network --query-size tiny --tab-counters + # App delivery + # python3 ./scripts/workbook_create.py --checklist-file ./checklists/network_appdelivery_checklist.en.json --output-file ./workbooks/appdelivery_checklist.en_network_workbook.json --blocks-path ./workbooks/blocks --create-arm-template --category=network --query-size tiny + # python3 ./scripts/workbook_create.py --checklist-file ./checklists/network_appdelivery_checklist.en.json --output-file ./workbooks/appdelivery_checklist.en_network_counters_workbook.json --blocks-path ./workbooks/blocks --create-arm-template --category=network --query-size tiny --counters + done + # Create the PR if any change was made + - name: Create pull request + uses: peter-evans/create-pull-request@v6 + if: ${{ steps.climpact.outputs.done_something == 'yes' }} + with: + title: 'Automated actions after change to ${{ steps.files.outputs.all }}' + body: 'Processed changed files ${{ steps.files.outputs.all }}' + labels: 'automated' + token: ${{ secrets.WORKFLOW_PAT }} diff --git a/checklists-ext/appservicewebapps_sg_checklist.en.json b/checklists-ext/appservicewebapps_sg_checklist.en.json index fd6463e21..f76a5606a 100644 --- a/checklists-ext/appservicewebapps_sg_checklist.en.json +++ b/checklists-ext/appservicewebapps_sg_checklist.en.json @@ -6,194 +6,217 @@ "service": "App Service Web Apps", "text": "(App Service plan) Choose the Premium tier of an App Service plan for production workloads. Set the maximum and minimum number of workers according to your capacity planning. For more information, see App Service plan overview.", "description": "A premium App Service plan offers advanced scaling features and ensures redundancy if failures occur.", - "type": "recommendation" + "type": "recommendation", + "guid": "a8bc7080-3d8a-43b1-aefc-1dcfdf45fff3" }, { "waf": "Reliability", "service": "App Service Web Apps", "text": "(App Service plan) Enable zone redundancy. Consider provisioning more than three instances to enhance fault tolerance. Check regional support for zone redundancy because not all regions offer this feature.", "description": "Your application can withstand failures in a single zone when multiple instances are spread across zones. Traffic automatically shifts to healthy instances in other zones and maintains application reliability if one zone is unavailable.", - "type": "recommendation" + "type": "recommendation", + "guid": "6421eda8-605d-4058-baf3-5d39c62695f2" }, { "waf": "Reliability", "service": "App Service Web Apps", "text": "(App Service) Consider disabling the application request routing (ARR) affinity feature. ARR affinity creates sticky sessions that redirect users to the node that handled their previous requests.", "description": "Incoming requests are evenly distributed across all available nodes when you disable ARR affinity. Evenly distributed requests prevent traffic from overwhelming any single node. Requests can be seamlessly redirected to other healthy nodes if a node is unavailable. Avoid session affinity to ensure that your App Service instance remains stateless. A stateless App Service reduces complexity and ensures consistent behavior across nodes. Remove sticky sessions so that App Service can add or remove instances to scale horizontally.", - "type": "recommendation" + "type": "recommendation", + "guid": "0b2003b3-120d-47e2-b088-6326688f6020" }, { "waf": "Reliability", "service": "App Service Web Apps", "text": "(App Service) Define automatic healing rules based on request count, slow requests, memory limits, and other indicators that are part of your performance baseline. Consider this configuration as part of your scaling strategy.", "description": "Automatic healing rules help your application recover automatically from unexpected problems. The configured rules trigger healing actions when thresholds are breached. Automatic healing enables automatic proactive maintenance.", - "type": "recommendation" + "type": "recommendation", + "guid": "c3976ed2-a374-4e1e-aaa9-6b5152dc79e6" }, { "waf": "Reliability", "service": "App Service Web Apps", "text": "(App Service) Enable the health check feature and provide a path that responds to the health check requests.", "description": "Health checks can detect problems early. Then the system can automatically take corrective actions when a health check request fails. The load balancer routes traffic away from unhealthy instances, which directs users to healthy nodes.", - "type": "recommendation" + "type": "recommendation", + "guid": "7ad7026a-e2e6-4e45-a0b4-9c707fe0e388" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) Assign managed identities to the web app. To maintain isolation boundaries, don't share or reuse identities across applications. Make sure that you securely connect to your container registry if you use containers for your deployment.", "description": "The application retrieves secrets from Key Vault to authenticate outward communication from the application. Azure manages the identity and doesn't require you to provision or rotate any secrets. You have distinct identities for granularity of control. Distinct identities make revocation easy if an identity is compromised.", - "type": "recommendation" + "type": "recommendation", + "guid": "a7caacdd-d39b-4e31-8dcf-c40f4c2bf86d" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) Configure custom domains for applications. Disable HTTP and only accept HTTPS requests.", "description": "Custom domains enable secure communication through HTTPS using Transport Layer Security (TLS) protocol, which ensures the protection of sensitive data and builds user trust.", - "type": "recommendation" + "type": "recommendation", + "guid": "669b3cbe-e126-445b-8707-ac7ed7a242f8" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) valuate whether App Service built-in authentication is the right mechanism to authenticate users that access your application. App Service built-in authentication integrates with Microsoft Entra ID. This feature handles token validation and user identity management across multiple sign-in providers and supports OpenID Connect. With this feature, you don't have authorization at a granular level, and you don't have a mechanism to test authentication.", "description": "When you use this feature, you don't have to use authentication libraries in application code, which reduces complexity. The user is already authenticated when a request reaches the application.", - "type": "recommendation" + "type": "recommendation", + "guid": "707d4208-95aa-44b5-946a-95951187fbbe" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) Configure the application for virtual network integration. Use private endpoints for App Service apps. Block all public traffic. Route the container image pull through the virtual network integration. All outgoing traffic from the application passes through the virtual network.", "description": "Get the security benefits of using an Azure virtual network. For example, the application can securely access resources within the network. Add a private endpoint to help protect your application. Private endpoints limit direct exposure to the public network and allow controlled access through the reverse proxy.", - "type": "recommendation" + "type": "recommendation", + "guid": "41d2b47e-9224-4f24-a14f-d7c389adc40a" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) To implement hardening: - Disable basic authentication that uses a username and password in favor of Microsoft Entra ID-based authentication. - Turn off remote debugging so that inbound ports aren't opened. - Enable CORS policies to tighten incoming requests. - Disable protocols, such as FTP.", "description": "We don't recommend basic authentication as a secure deployment method. Microsoft Entra ID employs OAuth 2.0 token-based authentication, which offers numerous advantages and enhancements that address the limitations that are associated with basic authentication. Policies restrict access to application resources, only allow requests from specific domains, and secure cross-region requests.", - "type": "recommendation" + "type": "recommendation", + "guid": "87580a6c-f8fb-4cf4-9086-3cb2e6bf09ab" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service) Always use Key Vault references as app settings.", "description": "Secrets are kept separate from your app's configuration. App settings are encrypted at rest. App Service also manages secret rotations.", - "type": "recommendation" + "type": "recommendation", + "guid": "14f83da8-4052-4d06-bd6c-ca6ea753c62e" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service plan) Enable Microsoft Defender for Cloud for App Service.", "description": "Get real-time protection for resources that run in an App Service plan. Guard against threats and enhance your overall security posture.", - "type": "recommendation" + "type": "recommendation", + "guid": "d55d6834-894e-4fa9-a5da-93d42d703e02" }, { "waf": "Security", "service": "App Service Web Apps", "text": "(App Service plan) Enable diagnostic logging and add instrumentation to your app. The logs are sent to Azure Storage accounts, Azure Event Hubs, and Log Analytics. For more information about audit log types, see Supported log types.", "description": "Logging captures access patterns. It records relevant events that provide valuable insights into how users interact with an application or platform. This information is crucial for accountability, compliance, and security purposes.", - "type": "recommendation" + "type": "recommendation", + "guid": "47eb1ae3-41cf-4925-8ad5-7c9d865e4392" }, { "waf": "Cost", "service": "App Service Web Apps", "text": "(App Service plan) Choose Free or Basic tiers for lower environments. We recommend these tiers for experimental use. Remove the tiers when you no longer need them.", "description": "The Free and Basic tiers are budget-friendly compared to higher tiers. They provide a cost-effective solution for nonproduction environments that don't need the full features and performance of premium plans.", - "type": "recommendation" + "type": "recommendation", + "guid": "353d556b-015a-4ae6-9352-4551b7c7e267" }, { "waf": "Cost", "service": "App Service Web Apps", "text": "(App Service plan) Take advantage of discounts and explore preferred pricing for: - Lower environments with dev/test plans. - Azure reservations and Azure savings plans for dedicated compute that you provision in the Premium V3 tier and App Service Environment. Use reserved instances for stable workloads that have predictable usage patterns.", "description": "Dev/test plans provide reduced rates for Azure services, which makes them cost-effective for nonproduction environments. Use reserved instances to prepay for compute resources and get significant discounts.", - "type": "recommendation" + "type": "recommendation", + "guid": "5ad6a3b4-65eb-407e-8547-ce4ecdf9fe89" }, { "waf": "Cost", "service": "App Service Web Apps", "text": "(App Service) Monitor costs that App Service resources incur. Run the cost analysis tool in the Azure portal. Create budgets and alerts to notify stakeholders.", "description": "You can identify cost spikes, inefficiencies, or unexpected expenses early on. This proactive approach helps you to provide budgetary controls to prevent overspending.", - "type": "recommendation" + "type": "recommendation", + "guid": "4cf20e78-3047-4eca-a608-421414e82e4b" }, { "waf": "Cost", "service": "App Service Web Apps", "text": "(App Service plan) Scale in when demand decreases. To scale in, define scale rules to reduce the number of instances in Azure Monitor.", "description": "Prevent wastage and reduce unnecessary expenses.", - "type": "recommendation" + "type": "recommendation", + "guid": "68b1b702-d272-4c97-8b70-727ba42a9b27" }, { "waf": "Operations", "service": "App Service Web Apps", "text": "(App Service) Monitor the health of your instances and activate instance health probes. Set up a specific path for handling health probe requests.", "description": "You can detect problems promptly and take necessary actions to maintain availability and performance.", - "type": "recommendation" + "type": "recommendation", + "guid": "5fe0c2c9-3403-47be-9e45-265107d05c71" }, { "waf": "Operations", "service": "App Service Web Apps", "text": "(App Service) Enable diagnostics logs for the application and the instance. Frequent logging can slow down the performance of the system, add to storage costs, and introduce risk if you have unsecure access to logs. Follow these best practices: - Log the right level of information. - Set retention policies. - Keep an audit trail of authorized access and unauthorized attempts. - Treat logs as data and apply data-protection controls.", "description": "Diagnostic logs provide valuable insights into your app's behavior. Monitor traffic patterns and identify anomalies.", - "type": "recommendation" + "type": "recommendation", + "guid": "e6afc11c-557b-4621-8716-606b90f670c7" }, { "waf": "Operations", "service": "App Service Web Apps", "text": "(App Service) Take advantage of App Service managed certificates to offload certification management to Azure.", "description": "App Service automatically handles processes like certificate procurement, certificate verification, certificate renewal, and importing certificates from Key Vault. Alternatively, upload your certificate to Key Vault and authorize the App Service resource provider to access it.", - "type": "recommendation" + "type": "recommendation", + "guid": "15a2cb5e-2a24-49f7-8d54-042d22543f54" }, { "waf": "Operations", "service": "App Service Web Apps", "text": "(App Service plan) Validate app changes in the staging slot before you swap it with the production slot.", "description": "Avoid downtime and errors. Quickly revert to the last-known good state if you detect a problem after a swap.", - "type": "recommendation" + "type": "recommendation", + "guid": "ce8266e4-c481-4133-a5ce-2ee070954eeb" }, { "waf": "Performance", "service": "App Service Web Apps", "text": "Enable the Always On setting when applications share a single App Service plan. App Service apps automatically unload when idle to save resources. The next request triggers a cold start, which can cause request timeouts.", "description": "The application is never unloaded with Always On enabled.", - "type": "recommendation" + "type": "recommendation", + "guid": "7a02f601-b092-4772-a044-a48a3caa335c" }, { "waf": "Performance", "service": "App Service Web Apps", "text": "Consider using HTTP/2 for applications to improve protocol efficiency.", "description": "Choose HTTP/2 over HTTP/1.1 because HTTP/2 fully multiplexes connections, reuses connections to reduce overhead, and compresses headers to minimize data transfer.", - "type": "recommendation" + "type": "recommendation", + "guid": "0a0eaf20-6b30-45ac-b302-0b7cb940fc90" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -230,6 +253,6 @@ "name": "App Service Web Apps Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/aprl_checklist.en.json b/checklists-ext/aprl_checklist.en.json index 565810fc5..ca6358ede 100644 --- a/checklists-ext/aprl_checklist.en.json +++ b/checklists-ext/aprl_checklist.en.json @@ -27,7 +27,9 @@ "severity": "High", "category": "High Availability", "guid": "bb6deb9d-24fa-4ee8-bc23-ac3ebc7fdf8e", - "source": "azure-resources/AAD/domainServices/recommendations.yaml", + "sourceFile": "azure-resources/AAD/domainServices/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Gets Entry Domain Services that are using the Standard SKU\nresources\n| where type == \"microsoft.aad/domainservices\"\n| extend sku = properties.sku\n| where sku =~ 'Standard'\n| project recommendationId='bb6deb9d-24fa-4ee8-bc23-ac3ebc7fdf8e', name=name, id=id, tags=tags, param1=strcat('SKU:', sku)\n" }, { @@ -56,7 +58,9 @@ "severity": "High", "category": "High Availability", "guid": "a3058909-fcf8-4450-88b5-499f57449178", - "source": "azure-resources/AAD/domainServices/recommendations.yaml", + "sourceFile": "azure-resources/AAD/domainServices/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Gets Entry Domain Services that are using only one replicaSet\nresources\n| where type == \"microsoft.aad/domainservices\"\n| extend replicaSets = properties.replicaSets\n| where array_length(replicaSets) < 2\n| project recommendationId='a3058909-fcf8-4450-88b5-499f57449178', name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)\n" }, { @@ -85,7 +89,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "74fcb9f2-9a25-49a6-8c42-d32851c4afb7", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VMware Solution resources that don't have one or more service health alerts covering AVS private clouds in the deployed subscription and region pairs.\n//full list of private clouds\n(resources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend locale = tolower(location)\n| extend subscriptionId = tolower(subscriptionId)\n| project id, name, tags, subscriptionId, locale)\n| join kind=leftouter\n//Alert ID's that include all incident types filtered by AVS Service Health alerts\n((resources\n| where type == \"microsoft.insights/activitylogalerts\"\n| extend alertproperties = todynamic(properties)\n| where alertproperties.condition.allOf[0].field == \"category\" and alertproperties.condition.allOf[0].equals == \"ServiceHealth\"\n| where alertproperties.condition.allOf[1].field == \"properties.impactedServices[*].ServiceName\" and set_has_element(alertproperties.condition.allOf[1].containsAny, \"Azure VMware Solution\")\n| extend locale = strcat_array(split(tolower(alertproperties.condition.allOf[2].containsAny),' '), '')\n| mv-expand todynamic(locale)\n| where locale != \"global\"\n| project subscriptionId, tostring(locale) )\n| union\n//Alert ID's that include only some of the incident types after filtering by service health alerts covering AVS private clouds.\n(resources\n| where type == \"microsoft.insights/activitylogalerts\"\n| extend subscriptionId = tolower(subscriptionId)\n| extend alertproperties = todynamic(properties)\n| where alertproperties.condition.allOf[0].field == \"category\" and alertproperties.condition.allOf[0].equals == \"ServiceHealth\"\n| where alertproperties.condition.allOf[2].field == \"properties.impactedServices[*].ServiceName\" and set_has_element(alertproperties.condition.allOf[2].containsAny, \"Azure VMware Solution\")\n| extend locale = strcat_array(split(tolower(alertproperties.condition.allOf[3].containsAny),' '), '')\n| mv-expand todynamic(locale)\n| mv-expand alertproperties.condition.allOf[1].anyOf\n| extend incidentType = alertproperties_condition_allOf_1_anyOf.equals\n| where locale != \"global\"\n| project id, subscriptionId, locale, incidentType\n| distinct subscriptionId, tostring(locale), tostring(incidentType)\n| summarize incidentTypes=count() by subscriptionId, locale\n| where incidentTypes == 5 //only include this subscription, region pair if it includes all the incident types.\n| project subscriptionId, locale)) on subscriptionId, locale\n| where subscriptionId1 == \"\" or locale1 == \"\" or isnull(subscriptionId1) or isnull(locale1)\n| project recommendationId = \"74fcb9f2-9a25-49a6-8c42-d32851c4afb7\", name, id, tags, param1 = \"avsServiceHealthAlertsAllIncidentTypesConfigured: False\"\n\n" }, { @@ -114,7 +120,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "29d7a115-dfb6-4df1-9205-04824109548f", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -143,7 +151,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "f86355e3-de7c-4dad-8080-1b0b411e66c8", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -176,7 +186,9 @@ "severity": "Low", "category": "High Availability", "guid": "9ec5b4c8-3dd8-473a-86ee-3273290331b9", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VMware Solution resources that aren't configured as stretched clusters and in supported regions.\nresources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend avsproperties = todynamic(properties)\n| where avsproperties.availability.strategy != \"DualZone\"\n| where location in (\"uksouth\", \"westeurope\", \"germanywestcentral\", \"australiaeast\")\n| project recommendationId = \"9ec5b4c8-3dd8-473a-86ee-3273290331b9\", name, id, tags, param1 = \"stretchClusters: Disabled\"\n\n" }, { @@ -205,7 +217,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "4232eb32-3241-4049-9e14-9b8005817b56", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VMware Solution resources that don't have a vSAN capacity critical alert with a threshold of 75% or a warning capacity of 70%.\n(\nresources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend scopeId = tolower(tostring(id))\n| project ['scopeId'], name, id, tags\n| join kind=leftouter (\nresources\n| where type == \"microsoft.insights/metricalerts\"\n| extend alertProperties = todynamic(properties)\n| mv-expand alertProperties.scopes\n| mv-expand alertProperties.criteria.allOf\n| extend scopeId = tolower(tostring(alertProperties_scopes))\n| extend metric = alertProperties_criteria_allOf.metricName\n| extend threshold = alertProperties_criteria_allOf.threshold\n| project scopeId, tostring(metric), toint(['threshold'])\n| where metric == \"DiskUsedPercentage\"\n| where threshold == 75\n) on scopeId\n| where isnull(['threshold'])\n| project recommendationId = \"4232eb32-3241-4049-9e14-9b8005817b56\", name, id, tags, param1 = \"vsanCapacityCriticalAlert: isNull or threshold != 75\"\n)\n| union (\nresources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend scopeId = tolower(tostring(id))\n| project ['scopeId'], name, id, tags\n| join kind=leftouter (\nresources\n| where type == \"microsoft.insights/metricalerts\"\n| extend alertProperties = todynamic(properties)\n| mv-expand alertProperties.scopes\n| mv-expand alertProperties.criteria.allOf\n| extend scopeId = tolower(tostring(alertProperties_scopes))\n| extend metric = alertProperties_criteria_allOf.metricName\n| extend threshold = alertProperties_criteria_allOf.threshold\n| project scopeId, tostring(metric), toint(['threshold'])\n| where metric == \"DiskUsedPercentage\"\n| where threshold == 70\n) on scopeId\n| where isnull(['threshold'])\n| project recommendationId = \"4232eb32-3241-4049-9e14-9b8005817b56\", name, id, tags, param1 = \"vsanCapacityWarningAlert: isNull or threshold != 70\"\n)\n\n" }, { @@ -234,7 +248,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "fa4ab927-bced-429a-971a-53350de7f14b", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -263,7 +279,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "4ee5d535-c47b-470a-9557-4a3dd297d62f", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VMware Solution resources that don't have a Cluster CPU capacity critical alert with a threshold of 95%.\nresources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend scopeId = tolower(tostring(id))\n| project ['scopeId'], name, id, tags\n| join kind=leftouter (\nresources\n| where type == \"microsoft.insights/metricalerts\"\n| extend alertProperties = todynamic(properties)\n| mv-expand alertProperties.scopes\n| mv-expand alertProperties.criteria.allOf\n| extend scopeId = tolower(tostring(alertProperties_scopes))\n| extend metric = alertProperties_criteria_allOf.metricName\n| extend threshold = alertProperties_criteria_allOf.threshold\n| project scopeId, tostring(metric), toint(['threshold'])\n| where metric == \"EffectiveCpuAverage\"\n| where threshold == 95\n) on scopeId\n| where isnull(['threshold'])\n| project recommendationId = \"4ee5d535-c47b-470a-9557-4a3dd297d62f\", name, id, tags, param1 = \"hostCpuCriticalAlert: isNull or threshold != 95\"\n\n" }, { @@ -292,7 +310,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "029208c8-5186-4a76-8ee8-6e3445fef4dd", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VMware Solution resources that don't have a cluster host memory critical alert with a threshold of 95%.\nresources\n| where ['type'] == \"microsoft.avs/privateclouds\"\n| extend scopeId = tolower(tostring(id))\n| project ['scopeId'], name, id, tags\n| join kind=leftouter (\nresources\n| where type == \"microsoft.insights/metricalerts\"\n| extend alertProperties = todynamic(properties)\n| mv-expand alertProperties.scopes\n| mv-expand alertProperties.criteria.allOf\n| extend scopeId = tolower(tostring(alertProperties_scopes))\n| extend metric = alertProperties_criteria_allOf.metricName\n| extend threshold = alertProperties_criteria_allOf.threshold\n| project scopeId, tostring(metric), toint(['threshold'])\n| where metric == \"UsageAverage\"\n| where threshold == 95\n) on scopeId\n| where isnull(['threshold'])\n| project recommendationId = \"029208c8-5186-4a76-8ee8-6e3445fef4dd\", name, id, tags, param1 = \"hostMemoryCriticalAlert: isNull or threshold != 95\"\n\n" }, { @@ -321,7 +341,9 @@ "severity": "High", "category": "Governance", "guid": "a5ef7c05-c611-4842-9af5-11efdc99123a", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -350,7 +372,9 @@ "severity": "High", "category": "Security", "guid": "e0ac2f57-c8c0-4b8c-a7c8-19e5797828b5", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -379,7 +403,9 @@ "severity": "High", "category": "High Availability", "guid": "fcc2e257-23af-4c68-aac8-9cc03033c939", - "source": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceFile": "azure-resources/AVS/privateClouds/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -412,7 +438,9 @@ "severity": "High", "category": "High Availability", "guid": "baf3bfc0-32a2-4c0c-926d-c9bf0b49808e", - "source": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceFile": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all API Management instances that aren't Premium\nresources\n| where type =~ 'Microsoft.ApiManagement/service'\n| extend skuName = sku.name\n| where tolower(skuName) != tolower('premium')\n| project recommendationId = \"baf3bfc0-32a2-4c0c-926d-c9bf0b49808e\", name, id, tags, param1=strcat(\"SKU: \", skuName)\n\n" }, { @@ -445,7 +473,9 @@ "severity": "High", "category": "High Availability", "guid": "740f2c1c-8857-4648-80eb-47d2c56d5a50", - "source": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceFile": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Premium API Management instances that aren't zone redundant\nresources\n| where type =~ 'Microsoft.ApiManagement/service'\n| extend skuName = sku.name\n| where tolower(skuName) == tolower('premium')\n| where isnull(zones) or array_length(zones) < 2\n| extend zoneValue = iff((isnull(zones)), \"null\", zones)\n| project recommendationId = \"740f2c1c-8857-4648-80eb-47d2c56d5a50\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Zones value: \", zoneValue )\n\n" }, { @@ -478,7 +508,9 @@ "severity": "High", "category": "High Availability", "guid": "e35cf148-8eee-49d1-a1c9-956160f99e0b", - "source": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceFile": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all API Management instances that aren't upgraded to platform version stv2\nresources\n| where type =~ 'Microsoft.ApiManagement/service'\n| extend plat_version = properties.platformVersion\n| extend skuName = sku.name\n| where tolower(plat_version) != tolower('stv2')\n| project recommendationId = \"e35cf148-8eee-49d1-a1c9-956160f99e0b\", name, id, tags, param1=strcat(\"Platform Version: \", plat_version) , param2=strcat(\"SKU: \", skuName)\n\n" }, { @@ -507,7 +539,9 @@ "severity": "Low", "category": "High Availability", "guid": "c79680ea-de85-44fa-a596-f31fa17a952f", - "source": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceFile": "azure-resources/ApiManagement/service/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -536,7 +570,9 @@ "severity": "High", "category": "High Availability", "guid": "8dbcd94b-0948-4df3-b608-1946726c3abf", - "source": "azure-resources/App/containerApps/recommendations.yaml", + "sourceFile": "azure-resources/App/containerApps/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -565,7 +601,9 @@ "severity": "High", "category": "High Availability", "guid": "f4201965-a88d-449d-b3b4-021394719eb2", - "source": "azure-resources/App/managedEnvironments/recommendations.yaml", + "sourceFile": "azure-resources/App/managedEnvironments/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// The query filters the qualified Container app environments that do not have Zone Redundancy enabled.\nresources\n| where type =~ \"microsoft.app/managedenvironments\"\n| where tobool(properties.zoneRedundant) == false\n| project recommendationId = \"f4201965-a88d-449d-b3b4-021394719eb2\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\n| order by id asc\n" }, { @@ -594,7 +632,9 @@ "severity": "Low", "category": "Governance", "guid": "bb4c8db4-f821-475b-b1ea-16e95358665e", - "source": "azure-resources/AppConfiguration/configurationStores/recommendations.yaml", + "sourceFile": "azure-resources/AppConfiguration/configurationStores/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Purge protection should be enabled for App Configuration stores to prevent accidental deletion of configuration data.\nresources\n| where type =~ \"Microsoft.AppConfiguration/configurationStores\"\n| where sku.name <> \"free\"\n| where (properties.enablePurgeProtection <> true) or isnull(properties.enablePurgeProtection )\n| project recommendationId = \"bb4c8db4-f821-475b-b1ea-16e95358665e\", name, id, tags, param1 = \"Enable purge protection\"\n" }, { @@ -623,7 +663,9 @@ "severity": "High", "category": "High Availability", "guid": "2102a57a-a056-4d5e-afe5-9df9f92177ca", - "source": "azure-resources/AppConfiguration/configurationStores/recommendations.yaml", + "sourceFile": "azure-resources/AppConfiguration/configurationStores/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Upgrade to App Configuration Standard tier\nresources\n| where type =~ \"Microsoft.AppConfiguration/configurationStores\"\n| where sku.name == \"free\"\n| project recommendationId = \"2102a57a-a056-4d5e-afe5-9df9f92177ca\", name, id, tags, param1 = \"Upgrade to Standard SKU\"\n" }, { @@ -656,7 +698,9 @@ "severity": "High", "category": "High Availability", "guid": "67205887-0733-466e-b50e-b1cd7316c514", - "source": "azure-resources/Automation/automationAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Automation/automationAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -685,7 +729,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "3464854d-6f75-4922-95e4-a2a308b53ce6", - "source": "azure-resources/Batch/batchAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Batch/batchAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -714,7 +760,9 @@ "severity": "High", "category": "High Availability", "guid": "71cfab8f-d588-4742-b175-b6e07ae48dbd", - "source": "azure-resources/Batch/batchAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Batch/batchAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -743,7 +791,9 @@ "severity": "High", "category": "High Availability", "guid": "5a44bd30-ae6a-4b81-9b68-dc3a8ffca4d8", - "source": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceFile": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Cache for Redis instances with one or no Zones selected\nresources\n| where type =~ \"microsoft.cache/redis\"\n| where array_length(zones) <= 1 or isnull(zones)\n| project recommendationId = \"5a44bd30-ae6a-4b81-9b68-dc3a8ffca4d8\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\n| order by id asc\n\n" }, { @@ -772,7 +822,9 @@ "severity": "Medium", "category": "High Availability", "guid": "cabc1f98-c8a7-44f7-ab24-977982ef3f70", - "source": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceFile": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -801,7 +853,9 @@ "severity": "Medium", "category": "Security", "guid": "c474fc96-4e6a-4fb0-95d0-a26b3f35933c", - "source": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceFile": "azure-resources/Cache/Redis/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Azure Redis cache services not protected by private endpoints.\nResources\n| where type =~ \"microsoft.cache/redis\"\n| where properties['publicNetworkAccess'] == \"Enabled\"\n| project recommendationId = \"c474fc96-4e6a-4fb0-95d0-a26b3f35933c\", name, id, tags\n| order by id asc\n\n" }, { @@ -842,7 +896,9 @@ "severity": "High", "category": "Business Continuity", "guid": "9437634c-d69e-2747-b13e-631c13182150", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Avoid combining Traffic Manager and Front Door\nresources\n| where type == \"microsoft.network/trafficmanagerprofiles\"\n| mvexpand(properties.endpoints)\n| extend endpoint=tostring(properties_endpoints.properties.target)\n| project name, trafficmanager=id, matchname=endpoint, tags\n| join (\n resources\n | where type =~ \"microsoft.cdn/profiles/afdendpoints\"\n | extend matchname= tostring(properties.hostName)\n | extend splitid=split(id, \"/\")\n | extend frontdoorid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\n | project name, id, matchname, frontdoorid, type\n | union\n (cdnresources\n | where type =~ \"Microsoft.Cdn/Profiles/CustomDomains\"\n | extend matchname= tostring(properties.hostName)\n | extend splitid=split(id, \"/\")\n | extend frontdoorid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\n | project name, id, matchname, frontdoorid, type)\n )\n on matchname\n| project\n recommendationId = \"9437634c-d69e-2747-b13e-631c13182150\",\n name=split(trafficmanager, \"/\")[-1],\n id=trafficmanager,\n tags,\n param1=strcat(\"hostname:\", matchname),\n param2=strcat(\"frontdoorid:\", frontdoorid)\n\n" }, { @@ -871,7 +927,9 @@ "severity": "High", "category": "Security", "guid": "6c40b7ae-2bea-5748-be1a-9e9e3b834649", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -908,7 +966,9 @@ "severity": "Medium", "category": "Scalability", "guid": "52bc9a7b-23c8-bc4c-9d2a-7bc43b50104a", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -945,7 +1005,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "1ad74c3c-e3d7-0046-b83f-a2199974ef15", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -974,7 +1036,9 @@ "severity": "High", "category": "Security", "guid": "d9bd6780-0d6f-cd4c-bc66-8ddcab12f3d1", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Use end-to-end TLS\ncdnresources\n| where type == \"microsoft.cdn/profiles/afdendpoints/routes\"\n| extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols\n| project id,name,forwardingProtocol,supportedProtocols,tags\n| where forwardingProtocol !~ \"httpsonly\" or supportedProtocols has \"http\"\n| project recommendationId= \"d9bd6780-0d6f-cd4c-bc66-8ddcab12f3d1\", name,id,tags,param1=strcat(\"forwardingProtocol:\",forwardingProtocol),param2=strcat(\"supportedProtocols:\",supportedProtocols)\n\n" }, { @@ -1003,7 +1067,9 @@ "severity": "High", "category": "Security", "guid": "24ab9f11-a3e4-3043-a985-22cf94c4933a", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Use HTTP to HTTPS redirection\ncdnresources\n| where type == \"microsoft.cdn/profiles/afdendpoints/routes\"\n| extend httpsRedirect=tostring(properties.httpsRedirect)\n| project id,name,httpsRedirect,tags\n| where httpsRedirect !~ \"enabled\"\n| project recommendationId= \"24ab9f11-a3e4-3043-a985-22cf94c4933a\", name,id,tags,param1=strcat(\"httpsRedirect:\",httpsRedirect)\n\n" }, { @@ -1032,7 +1098,9 @@ "severity": "High", "category": "Security", "guid": "29d65c41-2fad-d142-95eb-9eab95f6c0a5", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1061,7 +1129,9 @@ "severity": "Medium", "category": "High Availability", "guid": "4638c2c0-03de-6d42-9e09-82ee4478cbf3", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1090,7 +1160,9 @@ "severity": "Medium", "category": "Governance", "guid": "cd6a32af-747a-e649-82a7-a98f528ca842", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1119,7 +1191,9 @@ "severity": "Medium", "category": "Security", "guid": "1bd2b7e8-400f-e64a-99a2-c572f7b08a62", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Enable the WAF\n\nresources\n| where type =~ \"microsoft.cdn/profiles\" and sku has \"AzureFrontDoor\"\n| project name, cdnprofileid=tolower(id), tostring(tags), resourceGroup, subscriptionId,skuname=tostring(sku.name)\n| join kind= fullouter (\n cdnresources\n | where type == \"microsoft.cdn/profiles/securitypolicies\"\n | extend wafpolicyid=tostring(properties['parameters']['wafPolicy']['id'])\n | extend splitid=split(id, \"/\")\n | extend cdnprofileid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\n | project secpolname=name, cdnprofileid, wafpolicyid\n )\n on cdnprofileid\n| project name, cdnprofileid, secpolname, wafpolicyid,skuname\n| join kind = fullouter (\n resources\n | where type == \"microsoft.network/frontdoorwebapplicationfirewallpolicies\"\n | extend\n managedrulesenabled=iff(tostring(properties.managedRules.managedRuleSets) != \"[]\", true, false),\n enabledState = tostring(properties.policySettings.enabledState)\n | project afdwafname=name, managedrulesenabled, wafpolicyid=id, enabledState, tostring(tags)\n )\n on wafpolicyid\n| where name != \"\"\n| summarize\n associatedsecuritypolicies=countif(secpolname != \"\"),\n wafswithmanagedrules=countif(managedrulesenabled == 1)\n by name, id=cdnprofileid, tags,skuname\n| where associatedsecuritypolicies == 0 or wafswithmanagedrules == 0\n| project\n recommendationId = \"1bd2b7e8-400f-e64a-99a2-c572f7b08a62\",\n name,\n id,\n todynamic(tags),\n param1 = strcat(\"associatedsecuritypolicies:\", associatedsecuritypolicies),\n param2 = strcat(\"wafswithmanagedrules:\", wafswithmanagedrules),\n param3 = strcat(\"skuname:\",skuname)\n\n" }, { @@ -1148,7 +1222,9 @@ "severity": "Low", "category": "High Availability", "guid": "38f3d542-6de6-a44b-86c6-97e3be690281", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Disable health probes when there is only one origin in an origin group\ncdnresources\n| where type =~ \"microsoft.cdn/profiles/origingroups\"\n| extend healthprobe=tostring(properties.healthProbeSettings)\n| project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe\n| join (\n cdnresources\n | where type =~ \"microsoft.cdn/profiles/origingroups/Origins\"\n | extend origingroupname = tostring(properties.originGroupName)\n )\n on origingroupname\n| summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != \"\") by origingroupname, id, tostring(tags), resourceGroup, subscriptionId\n| where origincount == 1 and enabledhealthprobecount != 0\n| project\n recommendationId = \"38f3d542-6de6-a44b-86c6-97e3be690281\",\n name=origingroupname,\n id,\n todynamic(tags),\n param1 = strcat(\"origincount:\", origincount),\n param2 = strcat(\"enabledhealthprobecount:\", enabledhealthprobecount)\n\n" }, { @@ -1177,7 +1253,9 @@ "severity": "Medium", "category": "High Availability", "guid": "5225bba3-28ec-1e43-8986-7eedfd466d65", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1206,7 +1284,9 @@ "severity": "Medium", "category": "Scalability", "guid": "5783defe-b49e-d947-84f7-d8677593f324", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1235,7 +1315,9 @@ "severity": "Medium", "category": "Security", "guid": "b515690d-3bf9-3a49-8d38-188e0fd45896", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1264,7 +1346,9 @@ "severity": "Medium", "category": "Security", "guid": "1cfe7834-56ec-ff41-b11d-993734705dba", - "source": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceFile": "azure-resources/Cdn/profiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -1293,7 +1377,9 @@ "severity": "Medium", "category": "High Availability", "guid": "b49a39fd-f431-4b61-9062-f2157849d845", - "source": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceFile": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to list all image versions,its associated image name and version replica configurations per region in a compute gallery whose version replicas is less than 3\nresources\n| where type =~ \"microsoft.compute/galleries/images/versions\"\n| extend GalleryName = tostring(split(tostring(id), \"/\")[8]), ImageName = tostring(split(tostring(id), \"/\")[10])\n| mv-expand VersionReplicas = properties.publishingProfile.targetRegions\n| project RecommendationId=\"b49a39fd-f431-4b61-9062-f2157849d845\",name,id,tags,param1=strcat(\"GalleryName: \",GalleryName),param2=strcat(\"ImageName: \",ImageName),param3=strcat(\"VersionReplicaRegionName: \",VersionReplicas.name),param4=strcat(\"VersionReplicationCount: \",VersionReplicas.regionalReplicaCount),rc=toint(VersionReplicas.regionalReplicaCount)\n| where rc < 3\n| project-away rc\n\n" }, { @@ -1326,7 +1412,9 @@ "severity": "Medium", "category": "High Availability", "guid": "488dcc8b-f2e3-40ce-bf95-73deb2db095f", - "source": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceFile": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to list all image versions and its associated image and gallery name whose Storage account type is not using ZRS\nresources\n| where type =~ \"microsoft.compute/galleries/images/versions\"\n| extend GalleryName = tostring(split(tostring(id), \"/\")[8]), ImageName = tostring(split(tostring(id), \"/\")[10])\n| extend StorageAccountType = tostring(properties.publishingProfile.storageAccountType)\n| where StorageAccountType !has \"ZRS\"\n| project RecommendationId=\"488dcc8b-f2e3-40ce-bf95-73deb2db095f\",name,id,tags,param1=strcat(\"GalleryName: \",GalleryName),param2=strcat(\"ImageName: \",ImageName),param3=strcat(\"StorageAccountType: \",StorageAccountType)\n\n" }, { @@ -1363,7 +1451,9 @@ "severity": "Low", "category": "High Availability", "guid": "1c5e1e58-4e56-491c-8529-10f37af9d4ed", - "source": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceFile": "azure-resources/Compute/galleries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to list all images whose Hyper-V generation is not V2\nresources\n| where type =~ \"microsoft.compute/galleries/images\"\n| extend VMGeneration = properties.hyperVGeneration\n| where VMGeneration <> 'V2'\n| project RecommendationId=\"1c5e1e58-4e56-491c-8529-10f37af9d4ed\",name,id,tags,param1=strcat(\"VMGeneration: \",VMGeneration)\n\n" }, { @@ -1396,7 +1486,9 @@ "severity": "Medium", "category": "Scalability", "guid": "e7495e1c-0c75-0946-b266-b429b5c7f3bf", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all zonal VMs that are NOT deployed with Flex orchestration mode\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| where properties.orchestrationMode != \"Flexible\"\n| project recommendationId = \"e7495e1c-0c75-0946-b266-b429b5c7f3bf\", name, id, tags, param1 = strcat(\"orchestrationMode: \", tostring(properties.orchestrationMode))\n\n" }, { @@ -1425,7 +1517,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "94794d2a-eff0-2345-9b67-6f9349d0a627", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that do NOT have health monitoring enabled\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| join kind=leftouter (\n resources\n | where type == \"microsoft.compute/virtualmachinescalesets\"\n | mv-expand extension=properties.virtualMachineProfile.extensionProfile.extensions\n | where extension.properties.type in ( \"ApplicationHealthWindows\", \"ApplicationHealthLinux\" )\n | project id\n) on id\n| where id1 == \"\"\n| project recommendationId = \"94794d2a-eff0-2345-9b67-6f9349d0a627\", name, id, tags, param1 = \"extension: null\"\n\n" }, { @@ -1454,7 +1548,9 @@ "severity": "High", "category": "High Availability", "guid": "820f4743-1f94-e946-ae0b-45efafd87962", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that do NOT have automatic repair policy enabled\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| where properties.automaticRepairsPolicy.enabled == false\n| project recommendationId = \"820f4743-1f94-e946-ae0b-45efafd87962\", name, id, tags, param1 = \"automaticRepairsPolicy: Disabled\"\n\n" }, { @@ -1487,7 +1583,9 @@ "severity": "High", "category": "Scalability", "guid": "ee66ff65-9aa3-2345-93c1-25827cf79f44", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find VMSS instances associated with autoscale settings when autoscale is disabled\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| project name, id, tags\n| join kind=leftouter (\n resources\n | where type == \"microsoft.insights/autoscalesettings\"\n | where tostring(properties.targetResourceUri) contains \"Microsoft.Compute/virtualMachineScaleSets\"\n | project id = tostring(properties.targetResourceUri), autoscalesettings = properties\n) on id\n| where isnull(autoscalesettings) or autoscalesettings.enabled == \"false\"\n| project recommendationId = \"ee66ff65-9aa3-2345-93c1-25827cf79f44\", name, id, tags, param1 = \"autoscalesettings: Disabled\"\n| order by id asc\n\n" }, { @@ -1516,7 +1614,9 @@ "severity": "Low", "category": "Scalability", "guid": "3f85a51c-e286-9f44-b4dc-51d00768696c", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find VMSS instances associated with autoscale settings when predictiveAutoscalePolicy_scaleMode is disabled\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| project name, id, tags\n| join kind=leftouter (\n resources\n | where type == \"microsoft.insights/autoscalesettings\"\n | where tostring(properties.targetResourceUri) contains \"Microsoft.Compute/virtualMachineScaleSets\"\n | project id = tostring(properties.targetResourceUri), autoscalesettings = properties\n) on id\n| where autoscalesettings.enabled == \"true\" and autoscalesettings.predictiveAutoscalePolicy.scaleMode == \"Disabled\"\n| project recommendationId = \"3f85a51c-e286-9f44-b4dc-51d00768696c\", name, id, tags, param1 = \"predictiveAutoscalePolicy_scaleMode: Disabled\"\n| order by id asc\n\n" }, { @@ -1545,7 +1645,9 @@ "severity": "High", "category": "High Availability", "guid": "b5a63aa0-c58e-244f-b8a6-cbba0560a6db", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find VMSS instances where strictly zoneBalance is set to True\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| where properties.orchestrationMode == \"Uniform\" and properties.zoneBalance == true\n| project recommendationId = \"b5a63aa0-c58e-244f-b8a6-cbba0560a6db\", name, id, tags, param1 = \"strictly zoneBalance: Enabled\"\n| order by id asc\n\n" }, { @@ -1578,7 +1680,9 @@ "severity": "High", "category": "High Availability", "guid": "1422c567-782c-7148-ac7c-5fc14cf45adc", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find VMSS instances with one or no Zones selected\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| where array_length(zones) <= 1 or isnull(zones)\n| project recommendationId = \"1422c567-782c-7148-ac7c-5fc14cf45adc\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\n| order by id asc\n\n" }, { @@ -1611,7 +1715,9 @@ "severity": "Low", "category": "Other Best Practices", "guid": "e4ffd7b0-ba24-c84e-9352-ba4819f908c0", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// Identifies VMs and VMSS with manual patch settings, excluding automatic patch modes\nresources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| join kind=inner (\n resources\n | where type == \"microsoft.compute/virtualmachines\"\n | project id = tostring(properties.virtualMachineScaleSet.id), vmproperties = properties\n) on id\n| extend recommendationId = \"e4ffd7b0-ba24-c84e-9352-ba4819f908c0\", param1 = \"patchMode: Manual\", vmproperties.osProfile.linuxConfiguration.patchSettings.patchMode\n| where isnotnull(vmproperties.osProfile.linuxConfiguration) and vmproperties.osProfile.linuxConfiguration.patchSettings.patchMode !in (\"AutomaticByPlatform\", \"AutomaticByOS\")\n| distinct recommendationId, name, id, param1\n| union (resources\n| where type == \"microsoft.compute/virtualmachinescalesets\"\n| join kind=inner (\n resources\n | where type == \"microsoft.compute/virtualmachines\"\n | project id = tostring(properties.virtualMachineScaleSet.id), vmproperties = properties\n) on id\n| extend recommendationId = \"e4ffd7b0-ba24-c84e-9352-ba4819f908c0\", param1 = \"patchMode: Manual\", vmproperties.osProfile.windowsConfiguration.patchSettings.patchMode\n| where isnotnull(vmproperties.osProfile.windowsConfiguration) and vmproperties.osProfile.windowsConfiguration.patchSettings.patchMode !in (\"AutomaticByPlatform\", \"AutomaticByOS\")\n| distinct recommendationId, name, id, param1)\n\n" }, { @@ -1640,7 +1746,9 @@ "severity": "High", "category": "Governance", "guid": "83d61669-7bd6-9642-a305-175db8adcdf4", - "source": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachineScaleSets/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "//cannot-be-validated-with-arg\n\n" }, { @@ -1673,7 +1781,9 @@ "severity": "High", "category": "High Availability", "guid": "273f6b30-68e0-4241-85ea-acf15ffb60bf", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that are not associated with a VMSS Flex instance\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnull(properties.virtualMachineScaleSet.id)\n| project recommendationId=\"273f6b30-68e0-4241-85ea-acf15ffb60bf\", name, id, tags\n\n" }, { @@ -1702,18 +1812,20 @@ "severity": "High", "category": "High Availability", "guid": "2bd0be95-a825-6f47-a8c6-3db1fb5eb387", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that are not assigned to a Zone\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnull(zones)\n| project recommendationId=\"2bd0be95-a825-6f47-a8c6-3db1fb5eb387\", name, id, tags, param1=\"No Zone\"\n\n" }, { - "description": "Availability sets will soon be retired. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) and update domains (UDs) for better reliability.\n", + "description": "While availability sets are not scheduled for immediate deprecation, they are planned to be deprecated in the future. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) and update domains (UDs) for better reliability.\n", "aprlGuid": "a8d25876-7951-b646-b4e8-880c9031596b", "recommendationTypeId": null, "recommendationControl": "High Availability", "recommendationImpact": "High", "recommendationResourceType": "Microsoft.Compute/virtualMachines", "recommendationMetadataState": "Active", - "longDescription": "Availability sets will soon be retired. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) and update domains (UDs) for better reliability.\n", + "longDescription": "While availability sets are not scheduled for immediate deprecation, they are planned to be deprecated in the future. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) and update domains (UDs) for better reliability.\n", "potentialBenefits": "Enhances reliability and future-proofs VMs", "pgVerified": true, "publishedToLearn": false, @@ -1731,7 +1843,9 @@ "severity": "High", "category": "High Availability", "guid": "a8d25876-7951-b646-b4e8-880c9031596b", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs using Availability Sets\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnotnull(properties.availabilitySet)\n| project recommendationId = \"a8d25876-7951-b646-b4e8-880c9031596b\", name, id, tags, param1=strcat(\"availabilitySet: \",properties.availabilitySet.id)\n\n" }, { @@ -1764,7 +1878,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "cfe22a65-b1db-fd41-9e8e-d573922709ae", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that do NOT have replication with ASR enabled\nresources\n| where type =~ \"Microsoft.Compute/virtualMachines\"\n| extend securityType = iif(isnull(properties.securityProfile.securityType), \"Standard\", properties.securityProfile.securityType)\n| where securityType !in~ (\"TrustedLaunch\", \"ConfidentialVM\")\n| project id, vmIdForJoin = tolower(id), name, tags\n| join kind = leftouter (\n recoveryservicesresources\n | where type =~ \"Microsoft.RecoveryServices/vaults/replicationFabrics/replicationProtectionContainers/replicationProtectedItems\"\n and properties.providerSpecificDetails.dataSourceInfo.datasourceType =~ \"AzureVm\"\n | project vmResourceId = tolower(properties.providerSpecificDetails.dataSourceInfo.resourceId)\n )\n on $left.vmIdForJoin == $right.vmResourceId\n| where isempty(vmResourceId)\n| project recommendationId = \"cfe22a65-b1db-fd41-9e8e-d573922709ae\", name, id, tags\n" }, { @@ -1801,7 +1917,9 @@ "severity": "High", "category": "High Availability", "guid": "122d11d7-b91f-8747-a562-f56b79bcfbdc", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that are not using Managed Disks\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnull(properties.storageProfile.osDisk.managedDisk)\n| project recommendationId = \"122d11d7-b91f-8747-a562-f56b79bcfbdc\", name, id, tags\n\n" }, { @@ -1834,7 +1952,9 @@ "severity": "Low", "category": "Scalability", "guid": "4ea2878f-0d69-8d4a-b715-afc10d1e538e", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that only have OS Disk\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where array_length(properties.storageProfile.dataDisks) < 1\n| project recommendationId = \"4ea2878f-0d69-8d4a-b715-afc10d1e538e\", name, id, tags\n\n" }, { @@ -1863,7 +1983,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "1981f704-97b9-b645-9c57-33f8ded9261a", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that do NOT have Backup enabled\n// Run query to see results.\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| project name, id, tags\n| join kind=leftouter (\n recoveryservicesresources\n | where type =~ 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems'\n | where properties.dataSourceInfo.datasourceType =~ 'Microsoft.Compute/virtualMachines'\n | project idBackupEnabled=properties.sourceResourceId\n | extend name=strcat_array(array_slice(split(idBackupEnabled, '/'), 8, -1), '/')\n) on name\n| where isnull(idBackupEnabled)\n| project-away idBackupEnabled\n| project-away name1\n| project recommendationId = \"1981f704-97b9-b645-9c57-33f8ded9261a\", name, id, tags\n| order by id asc\n\n" }, { @@ -1892,7 +2014,9 @@ "severity": "Low", "category": "Governance", "guid": "98b334c0-8578-6046-9e43-b6e8fce6318e", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that are NOT running\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where properties.extended.instanceView.powerState.displayStatus != 'VM running'\n| project recommendationId = \"98b334c0-8578-6046-9e43-b6e8fce6318e\", name, id, tags\n\n" }, { @@ -1921,7 +2045,9 @@ "severity": "Medium", "category": "Scalability", "guid": "dfedbeb1-1519-fc47-86a5-52f96cf07105", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VM NICs that do not have Accelerated Networking enabled\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| mv-expand nic = properties.networkProfile.networkInterfaces\n| project name, id, tags, lowerCaseNicId = tolower(nic.id), vmSize = tostring(properties.hardwareProfile.vmSize)\n| join kind = inner (\n resources\n | where type =~ 'Microsoft.Network/networkInterfaces'\n | where properties.enableAcceleratedNetworking == false\n | project nicName = split(id, \"/\")[8], lowerCaseNicId = tolower(id)\n )\n on lowerCaseNicId\n| summarize nicNames = make_set(nicName) by name, id, tostring(tags), vmSize\n| extend param1 = strcat(\"NicName: \", strcat_array(nicNames, \", \")), param2 = strcat(\"VMSize: \", vmSize)\n| project recommendationId = \"dfedbeb1-1519-fc47-86a5-52f96cf07105\", name, id, tags, param1, param2\n| order by id asc\n\n" }, { @@ -1950,7 +2076,9 @@ "severity": "Low", "category": "Governance", "guid": "73d1bb04-7d3e-0d47-bc0d-63afe773b5fe", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -1979,7 +2107,9 @@ "severity": "Medium", "category": "Security", "guid": "1f629a30-c9d0-d241-82ee-6f2eb9d42cb4", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs with PublicIPs directly associated with them\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnotnull(properties.networkProfile.networkInterfaces)\n| mv-expand nic=properties.networkProfile.networkInterfaces\n| project name, id, tags, nicId = nic.id\n| extend nicId = tostring(nicId)\n| join kind=inner (\n Resources\n | where type =~ 'Microsoft.Network/networkInterfaces'\n | where isnotnull(properties.ipConfigurations)\n | mv-expand ipconfig=properties.ipConfigurations\n | extend publicIp = tostring(ipconfig.properties.publicIPAddress.id)\n | where publicIp != \"\"\n | project name, nicId = tostring(id), publicIp\n) on nicId\n| project recommendationId = \"1f629a30-c9d0-d241-82ee-6f2eb9d42cb4\", name, id, tags\n| order by id asc\n\n" }, { @@ -2008,7 +2138,9 @@ "severity": "Low", "category": "Security", "guid": "82b3cf6b-9ae2-2e44-b193-10793213f676", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of virtual machines and associated NICs that do have an NSG associated to them and also an NSG associated to the subnet.\nResources\n| where type =~ 'Microsoft.Network/networkInterfaces'\n| where isnotnull(properties.networkSecurityGroup)\n| mv-expand ipConfigurations = properties.ipConfigurations, nsg = properties.networkSecurityGroup\n| project nicId = tostring(id), subnetId = tostring(ipConfigurations.properties.subnet.id), nsgName=split(nsg.id, '/')[8]\n| parse kind=regex subnetId with '/virtualNetworks/' virtualNetwork '/subnets/' subnet\n | join kind=inner (\n Resources\n | where type =~ 'Microsoft.Network/NetworkSecurityGroups' and isnotnull(properties.subnets)\n | project name, resourceGroup, subnet=properties.subnets\n | mv-expand subnet\n | project subnetId=tostring(subnet.id)\n ) on subnetId\n | project nicId\n| join kind=leftouter (\n Resources\n | where type =~ 'Microsoft.Compute/virtualMachines'\n | where isnotnull(properties.networkProfile.networkInterfaces)\n | mv-expand nic=properties.networkProfile.networkInterfaces\n | project vmName = name, vmId = id, tags, nicId = nic.id, nicName=split(nic.id, '/')[8]\n | extend nicId = tostring(nicId)\n) on nicId\n| project recommendationId = \"82b3cf6b-9ae2-2e44-b193-10793213f676\", name=vmName, id = vmId, tags, param1 = strcat(\"nic-name=\", nicName)\n\n" }, { @@ -2037,7 +2169,9 @@ "severity": "Medium", "category": "Security", "guid": "41a22a5e-5e08-9647-92d0-2ffe9ef1bdad", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VM NICs that have IPForwarding enabled. This feature is usually only required for Network Virtual Appliances\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnotnull(properties.networkProfile.networkInterfaces)\n| mv-expand nic=properties.networkProfile.networkInterfaces\n| project name, id, tags, nicId = nic.id\n| extend nicId = tostring(nicId)\n| join kind=inner (\n Resources\n | where type =~ 'Microsoft.Network/networkInterfaces'\n | where properties.enableIPForwarding == true\n | project nicId = tostring(id)\n) on nicId\n| project recommendationId = \"41a22a5e-5e08-9647-92d0-2ffe9ef1bdad\", name, id, tags\n| order by id asc\n\n" }, { @@ -2066,7 +2200,9 @@ "severity": "Low", "category": "Other Best Practices", "guid": "1cf8fe21-9593-1e4e-966b-779a294c0d30", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VM NICs that have DNS Server settings configured in any of the NICs\nResources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnotnull(properties.networkProfile.networkInterfaces)\n| mv-expand nic=properties.networkProfile.networkInterfaces\n| project name, id, tags, nicId = nic.id\n| extend nicId = tostring(nicId)\n| join kind=inner (\n Resources\n | where type =~ 'Microsoft.Network/networkInterfaces'\n | project name, id, dnsServers = properties.dnsSettings.dnsServers\n | extend hasDns = array_length(dnsServers) >= 1\n | where hasDns != 0\n | project name, nicId = tostring(id)\n) on nicId\n| project recommendationId = \"1cf8fe21-9593-1e4e-966b-779a294c0d30\", name, id, tags\n| order by id asc\n\n" }, { @@ -2099,7 +2235,9 @@ "severity": "Medium", "category": "Other Best Practices", "guid": "3263a64a-c256-de48-9818-afd3cbc55c2a", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Disks configured to be Shared. This is not an indication of an issue, but if a disk with this configuration is assigned to two or more VMs without a proper disk control mechanism (like a WSFC) it can lead to data loss\nresources\n| where type =~ 'Microsoft.Compute/disks'\n| where isnotnull(properties.maxShares) and properties.maxShares >= 2\n| project id, name, tags, lowerCaseDiskId = tolower(id), diskState = tostring(properties.diskState)\n| join kind = leftouter (\n resources\n | where type =~ 'Microsoft.Compute/virtualMachines'\n | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)\n | join kind = fullouter (\n resources\n | where type =~ 'Microsoft.Compute/virtualMachines'\n | mv-expand dataDisks = properties.storageProfile.dataDisks\n | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)\n )\n on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId\n | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)\n )\n on lowerCaseDiskId\n| summarize vmNames = make_set(vmName) by name, id, tostring(tags), diskState\n| extend param1 = strcat(\"DiskState: \", diskState), param2 = iif(isempty(vmNames[0]), \"VMName: n/a\", strcat(\"VMName: \", strcat_array(vmNames, \", \")))\n| project recommendationId = \"3263a64a-c256-de48-9818-afd3cbc55c2a\", name, id, tags, param1, param2\n| order by id asc\n\n" }, { @@ -2128,7 +2266,9 @@ "severity": "Low", "category": "Security", "guid": "70b1d2be-e6c4-b54e-9959-b1b690f9e485", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Disks with \"Enable public access from all networks\" enabled\nresources\n| where type =~ 'Microsoft.Compute/disks'\n| where properties.publicNetworkAccess == \"Enabled\"\n| project id, name, tags, lowerCaseDiskId = tolower(id)\n| join kind = leftouter (\n resources\n | where type =~ 'Microsoft.Compute/virtualMachines'\n | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)\n | join kind = fullouter (\n resources\n | where type =~ 'Microsoft.Compute/virtualMachines'\n | mv-expand dataDisks = properties.storageProfile.dataDisks\n | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)\n )\n on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId\n | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)\n )\n on lowerCaseDiskId\n| summarize vmNames = make_set(vmName) by name, id, tostring(tags)\n| extend param1 = iif(isempty(vmNames[0]), \"VMName: n/a\", strcat(\"VMName: \", strcat_array(vmNames, \", \")))\n| project recommendationId = \"70b1d2be-e6c4-b54e-9959-b1b690f9e485\", name, id, tags, param1\n| order by id asc\n\n" }, { @@ -2161,7 +2301,9 @@ "severity": "Low", "category": "Governance", "guid": "c42343ae-2712-2843-a285-3437eb0b28a1", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs in \"Non-compliant\" state with Azure Policies\npolicyresources\n| where type =~ \"Microsoft.PolicyInsights/policyStates\" and properties.resourceType =~ \"Microsoft.Compute/virtualMachines\" and properties.complianceState =~ \"NonCompliant\"\n| project\n policyDefinitionId = tolower(properties.policyDefinitionId),\n policyAssignmentId = tolower(properties.policyAssignmentId),\n targetResourceId = tolower(properties.resourceId)\n// Join the policy definition details\n| join kind = leftouter (\n policyresources\n | where type =~ \"Microsoft.Authorization/policyDefinitions\"\n | project policyDefinitionId = tolower(id), policyDefinitionDisplayName = properties.displayName\n )\n on policyDefinitionId\n| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, targetResourceId\n// Join the policy assignment details\n| join kind = leftouter (\n policyresources\n | where type =~ \"Microsoft.Authorization/policyAssignments\"\n | project policyAssignmentId = tolower(id), policyAssignmentDisplayName = properties.displayName\n )\n on policyAssignmentId\n| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, policyAssignmentDisplayName, targetResourceId\n// Join the target resource details\n| join kind = leftouter (\n resources\n | where type =~ \"Microsoft.Compute/virtualMachines\"\n | project targetResourceId = tolower(id), targetResourceIdPreservedCase = id, targetResourceName = name, targetResourceTags = tags\n )\n on targetResourceId\n| project\n recommendationId = \"c42343ae-2712-2843-a285-3437eb0b28a1\",\n name = targetResourceName,\n id = targetResourceIdPreservedCase,\n tags = targetResourceTags,\n param1 = strcat(\"DefinitionName: \", policyDefinitionDisplayName),\n param2 = strcat(\"DefinitionID: \", policyDefinitionId),\n param3 = strcat(\"AssignmentName: \", policyAssignmentDisplayName),\n param4 = strcat(\"AssignmentID: \", policyAssignmentId)\n" }, { @@ -2190,7 +2332,9 @@ "severity": "High", "category": "Security", "guid": "f0a97179-133a-6e4f-8a49-8a44da73ffce", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure VM disks without Azure Disk Encryption or encryption at host enabled\nresources\n| where type =~ \"microsoft.compute/disks\"\n| project diskId = id, diskName = name, vmId = tolower(managedBy), azureDiskEncryption = iff(properties.encryptionSettingsCollection.enabled == true, true, false)\n| join kind=leftouter (resources\n| where type =~ \"microsoft.compute/virtualmachines\"\n| project vmId = tolower(id), vmName = name, encryptionAtHost = iff(properties.securityProfile.encryptionAtHost == true, true, false)) on vmId\n| where not(encryptionAtHost) and not(azureDiskEncryption)\n| project recommendationId = 'f0a97179-133a-6e4f-8a49-8a44da73ffce', name = vmName, id =vmId, param1 = strcat('diskName:',diskName), param2 = strcat('azureDiskEncryption:',iff(azureDiskEncryption, \"Enabled\", \"Disabled\")), param3 = strcat('encryptionAtHost:',iff(encryptionAtHost, \"Enabled\", \"Disabled\"))\n" }, { @@ -2223,7 +2367,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "b72214bb-e879-5f4b-b9cd-642db84f36f4", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Check for VMs without Azure Monitoring Agent extension installed, missing Data Collection Rule or Data Collection Rule without performance enabled.\nResources\n| where type == 'microsoft.compute/virtualmachines'\n| project idVm = tolower(id), name, tags\n| join kind=leftouter (\n InsightsResources\n | where type =~ \"Microsoft.Insights/dataCollectionRuleAssociations\" and id has \"Microsoft.Compute/virtualMachines\"\n | project idDcr = tolower(properties.dataCollectionRuleId), idVmDcr = tolower(substring(id, 0, indexof(id, \"/providers/Microsoft.Insights/dataCollectionRuleAssociations/\"))))\non $left.idVm == $right.idVmDcr\n| join kind=leftouter (\n Resources\n | where type =~ \"Microsoft.Insights/dataCollectionRules\"\n | extend\n isPerformanceEnabled = iif(properties.dataSources.performanceCounters contains \"Microsoft-InsightsMetrics\" and properties.dataFlows contains \"Microsoft-InsightsMetrics\", true, false),\n isMapEnabled = iif(properties.dataSources.extensions contains \"Microsoft-ServiceMap\" and properties.dataSources.extensions contains \"DependencyAgent\" and properties.dataFlows contains \"Microsoft-ServiceMap\", true, false)//,\n | where isPerformanceEnabled or isMapEnabled\n | project dcrName = name, isPerformanceEnabled, isMapEnabled, idDcr = tolower(id))\non $left.idDcr == $right.idDcr\n| join kind=leftouter (\n Resources\n | where type == 'microsoft.compute/virtualmachines/extensions' and (name contains 'AzureMonitorWindowsAgent' or name contains 'AzureMonitorLinuxAgent')\n | extend idVmExtension = tolower(substring(id, 0, indexof(id, '/extensions'))), extensionName = name)\non $left.idVm == $right.idVmExtension\n| where isPerformanceEnabled != 1 or (extensionName != 'AzureMonitorWindowsAgent' and extensionName != 'AzureMonitorLinuxAgent')\n| project recommendationId = \"b72214bb-e879-5f4b-b9cd-642db84f36f4\", name, id = idVm, tags, param1 = strcat('MonitoringExtension:', extensionName), param2 = strcat('DataCollectionRuleId:', idDcr), param3 = strcat('isPerformanceEnabled:', isPerformanceEnabled)\n\n" }, { @@ -2252,7 +2398,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "4a9d8973-6dba-0042-b3aa-07924877ebd5", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Virtual Machines without diagnostic settings enabled/with diagnostic settings enabled but not configured both performance counters and event logs/syslogs.\nresources\n| where type =~ \"microsoft.compute/virtualmachines\"\n| project name, id, tags, lowerCaseVmId = tolower(id)\n| join kind = leftouter (\n resources\n | where type =~ \"Microsoft.Compute/virtualMachines/extensions\" and properties.publisher =~ \"Microsoft.Azure.Diagnostics\"\n | project\n lowerCaseVmIdOfExtension = tolower(substring(id, 0, indexof(id, \"/extensions/\"))),\n extensionType = properties.type,\n provisioningState = properties.provisioningState,\n storageAccount = properties.settings.StorageAccount,\n // Windows\n wadPerfCounters = properties.settings.WadCfg.DiagnosticMonitorConfiguration.PerformanceCounters.PerformanceCounterConfiguration,\n wadEventLogs = properties.settings.WadCfg.DiagnosticMonitorConfiguration.WindowsEventLog,\n // Linux\n ladPerfCounters = properties.settings.ladCfg.diagnosticMonitorConfiguration.performanceCounters.performanceCounterConfiguration,\n ladSyslog = properties.settings.ladCfg.diagnosticMonitorConfiguration.syslogEvents\n | extend\n // Windows\n isWadPerfCountersConfigured = iif(array_length(wadPerfCounters) > 0, true, false),\n isWadEventLogsConfigured = iif(isnotnull(wadEventLogs) and array_length(wadEventLogs.DataSource) > 0, true, false),\n // Linux\n isLadPerfCountersConfigured = iif(array_length(ladPerfCounters) > 0, true, false),\n isLadSyslogConfigured = isnotnull(ladSyslog)\n | project\n lowerCaseVmIdOfExtension,\n extensionType,\n provisioningState,\n storageAccount,\n isPerfCountersConfigured = case(extensionType =~ \"IaaSDiagnostics\", isWadPerfCountersConfigured, extensionType =~ \"LinuxDiagnostic\", isLadPerfCountersConfigured, false),\n isEventLogsConfigured = case(extensionType =~ \"IaaSDiagnostics\", isWadEventLogsConfigured, extensionType =~ \"LinuxDiagnostic\", isLadSyslogConfigured, false)\n )\n on $left.lowerCaseVmId == $right.lowerCaseVmIdOfExtension\n| where isempty(lowerCaseVmIdOfExtension) or provisioningState !~ \"Succeeded\" or not(isPerfCountersConfigured and isEventLogsConfigured)\n| extend\n param1 = strcat(\"DiagnosticSetting: \", iif(isnotnull(extensionType), strcat(\"Enabled, partially configured (\", extensionType, \")\"), \"Not enabled\")),\n param2 = strcat(\"ProvisioningState: \", iif(isnotnull(provisioningState), provisioningState, \"n/a\")),\n param3 = strcat(\"storageAccount: \", iif(isnotnull(storageAccount), storageAccount, \"n/a\")),\n param4 = strcat(\"PerformanceCounters: \", case(isnull(isPerfCountersConfigured), \"n/a\", isPerfCountersConfigured, \"Configured\", \"Not configured\")),\n param5 = strcat(\"EventLogs/Syslogs: \", case(isnull(isEventLogsConfigured), \"n/a\", isEventLogsConfigured, \"Configured\", \"Not configured\"))\n| project recommendationId = \"4a9d8973-6dba-0042-b3aa-07924877ebd5\", name, id, tags, param1, param2, param3, param4, param5\n\n" }, { @@ -2281,7 +2429,9 @@ "severity": "High", "category": "High Availability", "guid": "52ab9e5c-eec0-3148-8bd7-b6dd9e1be870", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find VMS that do not have maintenance configuration assigned\nResources\n| extend resourceId = tolower(id)\n| project name, location, type, id, tags, resourceId, properties\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| join kind=leftouter (\nmaintenanceresources\n| where type =~ \"microsoft.maintenance/configurationassignments\"\n| project planName = name, type, maintenanceProps = properties\n| extend resourceId = tostring(maintenanceProps.resourceId)\n) on resourceId\n| where isnull(maintenanceProps)\n| project recommendationId = \"52ab9e5c-eec0-3148-8bd7-b6dd9e1be870\",name, id, tags\n| order by id asc\n\n" }, { @@ -2310,7 +2460,9 @@ "severity": "High", "category": "Scalability", "guid": "3201dba8-d1da-4826-98a4-104066545170", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs using A or B series families\nresources\n| where type == 'microsoft.compute/virtualmachines'\n| where properties.hardwareProfile.vmSize contains \"Standard_B\" or properties.hardwareProfile.vmSize contains \"Standard_A\"\n| project recommendationId = \"3201dba8-d1da-4826-98a4-104066545170\", name, id, tags, param1=strcat(\"vmSku: \" , properties.hardwareProfile.vmSize)\n\n" }, { @@ -2339,7 +2491,9 @@ "severity": "High", "category": "Scalability", "guid": "df0ff862-814d-45a3-95e4-4fad5a244ba6", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs that have an attached disk that is not in the Premium or Ultra sku tier.\n\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| extend lname = tolower(name)\n| join kind=leftouter(resources\n | where type =~ 'Microsoft.Compute/disks'\n | where not(sku.tier =~ 'Premium') and not(sku.tier =~ 'Ultra')\n | extend lname = tolower(tostring(split(managedBy, '/')[8]))\n | project lname, name\n | summarize disks = make_list(name) by lname) on lname\n| where isnotnull(disks)\n| project recommendationId = \"df0ff862-814d-45a3-95e4-4fad5a244ba6\", name, id, tags, param1=strcat(\"AffectedDisks: \", disks)\n\n" }, { @@ -2372,7 +2526,9 @@ "severity": "Medium", "category": "High Availability", "guid": "9ab499d8-8844-424d-a2d4-8f53690eb8f8", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -2409,7 +2565,9 @@ "severity": "Medium", "category": "High Availability", "guid": "2de8fa5e-14f4-4c4c-857f-1520f87a629f", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -2438,7 +2596,9 @@ "severity": "Medium", "category": "High Availability", "guid": "fa0cf4f5-0b21-47b7-89a9-ee936f193ce1", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find eligible Disks that are not zonal nor zone redundant\nresources\n| where type == 'microsoft.compute/disks'\n| where sku has \"Premium_LRS\" or sku has \"StandardSSD_LRS\"\n| where sku.name has_cs 'ZRS' or array_length(zones) > 0\n| project recommendationId=\"fa0cf4f5-0b21-47b7-89a9-ee936f193ce1\", name, id, tags, param1 = sku, param2 = sku.name\n" }, { @@ -2467,7 +2627,9 @@ "severity": "High", "category": "High Availability", "guid": "302fda08-ee65-4fbe-a916-6dc0b33169c4", - "source": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceFile": "azure-resources/Compute/virtualMachines/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Virtual Machines not associated with a Capacity Reservation, and provide details for Capacity Reservation like vmSize, location, and zone.\nresources\n| where type =~ 'Microsoft.Compute/virtualMachines'\n| where isnull(properties.capacityReservation)\n| extend zoneValue = iff(isnull(zones), \"null\", zones)\n| project recommendationId = \"302fda08-ee65-4fbe-a916-6dc0b33169c4\", name, id, tags, param1 = strcat(\"VmSize: \", properties.hardwareProfile.vmSize), param2 = strcat(\"Location: \", location), param3 = strcat(\"Zone: \", zoneValue)\n" }, { @@ -2496,7 +2658,9 @@ "severity": "High", "category": "Scalability", "guid": "eb005943-40a8-194b-9db2-474d430046b7", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Container Registries that are not using the Premium tier\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| where sku.name != \"Premium\"\n| project recommendationId = \"eb005943-40a8-194b-9db2-474d430046b7\", name, id, tags, param1=strcat(\"SkuName: \", tostring(sku.name))\n| order by id asc\n\n" }, { @@ -2525,7 +2689,9 @@ "severity": "High", "category": "High Availability", "guid": "63491f70-22e4-3b4a-8b0c-845450e46fac", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Container Registries that do not have zone redundancy enabled\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| where properties.zoneRedundancy != \"Enabled\"\n| project recommendationId = \"63491f70-22e4-3b4a-8b0c-845450e46fac\", name, id, tags, param1=strcat(\"zoneRedundancy: \", tostring(properties.zoneRedundancy))\n| order by id asc\n\n" }, { @@ -2558,7 +2724,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "36ea6c09-ef6e-d743-9cfb-bd0c928a430b", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Container Registries that do not have geo-replication enabled\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| project registryName = name, registryId = id, tags, primaryRegion = location\n| join kind=leftouter (\n Resources\n | where type =~ \"microsoft.containerregistry/registries/replications\"\n | project replicationRegion=name, replicationId = id\n | extend registryId=strcat_array(array_slice(split(replicationId, '/'), 0, -3), '/')\n ) on registryId\n| project-away registryId1, replicationId\n| where isempty(replicationRegion)\n| project recommendationId = \"36ea6c09-ef6e-d743-9cfb-bd0c928a430b\", name=registryName, id=registryId, tags\n| order by id asc\n\n" }, { @@ -2587,7 +2755,9 @@ "severity": "Low", "category": "Security", "guid": "a5a0101a-a240-8742-90ba-81dbde9a0c0c", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -2616,7 +2786,9 @@ "severity": "Low", "category": "Governance", "guid": "8e389532-5db5-7e4c-9d4d-443b3e55ae82", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List container registries that contain additional resources within the same resource group.\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| project registryName=name, registryId=id, registryTags=tags, resourceGroupId=strcat('/subscriptions/', subscriptionId, '/resourceGroups/', resourceGroup), resourceGroup, subscriptionId\n| join kind=inner (\n resources\n | where not(type =~ \"microsoft.containerregistry/registries\")\n | summarize recourceCount=count() by subscriptionId, resourceGroup\n | where recourceCount != 0\n) on resourceGroup, subscriptionId\n| project recommendationId = \"8e389532-5db5-7e4c-9d4d-443b3e55ae82\", name=registryName, id=registryId, tags=registryTags, param1=strcat('resourceGroupName:',resourceGroup), param2=strcat('resourceGroupId:',resourceGroupId)\n\n" }, { @@ -2649,7 +2821,9 @@ "severity": "Medium", "category": "Scalability", "guid": "3ef86f16-f65b-c645-9901-7830d6dc3a1b", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Container Registries that have their retention policy disabled\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| where properties.policies.retentionPolicy.status == \"disabled\"\n| project recommendationId = \"3ef86f16-f65b-c645-9901-7830d6dc3a1b\", name, id, tags, param1='retentionPolicy:disabled'\n| order by id asc\n\n" }, { @@ -2678,7 +2852,9 @@ "severity": "Medium", "category": "Security", "guid": "03f4a7d8-c5b4-7842-8e6e-14997a34842b", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Container Registries that have anonymous pull access enabled\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| where properties.anonymousPullEnabled == \"true\"\n| project recommendationId = \"03f4a7d8-c5b4-7842-8e6e-14997a34842b\", name, id, tags\n| order by id asc\n\n" }, { @@ -2711,7 +2887,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "44107155-7a32-9348-89f3-d5aa7e7c5a1d", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -2744,7 +2922,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "d594cde6-4116-d143-a64a-25f63289a2f8", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -2773,7 +2953,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "e7f0fd54-fba0-054e-9ab8-e676f2851f88", - "source": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceFile": "azure-resources/ContainerRegistry/registries/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure Container Registry resources that do not have soft delete enabled\nresources\n| where type =~ \"microsoft.containerregistry/registries\"\n| where properties.policies.softDeletePolicy.status == \"disabled\"\n| project recommendationId = \"e7f0fd54-fba0-054e-9ab8-e676f2851f88\", name, id, tags\n| order by id asc\n\n" }, { @@ -2806,7 +2988,9 @@ "severity": "High", "category": "High Availability", "guid": "4f63619f-5001-439c-bacb-8de891287727", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns AKS clusters that do not have any availability zones enabled or only use a single zone\nresources\n| where type =~ \"Microsoft.ContainerService/managedClusters\"\n| project id, name, tags, location, pools = properties.agentPoolProfiles\n| mv-expand pool = pools\n| extend\n numOfAvailabilityZones = iif(isnull(pool.availabilityZones), 0, array_length(pool.availabilityZones))\n| where numOfAvailabilityZones < 2\n| project\n recommendationId = \"4f63619f-5001-439c-bacb-8de891287727\",\n id,\n name,\n tags,\n param1 = strcat(\"NodePoolName: \", pool.name),\n param2 = strcat(\"Mode: \", pool.mode),\n param3 = strcat(\"AvailabilityZones: \", iif(numOfAvailabilityZones == 0, \"None\", strcat(\"Zone \", strcat_array(pool.availabilityZones, \", \")))),\n param4 = strcat(\"Location: \", location)\n" }, { @@ -2835,7 +3019,9 @@ "severity": "High", "category": "High Availability", "guid": "5ee083cd-6ac3-4a83-8913-9549dd36cf56", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns each AKS cluster with nodepools that do not have system pods labelled with CriticalAddonsOnly\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\n| where agentPoolProfile.mode =~ 'System' // system node pools\n| extend taint = tostring(parse_json(agentPoolProfile.nodeTaints))\n| extend hasCriticalAddonsTaint = agentPoolProfile.kubeletConfig has 'CriticalAddonsOnly'\n| extend hasNodeLabel = agentPoolProfile.customNodeLabels has 'CriticalAddonsOnly'\n| extend hasCriticalAddonsOnly = hasCriticalAddonsTaint or hasNodeLabel or isempty(taint)\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\n| where hasCriticalAddonsOnly\n| project\n recommendationId=\"5ee083cd-6ac3-4a83-8913-9549dd36cf56\",\n id,\n name,\n tags,\n param1=strcat(\"nodepoolName: \", nodePool)\n" }, { @@ -2872,7 +3058,9 @@ "severity": "High", "category": "Security", "guid": "ca324d71-54b0-4a3e-b9e4-10e767daa9fc", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns a list of AKS clusters not using AAD enabled\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend aadProfile = tostring (parse_json(properties.aadProfile))\n| extend disablelocalAdmin = tostring(parse_json(properties.disableLocalAccounts))\n| extend RBAC = tostring(parse_json(properties.enableRBAC))\n| where RBAC == \"false\"\n| project recommendationId=\"ca324d71-54b0-4a3e-b9e4-10e767daa9fc\", name, id, tags, param1=strcat(\"aadProfile: \", aadProfile), param2=strcat(\"disablelocalAdmin: \",disablelocalAdmin), param3=strcat(\"RBAC: \", RBAC)\n\n" }, { @@ -2905,7 +3093,9 @@ "severity": "Medium", "category": "Scalability", "guid": "c22db132-399b-4e7c-995d-577a60881be8", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Check AKS Clusters using kubenet network profile\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend networkProfile = tostring (parse_json(properties.networkProfile.networkPlugin))\n| where networkProfile ==\"kubenet\"\n| project recommendationId=\"c22db132-399b-4e7c-995d-577a60881be8\", name, id, tags, param1=strcat(\"networkProfile :\",networkProfile)\n\n" }, { @@ -2946,7 +3136,9 @@ "severity": "High", "category": "Scalability", "guid": "902c82ff-4910-4b61-942d-0d6ef7f39b67", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find AKS clusters with auto-scaling disabled\nResources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend autoScaling = tostring (parse_json(properties.agentPoolProfiles.[0].enableAutoScaling))\n| where autoScaling == \"false\"\n| project recommendationId=\"902c82ff-4910-4b61-942d-0d6ef7f39b67\", name, id, tags, param1=strcat(\"autoScaling :\", autoScaling)\n\n" }, { @@ -2979,7 +3171,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "269a9f1a-6675-460a-831e-b05a887a8c4b", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find AKS clusters that do not have backup enabled\n\nresources\n| where type =~ 'Microsoft.ContainerService/managedClusters'\n| extend lname = tolower(name)\n| join kind=leftouter(recoveryservicesresources\n | where type =~ 'microsoft.dataprotection/backupvaults/backupinstances'\n | extend lname = tolower(tostring(split(properties.dataSourceInfo.resourceID, '/')[8]))\n | extend protectionState = properties.currentProtectionState\n | project lname, protectionState) on lname\n| where protectionState != 'ProtectionConfigured'\n| extend param1 = iif(isnull(protectionState), 'Protection Not Configured', strcat('Protection State: ', protectionState))\n| project recommendationId = \"269a9f1a-6675-460a-831e-b05a887a8c4b\", name, id, tags, param1\n\n" }, { @@ -3024,7 +3218,9 @@ "severity": "Medium", "category": "High Availability", "guid": "d3111036-355d-431b-ab49-8ddad042800b", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3057,7 +3253,9 @@ "severity": "High", "category": "Governance", "guid": "b002c030-72e6-4a37-8217-1cb276c43169", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3086,7 +3284,9 @@ "severity": "Low", "category": "Scalability", "guid": "9a1c17e5-c9a0-43db-b920-adaf54d1bcb7", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3119,7 +3319,9 @@ "severity": "Low", "category": "Scalability", "guid": "b4639ca7-6308-429a-8b98-92f0bf9bf813", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3152,7 +3354,9 @@ "severity": "High", "category": "High Availability", "guid": "0611251f-e70f-4243-8ddd-cfe894bec2e7", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns all AKS clusters not running on the Standard tier\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| where sku.tier != \"Standard\"\n| project recommendationId=\"0611251f-e70f-4243-8ddd-cfe894bec2e7\", id, name, tags, param1=strcat(\"skuName: \", sku.name), param2=strcat(\"skuTier: \", sku.tier)\n\n" }, { @@ -3181,7 +3385,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "dcaf8128-94bd-4d53-9235-3a0371df6b74", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns AKS clusters where either Azure Monitor is not enabled and/or Container Insights is not enabled\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend azureMonitor = tostring(parse_json(properties.azureMonitorProfile.metrics.enabled))\n| extend insights = tostring(parse_json(properties.addonProfiles.omsagent.enabled))\n| where isempty(azureMonitor) or isempty(insights)\n| project recommendationId=\"dcaf8128-94bd-4d53-9235-3a0371df6b74\",id, name, tags, param1=strcat(\"azureMonitorProfileEnabled: \", iff(isempty(azureMonitor), \"false\", azureMonitor)), param2=strcat(\"containerInsightsEnabled: \", iff(isempty(insights), \"false\", insights))\n\n" }, { @@ -3218,7 +3424,9 @@ "severity": "Medium", "category": "Scalability", "guid": "a7bfcc18-b0d8-4d37-81f3-8131ed8bead5", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns any AKS cluster nodepools that do not have Ephemeral Disks\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\n| extend type = tostring(agentPoolProfile.osDiskType)\n| where type != 'Ephemeral'\n| project recommendationId=\"a7bfcc18-b0d8-4d37-81f3-8131ed8bead5\", name, id, param1=strcat(\"osDiskType: \", type)\n" }, { @@ -3251,7 +3459,9 @@ "severity": "Low", "category": "Governance", "guid": "26ebaf1f-c70d-4ebd-8641-4b60a0ce0094", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns a count of non-compliant policy items per AKS cluster\nPolicyResources\n| where type =~ 'Microsoft.PolicyInsights/PolicyStates'\n| extend complianceState = tostring(properties.complianceState)\n| where complianceState == 'NonCompliant'\n| where properties.resourceType =~ 'Microsoft.ContainerService/managedClusters'\n| extend\n id = tostring(properties.resourceId)\n| summarize count() by id\n| join kind=inner (\n resources\n | where type =~ 'Microsoft.ContainerService/managedClusters'\n | project id, name\n) on id\n| project recommendationId=\"26ebaf1f-c70d-4ebd-8641-4b60a0ce0094\", id, name, param1=strcat(\"numNonCompliantAlerts: \", count_)\n" }, { @@ -3284,7 +3494,9 @@ "severity": "Low", "category": "Other Best Practices", "guid": "5f3cbd68-692a-4121-988c-9770914859a9", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns AKS clusters where GitOps is not enabled\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend gitops = tostring (parse_json(properties.addOnProfiles.gitops.enabled))\n| where isempty(gitops)\n| project recommendationId=\"5f3cbd68-692a-4121-988c-9770914859a9\", id, name, tags, param1=strcat(\"gitopsEnabled: \", \"false\")\n\n" }, { @@ -3317,7 +3529,9 @@ "severity": "High", "category": "High Availability", "guid": "928fcc6f-5e9a-42d9-9bd4-260af42de2e5", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3350,7 +3564,9 @@ "severity": "High", "category": "High Availability", "guid": "cd6791b1-c60e-4b37-ac98-9897b1e6f4b8", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3379,7 +3595,9 @@ "severity": "High", "category": "High Availability", "guid": "bcfe71f1-ebed-49e5-a84a-193b81ad5d27", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3408,7 +3626,9 @@ "severity": "High", "category": "High Availability", "guid": "7f7ae535-a5ba-4665-b7e0-c451dbdda01f", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns each AKS cluster with nodepools that have system nodepools with less than 2 nodes\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\n| extend taints = tostring(parse_json(agentPoolProfile.nodeTaints))\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\n| where taints has \"CriticalAddonsOnly=true:NoSchedule\" and agentPoolProfile.minCount < 2\n| project recommendationId=\"7f7ae535-a5ba-4665-b7e0-c451dbdda01f\", id, name, param1=strcat(\"nodePoolName: \", nodePool), param2=strcat(\"nodePoolMinNodeCount: \", agentPoolProfile.minCount)\n\n" }, { @@ -3437,7 +3657,9 @@ "severity": "High", "category": "High Availability", "guid": "005ccbbd-aeab-46ef-80bd-9bd4479412ec", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns each AKS cluster with nodepools that have user nodepools with less than 2 nodes\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\n| extend taints = tostring(parse_json(agentPoolProfile.nodeTaints))\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\n| where taints !has \"CriticalAddonsOnly=true:NoSchedule\" and agentPoolProfile.minCount < 2\n| project recommendationId=\"005ccbbd-aeab-46ef-80bd-9bd4479412ec\", id, name, param1=strcat(\"nodePoolName: \", nodePool), param2=strcat(\"nodePoolMinNodeCount: \", agentPoolProfile.minCount)\n\n" }, { @@ -3470,7 +3692,9 @@ "severity": "Medium", "category": "High Availability", "guid": "a08a06a0-e41a-4b99-83bb-69ce8bca54cb", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -3499,7 +3723,9 @@ "severity": "High", "category": "High Availability", "guid": "e620fa98-7a40-41a0-bfc9-b4407297fb58", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns each AKS cluster with nodepools that have user nodepools with a subnetmask that does not match autoscale configured max-nodes\n// Subtracting the network address, broadcast address, and default 3 addresses Azure reserves within each subnet\n\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| extend nodePools = properties['agentPoolProfiles']\n| mv-expand nodePools = properties.agentPoolProfiles\n| where nodePools.enableAutoScaling == true\n| extend nodePoolName=nodePools.name, maxNodes = nodePools.maxCount, subnetId = tostring(nodePools.vnetSubnetID)\n| project clusterId = id, clusterName=name, nodePoolName=nodePools.name, toint(maxNodes), subnetId\n| join kind = leftouter (\n resources\n | where type == 'microsoft.network/virtualnetworks'\n | extend subnets = properties.subnets\n | mv-expand subnets\n | project id = tostring(subnets.id), addressPrefix = tostring(subnets.properties['addressPrefix'])\n | extend subnetmask = toint(substring(addressPrefix, indexof(addressPrefix, '/')+1, string_size(addressPrefix)))\n | extend possibleMaxNodeCount = toint(exp2(32-subnetmask) - 5)\n) on $left.subnetId == $right.id\n| project-away id, subnetmask\n| where possibleMaxNodeCount <= maxNodes\n| extend param1 = strcat(nodePoolName, \" autoscaler upper limit: \", maxNodes)\n| extend param2 = strcat(\"ip addresses on subnet: \", possibleMaxNodeCount)\n| project recommendationId=\"e620fa98-7a40-41a0-bfc9-b4407297fb58\", name=clusterName, id=clusterId, param1, param2\n\n" }, { @@ -3528,7 +3754,9 @@ "severity": "High", "category": "High Availability", "guid": "a01afc4c-7439-4919-b2da-3565992ea2a7", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -3557,7 +3785,9 @@ "severity": "High", "category": "High Availability", "guid": "f46b0d1d-56ef-4795-b98a-f6ee00cb341a", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns each AKS cluster with nodepools that have Linux nodepools not using Azure Linux\nresources\n| where type == \"microsoft.containerservice/managedclusters\"\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\n| where agentPoolProfile.osType == 'Linux' and agentPoolProfile.osSKU != 'AzureLinux'\n| project recommendationid=\"f46b0d1d-56ef-4795-b98a-f6ee00cb341a\", name, id, param1=strcat(\"nodePoolName: \", agentPoolProfile.name)\n" }, { @@ -3586,7 +3816,9 @@ "severity": "High", "category": "High Availability", "guid": "9200aca6-0e83-4749-a5eb-e3939367bdc2", - "source": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceFile": "azure-resources/ContainerService/managedClusters/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -3615,7 +3847,9 @@ "severity": "High", "category": "High Availability", "guid": "88856605-53d8-4bbd-a75b-4a7b14939d32", - "source": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for MySQL instances that are not zone redundant\nresources\n| where type == \"microsoft.dbformysql/flexibleservers\"\n| where properties.highAvailability.mode != \"ZoneRedundant\"\n| project recommendationId = \"88856605-53d8-4bbd-a75b-4a7b14939d32\", name, id, tags, param1 = \"ZoneRedundant: False\"\n" }, { @@ -3644,7 +3878,9 @@ "severity": "High", "category": "Scalability", "guid": "82a9a0f2-24ee-496f-9ad2-25f81710942d", - "source": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for MySQL instances that do not have a custom maintenance window\nresources\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\n| where properties.maintenanceWindow.customWindow != \"Enabled\"\n| project recommendationId = \"82a9a0f2-24ee-496f-9ad2-25f81710942d\", name, id, tags, param1 = strcat(\"customWindow:\", properties['maintenanceWindow']['customWindow'])\n" }, { @@ -3673,7 +3909,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "5c96afc3-7d2e-46ff-a4c7-9c32850c441b", - "source": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for MySQL instances that do not have geo redundant backup storage enabled\nresources\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\n| where properties.backup.geoRedundantBackup != \"Enabled\"\n| project recommendationId = \"5c96afc3-7d2e-46ff-a4c7-9c32850c441b\", name, id, tags, param1 = strcat(\"geoRedundantBackup:\", properties['backup']['geoRedundantBackup'])\n" }, { @@ -3702,7 +3940,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "b49a8653-cc43-48c9-8513-a2d2e3f14dd1", - "source": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for MySQL instances that do not have a read replica configured\nresources\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\n| where properties.replicationRole == \"None\"\n| project recommendationId = \"b49a8653-cc43-48c9-8513-a2d2e3f14dd1\", name, id, tags, param1 = strcat(\"replicationRole:\", properties['replicationRole'])\n" }, { @@ -3731,7 +3971,9 @@ "severity": "High", "category": "Scalability", "guid": "8176a79d-8645-4e52-96be-a10fc0204fe5", - "source": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforMySQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for MySQL instances that do not have a storage auto-grow\nresources\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\n| where properties.storage.autoGrow != \"Enabled\"\n| project recommendationId = \"8176a79d-8645-4e52-96be-a10fc0204fe5\", name, id, tags, param1 = strcat(\"autoGrow:\", properties['storage']['autoGrow'])\n" }, { @@ -3760,7 +4002,9 @@ "severity": "High", "category": "High Availability", "guid": "ca87914f-aac4-4783-ab67-82a6f936f194", - "source": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for PostgreSQL instances that are not zone redundant\nresources\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\n| where properties.highAvailability.mode != \"ZoneRedundant\"\n| project recommendationId = \"ca87914f-aac4-4783-ab67-82a6f936f194\", name, id, tags, param1 = \"ZoneRedundant: False\"\n" }, { @@ -3789,7 +4033,9 @@ "severity": "High", "category": "Scalability", "guid": "b2bad57d-7e03-4c0f-9024-597c9eb295bb", - "source": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for PostgreSQL instances that do not have a custom maintenance window\nresources\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\n| where properties.maintenanceWindow.customWindow != \"Enabled\"\n| project recommendationId = \"b2bad57d-7e03-4c0f-9024-597c9eb295bb\", name, id, tags, param1 = strcat(\"customWindow:\", properties['maintenanceWindow']['customWindow'])\n" }, { @@ -3818,7 +4064,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "31f4ac4b-29cb-4588-8de2-d8fe6f13ceb3", - "source": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for PostgreSQL instances that do not have geo redundant backup storage configured\nresources\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\n| where properties.backup.geoRedundantBackup != \"Enabled\"\n| project recommendationId = \"31f4ac4b-29cb-4588-8de2-d8fe6f13ceb3\", name, id, tags, param1 = strcat(\"geoRedundantBackup:\", properties['backup']['geoRedundantBackup'])\n" }, { @@ -3847,7 +4095,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "2ab85a67-26be-4ed2-a0bb-101b2513ec63", - "source": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Database for PostgreSQL instances that are read replicas\nresources\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\n| where properties.replicationRole == \"AsyncReplica\"\n| project recommendationId = \"2ab85a67-26be-4ed2-a0bb-101b2513ec63\", name, id, tags, param1 = strcat(\"replicationRole:\", properties['replicationRole'])\n" }, { @@ -3876,7 +4126,9 @@ "severity": "High", "category": "Scalability", "guid": "6293a3cc-6b4a-4c0f-9ea7-b8ae8d7dd3d5", - "source": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceFile": "azure-resources/DBforPostgreSQL/flexibleServers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -3905,7 +4157,9 @@ "severity": "Medium", "category": "Governance", "guid": "0e835cc2-2551-a247-b1f1-3c5f25c9cb70", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -3934,7 +4188,9 @@ "severity": "High", "category": "Scalability", "guid": "c166602e-0804-e34b-be8f-09b4d56e1fcd", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -3963,7 +4219,9 @@ "severity": "Medium", "category": "Scalability", "guid": "5877a510-8444-7a4c-8412-a8dab8662f7e", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -3992,7 +4250,9 @@ "severity": "High", "category": "Scalability", "guid": "5c72f0d6-55ec-d941-be84-36c194fa78c0", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4021,7 +4281,9 @@ "severity": "High", "category": "Scalability", "guid": "362ad2b6-b92c-414f-980a-0cf69467ccce", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4054,7 +4316,9 @@ "severity": "Medium", "category": "Scalability", "guid": "cd77db98-9b13-6e4b-bd2b-74c2cb538628", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4083,7 +4347,9 @@ "severity": "Medium", "category": "High Availability", "guid": "3d3e53b5-ebd1-db42-b43b-d4fad74824ec", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4112,7 +4378,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "7fb90127-5364-bb4d-86fa-30778ed713fb", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4141,7 +4409,9 @@ "severity": "High", "category": "High Availability", "guid": "da4ea916-4df3-8c4d-8060-17b49da45977", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4170,7 +4440,9 @@ "severity": "Low", "category": "High Availability", "guid": "892ca809-e2b5-9a47-924a-71132bf6f902", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4199,7 +4471,9 @@ "severity": "Low", "category": "Business Continuity", "guid": "7e52d64d-8cc0-8548-a593-eb49ab45630d", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4228,7 +4502,9 @@ "severity": "High", "category": "High Availability", "guid": "84e44da6-8cd7-b349-b02c-c8bf72cf587c", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4257,7 +4533,9 @@ "severity": "High", "category": "Scalability", "guid": "4cbb7744-ff3d-0447-badb-baf068c95696", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4286,7 +4564,9 @@ "severity": "Medium", "category": "High Availability", "guid": "1b0d0893-bf0e-8f4c-9dc6-f18f145c1ecf", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4315,7 +4595,9 @@ "severity": "Low", "category": "Business Continuity", "guid": "e93fe702-e385-d741-ba37-1f1656482ecd", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4344,7 +4626,9 @@ "severity": "Medium", "category": "Other Best Practices", "guid": "b7e1d13f-54c9-1648-8a52-34c0abe8ce16", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4373,7 +4657,9 @@ "severity": "Low", "category": "Business Continuity", "guid": "a42297c4-7e4f-8b41-8d4b-114033263f0e", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4402,7 +4688,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "932d45d6-b46d-e341-abfb-d97bce832f1f", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4431,7 +4719,9 @@ "severity": "High", "category": "High Availability", "guid": "12e9d852-5cdc-2743-bffe-ee21f2ef7781", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4460,7 +4750,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "a18d60f8-c98c-ba4e-ad6e-2fac72879df1", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4489,7 +4781,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "c0e22580-3819-444d-8546-a80e4ed85c83", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4518,7 +4812,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "4fdb7112-4531-6f48-b60e-c917a6068d9b", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4547,7 +4843,9 @@ "severity": "High", "category": "Other Best Practices", "guid": "42aedaa8-6151-424d-b782-b8666c779969", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4576,7 +4874,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "20193ff9-dbcd-a74e-b197-71d7d9d3c1e6", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4605,7 +4905,9 @@ "severity": "High", "category": "Scalability", "guid": "397cdebb-9d6e-ab4f-83a1-8c481de0a3a7", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4634,7 +4936,9 @@ "severity": "High", "category": "Scalability", "guid": "5e722c4f-415a-9b4c-bd4c-96b74dce29ad", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4663,7 +4967,9 @@ "severity": "High", "category": "High Availability", "guid": "14310ba6-77ad-3641-a2db-57a2218b9bc7", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4692,7 +4998,9 @@ "severity": "High", "category": "High Availability", "guid": "b5af7e26-3939-1b48-8fba-f8d4a475c67a", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4729,7 +5037,9 @@ "severity": "High", "category": "High Availability", "guid": "8aa63c34-dd9d-49bd-9582-21ec310dfbdd", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -4762,7 +5072,9 @@ "severity": "Medium", "category": "Personalized", "guid": "028593be-956e-4736-bccf-074cb10b92f4", - "source": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/Databricks/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4791,7 +5103,9 @@ "severity": "Medium", "category": "Governance", "guid": "013ac34e-7c4b-425f-9e0c-216f0cc06181", - "source": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceFile": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -4820,7 +5134,9 @@ "severity": "Medium", "category": "Governance", "guid": "979ff8be-5f3a-4d8e-9aa3-407ecdd6d6f7", - "source": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceFile": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This resource graph query will return all AVD host pools that does not have scheduled agent updates configured\nresources\n| where type =~ \"Microsoft.DesktopVirtualization/hostpools\"\n| where isnull(properties.agentUpdate)\n| project recommendationId = \"979ff8be-5f3a-4d8e-9aa3-407ecdd6d6f7\", name, id, tags, param1 = 'No scheduled agent updates'\n" }, { @@ -4849,7 +5165,9 @@ "severity": "Medium", "category": "Governance", "guid": "939cb85c-102a-4e0a-ab82-5c92116d3778", - "source": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceFile": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4878,7 +5196,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "38721758-2cc2-4d6b-b7b7-8b47dadbf7df", - "source": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceFile": "azure-resources/DesktopVirtualization/hostPools/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -4907,7 +5227,9 @@ "severity": "Medium", "category": "Scalability", "guid": "499769ae-67c9-492e-9ca5-cfd4cece5209", - "source": "azure-resources/DesktopVirtualization/scalingPlans/recommendations.yaml", + "sourceFile": "azure-resources/DesktopVirtualization/scalingPlans/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -4940,7 +5262,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "783c6c18-760b-4867-9ced-3010a0bc5aa3", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -4969,7 +5293,9 @@ "severity": "High", "category": "High Availability", "guid": "eeba3a49-fef0-481f-a471-7ff01139b474", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// list all IoT Hubs that are using the Free tier\nresources\n| where type =~ \"microsoft.devices/iothubs\" and\n tostring(sku.tier) =~ 'Free'\n| project recommendationId=\"eeba3a49-fef0-481f-a471-7ff01139b474\", name, id, tags, param1=strcat(\"tier:\", tostring(sku.tier))\n\n" }, { @@ -4998,7 +5324,9 @@ "severity": "High", "category": "High Availability", "guid": "214cbc46-747e-4354-af6e-6bf0054196a5", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -5035,7 +5363,9 @@ "severity": "High", "category": "Scalability", "guid": "b1e1378d-4572-4414-bebd-b8872a6d4d1c", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// list all IoT Hubs that do not have a linked IoT Hub Device Provisioning Service (DPS)\nresources\n| where type =~ \"microsoft.devices/iothubs\"\n| project id, iotHubName=tostring(properties.hostName), tags, resourceGroup\n| join kind=fullouter (\n resources\n | where type == \"microsoft.devices/provisioningservices\"\n | mv-expand iotHubs=properties.iotHubs\n | project iotHubName = tostring(iotHubs.name), dpsName = name, name=iotHubs.name\n) on iotHubName\n| where dpsName == ''\n| project recommendationId=\"b1e1378d-4572-4414-bebd-b8872a6d4d1c\", name=iotHubName, id, tags, param1='DPS:none'\n\n" }, { @@ -5064,7 +5394,9 @@ "severity": "High", "category": "High Availability", "guid": "02568a5d-335e-4e51-9f7c-fe2ada977300", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -5093,7 +5425,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "e7dbd21f-b27a-4b8c-a901-cedb1e6d8e1e", - "source": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceFile": "azure-resources/Devices/iotHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// list all IoT Hubs that have the fallback route disabled\nresources\n| where type == \"microsoft.devices/iothubs\"\n| extend fallbackEnabled=properties.routing.fallbackRoute.isEnabled\n| where fallbackEnabled == false\n| project recommendationId=\"e7dbd21f-b27a-4b8c-a901-cedb1e6d8e1e\", name, id, tags, param1='FallbackRouteEnabled:false'\n\n" }, { @@ -5126,7 +5460,9 @@ "severity": "High", "category": "High Availability", "guid": "43663217-a1d3-844b-80ea-571a2ce37c6c", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to find Azure Cosmos DB accounts that have less than 2 regions or less than 3 regions with strong consistency level\nResources\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\n| where\n array_length(properties.locations) < 2 or\n (array_length(properties.locations) < 3 and properties.consistencyPolicy.defaultConsistencyLevel == 'Strong')\n| project recommendationId='43663217-a1d3-844b-80ea-571a2ce37c6c', name, id, tags\n\n" }, { @@ -5155,7 +5491,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "9cabded7-a1fc-6e4a-944b-d7dd98ea31a2", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to list all Azure Cosmos DB accounts that do not have multiple write locations or automatic failover enabled\nResources\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\n| where\n array_length(properties.locations) > 1 and\n tobool(properties.enableAutomaticFailover) == false and\n tobool(properties.enableMultipleWriteLocations) == false\n| project recommendationId='9cabded7-a1fc-6e4a-944b-d7dd98ea31a2', name, id, tags\n" }, { @@ -5188,7 +5526,9 @@ "severity": "High", "category": "High Availability", "guid": "9ce78192-74a0-104c-b5bb-9a443f941649", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query to find Azure Cosmos DB accounts that have multiple read locations but do not have multiple write locations enabled\nResources\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\n| where\n array_length(properties.locations) > 1 and\n properties.enableMultipleWriteLocations == false\n| project recommendationId='9ce78192-74a0-104c-b5bb-9a443f941649', name, id, tags\n\n" }, { @@ -5217,7 +5557,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "e544520b-8505-7841-9e77-1f1974ee86ec", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Query all Azure Cosmos DB accounts that do not have continuous backup mode configured\nResources\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\n| where\n properties.backupPolicy.type == 'Periodic' and\n properties.enableMultipleWriteLocations == false and\n properties.enableAnalyticalStorage == false\n| project recommendationId='e544520b-8505-7841-9e77-1f1974ee86ec', name, id, tags\n" }, { @@ -5246,7 +5588,9 @@ "severity": "High", "category": "Scalability", "guid": "c006604a-0d29-684c-99f0-9729cb40dac5", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -5275,7 +5619,9 @@ "severity": "Medium", "category": "Scalability", "guid": "7eb32cf9-9a42-1540-acf8-597cbba8a418", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -5304,7 +5650,9 @@ "severity": "Medium", "category": "High Availability", "guid": "fa6ac22f-0584-bb4b-80e4-80f4755d1a97", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -5333,7 +5681,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "deaea200-013c-414b-ac9f-bfa7a7fb13f0", - "source": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceFile": "azure-resources/DocumentDB/databaseAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -5362,7 +5712,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "54c3191b-b535-1946-bba9-b754f44060f6", - "source": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceFile": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -5391,7 +5743,9 @@ "severity": "Low", "category": "Personalized", "guid": "92162eb5-4323-3145-8a6c-525ce2f0700e", - "source": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceFile": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -5420,7 +5774,9 @@ "severity": "Medium", "category": "Security", "guid": "b2069f64-4741-3d4a-a71d-50c8b03f5ab7", - "source": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceFile": "azure-resources/EventGrid/topics/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all eventgrid services not protected by private endpoints.\nResources\n| where type contains \"eventgrid\"\n| where properties['publicNetworkAccess'] == \"Enabled\"\n| project recommendationId = \"b2069f64-4741-3d4a-a71d-50c8b03f5ab7\", name, id, tags\n| order by id asc\n\n" }, { @@ -5449,7 +5805,9 @@ "severity": "High", "category": "High Availability", "guid": "84636c6c-b317-4722-b603-7b1ffc16384b", - "source": "azure-resources/EventHub/namespaces/recommendations.yaml" + "sourceFile": "azure-resources/EventHub/namespaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024" }, { "description": "Enable auto-inflate on Event Hub Standard tier namespaces to automatically scale up TUs, meeting usage needs and preventing data ingress or egress throttle scenarios by adjusting to allowed rates.\n", @@ -5477,7 +5835,9 @@ "severity": "High", "category": "Scalability", "guid": "fbfef3df-04a5-41b2-a8fd-b8541eb04956", - "source": "azure-resources/EventHub/namespaces/recommendations.yaml", + "sourceFile": "azure-resources/EventHub/namespaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Event Hub namespace instances that are Standard tier and do not have Auto Inflate enabled\nresources\n| where type == \"microsoft.eventhub/namespaces\"\n| where sku.tier == \"Standard\"\n| where properties.isAutoInflateEnabled == \"false\"\n| project recommendationId = \"fbfef3df-04a5-41b2-a8fd-b8541eb04956\", name, id, tags, param1 = \"AutoInflateEnabled: False\"\n\n" }, { @@ -5514,7 +5874,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "be448849-0d7d-49ba-9c94-9573ee533d5d", - "source": "azure-resources/Insights/activityLogAlerts/recommendations.yaml", + "sourceFile": "azure-resources/Insights/activityLogAlerts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -5547,7 +5909,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "9729c89d-8118-41b4-a39b-e12468fa872b", - "source": "azure-resources/Insights/activityLogAlerts/recommendations.yaml", + "sourceFile": "azure-resources/Insights/activityLogAlerts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This resource graph query will return all subscriptions without Service Health alerts configured.\n\nresourcecontainers\n| where type == 'microsoft.resources/subscriptions'\n| project subscriptionAlerts=tostring(id),name,tags\n| join kind=leftouter (\n resources\n | where type == 'microsoft.insights/activitylogalerts' and properties.condition contains \"ServiceHealth\"\n | extend subscriptions = properties.scopes\n | project subscriptions\n | mv-expand subscriptions\n | project subscriptionAlerts = tostring(subscriptions)\n) on subscriptionAlerts\n| where isempty(subscriptionAlerts1)\n| project-away subscriptionAlerts1\n| project recommendationId = \"9729c89d-8118-41b4-a39b-e12468fa872b\",id=subscriptionAlerts,name,tags\n\n" }, { @@ -5576,7 +5940,9 @@ "severity": "Medium", "category": "Service Upgrade and Retirement", "guid": "dac421ec-2832-4c37-839e-b6dc5a38f2fa", - "source": "azure-resources/Insights/components/recommendations.yaml", + "sourceFile": "azure-resources/Insights/components/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// Filters Application Insights resources with \u2018Classic\u2019 deployment type\nresources\n| where type =~ \"microsoft.insights/components\"\n| extend IngestionMode = properties.IngestionMode\n| where IngestionMode =~ 'ApplicationInsights'\n| project recommendationId= \"dac421ec-2832-4c37-839e-b6dc5a38f2fa\", name, id, tags, param1=\"ApplicationInsightsDeploymentType: Classic\"\n\n" }, { @@ -5605,7 +5971,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "1cca00d2-d9ab-8e42-a788-5d40f49405cb", - "source": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceFile": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Key Vaults that do not have soft delete enabled.\nresources\n| where type == \"microsoft.keyvault/vaults\"\n| where isnull(properties.enableSoftDelete) or properties.enableSoftDelete != \"true\"\n| project recommendationId = \"1cca00d2-d9ab-8e42-a788-5d40f49405cb\", name, id, tags, param1 = \"EnableSoftDelete: Disabled\"\n\n" }, { @@ -5634,7 +6002,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "70fcfe6d-00e9-5544-a63a-fff42b9f2edb", - "source": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceFile": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This resource graph query will return all Key Vaults that do not have Purge Protection enabled.\nresources\n| where type == \"microsoft.keyvault/vaults\"\n| where isnull(properties.enablePurgeProtection) or properties.enablePurgeProtection != \"true\"\n| project recommendationId = \"70fcfe6d-00e9-5544-a63a-fff42b9f2edb\", name, id, tags, param1 = \"EnablePurgeProtection: Disabled\"\n\n" }, { @@ -5663,7 +6033,9 @@ "severity": "Medium", "category": "Security", "guid": "00c3d2b0-ea6e-4c4b-89be-b78a35caeb51", - "source": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceFile": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This resource graph query will return all Key Vaults that does not have a Private Endpoint Connection or where a private endpoint exists but public access is enabled\n\nresources\n| where type == \"microsoft.keyvault/vaults\"\n| where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != (\"Succeeded\") or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled')\n| extend param1 = strcat('Private Endpoint: ', iif(isnotnull(properties.privateEndpointConnections),split(properties.privateEndpointConnections[0].properties.privateEndpoint.id,'/')[8],'No Private Endpoint'))\n| extend param2 = strcat('Access: ', iif(properties.publicNetworkAccess == 'Disabled', 'Public Access Disabled', iif(isnotnull(properties.networkAcls), 'NetworkACLs in place','Public Access Enabled')))\n| project recommendationId = \"00c3d2b0-ea6e-4c4b-89be-b78a35caeb51\", name, id, tags, param1, param2\n\n" }, { @@ -5692,7 +6064,9 @@ "severity": "High", "category": "Governance", "guid": "e7091145-3642-bd41-bb58-66502e64d2cd", - "source": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceFile": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -5721,7 +6095,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "1dc0821d-4f14-7644-bab4-ba208ff5f7fa", - "source": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceFile": "azure-resources/KeyVault/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -5750,7 +6126,9 @@ "severity": "Medium", "category": "Scalability", "guid": "af426a99-62a6-6b4c-9662-42d220b413b8", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -5779,7 +6157,9 @@ "severity": "High", "category": "Scalability", "guid": "ab984130-c57b-6c4a-8d04-6723b4e1bdb6", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without standard network features.\nresources\n| where type =~ \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\n| where properties.networkFeatures != \"Standard\"\n| project recommendationId = \"ab984130-c57b-6c4a-8d04-6723b4e1bdb6\", name, id, tags\n\n" }, { @@ -5808,7 +6188,9 @@ "severity": "High", "category": "High Availability", "guid": "47d100a5-7f85-5742-967a-67eb5081240a", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without an availability zone defined.\nResources\n| where type =~ \"Microsoft.NetApp/netAppAccounts/capacityPools/volumes\"\n| where array_length(zones) == 0 or isnull(zones)\n| project recommendationId = \"47d100a5-7f85-5742-967a-67eb5081240a\", name, id, tags\n\n" }, { @@ -5837,7 +6219,9 @@ "severity": "High", "category": "Other Best Practices", "guid": "8bb690e8-64d5-4838-8703-9ee3dbac688f", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -5866,7 +6250,9 @@ "severity": "High", "category": "High Availability", "guid": "72827434-c773-4345-9493-34848ddf5803", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without a snapshot policy defined.\nresources\n|\u00a0where\u00a0type\u00a0==\u00a0\"microsoft.netapp/netappaccounts/capacitypools/volumes\"\n| where properties.dataProtection.snapshot.snapshotPolicyId == \"\"\n| project recommendationId = \"72827434-c773-4345-9493-34848ddf5803\", name, id, tags\n\n" }, { @@ -5895,7 +6281,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "b2fb3e60-97ec-e34d-af29-b16a0d61c2ac", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without a backup policy defined.\nresources\n| where type == \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\n| where properties.dataProtection.backup.backupPolicyId == \"\"\n| project recommendationId = \"b2fb3e60-97ec-e34d-af29-b16a0d61c2ac\", name, id, tags\n" }, { @@ -5924,7 +6312,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "e30317d2-c502-4dfe-a2d3-0a737cc79545", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without cross-region replication.\nresources\n|\u00a0where\u00a0type\u00a0==\u00a0\"microsoft.netapp/netappaccounts/capacitypools/volumes\"\n|\u00a0extend\u00a0remoteVolumeRegion\u00a0=\u00a0properties.dataProtection.replication.remoteVolumeRegion\n|\u00a0extend\u00a0volumeType\u00a0=\u00a0properties.volumeType\n|\u00a0extend\u00a0replicationType\u00a0=\u00a0iff((remoteVolumeRegion\u00a0==\u00a0location),\u00a0\"CZR\",\u00a0iff((remoteVolumeRegion\u00a0==\u00a0\"\"),\"n/a\",\"CRR\"))\n| where replicationType != \"CRR\" and volumeType != \"DataProtection\"\n| project recommendationId = \"e30317d2-c502-4dfe-a2d3-0a737cc79545\", name, id, tags\n\n" }, { @@ -5953,7 +6343,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "e3d742e1-dacd-9b48-b6b1-510ec9f87c96", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Azure NetApp Files volumes without cross-zone replication.\nresources\n|\u00a0where\u00a0type\u00a0==\u00a0\"microsoft.netapp/netappaccounts/capacitypools/volumes\"\n|\u00a0extend\u00a0remoteVolumeRegion\u00a0=\u00a0properties.dataProtection.replication.remoteVolumeRegion\n|\u00a0extend\u00a0volumeType\u00a0=\u00a0properties.volumeType\n|\u00a0extend\u00a0replicationType\u00a0=\u00a0iff((remoteVolumeRegion\u00a0==\u00a0location),\u00a0\"CZR\",\u00a0iff((remoteVolumeRegion\u00a0==\u00a0\"\"),\"n/a\",\"CRR\"))\n| where replicationType != \"CZR\" and volumeType != \"DataProtection\"\n| project recommendationId = \"e3d742e1-dacd-9b48-b6b1-510ec9f87c96\", name, id, tags\n\n" }, { @@ -5982,7 +6374,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "2f579fc9-e599-0d44-8b97-254f50ae04d8", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6015,7 +6409,9 @@ "severity": "Medium", "category": "Governance", "guid": "687ae58f-517f-ca43-90fe-922497e61283", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6060,7 +6456,9 @@ "severity": "Medium", "category": "Security", "guid": "cfa2244b-5436-47de-8287-b217875d3b0a", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6089,7 +6487,9 @@ "severity": "High", "category": "High Availability", "guid": "d1e7ccc3-e6c1-40e9-a36e-fd134711c808", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6118,7 +6518,9 @@ "severity": "Medium", "category": "High Availability", "guid": "60f36f9b-fac9-4160-bbf5-57af04da4f53", - "source": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceFile": "azure-resources/NetApp/netAppAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6147,7 +6549,9 @@ "severity": "Medium", "category": "Scalability", "guid": "823b0cff-05c0-2e4e-a1e7-9965e1cfa16f", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all Application Gateways that do not have autoscale enabled or have a min capacity of 1\nresources\n| where type =~ \"microsoft.network/applicationGateways\"\n| where isnull(properties.autoscaleConfiguration) or properties.autoscaleConfiguration.minCapacity <= 1\n| project recommendationId = \"823b0cff-05c0-2e4e-a1e7-9965e1cfa16f\", name, id, tags, param1 = \"autoScaleConfiguration: isNull or MinCapacity <= 1\"\n| order by id asc\n\n\n" }, { @@ -6192,7 +6596,9 @@ "severity": "High", "category": "Security", "guid": "233a7008-71e9-e745-923e-1a1c7a0b92f3", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// You can use the following Azure Resource Graph query to check if an HTTP rule is using an SSL certificate or is using Azure Key Vault to store the certificates\nresources\n| where type =~ \"microsoft.network/applicationGateways\"\n| mv-expand frontendPorts = properties.frontendPorts\n| mv-expand httpListeners = properties.httpListeners\n| where isnull(parse_json(httpListeners.properties.sslCertificate))\n| project recommendationId=\"233a7008-71e9-e745-923e-1a1c7a0b92f3\", name, id, tags, param1=strcat(\"frontendPort: \", frontendPorts.properties.port), param2=\"tls: false\"\n\n" }, { @@ -6225,7 +6631,9 @@ "severity": "Low", "category": "Security", "guid": "8d9223c4-730d-ca47-af88-a9a024c37270", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all Application Gateways that do not have WAF enabled\nResources\n| where type =~ \"microsoft.network/applicationGateways\"\n| where properties.firewallpolicy != \"\"\n| project recommendationId = \"8d9223c4-730d-ca47-af88-a9a024c37270\", name, id, tags, param1 = \"webApplicationFirewallConfiguration: isNull\"\n| order by id asc\n\n\n" }, { @@ -6262,7 +6670,9 @@ "severity": "High", "category": "Scalability", "guid": "7893f0b3-8622-1d47-beed-4b50a19f7895", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Get all Application Gateways, which are using the deprecated V1 SKU\nresources\n| where type =~ 'microsoft.network/applicationgateways'\n| extend tier = properties.sku.tier\n| where tier == 'Standard' or tier == 'WAF'\n| project recommendationId = \"7893f0b3-8622-1d47-beed-4b50a19f7895\", name, id, tags\n\n" }, { @@ -6295,7 +6705,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "5d035919-898d-a047-8d5d-454e199692e5", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6328,7 +6740,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "847a8d88-21c4-bc48-a94e-562206edd767", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Application Gateways are not using health probes to monitor the availability of the backend systems\nresources\n| where type =~ \"microsoft.network/applicationGateways\"\n| where array_length(properties.probes) == 0\n| project recommendationId=\"847a8d88-21c4-bc48-a94e-562206edd767\", name, id, tags, param1=\"customHealthProbeUsed: false\"\n\n" }, { @@ -6361,7 +6775,9 @@ "severity": "High", "category": "High Availability", "guid": "c9c00f2a-3888-714b-a72b-b4c9e8fcffb2", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// list Application Gateways that are not configured to use at least 2 Availability Zones\nresources\n| where type =~ \"microsoft.network/applicationGateways\"\n| where isnull(zones) or array_length(zones) < 2\n| extend zoneValue = iff((isnull(zones)), \"null\", zones)\n| project recommendationId = \"c9c00f2a-3888-714b-a72b-b4c9e8fcffb2\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Zones value: \", zoneValue )\n\n" }, { @@ -6394,7 +6810,9 @@ "severity": "Medium", "category": "High Availability", "guid": "10f02bc6-e2e7-004d-a2c2-f9bf9f16b915", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will check if connection draining is enabled\nresources\n| where type =~ \"microsoft.network/applicationGateways\"\n| mv-expand backendHttpSettings = properties.backendHttpSettingsCollection\n| extend connectionDrainingEnabled = backendHttpSettings.properties.connectionDraining.enabled\n| where connectionDrainingEnabled != true\n| extend backendPoolName = backendHttpSettings.name\n| project recommendationId = \"10f02bc6-e2e7-004d-a2c2-f9bf9f16b915\", name, id, tags, param1 = \"connectionDraining: Disabled\", param2 = strcat(\"backendSettingsName: \", backendPoolName)\n\n" }, { @@ -6423,7 +6841,9 @@ "severity": "High", "category": "Other Best Practices", "guid": "8364fd0a-7c0e-e240-9d95-4bf965aec243", - "source": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/applicationGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will validate the subnet id for an appGW ends with a /24\n\nresources\n| where type =~ 'Microsoft.Network/applicationGateways'\n| extend subnetid = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id)\n| join kind=leftouter(resources\n | where type == \"microsoft.network/virtualnetworks\"\n | mv-expand properties.subnets\n | extend subnetid = tostring(properties_subnets.id)\n | extend addressprefix = tostring(properties_subnets.properties.addressPrefix)\n | project subnetid, addressprefix) on subnetid\n| where addressprefix !endswith '/24'\n| project recommendationId = \"8364fd0a-7c0e-e240-9d95-4bf965aec243\", name, id, tags, param1 = strcat('AppGW subnet prefix: ', addressprefix)\n\n" }, { @@ -6456,7 +6876,9 @@ "severity": "High", "category": "High Availability", "guid": "c72b7fee-1fa0-5b4b-98e5-54bcae95bb74", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List all Azure Firewalls that are not configured with multiple availability zones or deployed without a zone\nresources\n| where type == 'microsoft.network/azurefirewalls'\n| where array_length(zones) <= 1 or isnull(zones)\n| where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id)\n| project recommendationId = \"c72b7fee-1fa0-5b4b-98e5-54bcae95bb74\", name, id, tags, param1=\"multipleZones:false\"\n\n" }, { @@ -6489,7 +6911,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "3c8fa7c6-6b78-a24a-a63f-348a7c71acb9", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List all Azure Firewalls resources in-scope, along with any metrics associated to Azure Monitor alert rules, that are not fully configured.\nresources\n| where type == \"microsoft.network/azurefirewalls\"\n| project firewallId = tolower(id), name, tags\n| join kind = leftouter (\n resources\n | where type == \"microsoft.insights/metricalerts\"\n | mv-expand properties.scopes\n | mv-expand properties.criteria.allOf\n | where properties_scopes contains \"azureFirewalls\"\n | project metricId = tolower(properties_scopes), monitoredMetric = properties_criteria_allOf.metricName, tags\n | summarize monitoredMetrics = make_list(monitoredMetric) by tostring(metricId)\n | project\n metricId,\n monitoredMetrics,\n allAlertsConfigured = monitoredMetrics contains(\"FirewallHealth\") and monitoredMetrics contains (\"Throughput\") and monitoredMetrics contains (\"SNATPortUtilization\")\n) on $left.firewallId == $right.metricId\n| extend alertsNotFullyConfigured = isnull(allAlertsConfigured) or not(allAlertsConfigured)\n| where alertsNotFullyConfigured\n| project recommendationId = \"c8fa7c6-6b78-a24a-a63f-348a7c71acb9\", name, id = firewallId, tags, param1 = strcat(\"MetricsAlerts:\", monitoredMetrics)\n\n" }, { @@ -6518,7 +6942,9 @@ "severity": "High", "category": "Security", "guid": "1b2dbf4a-8a0b-5e4b-8f4e-3f758188910d", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List all in-scope Azure Firewall resources, where the VNet is not associated to a DDoS Protection Plan\nresources\n| where type =~ \"Microsoft.Network/azureFirewalls\"\n| where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id)\n| mv-expand ipConfig = properties.ipConfigurations\n| project\n name,\n firewallId = id,\n tags,\n vNetName = split(ipConfig.properties.subnet.id, \"/\", 8)[0],\n vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, \"/subnet\")))\n| join kind=fullouter (\n resources\n | where type =~ \"Microsoft.Network/ddosProtectionPlans\"\n | mv-expand vNet = properties.virtualNetworks\n | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id)\n )\n on vNetId\n| where isempty(ddosProtectionPlanId)\n| project recommendationId = \"1b2dbf4a-8a0b-5e4b-8f4e-3f758188910d\", name, id = firewallId, tags, param1 = strcat(\"vNet: \", vNetName), param2 = \"ddosProtection: Disabled\"\n" }, { @@ -6547,7 +6973,9 @@ "severity": "Medium", "category": "Governance", "guid": "3a63560a-1ed3-6140-acd1-d1d23f9a2e12", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6576,7 +7004,9 @@ "severity": "Medium", "category": "High Availability", "guid": "d2e4a38e-2307-4299-a217-4c0cebc9a7f6", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under development\n\n" }, { @@ -6609,7 +7039,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "8faace2d-a36e-425c-aa58-2ad99e3e0b7a", - "source": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceFile": "azure-resources/Network/azureFirewalls/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under development\n\n" }, { @@ -6638,7 +7070,9 @@ "severity": "Medium", "category": "Scalability", "guid": "f6a14b32-a727-4ace-b5fa-7b1c6bdff402", - "source": "azure-resources/Network/connections/recommendations.yaml", + "sourceFile": "azure-resources/Network/connections/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6667,7 +7101,9 @@ "severity": "High", "category": "High Availability", "guid": "a5f3a4bd-4cf1-4196-a3cb-f5a0876198b2", - "source": "azure-resources/Network/connections/recommendations.yaml", + "sourceFile": "azure-resources/Network/connections/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6696,7 +7132,9 @@ "severity": "Medium", "category": "Security", "guid": "ae054bf2-aefa-cf4a-8282-741194cef8da", - "source": "azure-resources/Network/ddosProtectionPlans/recommendations.yaml", + "sourceFile": "azure-resources/Network/ddosProtectionPlans/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6725,7 +7163,9 @@ "severity": "High", "category": "High Availability", "guid": "4d703025-dafc-f840-a183-5dc440456134", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -6758,7 +7198,9 @@ "severity": "High", "category": "High Availability", "guid": "0e19cc41-8274-1342-b0db-0e4146eacef8", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6787,7 +7229,9 @@ "severity": "High", "category": "High Availability", "guid": "f06a2bbe-5839-d447-9f39-fc3d20562d88", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6816,7 +7260,9 @@ "severity": "High", "category": "High Availability", "guid": "2a5bf650-586d-db4c-a292-d922be7d3e0e", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -6845,7 +7291,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "9771a435-d031-814e-9827-9b5fdafc0f87", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6874,7 +7322,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "26cb547f-aabc-dc40-be02-d0a9b6b04b1a", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6903,7 +7353,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "f902cf86-2b53-2942-abc2-781f4fb62be6", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -6932,9 +7384,73 @@ "severity": "Medium", "category": "Scalability", "guid": "d40c769d-2f08-4980-8d8f-a386946276e6", - "source": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRouteCircuits/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all the ExpressRoute circuits (Direct Based) that have Direct Port Rate Limiting disabled\nresources\n| where type =~ \"microsoft.network/expressroutecircuits\"\n| where properties.expressRoutePort != \"\" or isnotnull(properties.expressRoutePort)\n| where properties.enableDirectPortRateLimit == false\n| project recommendationId = \"d40c769d-2f08-4980-8d8f-a386946276e6\", name, id, tags, param1=strcat(\"enableDirectPortRateLimit: \",properties.enableDirectPortRateLimit)\n" }, + { + "description": "To increase reliability, it's advised that each v-Hub's ExpressRoute gateway connects to at least two circuits, with each circuit originating from a different peering location than the other, ensuring diverse connectivity paths for enhanced resilience.|", + "aprlGuid": "9987c813-d687-4163-a511-95f31bc5e536", + "recommendationTypeId": null, + "recommendationControl": "High Availability", + "recommendationImpact": "High", + "recommendationResourceType": "Microsoft.Network/expressRouteGateways", + "recommendationMetadataState": "Active", + "longDescription": "To increase reliability, it's advised that each v-Hub's ExpressRoute gateway connects to at least two circuits, with each circuit originating from a different peering location than the other, ensuring diverse connectivity paths for enhanced resilience.|", + "potentialBenefits": "Enhance resiliency for Azure Service", + "pgVerified": false, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": false, + "tags": null, + "learnMoreLink": [ + { + "name": "Designing for disaster recovery with ExpressRoute private peering", + "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering" + } + ], + "service": "Microsoft.Network/expressRouteGateways", + "text": "Connect v-Hub's ExpressRoute gateway to circuits from diverse peering locations for resilience", + "severity": "High", + "category": "High Availability", + "guid": "9987c813-d687-4163-a511-95f31bc5e536", + "sourceFile": "azure-resources/Network/expressRouteGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", + "graph": "// under-development\n" + }, + { + "description": "Set up monitoring and alerts for Virtual WAN Express Route Gateway. Create alert rule for ensuring promptly response to critical events such as exceeding packets per second, exceeding BGP routes prefixes, Gateway overutilization and high frequency in route changes.", + "aprlGuid": "17e8d380-e4b4-41a1-9b37-2e4df9fd5125", + "recommendationTypeId": null, + "recommendationControl": "Monitoring and Alerting", + "recommendationImpact": "High", + "recommendationResourceType": "Microsoft.Network/expressRouteGateways", + "recommendationMetadataState": "Active", + "longDescription": "Set up monitoring and alerts for Virtual WAN Express Route Gateway. Create alert rule for ensuring promptly response to critical events such as exceeding packets per second, exceeding BGP routes prefixes, Gateway overutilization and high frequency in route changes.", + "potentialBenefits": "Detection and mitigation to avoid disruptions.", + "pgVerified": false, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": false, + "tags": null, + "learnMoreLink": [ + { + "name": "Virtual WAN Monitoring Best Practices", + "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#expressroute-gateway" + } + ], + "service": "Microsoft.Network/expressRouteGateways", + "text": "Monitor health for v-Hub's ExpressRoute gateway", + "severity": "High", + "category": "Monitoring and Alerting", + "guid": "17e8d380-e4b4-41a1-9b37-2e4df9fd5125", + "sourceFile": "azure-resources/Network/expressRouteGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", + "graph": "// under-development\n" + }, { "description": "In Azure ExpressRoute Direct, the \"Admin State\" indicates the administrative status of layer 1 links, showing if a link is enabled or disabled, effectively turning the physical port on or off.\n", "aprlGuid": "60077378-7cb1-4b35-89bb-393884d9921d", @@ -6961,7 +7477,9 @@ "severity": "High", "category": "High Availability", "guid": "60077378-7cb1-4b35-89bb-393884d9921d", - "source": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Express Route Directs that do not have Admin State of both Links Enabled\nresources\n| where type == \"microsoft.network/expressrouteports\"\n| where properties['links'][0]['properties']['adminState'] == \"Disabled\" or properties['links'][1]['properties']['adminState'] == \"Disabled\"\n| project recommendationId = \"60077378-7cb1-4b35-89bb-393884d9921d\", name, id, tags, param1 = strcat(\"Link1AdminState: \", properties['links'][0]['properties']['adminState']), param2 = strcat(\"Link2AdminState: \", properties['links'][1]['properties']['adminState'])\n\n" }, { @@ -6990,7 +7508,9 @@ "severity": "High", "category": "Scalability", "guid": "0bee356b-7348-4799-8cab-0c71ffe13018", - "source": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Express Route Directs that are over subscribed\nresources\n| where type == \"microsoft.network/expressrouteports\"\n| where toint(properties['provisionedBandwidthInGbps']) > toint(properties['bandwidthInGbps'])\n| project recommendationId = \"0bee356b-7348-4799-8cab-0c71ffe13018\", name, id, tags, param1 = strcat(\"provisionedBandwidthInGbps: \", properties['provisionedBandwidthInGbps']), param2 = strcat(\"bandwidthInGbps: \", properties['bandwidthInGbps'])\n\n" }, { @@ -7019,7 +7539,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "55815823-d588-4cb7-a5b8-ae581837356e", - "source": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceFile": "azure-resources/Network/expressRoutePorts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n" }, { @@ -7060,7 +7582,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "d0cfe47f-686b-5043-bf83-5a3868acb80a", - "source": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceFile": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -7093,7 +7617,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "537b4d94-edd1-4041-b13d-8217dfa485f0", - "source": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceFile": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -7126,7 +7652,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "5357ae22-0f52-1a49-9fd4-1f00ace6add0", - "source": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceFile": "azure-resources/Network/frontDoorWebApplicationFirewallPolicies/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -7159,7 +7687,9 @@ "severity": "High", "category": "High Availability", "guid": "38c3bca1-97a1-eb42-8cd3-838b243f35ba", - "source": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceFile": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all LoadBalancers using Basic SKU\nresources\n| where type =~ 'Microsoft.Network/loadBalancers'\n| where sku.name == 'Basic'\n| project recommendationId = \"38c3bca1-97a1-eb42-8cd3-838b243f35ba\", name, id, tags, Param1=strcat(\"sku-tier: basic\")\n\n" }, { @@ -7188,7 +7718,9 @@ "severity": "High", "category": "High Availability", "guid": "6d82d042-6d61-ad49-86f0-6a5455398081", - "source": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceFile": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all LoadBalancers which only have 1 backend pool defined or only 1 VM in the backend pool\nresources\n| where type =~ 'Microsoft.Network/loadBalancers'\n| extend bep = properties.backendAddressPools\n| extend BackEndPools = array_length(bep)\n| where BackEndPools == 0\n| project recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", name, id, Param1=\"backendPools\", Param2=toint(0), tags\n| union (resources\n | where type =~ 'Microsoft.Network/loadBalancers'\n | where sku.name == \"Standard\"\n | extend bep = properties.backendAddressPools\n | extend BackEndPools = toint(array_length(bep))\n | mv-expand bip = properties.backendAddressPools\n | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses)\n | where toint(BackendAddresses) <= 1\n | project recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", name, id, tags, Param1=\"backendAddresses\", Param2=toint(BackendAddresses))\n| union (\n resources\n | where type =~ 'Microsoft.Network/loadBalancers'\n | where sku.name == \"Basic\"\n | mv-expand properties.backendAddressPools\n | extend backendPoolId = properties_backendAddressPools.id\n | project id, name, tags, tostring(backendPoolId), recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", Param1=\"BackEndPools\"\n | join kind = leftouter (\n resources\n | where type =~ \"Microsoft.Network/networkInterfaces\"\n | mv-expand properties.ipConfigurations\n | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools\n | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id)\n | summarize poolMembers = count() by backendPoolId\n | project tostring(backendPoolId), poolMembers ) on backendPoolId\n | where toint(poolMembers) <= 1\n | extend BackendAddresses = poolMembers\n | project id, name, tags, recommendationId, Param1=\"backendAddresses\", Param2=toint(BackendAddresses))\n" }, { @@ -7217,7 +7749,9 @@ "severity": "Medium", "category": "High Availability", "guid": "8d319a05-677b-944f-b9b4-ca0fb42e883c", - "source": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceFile": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all LoadBalancers with Outbound rules configured\nresources\n| where type =~ 'Microsoft.Network/loadBalancers'\n| extend outboundRules = array_length(properties.outboundRules)\n| where outboundRules > 0\n| project recommendationId = \"8d319a05-677b-944f-b9b4-ca0fb42e883c\", name, id, tags, Param1 = \"outboundRules: >=1\"\n\n" }, { @@ -7246,7 +7780,9 @@ "severity": "High", "category": "High Availability", "guid": "621dbc78-3745-4d32-8eac-9e65b27b7512", - "source": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceFile": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all LoadBalancers with with regional or zonal public IP Addresses\nresources\n| where type == \"microsoft.network/loadbalancers\"\n| where tolower(sku.name) != 'basic'\n| mv-expand feIPconfigs = properties.frontendIPConfigurations\n| extend\n feConfigName = (feIPconfigs.name),\n PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id),\n PrivateIPZones = feIPconfigs.zones,\n PIPid = toupper(feIPconfigs.properties.publicIPAddress.id),\n JoinID = toupper(id)\n| where isnotempty(PrivateSubnetId)\n| where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2\n| project name, feConfigName, id\n| union (resources\n | where type == \"microsoft.network/loadbalancers\"\n | where tolower(sku.name) != 'basic'\n | mv-expand feIPconfigs = properties.frontendIPConfigurations\n | extend\n feConfigName = (feIPconfigs.name),\n PIPid = toupper(feIPconfigs.properties.publicIPAddress.id),\n JoinID = toupper(id)\n | where isnotempty(PIPid)\n | join kind=innerunique (\n resources\n | where type == \"microsoft.network/publicipaddresses\"\n | where isnull(zones) or array_length(zones) < 2\n | extend\n LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))),\n InnerID = toupper(id)\n ) on $left.PIPid == $right.InnerID)\n| project recommendationId = \"621dbc78-3745-4d32-8eac-9e65b27b7512\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Frontend IP Configuration:\", \" \", feConfigName)\n\n" }, { @@ -7275,7 +7811,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "e5f5fcea-f925-4578-8599-9a391e888a60", - "source": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceFile": "azure-resources/Network/loadBalancers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List the load balancers which don't have health probe configured\nresources\n| where type =~ \"microsoft.network/loadbalancers\"\n| where array_length(properties.probes) == 0\n| project recommendationId=\"e5f5fcea-f925-4578-8599-9a391e888a60\", name, id, tags, param1=\"customHealthProbeUsed: false\"\n" }, { @@ -7308,7 +7846,9 @@ "severity": "Medium", "category": "Scalability", "guid": "4281631c-3d19-4994-8d96-084c2a51a534", - "source": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7341,7 +7881,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "babf75d6-6407-4d90-b01e-5a1768e621f5", - "source": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7370,7 +7912,9 @@ "severity": "Medium", "category": "High Availability", "guid": "419df1ea-336b-460a-b6b2-fefe2588fcef", - "source": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/natGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7399,7 +7943,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "d2976d3e-294b-4b49-a1f0-c42566a3758f", - "source": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7428,7 +7974,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "8bb4a57b-55e4-d24e-9c19-2679d8bc779f", - "source": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Network Security Groups without alerts for modification configured.\nresources\n| where type =~ \"Microsoft.Network/networkSecurityGroups\"\n| project name, id, tags, lowerCaseNsgId = tolower(id)\n| join kind = leftouter (\n resources\n | where type =~ \"Microsoft.Insights/activityLogAlerts\" and properties.enabled == true\n | mv-expand scope = properties.scopes\n | where scope has \"Microsoft.Network/networkSecurityGroups\"\n | project alertName = name, conditionJson = dynamic_to_json(properties.condition.allOf), scope\n | where conditionJson has '\"Administrative\"' and (\n // Create or Update Network Security Group\n (conditionJson has '\"Microsoft.Network/networkSecurityGroups/write\"') or\n // All administrative operations\n (conditionJson !has '\"Microsoft.Network/networkSecurityGroups/write\"' and conditionJson !has '\"Microsoft.Network/networkSecurityGroups/delete\"' and conditionJson !has '\"Microsoft.Network/networkSecurityGroups/join/action\"')\n )\n | project lowerCaseNsgIdOfScope = tolower(scope)\n )\n on $left.lowerCaseNsgId == $right.lowerCaseNsgIdOfScope\n| where isempty(lowerCaseNsgIdOfScope)\n| project recommendationId = \"8bb4a57b-55e4-d24e-9c19-2679d8bc779f\", name, id, tags, param1 = \"ModificationAlert: Not configured/Disabled\"\n\n" }, { @@ -7457,7 +8005,9 @@ "severity": "Low", "category": "Governance", "guid": "52ac35e8-9c3e-f84d-8ce8-2fab955333d3", - "source": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7486,7 +8036,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "da1a3c06-d1d5-a940-9a99-fcc05966fe7c", - "source": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Network Security Groups without NSG Flow logs configured or disabled.\nresources\n| where type =~ \"Microsoft.Network/networkSecurityGroups\"\n| project name, id, tags, lowerCaseNsgId = tolower(id)\n| join kind = leftouter (\n resources\n | where type == \"microsoft.network/networkwatchers/flowlogs\" and properties.enabled == true\n | project flowLogName = name, lowerCaseTargetNsgId = tolower(properties.targetResourceId)\n )\n on $left.lowerCaseNsgId == $right.lowerCaseTargetNsgId\n| where isempty(lowerCaseTargetNsgId)\n| project recommendationId = \"da1a3c06-d1d5-a940-9a99-fcc05966fe7c\", name, id, tags, param1 = \"NSGFlowLog: Not configured/Disabled\"\n\n" }, { @@ -7515,7 +8067,9 @@ "severity": "Medium", "category": "Security", "guid": "8291c1fa-650c-b44b-b008-4deb7465919d", - "source": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkSecurityGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all NSGs that have NO security rules\nresources\n| where type =~ \"microsoft.network/networksecuritygroups\"\n| extend sr = string_size(properties.securityRules)\n| where sr <=2 or isnull(properties.securityRules)\n| project recommendationId = \"8291c1fa-650c-b44b-b008-4deb7465919d\", name, id\n\n" }, { @@ -7544,7 +8098,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "4e133bd0-8762-bc40-a95b-b29142427d73", - "source": "azure-resources/Network/networkWatchers/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkWatchers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all locations that do not have a Network Watcher deployed\nresources\n| where location != \"global\"\n| union (Resources\n | where type =~ \"microsoft.network/networkwatchers\")\n| summarize NetworkWatcherCount = countif(type =~ 'Microsoft.Network/networkWatchers') by location\n| where NetworkWatcherCount == 0\n| project recommendationId = \"4e133bd0-8762-bc40-a95b-b29142427d73\", name=location, id=\"n/a\", param1 = strcat(\"LocationMisingNetworkWatcher:\", location)\n\n" }, { @@ -7573,9 +8129,72 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "22a769ed-0ecb-8b49-bafe-8f52e6373d9c", - "source": "azure-resources/Network/networkWatchers/recommendations.yaml", + "sourceFile": "azure-resources/Network/networkWatchers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all Network Watcher Flow Logs that are not enabled or in a succeeded state\nresources\n| where type =~ \"microsoft.network/networkwatchers/flowlogs\" and isnotnull(properties)\n| extend targetResourceId = tostring(properties.targetResourceId)\n| extend status = iff(properties.enabled =~ 'true', \"Enabled\", \"Disabled\")\n| extend provisioningState = tostring(properties.provisioningState)\n| extend flowLogType = iff(properties.targetResourceId contains \"Microsoft.Network/virtualNetworks\", 'Virtual network', 'Network security group')\n| where provisioningState != \"Succeeded\" or status != \"Enabled\"\n| project recommendationId = \"22a769ed-0ecb-8b49-bafe-8f52e6373d9c\", name, id, tags, param1 = strcat(\"provisioningState:\", provisioningState), param2=strcat(\"Status:\", status), param3=strcat(\"targetResourceId:\",targetResourceId), param4=strcat(\"flowLogType:\",flowLogType)\n\n" }, + { + "description": "Improves monitoring for Azure and Hybrid connectivity\n", + "aprlGuid": "1e28bbc1-1eb7-486f-8d7f-93943f40219c", + "recommendationTypeId": null, + "recommendationControl": "Monitoring and Alerting", + "recommendationImpact": "High", + "recommendationResourceType": "Microsoft.Network/networkWatchers", + "recommendationMetadataState": "Active", + "longDescription": "Improves monitoring for Azure and Hybrid connectivity\n", + "potentialBenefits": "Improves monitoring for Azure and Hybrid connectivity", + "pgVerified": true, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": "arg", + "tags": null, + "learnMoreLink": [ + { + "name": "Connection monitor overview", + "url": "https://learn.microsoft.com/en-us/azure/network-watcher/connection-monitor-overview" + } + ], + "service": "Microsoft.Network/networkWatchers", + "text": "Configure Network Watcher Connection monitor", + "severity": "High", + "category": "Monitoring and Alerting", + "guid": "1e28bbc1-1eb7-486f-8d7f-93943f40219c", + "sourceFile": "azure-resources/Network/networkWatchers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024" + }, + { + "description": "Set up monitoring and alerts for Point-to-Site VPN gateways. Create alert rule for ensuring promptly response to critical events such as Gateway overutilization, connection count limits and User VPN route limits.", + "aprlGuid": "fd43ea32-2ccf-49a8-ada4-9a78794e3ff1", + "recommendationTypeId": null, + "recommendationControl": "Monitoring and Alerting", + "recommendationImpact": "High", + "recommendationResourceType": "Microsoft.Network/p2sVpnGateways", + "recommendationMetadataState": "Active", + "longDescription": "Set up monitoring and alerts for Point-to-Site VPN gateways. Create alert rule for ensuring promptly response to critical events such as Gateway overutilization, connection count limits and User VPN route limits.", + "potentialBenefits": "Detection and mitigation to avoid disruptions.", + "pgVerified": false, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": false, + "tags": null, + "learnMoreLink": [ + { + "name": "Virtual WAN Monitoring Best Practices", + "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#point-to-site-vpn-gateway" + } + ], + "service": "Microsoft.Network/p2sVpnGateways", + "text": "Monitor health for v-Hub's Point-to-Site VPN gateways", + "severity": "High", + "category": "Monitoring and Alerting", + "guid": "fd43ea32-2ccf-49a8-ada4-9a78794e3ff1", + "sourceFile": "azure-resources/Network/p2sVpnGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", + "graph": "// under-development\n" + }, { "description": "Private DNS zones and records are critical and their deletion can cause service outages. To protect against unauthorized or accidental changes, the Private DNS Zone Contributor role, a built-in role for managing these resources, should be assigned to specific users or groups.\n", "aprlGuid": "2820f6d6-a23c-7a40-aec5-506f3bd1aeb6", @@ -7602,7 +8221,9 @@ "severity": "Medium", "category": "Security", "guid": "2820f6d6-a23c-7a40-aec5-506f3bd1aeb6", - "source": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceFile": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7631,7 +8252,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "ab896e8c-49b9-2c44-adec-98339aff7821", - "source": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceFile": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7660,7 +8283,9 @@ "severity": "Medium", "category": "Governance", "guid": "1e02335c-1f90-fd4e-a5a5-d359c7b22d70", - "source": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceFile": "azure-resources/Network/privateDnsZones/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7689,7 +8314,9 @@ "severity": "Medium", "category": "High Availability", "guid": "b89c9acc-0aba-fb44-9ff2-3dbfcf97dce7", - "source": "azure-resources/Network/privateEndpoints/recommendations.yaml", + "sourceFile": "azure-resources/Network/privateEndpoints/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all Private Endpoints that are not in a Succeeded state\nresources\n| where type =~ \"microsoft.network/privateendpoints\"\n| where (properties.provisioningState =~ \"Succeeded\" and (properties.privateLinkServiceConnections[0].properties.provisioningState =~ \"Succeeded\" or properties.manualPrivateLinkServiceConnections[0].properties.provisioningState =~ \"Succeeded\")) == false\n| project recommendationId = \"b89c9acc-0aba-fb44-9ff2-3dbfcf97dce7\", name, id, tags, param1 = strcat(\"provisioningState: \", tostring(properties.provisioningState)), param2 = strcat(\"provisioningState: \", tostring(properties.privateLinkServiceConnections[0].properties.provisioningState)), param3 = strcat(\"manualProvisioningState: \", tostring(properties.manualPrivateLinkServiceConnections[0].properties.provisioningState))\n" }, { @@ -7722,7 +8349,9 @@ "severity": "High", "category": "High Availability", "guid": "c63b81fb-7afc-894c-a840-91bb8a8dcfaf", - "source": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceFile": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// List public IP addresses that are not Zone-Redundant\nResources\n| where type =~ \"Microsoft.Network/publicIPAddresses\" and sku.tier =~ \"Regional\"\n| where isempty(zones) or array_length(zones) <= 1\n| extend az = case(isempty(zones), \"Non-zonal\", array_length(zones) <= 1, strcat(\"Zonal (\", strcat_array(zones, \",\"), \")\"), zones)\n| project recommendationId = \"c63b81fb-7afc-894c-a840-91bb8a8dcfaf\", name, id, tags, param1 = strcat(\"sku: \", sku.name), param2 = strcat(\"availabilityZone: \", az)\n\n" }, { @@ -7755,7 +8384,9 @@ "severity": "Medium", "category": "High Availability", "guid": "1adba190-5c4c-e646-8527-dd1b2a6d8b15", - "source": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceFile": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// Lists VMs with PIPs\nresources\n| where type =~ 'Microsoft.Network/publicIPAddresses'\n| where tostring(properties.ipConfiguration.id) contains \"microsoft.network/networkinterfaces\"\n| project recommendationId=\"1adba190-5c4c-e646-8527-dd1b2a6d8b15\", name, id, tags, param1=strcat(\"Migrate from instance IP to NAT Gateway\")\n\n" }, { @@ -7788,7 +8419,9 @@ "severity": "Medium", "category": "High Availability", "guid": "5cea1501-6fe4-4ec4-ac8f-f72320eb18d3", - "source": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceFile": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// List Basic SKU public IP addresses\nResources\n| where type =~ \"Microsoft.Network/publicIPAddresses\"\n| where sku.name =~ \"Basic\"\n| project recommendationId = \"5cea1501-6fe4-4ec4-ac8f-f72320eb18d3\", name, id, tags, param1 = strcat(\"sku: \", sku.name)\n\n" }, { @@ -7817,7 +8450,9 @@ "severity": "Medium", "category": "Security", "guid": "c4254c66-b8a5-47aa-82f6-e7d7fb418f47", - "source": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceFile": "azure-resources/Network/publicIPAddresses/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph query\n// Public IP addresses should have DDoS protection enabled\nresources\n| where type =~ 'Microsoft.Network/publicIPAddresses'\n| where properties.ddosSettings.protectionMode !in~ (\"Enabled\", \"VirtualNetworkInherited\")\n| project recommendationId=\"c4254c66-b8a5-47aa-82f6-e7d7fb418f47\", name, id, tags, param1=strcat(\"Apply either DDoS Network protection or DDoS IP Protrection to the public IP address.\")\n" }, { @@ -7846,7 +8481,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "23b2dfc7-7e5d-9443-9f62-980ca621b561", - "source": "azure-resources/Network/routeTables/recommendations.yaml", + "sourceFile": "azure-resources/Network/routeTables/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Route Tables without alerts for modification configured.\nresources\n| where type =~ \"Microsoft.Network/routeTables\"\n| project name, id, tags, lowerCaseRouteTableId = tolower(id)\n| join kind = leftouter (\n resources\n | where type =~ \"Microsoft.Insights/activityLogAlerts\" and properties.enabled == true\n | mv-expand scope = properties.scopes\n | where scope has \"Microsoft.Network/routeTables\"\n | project alertName = name, conditionJson = dynamic_to_json(properties.condition.allOf), scope\n | where conditionJson has '\"Administrative\"' and (\n // Create or Update Route Table\n (conditionJson has '\"Microsoft.Network/routeTables/write\"') or\n // All Administrative operations\n (conditionJson !has '\"Microsoft.Network/routeTables/write\"' and conditionJson !has '\"Microsoft.Network/routeTables/delete\"' and conditionJson !has '\"Microsoft.Network/routeTables/join/action\"')\n )\n | project lowerCaseRouteTableIdOfScope = tolower(scope)\n )\n on $left.lowerCaseRouteTableId == $right.lowerCaseRouteTableIdOfScope\n| where isempty(lowerCaseRouteTableIdOfScope)\n| project recommendationId = \"23b2dfc7-7e5d-9443-9f62-980ca621b561\", name, id, tags, param1 = \"ModificationAlert: Not configured/Disabled\"\n\n" }, { @@ -7875,7 +8512,9 @@ "severity": "Low", "category": "Governance", "guid": "89d1166a-1a20-0f46-acc8-3194387bf127", - "source": "azure-resources/Network/routeTables/recommendations.yaml", + "sourceFile": "azure-resources/Network/routeTables/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -7912,7 +8551,9 @@ "severity": "High", "category": "High Availability", "guid": "f05a3e6d-49db-2740-88e2-2b13706c1f67", - "source": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceFile": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find traffic manager profiles that have an endpoint monitor status of not 'Online'\nresources\n| where type == \"microsoft.network/trafficmanagerprofiles\"\n| mv-expand properties.endpoints\n| where properties_endpoints.properties.endpointMonitorStatus != \"Online\"\n| project recommendationId = \"f05a3e6d-49db-2740-88e2-2b13706c1f67\", name, id, tags, param1 = strcat('Profile name: ',properties_endpoints.name), param2 = strcat('endpointMonitorStatus: ', properties_endpoints.properties.endpointMonitorStatus)\n\n" }, { @@ -7941,7 +8582,9 @@ "severity": "Medium", "category": "High Availability", "guid": "5b422a7f-8caa-3d48-becb-511599e5bba9", - "source": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceFile": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find traffic manager profiles that have less than 2 endpoints\nresources\n| where type == \"microsoft.network/trafficmanagerprofiles\"\n| where array_length(properties.endpoints) < 2\n| project recommendationId = \"5b422a7f-8caa-3d48-becb-511599e5bba9\", name, id, tags, param1 = strcat('EndpointCount: ', array_length(properties.endpoints))\n\n" }, { @@ -7970,7 +8613,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "1ad9d7b7-9692-1441-a8f4-93792efbe97a", - "source": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceFile": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -8003,9 +8648,41 @@ "severity": "High", "category": "Disaster Recovery", "guid": "c31f76a0-48cd-9f44-aa43-99ee904db9bc", - "source": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceFile": "azure-resources/Network/trafficManagerProfiles/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Traffic Manager resources that are not confirgured for all-World access\nResources\n| where type == 'microsoft.network/trafficmanagerprofiles'\n| where properties.trafficRoutingMethod =~ \"Geographic\"\n| extend endpoints = properties.endpoints\n| mv-expand endpoint = endpoints\n| where endpoint.properties.geoMapping !contains \"WORLD\"\n| extend endpointName = endpoint.name\n| project recommendationId=\"c31f76a0-48cd-9f44-aa43-99ee904db9bc\", name, id, tags, param1=strcat(\"endpointName:\",endpointName), param2=strcat(\"GeoMapping:\", tostring(endpoint.properties.geoMapping))\n" }, + { + "description": "Set up monitoring and alerts for v-Hubs. Create alert rule for ensuring promptly response to changes in BGP status and Data processed by v-Hubs.", + "aprlGuid": "30ec8a5e-46de-4323-87e9-a7c56b72813b", + "recommendationTypeId": null, + "recommendationControl": "Monitoring and Alerting", + "recommendationImpact": "Medium", + "recommendationResourceType": "Microsoft.Network/virtualHubs", + "recommendationMetadataState": "Active", + "longDescription": "Set up monitoring and alerts for v-Hubs. Create alert rule for ensuring promptly response to changes in BGP status and Data processed by v-Hubs.", + "potentialBenefits": "Detection and mitigation to avoid disruptions.", + "pgVerified": false, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": false, + "tags": null, + "learnMoreLink": [ + { + "name": "Virtual WAN Monitoring Best Practices", + "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#virtual-hub" + } + ], + "service": "Microsoft.Network/virtualHubs", + "text": "Monitor health for v-Hubs", + "severity": "Medium", + "category": "Monitoring and Alerting", + "guid": "30ec8a5e-46de-4323-87e9-a7c56b72813b", + "sourceFile": "azure-resources/Network/virtualHubs/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024" + }, { "description": "To increase reliability, it's advised that each ExpressRoute gateway connects to at least two circuits, with each circuit originating from a different peering location than the other, ensuring diverse connectivity paths for enhanced resilience.\n", "aprlGuid": "d37db635-157f-584d-9bce-4f6fc8c65ce5", @@ -8032,7 +8709,9 @@ "severity": "High", "category": "High Availability", "guid": "d37db635-157f-584d-9bce-4f6fc8c65ce5", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of ExpressRoute Gateways that are not connected to two or more ExpressRoute Circuits. Baremetal circuits are excluded from consideration\n//This query assumes that the running entity has visibilty to the gateway, connection, and circuit scopes.\n//Start with a full list of gateways\n(resources\n| where type == \"microsoft.network/virtualnetworkgateways\"\n| where properties.gatewayType == \"ExpressRoute\"\n| extend exrGatewayId = tolower(tostring(id))\n| join kind=inner(\nresources\n| where type == \"microsoft.network/virtualnetworkgateways\"\n| where properties.gatewayType == \"ExpressRoute\"\n| extend exrGatewayId = tolower(tostring(id))\n| join kind=leftouter(\n//connections joined with circuit peer info\nresources\n| where type == \"microsoft.network/connections\"\n| extend connectionType = properties.connectionType\n| extend exrGatewayId = tolower(tostring(properties.virtualNetworkGateway1.id))\n| extend peerId = tolower(tostring(properties.peer.id))\n| extend connectionId = tolower(tostring(id))\n| where connectionType == \"ExpressRoute\"\n| join kind=leftouter(\n resources\n | where type == \"microsoft.network/expressroutecircuits\"\n //should this be location instead of peeringLocation\n | extend circuitId = tolower(tostring(id))\n | extend peeringLocation = tostring(properties.serviceProviderProperties.peeringLocation)\n | extend peerId = tolower(id)\n) on peerId ) on exrGatewayId\n//remove bare metal services connections/circuits\n| where not(isnotnull(connectionId) and isnull(sku1))\n//group by gateway ID's and peering locations\n| summarize by exrGatewayId, peeringLocation\n//summarize to connections with fewer than two unique connections\n| summarize connCount = count() by exrGatewayId\n| where connCount < 2) on exrGatewayId\n| project recommendationId = \"d37db635-157f-584d-9bce-4f6fc8c65ce5\", name, id, tags, param1 = \"twoOrMoreCircuitsConnectedFromDifferentPeeringLocations: false\")\n| union\n(\nresources\n| where type == \"microsoft.network/virtualnetworkgateways\"\n| where properties.gatewayType == \"ExpressRoute\"\n| extend exrGatewayId = tolower(tostring(id))\n| join kind=leftouter(\n//connections joined with circuit peer info\nresources\n| where type == \"microsoft.network/connections\"\n| extend connectionType = properties.connectionType\n| extend exrGatewayId = tolower(tostring(properties.virtualNetworkGateway1.id))\n| extend peerId = tolower(tostring(properties.peer.id))\n| extend connectionId = tolower(tostring(id))\n| where connectionType == \"ExpressRoute\") on exrGatewayId\n| where isnull(connectionType)\n| project recommendationId = \"d37db635-157f-584d-9bce-4f6fc8c65ce5\", name, id, tags, param1 = \"twoOrMoreCircuitsConnectedFromDifferentPeeringLocations: false\", param2 = \"noConnectionsOnGateway: true\"\n)\n\n" }, { @@ -8069,7 +8748,9 @@ "severity": "High", "category": "High Availability", "guid": "bbe668b7-eb5c-c746-8b82-70afdedf0cae", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// For all VNGs of type ExpressRoute, show any that do not have AZ in the SKU tier\nresources\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\n| where properties.gatewayType == \"ExpressRoute\"\n| where properties.sku.tier !contains 'AZ'\n| project recommendationId = \"bbe668b7-eb5c-c746-8b82-70afdedf0cae\", name, id, tags, param1= strcat(\"sku-tier: \" , properties.sku.tier), param2=location\n| order by id asc\n\n" }, { @@ -8098,7 +8779,9 @@ "severity": "Medium", "category": "High Availability", "guid": "c0f23a92-d322-4d4d-97e9-a238b5e3bbb8", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -8131,7 +8814,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "1c34faa8-8b99-974c-adbf-71922eae943c", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n\n" }, { @@ -8160,7 +8845,9 @@ "severity": "Medium", "category": "High Availability", "guid": "194c14ac-0d7a-5a48-ae32-75fa450ee564", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -8189,7 +8876,9 @@ "severity": "High", "category": "High Availability", "guid": "3e115044-a3aa-433e-be01-ce17d67e50da", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Virtual Network Gateways without Maintenance Configurations\n\nresources\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\n| extend resourceId = tolower(id)\n| join kind=leftouter (\n maintenanceresources\n | where type =~ \"Microsoft.Maintenance/configurationAssignments\"\n | project JsonData = parse_json(properties)\n | extend maintenanceConfigurationId = tolower(tostring(JsonData.maintenanceConfigurationId))\n | join kind=inner (\n resources\n | where type =~ \"Microsoft.Maintenance/maintenanceConfigurations\"\n | project maintenanceConfigurationId=tolower(id)\n ) on maintenanceConfigurationId\n | project maintenanceConfigurationId, resourceId=tolower(tostring(JsonData.resourceId))\n) on resourceId\n| where isempty(maintenanceConfigurationId)\n| project recommendationId = \"3e115044-a3aa-433e-be01-ce17d67e50da\", name, id, tags, param1= strcat(\"sku-tier: \" , properties.sku.tier), param2=location\n\n" }, { @@ -8226,7 +8915,9 @@ "severity": "High", "category": "High Availability", "guid": "5b1933a6-90e4-f642-a01f-e58594e5aab2", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// For all VNGs of type Vpn, show any that do not have AZ in the SKU tier\nresources\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\n| where properties.gatewayType == \"Vpn\"\n| where properties.sku.tier !contains 'AZ'\n| project recommendationId = \"5b1933a6-90e4-f642-a01f-e58594e5aab2\", name, id, tags, param1= strcat(\"sku-tier: \" , properties.sku.tier), param2=location\n| order by id asc\n\n" }, { @@ -8259,7 +8950,9 @@ "severity": "Medium", "category": "High Availability", "guid": "281a2713-c0e0-3c48-b596-19f590c46671", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Identifies non-active-active VPN type virtual network gateways\nresources\n| where type =~ 'Microsoft.Network/virtualNetworkGateways'\n| where properties.gatewayType =~ \"vpn\"\n| extend gatewayType = properties.gatewayType, vpnType = properties.vpnType, connections = properties.connections, activeactive=properties.activeActive\n| where activeactive == false\n| project recommendationId = \"281a2713-c0e0-3c48-b596-19f590c46671\", name, id, tags\n\n\n" }, { @@ -8288,7 +8981,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "af11fc4c-c06c-4f4c-b98d-6eee6d5c4c70", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n\n" }, { @@ -8317,7 +9012,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "9eab120e-f6d3-ee49-ba0d-766562ce7df1", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -8350,7 +9047,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "9186dae0-7ddc-8f4b-bea5-55538cea4893", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n\n" }, { @@ -8379,7 +9078,9 @@ "severity": "High", "category": "High Availability", "guid": "4bae5a28-5cf4-40d9-bcf1-623d28f6d917", - "source": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworkGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of zone-redundant Azure VPN gateways associated with non-zone-redundant Public IPs\nresources\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\n| where properties.gatewayType == \"Vpn\"\n| where properties.sku.tier contains 'AZ'\n| mv-expand ipconfig = properties.ipConfigurations\n| extend pipId = tostring(ipconfig.properties.publicIPAddress.id)\n| join kind=inner (\n resources\n | where type == \"microsoft.network/publicipaddresses\"\n | where isnull(zones) or array_length(zones) < 3 )\n on $left.pipId == $right.id\n| project recommendationId = \"4bae5a28-5cf4-40d9-bcf1-623d28f6d917\", name, id, tags, param1 = strcat(\"PublicIpAddressName: \", name1), param2 = strcat (\"PublicIpAddressId: \",id1), param3 = strcat (\"PublicIpAddressTags: \",tags1)\n\n" }, { @@ -8420,7 +9121,9 @@ "severity": "Low", "category": "Security", "guid": "f0bf9ae6-25a5-974d-87d5-025abec73539", - "source": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Subnets without NSG associated\nresources\n| where type =~ 'Microsoft.Network/virtualnetworks'\n| mv-expand subnets = properties.subnets\n| extend sn = string_size(subnets.properties.networkSecurityGroup)\n| where sn == 0 and subnets.name !in (\"GatewaySubnet\", \"AzureFirewallSubnet\", \"AzureFirewallManagementSubnet\", \"RouteServerSubnet\")\n| project recommendationId = \"f0bf9ae6-25a5-974d-87d5-025abec73539\", name, id, tags, param1 = strcat(\"SubnetName: \", subnets.name), param2 = \"NSG: False\"\n\n" }, { @@ -8449,7 +9152,9 @@ "severity": "High", "category": "Security", "guid": "69ea1185-19b7-de40-9da1-9e8493547a5c", - "source": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find virtual networks without DDoS Protection\nresources\n| where type =~ 'Microsoft.Network/virtualNetworks'\n| where isnull(properties.enableDdosProtection) or properties.enableDdosProtection contains \"false\"\n| project recommendationId = \"69ea1185-19b7-de40-9da1-9e8493547a5c\", name, id, tags, param1 = strcat(\"EnableDdosProtection: \", properties.enableDdosProtection)\n\n" }, { @@ -8486,18 +9191,51 @@ "severity": "Medium", "category": "Security", "guid": "24ae3773-cc2c-3649-88de-c9788e25b463", - "source": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceFile": "azure-resources/Network/virtualNetworks/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find Subnets with Service Endpoint enabled for services that offer Private Link\nresources\n| where type =~ 'Microsoft.Network/virtualnetworks'\n| mv-expand subnets = properties.subnets\n| extend se = array_length(subnets.properties.serviceEndpoints)\n| where se >= 1\n| project name, id, tags, subnets, serviceEndpoints=todynamic(subnets.properties.serviceEndpoints)\n| mv-expand serviceEndpoints\n| project name, id, tags, subnetName=subnets.name, serviceName=tostring(serviceEndpoints.service)\n| where serviceName in (parse_json('[\"Microsoft.CognitiveServices\",\"Microsoft.AzureCosmosDB\",\"Microsoft.DBforMariaDB\",\"Microsoft.DBforMySQL\",\"Microsoft.DBforPostgreSQL\",\"Microsoft.EventHub\",\"Microsoft.KeyVault\",\"Microsoft.ServiceBus\",\"Microsoft.Sql\", \"Microsoft.Storage\",\"Microsoft.StorageSync\",\"Microsoft.Synapse\",\"Microsoft.Web\"]'))\n| project recommendationId = \"24ae3773-cc2c-3649-88de-c9788e25b463\", name, id, tags, param1 = strcat(\"subnet=\", subnetName), param2=strcat(\"serviceName=\",serviceName), param3=\"ServiceEndpoints=true\"\n\n" }, { - "description": "ExpressRoute Traffic Collector samples network flows over ExpressRoute Direct circuits, sending flow logs to a Log Analytics workspace for analysis or export to visualization tools/SIEM.\n", + "description": "Set up monitoring and alerts for v-Hub's VPN Gateway. Create alert rule for ensuring promptly response to critical events such as packet drop counts, BGP status, Gateway overutilization.", + "aprlGuid": "f0d4f766-ac19-48c4-b228-4601cc038baa", + "recommendationTypeId": null, + "recommendationControl": "Monitoring and Alerting", + "recommendationImpact": "High", + "recommendationResourceType": "Microsoft.Network/vpnGateways", + "recommendationMetadataState": "Active", + "longDescription": "Set up monitoring and alerts for v-Hub's VPN Gateway. Create alert rule for ensuring promptly response to critical events such as packet drop counts, BGP status, Gateway overutilization.", + "potentialBenefits": "Detection and mitigation to avoid disruptions.", + "pgVerified": false, + "publishedToLearn": false, + "publishedToAdvisor": false, + "automationAvailable": false, + "tags": null, + "learnMoreLink": [ + { + "name": "Virtual WAN Monitoring Best Practices", + "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#virtual-wan-gateways" + } + ], + "service": "Microsoft.Network/vpnGateways", + "text": "Monitor gateway for Site-to-site v-Hub's VPN gateway", + "severity": "High", + "category": "Monitoring and Alerting", + "guid": "f0d4f766-ac19-48c4-b228-4601cc038baa", + "sourceFile": "azure-resources/Network/vpnGateways/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", + "graph": "// under-development\n" + }, + { + "description": "ExpressRoute Traffic Collector samples network flows over ExpressRoute Direct or Service-Provider based circuits, sending flow logs to a Log Analytics workspace for analysis or export to visualization tools/SIEM.\n", "aprlGuid": "1ceea4b5-1d8b-4be0-9bbe-9594557be51a", "recommendationTypeId": null, "recommendationControl": "Monitoring and Alerting", "recommendationImpact": "Medium", "recommendationResourceType": "Microsoft.NetworkFunction/azureTrafficCollectors", "recommendationMetadataState": "Active", - "longDescription": "ExpressRoute Traffic Collector samples network flows over ExpressRoute Direct circuits, sending flow logs to a Log Analytics workspace for analysis or export to visualization tools/SIEM.\n", + "longDescription": "ExpressRoute Traffic Collector samples network flows over ExpressRoute Direct or Service-Provider based circuits, sending flow logs to a Log Analytics workspace for analysis or export to visualization tools/SIEM.\n", "potentialBenefits": "Enhanced network flow analysis and DR readiness", "pgVerified": true, "publishedToLearn": false, @@ -8511,11 +9249,13 @@ } ], "service": "Microsoft.NetworkFunction/azureTrafficCollectors", - "text": "Ensure ExpressRoute Traffic Collector is enabled and configured for ExpressRoute Direct circuits", + "text": "Ensure ExpressRoute Traffic Collector is enabled and configured for Direct or Provider circuits", "severity": "Medium", "category": "Monitoring and Alerting", "guid": "1ceea4b5-1d8b-4be0-9bbe-9594557be51a", - "source": "azure-resources/NetworkFunction/azureTrafficCollectors/recommendations.yaml", + "sourceFile": "azure-resources/NetworkFunction/azureTrafficCollectors/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -8548,7 +9288,9 @@ "severity": "Medium", "category": "Governance", "guid": "b36fd2ac-dd83-664a-ab48-ff7b8d3b189d", - "source": "azure-resources/OperationalInsights/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/OperationalInsights/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -8581,7 +9323,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "4b77191c-cc3c-8c4e-844b-0f56d0927890", - "source": "azure-resources/OperationalInsights/workspaces/recommendations.yaml", + "sourceFile": "azure-resources/OperationalInsights/workspaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -8610,7 +9354,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "e93bb813-b356-48f3-9bdf-a06a0a6ba039", - "source": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceFile": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -8639,7 +9385,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "17e877f7-3a89-4205-8a24-0670de54ddcd", - "source": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceFile": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all VMs where replication has been enabled but Test Failover was never performed\nrecoveryservicesresources\n| where type == \"microsoft.recoveryservices/vaults/replicationfabrics/replicationprotectioncontainers/replicationprotecteditems\"\n| where properties.providerSpecificDetails.dataSourceInfo.datasourceType == 'AzureVm' and isnull(properties.lastSuccessfulTestFailoverTime)\n| project recommendationId=\"17e877f7-3a89-4205-8a24-0670de54ddcd\" , name = properties.providerSpecificDetails.recoveryAzureVMName, id=properties.providerSpecificDetails.dataSourceInfo.resourceId\n\n" }, { @@ -8672,7 +9420,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "2912472d-0198-4bdc-aa90-37f145790edc", - "source": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceFile": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This Resource Graph query will return all Recovery services vault with Classic alerts enabled.\nresources\n| where type in~ ('microsoft.recoveryservices/vaults')\n| extend monitoringSettings = parse_json(properties).monitoringSettings\n| extend isUsingClassicAlerts = case(isnull(monitoringSettings),'Enabled',monitoringSettings.classicAlertSettings.alertsForCriticalOperations)\n| extend isUsingJobsAlerts = case(isnull(monitoringSettings), 'Enabled', monitoringSettings.azureMonitorAlertSettings.alertsForAllJobFailures)\n| where isUsingClassicAlerts == 'Enabled'\n| project recommendationId = \"2912472d-0198-4bdc-aa90-37f145790edc\", name, id, tags, param1=strcat(\"isUsingClassicAlerts: \", isUsingClassicAlerts), param2=strcat(\"isUsingJobsAlerts: \", isUsingJobsAlerts)\n\n" }, { @@ -8713,7 +9463,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "1549b91f-2ea0-4d4f-ba2a-4596becbe3de", - "source": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceFile": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Displays all recovery services vaults that do not have cross region restore enabled\nresources\n| where type =~ \"Microsoft.RecoveryServices/vaults\" and\n properties.redundancySettings.standardTierStorageRedundancy =~ \"GeoRedundant\" and\n properties.redundancySettings.crossRegionRestore !~ \"Enabled\"\n| extend\n param1 = strcat(\"CrossRegionRestore: \", properties.redundancySettings.crossRegionRestore),\n param2 = strcat(\"StorageReplicationType: \", properties.redundancySettings.standardTierStorageRedundancy)\n| project recommendationId = \"1549b91f-2ea0-4d4f-ba2a-4596becbe3de\", name, id, tags, param1, param2\n" }, { @@ -8742,7 +9494,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "9e39919b-78af-4a0b-b70f-c548dae97c25", - "source": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceFile": "azure-resources/RecoveryServices/vaults/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Azure Recovery Services vaults that do not have soft delete enabled\nresources\n| where type == \"microsoft.recoveryservices/vaults\"\n| mv-expand issoftDelete=properties.securitySettings.softDeleteSettings.softDeleteState\n| where issoftDelete == 'Disabled'\n| project recommendationId = \"9e39919b-78af-4a0b-b70f-c548dae97c25\", name, id, tags, param1=strcat(\"Soft Delete: \",issoftDelete)\n" }, { @@ -8771,7 +9525,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "98bd7098-49d6-491b-86f1-b143d6b1a0ff", - "source": "azure-resources/Resources/resourceGroups/recommendations.yaml", + "sourceFile": "azure-resources/Resources/resourceGroups/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure Resource Groups that have resources deployed in a region different than the Resource Group region\nresources\n| project id, name, tags, resourceGroup, location\n| where location != \"global\" // exclude global resources\n| where resourceGroup != \"networkwatcherrg\" // exclude networkwatcherrg\n| where split(id, \"/\", 3)[0] =~ \"resourceGroups\" // resource is in a resource group\n| extend resourceGroupId = strcat_array(array_slice(split(id, \"/\"),0,4), \"/\") // create resource group resource id\n| join (resourcecontainers | project containerid=id, containerlocation=location ) on $left.resourceGroupId == $right.['containerid'] // join to resourcecontainers table\n| where location != containerlocation\n| project recommendationId=\"98bd7098-49d6-491b-86f1-b143d6b1a0ff\", name, id, tags\n| order by id asc\n\n" }, { @@ -8808,7 +9564,9 @@ "severity": "High", "category": "High Availability", "guid": "20057905-262c-49fe-a9be-49f423afb359", - "source": "azure-resources/ServiceBus/namespaces/recommendations.yaml", + "sourceFile": "azure-resources/ServiceBus/namespaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Returns Service Bus namespaces that do not have any availability zones enabled\nresources\n| where type =~ 'Microsoft.ServiceBus/namespaces'\n| where properties.zoneRedundant == 'false'\n| project recommendationId = \"20057905-262c-49fe-a9be-49f423afb359\", name, id, tags, param1=strcat(\"zoneRedundant: \", properties.zoneRedundant), param2=strcat(\"SKU: \", sku.name), param3=iff(tolower(sku.name) == 'premium', 'Move Service Bus namespace to a region that supports Availability Zones', 'Migrate to Premium SKU in a region that supports Availability Zones')\n\n" }, { @@ -8837,7 +9595,9 @@ "severity": "High", "category": "High Availability", "guid": "d810e3a8-600f-4be1-895b-1a93e61d37fd", - "source": "azure-resources/ServiceBus/namespaces/recommendations.yaml", + "sourceFile": "azure-resources/ServiceBus/namespaces/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -8866,7 +9626,9 @@ "severity": "High", "category": "High Availability", "guid": "6a8b3db9-5773-413a-a127-4f7032f34bbd", - "source": "azure-resources/SignalRService/signalR/recommendations.yaml", + "sourceFile": "azure-resources/SignalRService/signalR/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find SignalR instances that are not configured with the Premium tier\nresources\n| where type == \"microsoft.signalrservice/signalr\"\n| where sku.tier != \"Premium\"\n| project recommendationId = \"6a8b3db9-5773-413a-a127-4f7032f34bbd\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\n| order by id asc\n\n" }, { @@ -8895,7 +9657,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "74c2491d-048b-0041-a140-935960220e20", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of SQL databases that are not part of Geo Replication.\nresources\n| where type == \"microsoft.sql/servers/databases\"\n| summarize secondaryTypeCount = countif(isnotempty(properties.secondaryType)) by name\n| where secondaryTypeCount == 0\n| join kind=inner (\n Resources\n | where type == \"microsoft.sql/servers/databases\"\n) on name\n| extend param1 = \"Not part of Geo Replication\"\n| project recommendationId = \"74c2491d-048b-0041-a140-935960220e20\", name, id, tags, param1\n" }, { @@ -8928,7 +9692,9 @@ "severity": "High", "category": "Disaster Recovery", "guid": "943c168a-2ec2-a94c-8015-85732a1b4859", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of SQL databases that are not configured to use a failover-group.\nresources\n| where type =~'microsoft.sql/servers/databases'\n| where isnull(properties['failoverGroupId'])\n| project recommendationId = \"943c168a-2ec2-a94c-8015-85732a1b4859\", name, id, tags, param1= strcat(\"databaseId=\", properties['databaseId'])\n" }, { @@ -8957,7 +9723,9 @@ "severity": "Medium", "category": "High Availability", "guid": "c0085c32-84c0-c247-bfa9-e70977cbf108", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Finds non-zone redundant SQL databases and lists them\nResources\n| where type =~ 'microsoft.sql/servers/databases'\n| where tolower(tostring(properties.zoneRedundant))=~'false'\n|project recommendationId = \"c0085c32-84c0-c247-bfa9-e70977cbf108\", name, id, tags\n\n\n" }, { @@ -8986,7 +9754,9 @@ "severity": "High", "category": "High Availability", "guid": "cbb17a29-64fb-c943-95d0-8df814a37c40", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9023,7 +9793,9 @@ "severity": "High", "category": "Monitoring and Alerting", "guid": "7e7daec9-6a81-3546-a4cc-9aef72fec1f7", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of SQL databases that are not configured for monitoring.\nresources\n| where type == \"microsoft.insights/metricalerts\"\n| mv-expand properties.scopes\n| mv-expand properties.criteria.allOf\n| project databaseid = properties_scopes, monitoredMetric = properties_criteria_allOf.metricName\n| where databaseid contains 'databases'\n| summarize monitoredMetrics=make_list(monitoredMetric) by databaseid=tolower(tostring(databaseid))\n| join kind=fullouter (\n resources\n | where type =~ 'microsoft.sql/servers/databases'\n | project databaseid = tolower(id), name, tags\n) on databaseid\n| where isnull(monitoredMetrics)\n| project recommendationId = \"7e7daec9-6a81-3546-a4cc-9aef72fec1f7\", name, id=databaseid1, tags, param1=strcat(\"MonitoringMetrics=false\" )\n\n" }, { @@ -9056,7 +9828,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "d6ef87aa-574e-584e-a955-3e6bb8b5425b", - "source": "azure-resources/Sql/servers/recommendations.yaml", + "sourceFile": "azure-resources/Sql/servers/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9089,7 +9863,9 @@ "severity": "High", "category": "High Availability", "guid": "e6c7e1cc-2f47-264d-aa50-1da421314472", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This query will return all storage accounts that are not using Zone or Region replication\nResources\n| where type =~ \"Microsoft.Storage/storageAccounts\"\n| where sku.name in~ (\"Standard_LRS\", \"Premium_LRS\")\n| project recommendationId = \"e6c7e1cc-2f47-264d-aa50-1da421314472\", name, id, tags, param1 = strcat(\"sku: \", sku.name)\n\n" }, { @@ -9122,7 +9898,9 @@ "severity": "High", "category": "Service Upgrade and Retirement", "guid": "63ad027e-611c-294b-acc5-8e3234db9a40", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Azure classic Storage Account\nresources\n| where type =~ 'microsoft.classicstorage/storageaccounts'\n| project recommendationId = '63ad027e-611c-294b-acc5-8e3234db9a40', name, id, tags, param1=type\n\n" }, { @@ -9167,7 +9945,9 @@ "severity": "Medium", "category": "Scalability", "guid": "5587ef77-7a05-a74d-9c6e-449547a12f27", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9196,7 +9976,9 @@ "severity": "Medium", "category": "Disaster Recovery", "guid": "03263c57-c869-3841-9e0a-3dbb9ef3e28d", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9225,7 +10007,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "8ebda7c0-e0e1-ed45-af59-2d7ea9a1c05d", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9258,7 +10042,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "1b965cb9-7629-214e-b682-6bf6e450a100", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9291,7 +10077,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "96cb8331-6b06-8242-8ce8-4e2f665dc679", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9324,7 +10112,9 @@ "severity": "Low", "category": "Scalability", "guid": "2ad78dec-5a4d-4a30-8fd1-8584335ad781", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Find all Azure Storage Accounts, that upgradeable to General purpose v2.\nResources\n| where type =~ \"Microsoft.Storage/storageAccounts\" and kind in~ (\"Storage\", \"BlobStorage\")\n| extend\n param1 = strcat(\"AccountKind: \", case(kind =~ \"Storage\", \"Storage (general purpose v1)\", kind =~ \"BlobStorage\", \"BlobStorage\", kind)),\n param2 = strcat(\"Performance: \", sku.tier),\n param3 = strcat(\"Replication: \", sku.name)\n| project recommendationId = \"2ad78dec-5a4d-4a30-8fd1-8584335ad781\", name, id, tags, param1, param2, param3\n\n" }, { @@ -9357,7 +10147,9 @@ "severity": "Medium", "category": "Security", "guid": "dc55be60-6f8c-461e-a9d5-a3c7686ed94e", - "source": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceFile": "azure-resources/Storage/storageAccounts/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// This resource graph query will return all storage accounts that does not have a Private Endpoint Connection or where a private endpoint exists but public access is enabled\nresources\n| where type =~ \"Microsoft.Storage/StorageAccounts\"\n| where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != (\"Succeeded\") or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled')\n| extend param1 = strcat('Private Endpoint: ', iif(isnotnull(properties.privateEndpointConnections),split(properties.privateEndpointConnections[0].properties.privateEndpoint.id,'/')[8],'No Private Endpoint'))\n| extend param2 = strcat('Access: ', iif(properties.publicNetworkAccess == 'Disabled', 'Public Access Disabled', iif(isnotnull(properties.networkAcls), 'NetworkACLs in place','Public Access Enabled')))\n| project recommendationId = \"dc55be60-6f8c-461e-a9d5-a3c7686ed94e\", name, id, tags, param1, param2\n" }, { @@ -9386,7 +10178,9 @@ "severity": "High", "category": "Governance", "guid": "c041d596-6c97-4c5f-b4b3-9cd37628f2e2", - "source": "azure-resources/Subscription/subscriptions/recommendations.yaml", + "sourceFile": "azure-resources/Subscription/subscriptions/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Count VM instances with a tag that contains \"Citrix VDA\" and create output if that count is >2000 for each subscription.\n// The Citrix published limit is 2500. This query runs an 80% check.\n\nresources\n| where type == 'microsoft.compute/virtualmachines'\n| where tags contains 'Citrix VDA'\n| summarize VMs=count() by subscriptionId\n| where VMs > 2000\n| join (resourcecontainers| where type =='microsoft.resources/subscriptions' | project subname=name, subscriptionId) on subscriptionId\n| project recommendationId='c041d596-6c97-4c5f-b4b3-9cd37628f2e2', name= subname, id = subscriptionId, param1='Too many instances.', param2= VMs\n\n" }, { @@ -9419,7 +10213,9 @@ "severity": "Medium", "category": "Governance", "guid": "5ada5ffa-7149-4e49-9fbf-e67be7c2594c", - "source": "azure-resources/Subscription/subscriptions/recommendations.yaml", + "sourceFile": "azure-resources/Subscription/subscriptions/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure Subscriptions that are placed under the Tenant Root Management Group\nresourcecontainers\n| where type == 'microsoft.resources/subscriptions'\n| extend mgParentSize = array_length(properties.managementGroupAncestorsChain)\n| where mgParentSize == 1\n| project recommendationId=\"5ada5ffa-7149-4e49-9fbf-e67be7c2594c\", name, id, tags\n\n" }, { @@ -9448,7 +10244,9 @@ "severity": "Low", "category": "High Availability", "guid": "19b6df57-f6b5-3e4f-843a-273daa087cb0", - "source": "azure-resources/VirtualMachineImages/imageTemplates/recommendations.yaml", + "sourceFile": "azure-resources/VirtualMachineImages/imageTemplates/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9481,7 +10279,9 @@ "severity": "Low", "category": "Disaster Recovery", "guid": "21fb841b-ba70-1f4e-a460-1f72fb41aa51", - "source": "azure-resources/VirtualMachineImages/imageTemplates/recommendations.yaml", + "sourceFile": "azure-resources/VirtualMachineImages/imageTemplates/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// List all Image Templates that are not replicated to another region\nresources\n| where type =~ \"microsoft.virtualmachineimages/imagetemplates\"\n| mv-expand distribution=properties.distribute\n| where array_length(parse_json(distribution).replicationRegions) == 1\n| project recommendationId = \"21fb841b-ba70-1f4e-a460-1f72fb41aa51\", name, id, param1=strcat(\"replicationRegions:\",parse_json(distribution).replicationRegions)\n\n" }, { @@ -9514,7 +10314,9 @@ "severity": "High", "category": "High Availability", "guid": "88cb90c2-3b99-814b-9820-821a63f600dd", - "source": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceFile": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// The query filters the qualified App Service Plans that do not have Zone Redundancy enabled.\n// Its important to check regions that support availability zones for Azure App Services running on multi-tenant and App Service Environments https://learn.microsoft.com/en-us/azure/reliability/reliability-app-service?tabs=graph%2Ccli#:~:text=The%20following%20regions%20support%20Azure%20App%20Services%20running%20on%20multi%2Dtenant%20environments%3A\n\nresources\n| where type =~ 'microsoft.web/serverfarms'\n| extend zoneRedundant = tobool(properties.zoneRedundant)\n| extend sku_tier = tostring(sku.tier)\n| where (tolower(sku_tier) contains \"isolated\" or tolower(sku_tier) contains \"premium\") and zoneRedundant == false\n| project recommendationId=\"88cb90c2-3b99-814b-9820-821a63f600dd\", name, id, tags, param1=sku_tier, param2=\"Not Zone Redundant\"\n\n" }, { @@ -9543,7 +10345,9 @@ "severity": "High", "category": "High Availability", "guid": "b2113023-a553-2e41-9789-597e2fb54c31", - "source": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceFile": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure App Service Plans that are not in the \"Standard\", \"Premium\", or \"IsolatedV2\" SKU tiers.\n\nresources\n| where type =~ 'microsoft.web/serverfarms'\n| extend sku_tier = tostring(sku.tier)\n| where tolower(sku_tier) !contains \"standard\" and\n tolower(sku_tier) !contains \"premium\" and\n tolower(sku_tier) !contains \"isolatedv2\"\n| project recommendationId=\"b2113023-a553-2e41-9789-597e2fb54c31\", name, id, tags, param1= strcat(\"SKU=\",sku_tier)\n\n" }, { @@ -9572,7 +10376,9 @@ "severity": "Medium", "category": "Scalability", "guid": "07243659-4643-d44c-a1c6-07ac21635072", - "source": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceFile": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure App Service Plans and the number of changes that was made to the pricing tier, if the count is higher that 3 it means you need to avoid scaling up and down that often\n\nresourcechanges\n| extend changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId),\nchangeType = tostring(properties.changeType), correlationId = properties.changeAttributes.correlationId,\nchangedProperties = properties.changes, changeCount = properties.changeAttributes.changesCount\n| where changeTime > ago(14d)\n| join kind=inner (resources | project resources_Name = name, resources_Type = type, resources_Subscription= subscriptionId, resources_ResourceGroup= resourceGroup, id) on $left.targetResourceId == $right.id\n| where resources_Type contains \"microsoft.web/serverfarms\"\n| where changedProperties['sku.name'].propertyChangeType == 'Update' or changedProperties['sku.tier'].propertyChangeType == 'Update'\n| summarize count() by targetResourceId, resources_Name ,tostring(changedProperties['sku.name'].previousValue), tostring(changedProperties['sku.tier'].newValue)\n| project recommendationId=\"07243659-4643-d44c-a1c6-07ac21635072\", name=resources_Name, id=targetResourceId, tags=\"\", param1=['changedProperties_sku.name_previousValue'], param2=['changedProperties_sku.tier_newValue'], param3=count_\n\n" }, { @@ -9601,7 +10407,9 @@ "severity": "High", "category": "Governance", "guid": "dbe3fd66-fb2a-9d46-b162-1791e21da236", - "source": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceFile": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9634,7 +10442,9 @@ "severity": "Medium", "category": "Scalability", "guid": "6320abf6-f917-1843-b2ae-4779c35985ae", - "source": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceFile": "azure-resources/Web/serverFarms/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// under-development\n\n" }, { @@ -9663,7 +10473,9 @@ "severity": "Low", "category": "Monitoring and Alerting", "guid": "493f6079-3bb6-4a56-96ba-ab3248474cb1", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n\n" }, { @@ -9696,7 +10508,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "a7e8bb3d-8ceb-442d-b26f-007cd63f9ffc", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n\n" }, { @@ -9725,7 +10539,9 @@ "severity": "Low", "category": "Scalability", "guid": "78a5c033-ff51-4332-8a71-83464c34494b", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9754,7 +10570,9 @@ "severity": "Medium", "category": "Scalability", "guid": "3f9ddb59-0bb3-4acb-9c9b-99aa1776f0ab", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n\n" }, { @@ -9783,7 +10601,9 @@ "severity": "Low", "category": "Governance", "guid": "a1d91661-32d4-430b-b3b6-5adeb0975df7", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Display App Service with the count of deployment slots for Apps under eligible App service plans and it shows if deployment slot is enabled or not\n\nresources\n| where type =~ 'microsoft.web/sites' or type =~ 'microsoft.web/sites/slots'\n| extend isSlot = iff(type =~ 'microsoft.web/sites/slots', 1, 0)\n| extend AspName = iff(isSlot == 1, split(name, '/')[0], name)\n| extend Sku = tostring(properties.sku)\n| where tolower(Sku) contains \"standard\" or tolower(Sku) contains \"premium\" or tolower(Sku) contains \"isolatedv2\"\n| project id, name, AspName, isSlot, Sku\n| summarize Slots = countif(isSlot == 1) by id, name, AspName, Sku\n| extend DeploymentSlotEnabled = iff(Slots > 1, true, false)\n| where DeploymentSlotEnabled = false\n| project recommendationId=\"a1d91661-32d4-430b-b3b6-5adeb0975df7\", name, id, tags=\"\", param1=Sku, param2=Slots, param3=\"DeploymentSlotEnabled=false\"\n\n" }, { @@ -9812,7 +10632,9 @@ "severity": "Medium", "category": "Other Best Practices", "guid": "0b80b67c-afbe-4988-ad58-a85a146b681e", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure App Service resources that don't have App Settings configured\n\nappserviceresources\n| where type == \"microsoft.web/sites/config\"\n| extend AppSettings = iif(isempty(properties.AppSettings), true, false)\n| where AppSettings == false\n| project recommendationId=\"0b80b67c-afbe-4988-ad58-a85a146b681e\", id, name, tags=\"\", param1=\"AppSettings is not configured\"\n\n" }, { @@ -9841,7 +10663,9 @@ "severity": "Medium", "category": "Other Best Practices", "guid": "fd049c28-ae6d-48f0-a641-cc3ba1a3fe1d", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Check if Health Check is enabled for App Service\n\nresources\n| where type =~ 'microsoft.web/sites'\n| where properties.kind has 'app'\n| join kind = inner\n (\n appserviceresources\n | where isnull(properties.HealthCheckPath) == true\n | project name\n ) on name\n| project recommendationId = \"fd049c28-ae6d-48f0-a641-cc3ba1a3fe1d\", name, id, tags, param1 = \"Healthcheckpath = not set\"\n" }, { @@ -9870,7 +10694,9 @@ "severity": "Medium", "category": "Governance", "guid": "aab6b4a4-9981-43a4-8728-35c7ecbb746d", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Check if Network access restrictions defined for App service\n\nresources\n| where type =~ 'microsoft.web/sites'\n| where properties.kind has 'app'\n| join kind = inner\n (\n appserviceresources\n | mv-expand IpSecurityRestrictions = properties.IpSecurityRestrictions\n | where isnotnull(IpSecurityRestrictions) == true\n | project name\n ) on name\n| project recommendationId = \"aab6b4a4-9981-43a4-8728-35c7ecbb746d\", name, id, tags, param1 = \"No network restrictions set\"\n" }, { @@ -9899,7 +10725,9 @@ "severity": "Medium", "category": "Scalability", "guid": "9e6682ac-31bc-4635-9959-ab74b52454e6", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of App services that do not have minimum instance count of 2\n\nresources\n| where type =~ 'microsoft.web/sites'\n| where properties.kind has 'app'\n| join kind = inner\n (\n appserviceresources\n | where properties.PreWarmedInstanceCount < 2\n | project name\n ) on name\n| project recommendationId = \"9e6682ac-31bc-4635-9959-ab74b52454e6\", name, id, tags, param1 = \"PreWarmedInstanceCount is less than 2\"\n" }, { @@ -9928,7 +10756,9 @@ "severity": "Low", "category": "High Availability", "guid": "c6c4b962-5af4-447a-9d74-7b9c53a5dff5", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// Azure Resource Graph Query\n// Provides a list of Azure Function App resources that do not have auto heal enabled\n\nResources\n| where type =~ 'microsoft.web/sites'\n| where properties.kind contains 'functionapp'\n| join kind=inner\n (appserviceresources\n | where type == \"microsoft.web/sites/config\"\n | where properties.AutoHealEnabled == 'false'\n | project id, name, tenantId, location, resourceGroup, properties.AutoHealEnabled\n ) on name\n| project recommendationID = \"c6c4b962-5af4-447a-9d74-7b9c53a5dff5\", name, id, type, kind, param1=\"AutoHealEnabled =false\"\n" }, { @@ -9957,7 +10787,9 @@ "severity": "Medium", "category": "Monitoring and Alerting", "guid": "52f368ee-1d77-4b34-92db-64be269642d0", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -9986,7 +10818,9 @@ "severity": "Low", "category": "Governance", "guid": "0b06a688-0dd6-4d73-9f72-6666ff853ca9", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -10015,7 +10849,9 @@ "severity": "Medium", "category": "Governance", "guid": "c9a278b7-024b-454b-bd54-41587c512b74", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" }, { @@ -10044,51 +10880,53 @@ "severity": "Medium", "category": "Governance", "guid": "7c608f46-46b2-4cc0-bbd6-1d457c16671c", - "source": "azure-resources/Web/sites/recommendations.yaml", + "sourceFile": "azure-resources/Web/sites/recommendations.yaml", + "sourceType": "aprl", + "timestamp": "July 24, 2024", "graph": "// cannot-be-validated-with-arg\n" } ], "categories": [ { - "name": "Disaster Recovery" + "name": "Service Upgrade and Retirement" }, { - "name": "Scalability" + "name": "Disaster Recovery" }, { - "name": "Monitoring and Alerting" + "name": "Other Best Practices" }, { - "name": "High Availability" + "name": "Business Continuity" }, { - "name": "Other Best Practices" + "name": "Personalized" }, { - "name": "Business Continuity" + "name": "Monitoring and Alerting" }, { - "name": "Personalized" + "name": "Security" }, { "name": "Governance" }, { - "name": "Service Upgrade and Retirement" + "name": "High Availability" }, { - "name": "Security" + "name": "Scalability" } ], "severities": [ - { - "name": "Low" - }, { "name": "High" }, { "name": "Medium" + }, + { + "name": "Low" } ], "waf": [ @@ -10142,6 +10980,6 @@ "name": "APRL Checklist", "waf": "none", "state": "preview", - "timestamp": "July 14, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azureapplicationgateway_sg_checklist.en.json b/checklists-ext/azureapplicationgateway_sg_checklist.en.json index d2c3f09f4..bde5684ce 100644 --- a/checklists-ext/azureapplicationgateway_sg_checklist.en.json +++ b/checklists-ext/azureapplicationgateway_sg_checklist.en.json @@ -6,236 +6,265 @@ "service": "Azure Application Gateway", "text": "Plan for rule updates", "description": "Plan enough time for updates before accessing Application Gateway or making further changes. For example, removing servers from backend pool might take some time because they have to drain existing connections.", - "type": "recommendation" + "type": "recommendation", + "guid": "aa2f47b2-36a3-4277-a7f9-530ebe697d26" }, { "waf": "Reliability", "service": "Azure Application Gateway", "text": "Use health probes to detect backend unavailability", "description": "If Application Gateway is used to load balance incoming traffic over multiple backend instances, we recommend the use of health probes. These will ensure that traffic is not routed to backends that are unable to handle the traffic.", - "type": "recommendation" + "type": "recommendation", + "guid": "26730c7f-aa79-4887-bef2-3c6fa3c796b4" }, { "waf": "Reliability", "service": "Azure Application Gateway", "text": "Review the impact of the interval and threshold settings on health probes", "description": "The health probe sends requests to the configured endpoint at a set interval. Also, there's a threshold of failed requests that will be tolerated before the backend is marked unhealthy. These numbers present a trade-off.- Setting a higher interval puts a higher load on your service. Each Application Gateway instance sends its own health probes, so 100 instances every 30 seconds means 100 requests per 30 seconds.- Setting a lower interval leaves more time before an outage is detected.- Setting a low unhealthy threshold might mean that short, transient failures might take down a backend. - Setting a high threshold it can take longer to take a backend out of rotation.", - "type": "recommendation" + "type": "recommendation", + "guid": "dc370d3b-180d-474b-ad33-3e3adc684768" }, { "waf": "Reliability", "service": "Azure Application Gateway", "text": "Verify downstream dependencies through health endpoints", "description": "Suppose each backend has its own dependencies to ensure failures are isolated. For example, an application hosted behind Application Gateway might have multiple backends, each connected to a different database (replica). When such a dependency fails, the application might be working but won't return valid results. For that reason, the health endpoint should ideally validate all dependencies. Keep in mind that if each call to the health endpoint has a direct dependency call, that database would receive 100 queries every 30 seconds instead of 1. To avoid this, the health endpoint should cache the state of the dependencies for a short period of time.", - "type": "recommendation" + "type": "recommendation", + "guid": "ff13f531-ebf7-4051-a2f9-6f6688200bd8" }, { "waf": "Reliability", "service": "Azure Application Gateway", "text": "When using Azure Front Door and Application Gateway to protect `HTTP/S` applications, use WAF policies in Front Door and lock down Application Gateway to receive traffic only from Azure Front Door.", "description": "Certain scenarios can force you to implement rules specifically on Application Gateway. For example, if ModSec CRS 2.2.9, CRS 3.0 or CRS 3.1 rules are required, these rules can be only implemented on Application Gateway. Conversely, rate-limiting and geo-filtering are available only on Azure Front Door, not on AppGateway.", - "type": "recommendation" + "type": "recommendation", + "guid": "1cacf8b7-2158-4fbf-8a2a-8021a0b7e54d" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Set up a TLS policy for enhanced security", "description": "Set up a TLS policy for extra security. Ensure you're always using the latest TLS policy version available. This enforces TLS 1.2 and stronger ciphers.", - "type": "recommendation" + "type": "recommendation", + "guid": "6f66822e-e720-4449-9109-d536e95e9aca" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Use AppGateway for TLS termination", "description": "There are advantages of using Application Gateway for TLS termination:- Performance improves because requests going to different backends to have to re-authenticate to each backend.- Better utilization of backend servers because they don't have to perform TLS processing- Intelligent routing by accessing the request content.- Easier certificate management because the certificate only needs to be installed on Application Gateway.", - "type": "recommendation" + "type": "recommendation", + "guid": "2e78b1af-30aa-48fb-a8c3-852e109871a6" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Use Azure Key Vault to store TLS certificates", "description": "Application Gateway can be integrated with Key Vault. This provides stronger security, easier separation of roles and responsibilities, support for managed certificates, and an easier certificate renewal and rotation process.", - "type": "recommendation" + "type": "recommendation", + "guid": "2d18cf76-75ec-4b98-b76c-a4d6fb44e043" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "When re-encrypting backend traffic, ensure the backend server certificate contains both the root and intermediate Certificate Authorities (CAs)", "description": "A TLS certificate of the backend server must be issued by a well-known CA. If the certificate was not issued by a trusted CA, the Application Gateway checks if the certificate was issued by a trusted CA, and so on, until a trusted CA certificate is found. Only then a secure connection is established. Otherwise, Application Gateway marks the backend as unhealthy.", - "type": "recommendation" + "type": "recommendation", + "guid": "8bc7c922-c69c-4280-9b9a-c9beecead835" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Use an appropriate DNS server for backend pool resources", "description": "When the backend pool contains a resolvable FQDN, the DNS resolution is based on a private DNS zone or custom DNS server (if configured on the VNet), or it uses the default Azure-provided DNS.", - "type": "recommendation" + "type": "recommendation", + "guid": "99518dfb-4e20-4868-8991-1c75f297a55d" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Comply with all NSG restrictions for Application Gateway", "description": "NSGs are supported on Application Gateway subnet, but there are some restrictions. For instance, some communication with certain port ranges is prohibited. Make sure you understand the implications of those restrictions. For details, see Network security groups.", - "type": "recommendation" + "type": "recommendation", + "guid": "1437298d-0abb-484b-9152-5400d6b4d258" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Refrain from using UDRs on the Application gateway subnet", "description": "Using User Defined Routes (UDR) on the Application Gateway subnet can cause some issues. Health status in the back-end might be unknown. Application Gateway logs and metrics might not get generated. We recommend that you don't use UDRs on the Application Gateway subnet so that you can view the back-end health, logs, and metrics. If your organizations require to use UDR in the Application Gateway subnet, please ensure you review the supported scenarios. For more information, see Supported user-defined routes.", - "type": "recommendation" + "type": "recommendation", + "guid": "aad6f93d-60b5-44e2-a166-a85d4fe7f6e9" }, { "waf": "Security", "service": "Azure Application Gateway", "text": "Be aware of Application Gateway capacity changes when enabling WAF", "description": "When WAF is enabled, every request must be buffered by the Application Gateway until it fully arrives, checks if the request matches with any rule violation in its core rule set, and then forwards the packet to the backend instances. When there are large file uploads (30MB+ in size), it can result in a significant latency. Because Application Gateway capacity requirements are different with WAF, we do not recommend enabling WAF on Application Gateway without proper testing and validation.", - "type": "recommendation" + "type": "recommendation", + "guid": "32b914b9-a439-42ab-ac1b-e131333896d3" }, { "waf": "Cost", "service": "Azure Application Gateway", "text": "Familiarize yourself with Application Gateway pricing", "description": "For information about Application Gateway pricing, see Understanding Pricing for Azure Application Gateway and Web Application Firewall. You can also leverage the Pricing calculator.Ensure that the options are adequately sized to meet the capacity demand and deliver expected performance without wasting resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "0edcbe2d-deaf-4319-ad1e-80a9393fa444" }, { "waf": "Cost", "service": "Azure Application Gateway", "text": "Review underutilized resources", "description": "Identify and delete Application Gateway instances with empty backend pools to avoid unnecessary costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "4b19fe95-feb3-4d0f-87b4-b06897703775" }, { "waf": "Cost", "service": "Azure Application Gateway", "text": "Stop Application Gateway instances when not in use", "description": "You aren't billed when Application Gateway is in the stopped state. Continuously running Application Gateway instances can incur extraneous costs. Evaluate usage patterns and stop instances when you don't need them. For example, usage after business hours in Dev/Test environments is expected to be low.See these articles for information about how to stop and start instances.- Stop-AzApplicationGateway- Start-AzApplicationGateway", - "type": "recommendation" + "type": "recommendation", + "guid": "4574f29b-5ff1-4acb-9914-dc5c912f31df" }, { "waf": "Cost", "service": "Azure Application Gateway", "text": "Have a scale-in and scale-out policy", "description": "A scale-out policy ensures that there will be enough instances to handle incoming traffic and spikes. Also, have a scale-in policy that makes sure the number of instances are reduced when demand drops. Consider the choice of instance size. The size can significantly impact the cost. Some considerations are described in the Estimate the Application Gateway instance count.For more information, see What is Azure Application Gateway v2?", - "type": "recommendation" + "type": "recommendation", + "guid": "4cf0112c-e271-4802-ae11-4a95e14e1564" }, { "waf": "Cost", "service": "Azure Application Gateway", "text": "Review consumption metrics across different parameters", "description": "You're billed based on metered instances of Application Gateway based on the metrics tracked by Azure. Evaluate the various metrics and capacity units and determine the cost drivers. For more information, see Microsoft Cost Management and Billing. The following metrics are key for Application Gateway. This information can be used to validate that the provisioned instance count matches the amount of incoming traffic.- Estimated Billed Capacity Units- Fixed Billable Capacity Units- Current Capacity UnitsFor more information, see Application Gateway metrics.Make sure you account for bandwidth costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "98244878-55bd-49b1-ac07-ca6e96d5ba83" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Monitor capacity metrics", "description": "Use these metrics as indicators of utilization of the provisioned Application Gateway capacity. We strongly recommend setting up alerts on capacity. For details, see Application Gateway high traffic support.", - "type": "recommendation" + "type": "recommendation", + "guid": "6a41de7f-c4c6-48c6-b997-1dcff0c8ac25" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Troubleshoot using metrics", "description": "There are other metrics that can indicate issues either at Application Gateway or the backend. We recommend evaluating the following alerts:- Unhealthy Host Count- Response Status (dimension 4xx and 5xx)- Backend Response Status (dimension 4xx and 5xx)- Backend Last Byte Response Time- Application Gateway Total TimeFor more information, see Metrics for Application Gateway.", - "type": "recommendation" + "type": "recommendation", + "guid": "886af6e8-8d4e-4963-bffc-ec91cfeac600" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Enable diagnostics on Application Gateway and Web Application Firewall (WAF)", "description": "Diagnostic logs allow you to view firewall logs, performance logs, and access logs. Use these logs to manage and troubleshoot issues with Application Gateway instances. For more information, see Back-end health and diagnostic logs for Application Gateway.", - "type": "recommendation" + "type": "recommendation", + "guid": "1d2ea6e3-cf4a-4342-94d0-05204da3e0f4" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Use Azure Monitor Network Insights", "description": "Azure Monitor Network Insights provides a comprehensive view of health and metrics for network resources, including Application Gateway. For additional details and supported capabilities for Application Gateway, see Azure Monitor Network insights.", - "type": "recommendation" + "type": "recommendation", + "guid": "2273b46e-b8f5-43ae-842c-54b042a9d984" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Match timeout settings with the backend application", "description": "Ensure you have configured the IdleTimeout settings to match the listener and traffic characteristics of the backend application. The default value is set to four minutes and can be configured to a maximum of 30. For more information, see Load Balancer TCP Reset and Idle Timeout.For workload considerations, see Monitoring application health for reliability.", - "type": "recommendation" + "type": "recommendation", + "guid": "41027b9b-d6e6-43b4-9827-48d59abf1cbd" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Monitor Key Vault configuration issues using Azure Advisor", "description": "Application Gateway checks for the renewed certificate version in the linked Key Vault at every 4-hour interval. If it is inaccessible due to any incorrect Key Vault configuration, it logs that error and pushes a corresponding Advisor recommendation. You must configure the Advisor alerts to stay updated and fix such issues immediately to avoid any Control or Data plane related problems. For more information, see Investigating and resolving key vault errors. To set an alert for this specific case, use the Recommendation Type as Resolve Azure Key Vault issue for your Application Gateway.", - "type": "recommendation" + "type": "recommendation", + "guid": "5d5a0e24-e4e8-4454-83d0-313bce959d0f" }, { "waf": "Operations", "service": "Azure Application Gateway", "text": "Consider SNAT port limitations in your design", "description": "SNAT port limitations are important for backend connections on the Application Gateway. There are separate factors that affect how Application Gateway reaches the SNAT port limit. For example, if the backend is a public IP address, it will require its own SNAT port. In order to avoid SNAT port limitations, you can increase the number of instances per Application Gateway, scale out the backends to have more IP addresses, or move your backends into the same virtual network and use private IP addresses for the backends.Requests per second (RPS) on the Application Gateway will be affected if the SNAT port limit is reached. For example, if an Application Gateway reaches the SNAT port limit, then it won't be able to open a new connection to the backend, and the request will fail.", - "type": "recommendation" + "type": "recommendation", + "guid": "5acb5642-e3d0-4aa4-98cc-3bd36b826713" }, { "waf": "Performance", "service": "Azure Application Gateway", "text": "Define the minimum instance count", "description": "For Application Gateway v2 SKU, autoscaling takes some time (approximately six to seven minutes) before the additional set of instances is ready to serve traffic. During that time, if there are short spikes in traffic, expect transient latency or loss of traffic.We recommend that you set your minimum instance count to an optimal level. After you estimate the average instance count and determine your Application Gateway autoscaling trends, define the minimum instance count based on your application patterns. For information, see Application Gateway high traffic support.Check the Current Compute Units for the past one month. This metric represents the gateway's CPU utilization. To define the minimum instance count, divide the peak usage by 10. For example, if your average Current Compute Units in the past month is 50, set the minimum instance count to five.", - "type": "recommendation" + "type": "recommendation", + "guid": "e7f3c963-e70a-48dd-954b-27619837daab" }, { "waf": "Performance", "service": "Azure Application Gateway", "text": "Define the maximum instance count", "description": "We recommend 125 as the maximum autoscale instance count. Make sure the subnet that has the Application Gateway has sufficient available IP addresses to support the scale-up set of instances.Setting the maximum instance count to 125 has no cost implications because you're billed only for the consumed capacity.", - "type": "recommendation" + "type": "recommendation", + "guid": "3539073c-2694-4459-bcb4-a943a628101b" }, { "waf": "Performance", "service": "Azure Application Gateway", "text": "Define Application Gateway subnet size", "description": "Application Gateway needs a dedicated subnet within a virtual network. The subnet can have multiple instances of the deployed Application Gateway resource. You can also deploy other Application Gateway resources in that subnet, v1 or v2 SKU.Here are some considerations for defining the subnet size:- Application Gateway uses one private IP address per instance and another private IP address if a private front-end IP is configured.- Azure reserves five IP addresses in each subnet for internal use.- Application Gateway (Standard or WAF SKU) can support up to 32 instances. Taking 32 instance IP addresses + 1 private front-end IP + 5 Azure reserved, a minimum subnet size of /26 is recommended. Because the Standard_v2 or WAF_v2 SKU can support up to 125 instances, using the same calculation, a subnet size of /24 is recommended.- If you want to deploy additional Application Gateway resources in the same subnet, consider the additional IP addresses that will be required for their maximum instance count for both, Standard and Standard v2.", - "type": "recommendation" + "type": "recommendation", + "guid": "75c2360c-8a5d-46ae-8471-7636e7e16313" }, { "waf": "Performance", "service": "Azure Application Gateway", "text": "Take advantage of features for autoscaling and performance benefits", "description": "The v2 SKU offers autoscaling to ensure that your Application Gateway can scale up as traffic increases. When compared to v1 SKU, v2 has capabilities that enhance the performance of the workload. For example, better TLS offload performance, quicker deployment and update times, zone redundancy, and more. For more information about autoscaling features, see Scaling Application Gateway v2 and WAF v2.If you are running v1 SKU Application gateway, consider migrating to the Application gateway v2 SKU. For more information, see Migrate Azure Application Gateway and Web Application Firewall from v1 to v2.", - "type": "recommendation" + "type": "recommendation", + "guid": "a8924ef1-8a49-4cf6-9858-b475d9618d9d" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -272,6 +301,6 @@ "name": "Azure Application Gateway Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azureblobstorage_sg_checklist.en.json b/checklists-ext/azureblobstorage_sg_checklist.en.json index 89aa998ce..735f3463d 100644 --- a/checklists-ext/azureblobstorage_sg_checklist.en.json +++ b/checklists-ext/azureblobstorage_sg_checklist.en.json @@ -6,215 +6,241 @@ "service": "Azure Blob Storage", "text": "Configure your account for redundancy. For maximum availability and durability, configure your account by using zone-redundant storage (ZRS) or GZRS.", "description": "Redundancy protects your data against unexpected failures. The ZRS and GZRS configuration options replicate across different availability zones and enable applications to continue reading data during an outage. For more information, see Durability and availability by outage scenario and Durability and availability parameters.", - "type": "recommendation" + "type": "recommendation", + "guid": "6e3a0d4c-f59e-4049-a15d-30ca8ac3bc5e" }, { "waf": "Reliability", "service": "Azure Blob Storage", "text": "Before initiating a failover or failback, evaluate the potential for data loss by checking the value of the last synchronization time property. This recommendation applies only to GRS and GZRS configurations.", "description": "This property helps you estimate how much data you might lose by initiating an account failover. All data and metadata written before the last synchronization time is available on the secondary region, but data and metadata written after the last synchronization time might be lost because it's not written to the secondary region.", - "type": "recommendation" + "type": "recommendation", + "guid": "b9413c5c-1467-4f04-aa56-66756174bfe4" }, { "waf": "Reliability", "service": "Azure Blob Storage", "text": "As a part of your backup and recovery strategy, enable the container soft delete, blob soft delete, versioning, and point-in-time restore options.", "description": "The soft delete option enables a storage account to recover deleted containers and blobs. The versioning option automatically tracks changes made to blobs. This option lets you restore a blob to a previous state.The point-in-time restore option protects against accidental blob deletion or corruption and lets you restore block blob data to an earlier state. For more information, see Data protection overview.", - "type": "recommendation" + "type": "recommendation", + "guid": "7900bd00-c4b2-4e8d-b006-0efdf966daa7" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Disable anonymous read access to containers and blob.", "description": "When anonymous access is allowed for a storage account, a user that has the appropriate permissions can modify a container's anonymous access setting to enable anonymous access to the data in that container.", - "type": "recommendation" + "type": "recommendation", + "guid": "5d7648fc-6e65-46da-beb4-b7da768cd856" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Apply an Azure Resource Manager lock on the storage account.", "description": "Locking an account prevents it from being deleted and causing data loss.", - "type": "recommendation" + "type": "recommendation", + "guid": "a279d1d6-4a74-4533-aef0-6d658c196084" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Disable traffic to the public endpoints of your storage account. Create private endpoints for clients that run in Azure. Enable the public endpoint only if clients and services external to Azure require direct access to your storage account. Enable firewall rules that limit access to specific virtual networks.", "description": "Start with zero access and then incrementally authorize the lowest levels of access required for clients and services to minimize the risk of creating unnecessary openings for attackers.", - "type": "recommendation" + "type": "recommendation", + "guid": "a3a5d6f5-b15b-4b9f-83a4-590d9f826f11" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Authorize access by using Azure role-based access control (RBAC).", "description": "With RBAC, there are no passwords or keys that can be compromised. The security principal (user, group, managed identity, or service principal) is authenticated by Microsoft Entra ID to return an OAuth 2.0 token. The token is used to authorize a request against the Blob Storage service.", - "type": "recommendation" + "type": "recommendation", + "guid": "945c0935-f1fd-4b22-a24e-5b767202d86e" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Disallow shared key authorization. This disables not only account key access but also service and account shared access signature tokens because they're based on account keys.", "description": "Only secured requests that are authorized with Microsoft Entra ID are permitted.", - "type": "recommendation" + "type": "recommendation", + "guid": "20c571b0-d4cf-4641-bd1d-1310f8cd6eb2" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "We recommend that you don't use an account key. If you must use account keys, then store them in Key Vault, and make sure that you regenerate them periodically.", "description": "Key Vault lets you retrieve keys at runtime, instead of saving them by using your application. Key Vault also makes it easy to rotate your keys without interruption to your applications. Rotating the account keys periodically reduces the risk of exposing your data to malicious attacks.", - "type": "recommendation" + "type": "recommendation", + "guid": "49899213-759d-4cac-b34a-446526b56f4b" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "We recommend that you don't use shared access signature tokens. Evaluate whether you need shared access signature tokens to secure access to Blob Storage resources. If you must create one, then review this list of shared access signature best practices before you create and distribute it.", "description": "Best practices can help you prevent a shared access signature token from being leaked and quickly recover if a leak does occur.", - "type": "recommendation" + "type": "recommendation", + "guid": "cb1a2ad8-7833-45be-97e5-4afc4a38cfc4" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Configure your storage account so clients can send and receive data by using the minimum version of TLS 1.2.", "description": "TLS 1.2 is more secure and faster than TLS 1.0 and 1.1, which don't support modern cryptographic algorithms and cipher suites.", - "type": "recommendation" + "type": "recommendation", + "guid": "9bf21313-427b-4208-8815-9e6323d55f4c" }, { "waf": "Security", "service": "Azure Blob Storage", "text": "Consider using your own encryption key to protect the data in your storage account. For more information, see Customer-managed keys for Azure Storage encryption.", "description": "Customer-managed keys provide greater flexibility and control. For example, you can store encryption keys in Key Vault and automatically rotate them.", - "type": "recommendation" + "type": "recommendation", + "guid": "76f6e285-5bed-46c0-a50d-b8024c4fd512" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "Pack small files into larger files before moving them to cooler tiers. You can use file formats such as TAR or ZIP.", "description": "Cooler tiers have higher data transfer costs. By having fewer large files, you can reduce the number of operations required to transfer data.", - "type": "recommendation" + "type": "recommendation", + "guid": "68a2d8f2-ccf3-4cde-9466-61444d55d7d3" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "Use standard-priority rehydration when rehydrating blobs from archive storage. Use high-priority rehydration only for emergency data restoration situations. For more information, see Rehydrate an archived blob to an online tier", "description": "High-priority rehydration from the archive tier can lead to higher-than-normal bills.", - "type": "recommendation" + "type": "recommendation", + "guid": "b3b25570-9501-4ccf-a42f-bf1ab7a1796d" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "Reduce the cost of using resource logs by choosing the appropriate log storage location and by managing log-retention periods. If you only plan to query logs occasionally (for example, querying logs for compliance auditing), consider sending resource logs to a storage account instead of sending them to an Azure Monitor Logs workspace. You can use a serverless query solution such as Azure Synapse Analytics to analyze logs. For more information, see Optimize cost for infrequent queries. Use lifecycle management policies to delete or archive logs.", "description": "Storing resource logs in a storage account for later analysis can be a cheaper option. Using lifecycle management policies to manage log retention in a storage account prevents large numbers of logs files building up over time, which can lead to unnecessary capacity charges.", - "type": "recommendation" + "type": "recommendation", + "guid": "9c10778d-ed29-4ac4-b310-38987b3ba76b" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "If you enable versioning, use a lifecycle management policy to automatically delete old blob versions.", "description": "Every write operation to a blob creates a new version. This increases capacity costs. You can keep costs in check by removing versions that you no longer need.", - "type": "recommendation" + "type": "recommendation", + "guid": "05ba2481-3ecf-4808-a6fd-211f0a7db6ce" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "If you enable versioning, then place blobs that are frequently overwritten into an account that doesn't have versioning enabled.", "description": "Every time a blob is overwritten, a new version is added which leads to increased storage capacity charges. To reduce capacity charges, store frequently overwritten data in a separate storage account with versioning disabled.", - "type": "recommendation" + "type": "recommendation", + "guid": "2b3cf36b-31a3-48c2-8624-9c8bdbf15a07" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "If you enable soft delete, then place blobs that are frequently overwritten into an account that doesn't have soft delete enabled. Set retention periods. Consider starting with a short retention period to better understand how the feature affects your bill. The minimum recommended retention period is seven days.", "description": "Every time a blob is overwritten, a new snapshot is created. The cause of increased capacity charges might be difficult to access because the creation of these snapshots doesn't appear in logs. To reduce capacity charges, store frequently overwritten data in a separate storage account with soft delete disabled. A retention period keeps soft-deleted blobs from piling up and adding to the cost of capacity.", - "type": "recommendation" + "type": "recommendation", + "guid": "ea98ff0a-e389-4eb1-9f55-98d638152d68" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "Enable SFTP support only when it's used to transfer data.", "description": "Enabling the SFTP endpoint incurs an hourly cost. By thoughtfully disabling SFTP support, and then enabling it as needed, you can avoid passive charges from accruing in your account.", - "type": "recommendation" + "type": "recommendation", + "guid": "918a9943-7dd2-47be-9d8f-d7088e08247d" }, { "waf": "Cost", "service": "Azure Blob Storage", "text": "Disable any encryption scopes that aren't needed to avoid unnecessary charges.", "description": "Encryptions scopes incur a per month charge.", - "type": "recommendation" + "type": "recommendation", + "guid": "dda91f7c-dd40-485d-af07-7ef14c90de03" }, { "waf": "Operations", "service": "Azure Blob Storage", "text": "Use infrastructure as code (IaC) to define the details of your storage accounts in Azure Resource Manager templates (ARM templates), Bicep, or Terraform.", "description": "You can use your existing DevOps processes to deploy new storage accounts, and use Azure Policy to enforce their configuration.", - "type": "recommendation" + "type": "recommendation", + "guid": "fab63e96-cd06-4c4d-b92c-3b32a554e2d5" }, { "waf": "Operations", "service": "Azure Blob Storage", "text": "Use Storage insights to track the health and performance of your storage accounts. Storage insights provides a unified view of the failures, performance, availability, and capacity for all your storage accounts.", "description": "You can track the health and operation of each of your accounts. Easily create dashboards and reports that stakeholders can use to track the health of your storage accounts.", - "type": "recommendation" + "type": "recommendation", + "guid": "fe67dbff-1ce7-4ac5-8b12-b0c3e23e66f3" }, { "waf": "Performance", "service": "Azure Blob Storage", "text": "Provision storage accounts in the same region where dependent resources are placed. For applications that aren't hosted on Azure, such as mobile device apps or on-premises enterprise services, locate the storage account in a region nearer to those clients. For more information, see Azure geographies.If clients from a different region don't require the same data, then create a separate account in each region.If clients from a different region require only some data, consider using an object-replication policy to asynchronously copy relevant objects to a storage account in the other region.", "description": "Reducing the physical distance between the storage account and VMs, services, and on-premises clients can improve performance and reduce network latency. Reducing the physical distance also reduces cost for applications hosted in Azure because bandwidth usage within a single region is free.", - "type": "recommendation" + "type": "recommendation", + "guid": "f8126892-8d54-4a95-8e93-cc34bd50443d" }, { "waf": "Performance", "service": "Azure Blob Storage", "text": "For broad consumption by web clients (streaming video, audio, or static website content), consider using a content delivery network through Azure Front Door.", "description": "Content is delivered to clients faster because it uses the Microsoft global edge network with hundreds of global and local points of presence around the world.", - "type": "recommendation" + "type": "recommendation", + "guid": "9a8a245d-71e9-45a8-b143-de66b3b87fd1" }, { "waf": "Performance", "service": "Azure Blob Storage", "text": "Add a hash character sequence (such as three digits) as early as possible in the partition key of a blob. The partition key is the account name, container name, virtual directory name, and blob name. If you plan to use timestamps in names, then consider adding a seconds value to the beginning of that stamp. For more information, see Partitioning.", "description": "Using a hash code or seconds value nearest the beginning of a partition key reduces the time required to list query and read blobs.", - "type": "recommendation" + "type": "recommendation", + "guid": "215dace2-6d30-430f-9ab0-90ada951e981" }, { "waf": "Performance", "service": "Azure Blob Storage", "text": "When uploading blobs or blocks, use a blob or block size that's greater than 256 KiB.", "description": "Blob or block sizes above 256 KiB takes advantage of performance enhancements in the platform made specifically for larger blobs and block sizes.", - "type": "recommendation" + "type": "recommendation", + "guid": "7c748c26-7894-46d4-811b-3f792790b567" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -251,6 +277,6 @@ "name": "Azure Blob Storage Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azureexpressroute_sg_checklist.en.json b/checklists-ext/azureexpressroute_sg_checklist.en.json index 210d6f749..d608a37bb 100644 --- a/checklists-ext/azureexpressroute_sg_checklist.en.json +++ b/checklists-ext/azureexpressroute_sg_checklist.en.json @@ -6,215 +6,241 @@ "service": "Azure Expressroute", "text": "Plan for ExpressRoute circuit or ExpressRoute Direct", "description": "During the initial planning phase, you want to decide whether you want to configure an ExpressRoute circuit or an ExpressRoute Direct connection. An ExpressRoute circuit allows a private dedicated connection into Azure with the help of a connectivity provider. ExpressRoute Direct allows you to extend on-premises network directly into the Microsoft network at a peering location. You also need to identify the bandwidth requirement and the SKU type requirement for your business needs.", - "type": "recommendation" + "type": "recommendation", + "guid": "1fd730ba-d5b5-450b-9444-3daff21bc4b9" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Physical layer diversity", "description": "For better resiliency, plan to have multiple paths between the on-premises edge and the peering locations (provider/Microsoft edge locations). This configuration can be achieved by going through different service provider or through a different location from the on-premises network.", - "type": "recommendation" + "type": "recommendation", + "guid": "ecab565f-2cbe-4bb9-81e9-d1a4c3771e57" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Plan for geo-redundant circuits", "description": "To plan for disaster recovery, set up ExpressRoute circuits in more than one peering locations. You can create circuits in peering locations in the same metro or different metro and choose to work with different service providers for diverse paths through each circuit. For more information, see Designing for disaster recovery and Designing for high availability.", - "type": "recommendation" + "type": "recommendation", + "guid": "c7a9ccf7-7daf-4f2d-871e-1f7c4dfdba33" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Plan for Active-Active connectivity", "description": "ExpressRoute dedicated circuits guarantee `99.95%` availability when an active-active connectivity is configured between on-premises and Azure. This mode provides higher availability of your Expressroute connection. It's also recommended to configure BFD for faster failover if there's a link failure on a connection.", - "type": "recommendation" + "type": "recommendation", + "guid": "3206bf94-9a6e-436b-a9c2-785a79d3bdf7" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Planning for Virtual Network Gateways", "description": "Create availability zone aware Virtual Network Gateway for higher resiliency and plan for Virtual Network Gateways in different region for disaster recovery and high availability.", - "type": "recommendation" + "type": "recommendation", + "guid": "1cbe905b-cc57-4571-9415-cd13c4320fec" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Monitor circuits and gateway health", "description": "Set up monitoring and alerts for ExpressRoute circuits and Virtual Network Gateway health based on various metrics available.", - "type": "recommendation" + "type": "recommendation", + "guid": "8f4eb27d-3de4-4265-a35b-d5243506b1b3" }, { "waf": "Reliability", "service": "Azure Expressroute", "text": "Enable service health", "description": "ExpressRoute uses service health to notify about planned and unplanned maintenance. Configuring service health will notify you about changes made to your ExpressRoute circuits.", - "type": "recommendation" + "type": "recommendation", + "guid": "ee6ce588-143a-4ab4-acb1-0c7487484015" }, { "waf": "Security", "service": "Azure Expressroute", "text": "Configure Activity log to send logs to archive", "description": "Activity logs provide insights into operations that were performed at the subscription level for ExpressRoute resources. With Activity logs, you can determine who and when an operation was performed at the control plane. Data retention is only 90 days and required to be stored in Log Analytics, Event Hubs or a storage account for archive.", - "type": "recommendation" + "type": "recommendation", + "guid": "0c9fcbb1-5c1c-47ec-a5a8-413c7ef6d9c0" }, { "waf": "Security", "service": "Azure Expressroute", "text": "Maintain inventory of administrative accounts", "description": "Use Azure RBAC to configure roles to limit user accounts that can add, update, or delete peering configuration on an ExpressRoute circuit.", - "type": "recommendation" + "type": "recommendation", + "guid": "5a43370c-8625-4a7a-a86a-8482baa5e27d" }, { "waf": "Security", "service": "Azure Expressroute", "text": "Configure MD5 hash on ExpressRoute circuit", "description": "During configuration of private peering or Microsoft peering, apply an MD5 hash to secure messages between the on-premises route and the MSEE routers.", - "type": "recommendation" + "type": "recommendation", + "guid": "8a9dc0cc-86a6-45c1-8441-a0d77757a8e2" }, { "waf": "Security", "service": "Azure Expressroute", "text": "Configure MACSec for ExpressRoute Direct resources", "description": "Media Access Control security is a point-to-point security at the data link layer. ExpressRoute Direct supports configuring MACSec to prevent security threats to protocols such as ARP, DHCP, LACP not normally secured on the Ethernet link. For more information on how to configure MACSec, see MACSec for ExpressRoute Direct ports.", - "type": "recommendation" + "type": "recommendation", + "guid": "500c8980-c0ef-43a0-b9a8-2d3d14980e97" }, { "waf": "Security", "service": "Azure Expressroute", "text": "Encrypt traffic using IPsec", "description": "Configure a Site-to-site VPN tunnel over your ExpressRoute circuit to encrypt data transferring between your on-premises network and Azure virtual network. You can configure a tunnel using private peering or using Microsoft peering.", - "type": "recommendation" + "type": "recommendation", + "guid": "91c50223-7778-4996-99c6-4dd5be8a7634" }, { "waf": "Cost", "service": "Azure Expressroute", "text": "Familiarize yourself with ExpressRoute pricing", "description": "For information about ExpressRoute pricing, see Understand pricing for Azure ExpressRoute. You can also use the Pricing calculator.Ensure that the options are adequately sized to meet the capacity demand and deliver expected performance without wasting resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "cee32b00-067e-4548-b020-f187b4a8c31c" }, { "waf": "Cost", "service": "Azure Expressroute", "text": "Determine SKU and bandwidth required", "description": "The way you're charged for your ExpressRoute usage varies between the three different SKU types. With Local SKU, you're automatically charged with an Unlimited data plan. With Standard and Premium SKU, you can select between a Metered or an Unlimited data plan. All ingress data are free of charge except when using the Global Reach add-on. It's important to understand which SKU types and data plan works best for your workload to best optimize cost and budget. For more information resizing ExpressRoute circuit, see upgrading ExpressRoute circuit bandwidth.", - "type": "recommendation" + "type": "recommendation", + "guid": "bbd469cf-f785-414a-81b5-8b32b458d36b" }, { "waf": "Cost", "service": "Azure Expressroute", "text": "Determine the ExpressRoute virtual network gateway size", "description": "ExpressRoute virtual network gateways are used to pass traffic into a virtual network over private peering. Review the performance and scale needs of your preferred Virtual Network Gateway SKU. Select the appropriate gateway SKU on your on-premises to Azure workload.", - "type": "recommendation" + "type": "recommendation", + "guid": "f1a986d4-44ab-4f57-8e90-7d543b1f69ef" }, { "waf": "Cost", "service": "Azure Expressroute", "text": "Monitor cost and create budget alerts", "description": "Monitor the cost of your ExpressRoute circuit and create alerts for spending anomalies and overspending risks. For more information, see Monitoring ExpressRoute costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "a99b7390-8fcd-4982-874d-716d0e33a556" }, { "waf": "Cost", "service": "Azure Expressroute", "text": "Deprovision and delete ExpressRoute circuits no longer in use.", "description": "ExpressRoute circuits are charged from the moment they're created. To reduce unnecessary cost, deprovision the circuit with the service provider and delete the ExpressRoute circuit from your subscription. For steps on how to remove an ExpressRoute circuit, see Deprovisioning an ExpressRoute circuit.", - "type": "recommendation" + "type": "recommendation", + "guid": "af36cdef-2fb3-40c2-9aad-9737a0923106" }, { "waf": "Operations", "service": "Azure Expressroute", "text": "Configure connection monitoring", "description": "Connection monitoring allows you to monitor connectivity between your on-premises resources and Azure over the ExpressRoute private peering and Microsoft peering connection. Connection monitor can detect networking issues by identifying where along the network path the problem is and help you quickly resolve configuration or hardware failures.", - "type": "recommendation" + "type": "recommendation", + "guid": "ed434cb2-77d8-42de-b470-bc4badecb570" }, { "waf": "Operations", "service": "Azure Expressroute", "text": "Configure Service Health", "description": "Set up Service Health notifications to alert when planned and upcoming maintenance is happening to all ExpressRoute circuits in your subscription. Service Health also displays past maintenance along with RCA if an unplanned maintenance were to occur.", - "type": "recommendation" + "type": "recommendation", + "guid": "c840ed18-2c79-4052-981f-db4fe43778f7" }, { "waf": "Operations", "service": "Azure Expressroute", "text": "Review metrics with Network Insights", "description": "ExpressRoute Insights with Network Insights allow you to review and analyze ExpressRoute circuits, gateways, connections metrics and health dashboards. ExpressRoute Insights also provide a topology view of your ExpressRoute connections where you can view details of your peering components all in a single place.Metrics available:- Availability- Throughput- Gateway metrics", - "type": "recommendation" + "type": "recommendation", + "guid": "750d3e90-ad08-4bf0-b5d0-615ae4989959" }, { "waf": "Operations", "service": "Azure Expressroute", "text": "Review ExpressRoute resource metrics", "description": "ExpressRoute uses Azure Monitor to collect metrics and create alerts base on your configuration. Metrics are collected for ExpressRoute circuits, ExpressRoute gateways, ExpressRoute gateway connections, and ExpressRoute Direct. These metrics are useful for diagnosing connectivity problems and understanding the performance of your ExpressRoute connection.", - "type": "recommendation" + "type": "recommendation", + "guid": "786e08d7-92ce-4431-92d4-0e562e040ec5" }, { "waf": "Performance", "service": "Azure Expressroute", "text": "Test ExpressRoute gateway performance to meet work load requirements.", "description": "Use Azure Connectivity Toolkit to test performance across your ExpressRoute circuit to understand bandwidth capacity and latency of your network connection.", - "type": "recommendation" + "type": "recommendation", + "guid": "f3ae82d5-c234-45f3-aa60-fda19953882b" }, { "waf": "Performance", "service": "Azure Expressroute", "text": "Increase the size of the ExpressRoute gateway.", "description": "Upgrade to a higher gateway SKU for improved throughput performance between on-premises and Azure environment.", - "type": "recommendation" + "type": "recommendation", + "guid": "7bb82173-fbe7-4006-8748-8563ced2099c" }, { "waf": "Performance", "service": "Azure Expressroute", "text": "Upgrade ExpressRoute circuit bandwidth", "description": "Upgrade your circuit bandwidth to meet your work load requirements. Circuit bandwidth is shared between all virtual networks connected to the ExpressRoute circuit. Depending on your work load, one or more virtual networks can use up all the bandwidth on the circuit.", - "type": "recommendation" + "type": "recommendation", + "guid": "c971e654-a452-41cd-a068-2ce7b847e70b" }, { "waf": "Performance", "service": "Azure Expressroute", "text": "Enable ExpressRoute FastPath for higher throughput", "description": "If you're using an Ultra performance or an ErGW3AZ virtual network gateway, you can enable FastPath to improve the data path performance between your on-premises network and Azure virtual network.", - "type": "recommendation" + "type": "recommendation", + "guid": "afb1b0d7-d12f-41e2-83da-9f34a421fab2" }, { "waf": "Performance", "service": "Azure Expressroute", "text": "Monitor ExpressRoute circuit and gateway metrics", "description": "Set up alerts base on ExpressRoute metrics to proactively notify you when a certain threshold is met. These metrics are useful to understand anomalies that can happen with your ExpressRoute connection such as outages and maintenance happening to your ExpressRoute circuits.", - "type": "recommendation" + "type": "recommendation", + "guid": "36957ecf-2ad2-41d3-9c53-f0ba27050799" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -251,6 +277,6 @@ "name": "Azure Expressroute Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azurefiles_sg_checklist.en.json b/checklists-ext/azurefiles_sg_checklist.en.json index 6d83dc655..638be19b5 100644 --- a/checklists-ext/azurefiles_sg_checklist.en.json +++ b/checklists-ext/azurefiles_sg_checklist.en.json @@ -6,236 +6,265 @@ "service": "Azure Files", "text": "Configure your storage account for redundancy. For maximum availability and durability, configure your account with\u202fzone-redundant storage (ZRS), GRS, or\u202fGZRS. Limited Azure regions support ZRS for standard and premium file shares. Only standard SMB accounts support GRS and GZRS. Premium SMB shares and NFS shares don't support GRS and GZRS. Azure Files doesn't support read-access geo-redundant storage (RA-GRS) or read-access geo-zone-redundant storage (RA-GZRS). If you configure a storage account to use RA-GRS or RA-GZRS, the file shares are configured and billed as GRS or GZRS.", "description": "Redundancy protects your data against unexpected failures. The ZRS and GZRS configuration options replicate across various availability zones and enable applications to continue reading data during an outage. For more information, see Durability and availability by outage scenario and Durability and availability parameters.", - "type": "recommendation" + "type": "recommendation", + "guid": "782065a8-04b9-4cf6-adec-da6ba3e6e42b" }, { "waf": "Reliability", "service": "Azure Files", "text": "Before you initiate a failover or failback, check the value of the last synchronization time property to evaluate the potential for data loss. This recommendation applies only to GRS and GZRS configurations.", "description": "This property helps you estimate how much data you might lose if you initiate an account failover. All data and metadata that's written before the last synchronization time is available on the secondary region, but you might lose data and metadata that's written after the last synchronization time because it's not written to the secondary region.", - "type": "recommendation" + "type": "recommendation", + "guid": "16e559b4-0842-4a5f-83bf-16dc3e3cbfe8" }, { "waf": "Reliability", "service": "Azure Files", "text": "As a part of your backup and recovery strategy, enable\u202fsoft delete\u202fand\u202fuse snapshots for point-in-time restore. You can use Azure Backup to back up your SMB file shares. You can also use Azure File Sync to back up on-premises SMB file shares to an Azure file share. Azure Backup also allows you to do a vaulted backup (preview) of Azure Files to protect your data from ransomware attacks or source data loss due to a malicious actor or rogue admin. By using vaulted backup, Azure Backup copies and stores data in the Recovery Services vault. This creates an offsite copy of data that you can retain for up to 99 years. Azure Backup creates and manages the recovery points as per the schedule and retention defined in the backup policy. Learn more.", "description": "Soft delete works on a file share level to protect Azure file shares against accidental deletion. Point-in-time restore protects against accidental deletion or corruption because you can restore file shares to an earlier state. For more information, see Data protection overview.", - "type": "recommendation" + "type": "recommendation", + "guid": "7011d46a-99b8-49ff-944e-26f5cc2b817c" }, { "waf": "Security", "service": "Azure Files", "text": "Apply an Azure Resource Manager lock on the storage account.", "description": "Lock the account to prevent accidental or malicious deletion of the storage account, which can cause data loss.", - "type": "recommendation" + "type": "recommendation", + "guid": "750b7241-5ddc-4a6a-9e06-0019d5d3dd99" }, { "waf": "Security", "service": "Azure Files", "text": "Open TCP port 445 outbound or set up a VPN gateway or Azure ExpressRoute connection for clients outside of Azure to access the file share.", "description": "SMB 3.x is an internet-safe protocol, but you might not have the ability to change organizational or ISP policies. You can use a VPN gateway or an ExpressRoute connection as an alternative option.", - "type": "recommendation" + "type": "recommendation", + "guid": "544aa9b7-1339-462b-b05d-423bfa23f160" }, { "waf": "Security", "service": "Azure Files", "text": "If you open port 445, be sure to disable SMBv1 on Windows and Linux clients. Azure Files doesn't support SMB 1, but you should still disable it on your clients.", "description": "SMB 1 is an outdated, inefficient, and insecure protocol. Disable it on clients to improve your security posture.", - "type": "recommendation" + "type": "recommendation", + "guid": "68e6b6ec-0d1a-4b5b-b864-0a84684d9dd2" }, { "waf": "Security", "service": "Azure Files", "text": "Consider disabling public network access to your storage account. Enable public network access only if SMB clients and services that are external to Azure require access to your storage account. If you disable public network access,create a private endpoint for your storage account. Standard data processing rates for private endpoints apply. A private endpoint doesn't block connections to the public endpoint. You should still disable public network access as previously described. If you don't require a static IP address for your file share and want to avoid the cost of private endpoints, you can instead restrict public endpoint access to specific virtual networks and IP addresses.", "description": "Network traffic travels over the Microsoft backbone network instead of the public internet, which eliminates risk exposure from the public internet.", - "type": "recommendation" + "type": "recommendation", + "guid": "aa4bcf28-fe1b-487d-8aca-57a4ca53e481" }, { "waf": "Security", "service": "Azure Files", "text": "Enable firewall rules that limit access to specific virtual networks. Start with zero access, and then methodically and incrementally provide the least amount of access required for clients and services.", "description": "Minimize the risk of creating openings for attackers.", - "type": "recommendation" + "type": "recommendation", + "guid": "2c486988-91fe-46d6-bb1b-695f9c3f32bd" }, { "waf": "Security", "service": "Azure Files", "text": "When possible, use identity-based authentication with AES-256 Kerberos ticket encryption to authorize access to SMB Azure file shares.", "description": "Use identity-based authentication to decrease the possibility of an attacker using a storage account key to access file shares.", - "type": "recommendation" + "type": "recommendation", + "guid": "66352a0c-5c71-46d4-85c5-b5097fe941a6" }, { "waf": "Security", "service": "Azure Files", "text": "If you use storage account keys, store them in Key Vault, and make sure to regenerate them periodically. You can completely disallow storage account key access to the file share by removing NTLMv2 from the share's SMB security settings. But you generally shouldn't remove NTLMv2 from the share's SMB security settings because administrators still need to use the account key for some tasks.", "description": "Use Key Vault to retrieve keys at runtime instead of saving them with your application. Key Vault also makes it easy to rotate your keys without interruption to your applications. Periodically rotate the account keys to reduce the risk of exposing your data to malicious attacks.", - "type": "recommendation" + "type": "recommendation", + "guid": "d39ad222-964f-4404-b8c4-bad919fca4ae" }, { "waf": "Security", "service": "Azure Files", "text": "In most cases, you should enable the Secure transfer required option on all your storage accounts to enable encryption in transit for SMB file shares. Don't enable this option if you need to allow very old clients to access the share. If you disable secure transfer, be sure to use network controls to restrict traffic.", "description": "This setting ensures that all requests that are made against the storage account take place over secure connections (HTTPS). Any requests made over HTTP will fail.", - "type": "recommendation" + "type": "recommendation", + "guid": "536e86a5-e2ea-47a2-8853-82651ced1265" }, { "waf": "Security", "service": "Azure Files", "text": "Configure your storage account so that TLS 1.2 is the minimum version for clients to send and receive data.", "description": "TLS 1.2 is more secure and faster than TLS 1.0 and 1.1, which don't support modern cryptographic algorithms and cipher suites.", - "type": "recommendation" + "type": "recommendation", + "guid": "80854b65-9017-498a-9b12-9e5aa5d6b93b" }, { "waf": "Security", "service": "Azure Files", "text": "Use only the most recent supported SMB protocol version (currently 3.1.1.), and use only AES-256-GCM for SMB channel encryption. Azure Files exposes settings that you can use to toggle the SMB protocol and make it more compatible or more secure, depending on your organization's requirements. By default, all SMB versions are allowed. However, SMB 2.1 is disallowed if you enable Require secure transfer because SMB 2.1 doesn't support encryption of data in transit. If you restrict these settings to a high level of security, some clients might not be able to connect to the file share.", "description": "SMB 3.1.1, released with Windows 10, contains important security and performance updates. AES-256-GCM offers more secure channel encryption.", - "type": "recommendation" + "type": "recommendation", + "guid": "41a8d523-2cb4-499b-9a7f-e9cdc708e28e" }, { "waf": "Security", "service": "Azure Files", "text": "Apply a Resource Manager lock on the storage account.", "description": "Lock the account to prevent accidental or malicious deletion of the storage account, which might cause data loss.", - "type": "recommendation" + "type": "recommendation", + "guid": "ca0d9179-144c-4ef2-a617-046f3983000e" }, { "waf": "Security", "service": "Azure Files", "text": "You must open port 2049 on the clients that you want to mount your NFS share to.", "description": "Open port 2049 to let clients communicate with the NFS Azure file share.", - "type": "recommendation" + "type": "recommendation", + "guid": "e6ee6652-c7bf-474b-b47e-e0d739e94901" }, { "waf": "Security", "service": "Azure Files", "text": "NFS Azure file shares are only accessible through restricted networks. So you must create a private endpoint for your storage account or restrict public endpoint access to selected virtual networks and IP addresses. We recommend that you create a private endpoint. You must configure network-level security for NFS shares because Azure Files doesn't support encryption in transit with the NFS protocol. You need to disable the Require secure transfer setting on the storage account to use NFS Azure file shares. Standard data processing rates apply for private endpoints. If you don't require a static IP address for your file share and want to avoid the cost of private endpoints, you can restrict public endpoint access instead.", "description": "Network traffic travels over the Microsoft backbone network instead of the public internet, which eliminates risk exposure from the public internet.", - "type": "recommendation" + "type": "recommendation", + "guid": "e79615fa-f453-43f7-b9db-e4564a08fa6e" }, { "waf": "Security", "service": "Azure Files", "text": "Consider disallowing storage account key access at the storage account level. You don't need this access to mount NFS file shares. But keep in mind that full administrative control of a file share, including the ability to take ownership of a file, requires use of a storage account key.", "description": "Disallow the use of storage account keys to make your storage account more secure.", - "type": "recommendation" + "type": "recommendation", + "guid": "5d1ca94b-ac1b-482c-922e-8ee47b9c7ba6" }, { "waf": "Cost", "service": "Azure Files", "text": "When you migrate to standard Azure file shares, we recommend that you start in the transaction-optimized tier during the initial migration. Transaction usage during migration isn't typically indicative of normal transaction usage. This consideration doesn't apply for premium file shares because the provisioned billing model doesn't charge for transactions.", "description": "Migrating to Azure Files is a temporary, transaction-heavy workload. Optimize the price for high-transaction workloads to help reduce migration costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "e9863488-d023-4763-a169-161d1dba4b02" }, { "waf": "Cost", "service": "Azure Files", "text": "After you migrate your workload, if you use standard file shares, carefully choose the most cost effective access tier for your file share: hot, cool, or transaction optimized. After you operate for a few days or weeks with regular usage, you can insert your transaction counts in the pricing calculator to figure out which tier best suits your workload. Most customers should choose cool even if they actively use the share. But you should examine each share and compare the balance of storage capacity to transactions to determine your tier. If transaction costs make up a significant percentage of your bill, the savings from using the cool access tier often offsets this cost and minimizes the total overall cost. We recommend that you move standard file shares between access tiers only when necessary to optimize for changes in your workload pattern. Each move incurs transactions. For more information, see Switching between standard tiers.", "description": "Select the appropriate access tier for standard file shares to considerably reduce your costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "51b872e9-5fcd-44eb-931f-9a249e459e65" }, { "waf": "Cost", "service": "Azure Files", "text": "If you use premium shares, ensure that you provision more than enough capacity and performance for your workload but not so much that you incur unnecessary costs. We recommend overprovisioning by two to three times. You can dynamically scale premium file shares up or down depending on your storage and input/output (IO) performance characteristics.", "description": "Overprovision premium file shares by a reasonable amount to help maintain performance and account for future growth and performance requirements.", - "type": "recommendation" + "type": "recommendation", + "guid": "534d8587-584b-4b2c-b671-3effdcbd01be" }, { "waf": "Cost", "service": "Azure Files", "text": "Use Azure Files reservations, also referred to as reserved instances, to precommit to storage usage and get a discount. Use reservations for production workloads or dev/test workloads with consistent footprints. For more information, see Optimize costs with storage reservations. Reservations don't include transaction, bandwidth, data transfer, and metadata storage charges.", "description": "Three-year reservations can provide a discount up to 36% on the total cost of file storage. Reservations don't affect performance.", - "type": "recommendation" + "type": "recommendation", + "guid": "e2101858-bba3-4f27-b2b6-aa5c34bce700" }, { "waf": "Cost", "service": "Azure Files", "text": "Monitor snapshot usage. Snapshots incur charges, but they're billed based on the differential storage usage of each snapshot. You pay only for the difference in each snapshot. For more information, see Snapshots. Azure File Sync takes share-level and file-level snapshots as part of regular usage, which can increase your total Azure Files bill.", "description": "Differential snapshots ensure that you're not billed multiple times for storing the same data. However, you should still monitor snapshot usage to help reduce your Azure Files bill.", - "type": "recommendation" + "type": "recommendation", + "guid": "92ac1897-48f1-4f92-8305-462072504522" }, { "waf": "Cost", "service": "Azure Files", "text": "Set retention periods for the soft-delete feature, especially when you first start using it. Consider starting with a short retention period to better understand how the feature affects your bill. The minimum recommended retention period is seven days. When you soft delete standard and premium file shares, they're billed as used capacity rather than provisioned capacity. And premium file shares are billed at the snapshot rate while in the soft-delete state. Standard file shares are billed at the regular rate while in the soft-delete state.", "description": "Set a retention period so that soft-deleted files don't pile up and increase the cost of capacity. After the configured retention period, permanently deleted data doesn't incur cost.", - "type": "recommendation" + "type": "recommendation", + "guid": "06ba65dd-f706-428a-9e28-f25b2239e603" }, { "waf": "Operations", "service": "Azure Files", "text": "Use infrastructure as code (IaC) to define the details of your storage accounts in Azure Resource Manager templates (ARM templates), Bicep, or Terraform.", "description": "You can use your existing DevOps processes to deploy new storage accounts, and use Azure Policy to enforce their configuration.", - "type": "recommendation" + "type": "recommendation", + "guid": "a40b648a-7c87-45d0-815b-47495a2b0e01" }, { "waf": "Operations", "service": "Azure Files", "text": "Use Storage insights to track the health and performance of your storage accounts. Storage insights provides a unified view of the failures, performance, availability, and capacity for all your storage accounts.", "description": "You can track the health and operation of each of your accounts. Easily create dashboards and reports that stakeholders can use to track the health of your storage accounts.", - "type": "recommendation" + "type": "recommendation", + "guid": "f63aa6ba-25c6-49be-bda2-0c51c1d571b5" }, { "waf": "Operations", "service": "Azure Files", "text": "Use Monitor to analyze metrics, such as availability, latency, and usage, and to create alerts.", "description": "Monitor provides a view of availability, performance, and resiliency for your file shares.", - "type": "recommendation" + "type": "recommendation", + "guid": "15160eee-b0c3-48cd-ba6d-0f8577ffcd61" }, { "waf": "Performance", "service": "Azure Files", "text": "Enable SMB Multichannel for premium SMB file shares. SMB Multichannel allows an SMB 3.1.1 client to establish multiple network connections to an SMB Azure file share. SMB Multichannel only works when the feature is enabled on both client-side (your client) and service-side (Azure). On Windows clients, SMB Multichannel is enabled by default, but you need to enable it on your storage account.", "description": "Increase throughput and IOPS while reducing the total cost of ownership. Performance benefits increase with the number of files that distribute load.", - "type": "recommendation" + "type": "recommendation", + "guid": "daf30eda-f801-45ee-be0e-03d46dc88f79" }, { "waf": "Performance", "service": "Azure Files", "text": "Use the nconnect client-side mount option with NFS Azure file shares on Linux clients. Nconnect enables you to use more TCP connections between the client and the Azure Files premium service for NFSv4.1.", "description": "Increase performance at scale, and reduce the total cost of ownership for NFS file shares.", - "type": "recommendation" + "type": "recommendation", + "guid": "9efba372-db55-473f-a8bb-26f0c718612f" }, { "waf": "Performance", "service": "Azure Files", "text": "Make sure your file share or storage account isn't being throttled, which can result in high latency, low throughput, or low IOPS. Requests are throttled when the IOPS, ingress, or egress limits are reached. For standard storage accounts, throttling occurs at the account level. For premium file shares, throttling usually occurs at the share level.", "description": "Avoid throttling to provide the best possible client experience.", - "type": "recommendation" + "type": "recommendation", + "guid": "6da39eb6-e932-4c5a-a2f2-6b728108cd7b" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -272,6 +301,6 @@ "name": "Azure Files Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azurefirewall_sg_checklist.en.json b/checklists-ext/azurefirewall_sg_checklist.en.json index 102737ef9..9e2710dc2 100644 --- a/checklists-ext/azurefirewall_sg_checklist.en.json +++ b/checklists-ext/azurefirewall_sg_checklist.en.json @@ -6,355 +6,401 @@ "service": "Azure Firewall", "text": "Use Azure Firewall Manager with traditional Hub & Spokes or Azure Virtual WAN network topologies to deploy and manage instances of Azure Firewall.", "description": "Easily create hub-and-spoke and transitive architectures with native security services for traffic governance and protection. For more information on network topologies, see the Azure Cloud Adoption Framework documentation.", - "type": "recommendation" + "type": "recommendation", + "guid": "906a66c0-f3fc-4766-bcc9-f483a13302d0" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Create Azure Firewall Policies to govern the security posture across global network environments. Assign policies to all instances of Azure Firewall.", "description": "Azure Firewall Policies can be arranged in an hierarchical structure to overlay a central base policy. Allow for granular policies to meet the requirements of specific regions. Delegate incremental firewall policies to local security teams through role-based access control (RBAC). Some settings are specific per instance, for example DNAT Rules and DNS configuration, then multiple specialized policies might be required.", - "type": "recommendation" + "type": "recommendation", + "guid": "02b98555-573c-44ff-b81b-8cf4d6c246c3" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Migrate Azure Firewall Classic Rules to Azure Firewall Manager Policies for existing deployments.", "description": "For existing deployments, migrate Azure Firewall rules to Azure Firewall Manager policies. Use Azure Firewall Manager to centrally manage your firewalls and policies. For more information, see Migrate to Azure Firewall Premium.", - "type": "recommendation" + "type": "recommendation", + "guid": "d122223e-4634-4b87-8736-1fe446f2dc4b" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Review the list of Azure Firewall Known Issues.", "description": "Azure Firewall Product Group maintains an updated list of known-issues at this location. This list contains important information related to by-design behavior, fixes under construction, platform limitations, along with possible workarounds or mitigation.", - "type": "recommendation" + "type": "recommendation", + "guid": "7aa2c745-40cd-494b-a465-e3f57aa5db89" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Ensure your Azure Firewall Policy adheres to Azure Firewall limits and recommendations.", "description": "There are limits on the policy structure, including numbers of Rules and Rule Collection Groups, total policy size, source/target destinations. Be sure to compose your policy and stay behind the documented thresholds.", - "type": "recommendation" + "type": "recommendation", + "guid": "a5d749c4-2d8f-4503-89d8-d09590d0cb75" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Deploy Azure Firewall across multiple availability zones for higher service-level agreement (SLA).", "description": "Azure Firewall provides different SLAs when it's deployed in a single availability zone and when it's deployed in multiple zones. For more information, see SLA for Azure Firewall. For information about all Azure SLAs, see SLA summary for Azure services.", - "type": "recommendation" + "type": "recommendation", + "guid": "2abbe12f-832c-4c12-9ef2-7b5941de0d1c" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "In multi-region environments, deploy an Azure Firewall instance per region.", "description": "For traditional Hub & Spokes architectures, multi-region details are explained in this article. For secured virtual hubs (Azure Virtual WAN), Routing Intent and Policies must be configured to secure inter-hub and branch-to-branch communications. For workloads designed to be resistant to failures and fault tolerant, remember to consider that instances of Azure Firewall and Azure Virtual Network as regional resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "a5a128ef-71f4-4001-8cd8-01afdf78ed87" }, { "waf": "Reliability", "service": "Azure Firewall", "text": "Monitor Azure Firewall Metrics and Resource Health state.", "description": "Closely monitor key metrics indicator of Azure Firewall health state such as Throughput, Firewall health state, SNAT port utilization and AZFW Latency Probe metrics. Additionally, Azure Firewall now integrates with Azure Resource Health. With the Azure Firewall Resource Health check, you can now view the health status of your Azure Firewall and address service problems that might affect your Azure Firewall resource.", - "type": "recommendation" + "type": "recommendation", + "guid": "b2e9619a-7495-4f85-8baf-1cf06575a966" }, { "waf": "Security", "service": "Azure Firewall", "text": "If required to route all internet-bound traffic to a designated next hop instead of going directly to the internet, configure Azure Firewall in forced tunneling mode (does not apply to Azure Virtual WAN).", "description": "Azure Firewall must have direct internet connectivity. If your AzureFirewallSubnet learns a default route to your on-premises network via the Border Gateway Protocol, you must configure Azure Firewall in the forced tunneling mode. Using the forced tunneling feature, you'll need another /26 address space for the Azure Firewall Management subnet. You're required to name it AzureFirewallManagementSubnet.If this is an existing Azure Firewall instance that can't be reconfigured in the forced tunneling mode, create a UDR with a 0.0.0.0/0 route. Set the NextHopType value as Internet. Associate it with AzureFirewallSubnet to maintain internet connectivity.", - "type": "recommendation" + "type": "recommendation", + "guid": "77e598e8-9cf8-43d0-931f-4ad1cedfee4a" }, { "waf": "Security", "service": "Azure Firewall", "text": "Set the public IP address to None to deploy a fully private data plane when you configure Azure Firewall in the forced tunneling mode (does not apply to Azure Virtual WAN).", "description": "When you deploy a new Azure Firewall instance, if you enable the forced tunneling mode, you can set the public IP address to None to deploy a fully private data plane. However, the management plane still requires a public IP for management purposes only. The internal traffic from virtual and on-premises networks won't use that public IP. For more about forced tunneling, see Azure Firewall forced tunneling.", - "type": "recommendation" + "type": "recommendation", + "guid": "dbc69891-14e6-428c-adca-cd11b01d9226" }, { "waf": "Security", "service": "Azure Firewall", "text": "Create rules for Firewall Policies based on least privilege access criteria.", "description": "Azure Firewall Policies can be arranged in an hierarchical structure to overlay a central base policy. Allow for granular policies to meet the requirements of specific regions. Each policy can contains different sets of DNAT, Network and Application rules with specific priority, action and processing order. Create your rules based on least privilege access Zero Trust principle . How rules are processed is explained in this article.", - "type": "recommendation" + "type": "recommendation", + "guid": "a25be6b5-03c3-4bee-a348-ba338419ee17" }, { "waf": "Security", "service": "Azure Firewall", "text": "Enable IDPS in Alert or Alert and deny mode.", "description": "IDPS is one of the most powerful Azure Firewall (Premium) security features and should be enabled. Based on security and application requirements, and considering the performance impact (see the Cost section below), Alert or Alert and deny modes can be selected.", - "type": "recommendation" + "type": "recommendation", + "guid": "5c7fbe3b-1d6d-49c4-bed1-2ac02ec15444" }, { "waf": "Security", "service": "Azure Firewall", "text": "Enable Azure Firewall (DNS) proxy configuration.", "description": "Enabling this feature points clients in the VNets to Azure Firewall as a DNS server. It will protect internal DNS infrastructure that will not be directly accessed and exposed. Azure Firewall must be also configured to use custom DNS that will be used to forward DNS queries.", - "type": "recommendation" + "type": "recommendation", + "guid": "1ed3e1a5-0748-4ae3-92c4-61cdc805a881" }, { "waf": "Security", "service": "Azure Firewall", "text": "Configure user-defined routes (UDR) to force traffic through Azure Firewall.", "description": "In a traditional Hub & Spokes architecture, configure UDRs to force traffic through Azure Firewall for `SpoketoSpoke`, `SpoketoInternet`, and `SpoketoHybrid` connectivity. In Azure Virtual WAN, instead, configure Routing Intent and Policies to redirect private and/or Internet traffic through the Azure Firewall instance integrated into the hub.", - "type": "recommendation" + "type": "recommendation", + "guid": "219a0f29-198c-43ff-86b6-dd5887856c9f" }, { "waf": "Security", "service": "Azure Firewall", "text": "If not possible to apply UDR, and only web traffic redirection is required, consider using Azure Firewall as an Explicit Proxy", "description": "With explicit proxy feature enabled on the outbound path, you can configure a proxy setting on the sending web application (such as a web browser) with Azure Firewall configured as the proxy. As a result, web traffic will reach the firewall's private IP address and therefore egresses directly from the firewall without using a UDR. This feature also facilitates the usage of multiple firewalls without modifying existing network routes.", - "type": "recommendation" + "type": "recommendation", + "guid": "4ba66379-9878-42b4-bc50-d6495cf000b4" }, { "waf": "Security", "service": "Azure Firewall", "text": "Configure supported third-party software as a service (SaaS) security providers within Firewall Manager if you want to use these solutions to protect outbound connections.", "description": "You can use your familiar, best-in-breed, third-party SECaaS offerings to protect internet access for your users. This scenario does require Azure Virtual WAN with a S2S VPN Gateway in the Hub, as it uses an IPSec tunnel to connect to the provider's infrastructure. SECaaS providers might charge additional license fees and limit throughput on IPSec connections. Alternative solutions such as ZScaler Cloud Connector exist and might be more suitable.", - "type": "recommendation" + "type": "recommendation", + "guid": "0e0c6a0a-0627-47cc-8581-34280d7d4cba" }, { "waf": "Security", "service": "Azure Firewall", "text": "Use Fully Qualified Domain Name (FQDN) filtering in network rules.", "description": "You can use FQDN based on DNS resolution in Azure Firewall and firewall policies. This capability allows you to filter outbound traffic with any TCP/UDP protocol (including NTP, SSH, RDP, and more). You must enable the Azure Firewall DNS Proxy configuration to use FQDNs in your network rules. To learn how it works, see Azure Firewall FQDN filtering in network rules.", - "type": "recommendation" + "type": "recommendation", + "guid": "f6b95447-f9b8-46e0-b068-f9116791466d" }, { "waf": "Security", "service": "Azure Firewall", "text": "Use Service Tags in Network Rules to enable selective access to specific Microsoft services.", "description": "A service tag represents a group of IP address prefixes to help minimize complexity for security rule creation. Using Service Tags in Network Rules, it is possible to enable outbound access to specific services in Azure, Dynamics and Office 365 without opening wide ranges of IP addresses. Azure will maintain automatically the mapping between these tags and underlying IP addresses used by each service. The list of Service Tags available to Azure Firewall are listed here: Az Firewall Service Tags.", - "type": "recommendation" + "type": "recommendation", + "guid": "101e4c48-234c-48fb-84a2-f23915ecbf15" }, { "waf": "Security", "service": "Azure Firewall", "text": "Use FQDN Tags in Application Rules to enable selective access to specific Microsoft services.", "description": "An FQDN tag represents a group of fully qualified domain names (FQDNs) associated with well known Microsoft services. You can use an FQDN tag in application rules to allow the required outbound network traffic through your firewall for some specific Azure services, Office 365, Windows 365 and Intune.", - "type": "recommendation" + "type": "recommendation", + "guid": "88d9e6f8-4f96-4c83-9268-b3f7cfbd0559" }, { "waf": "Security", "service": "Azure Firewall", "text": "Use Azure Firewall Manager to create and associate a DDoS protection plan with your hub virtual network (does not apply to Azure Virtual WAN).", "description": "A DDoS protection plan provides enhanced mitigation features to defend your firewall from DDoS attacks. Azure Firewall Manager is an integrated tool to create your firewall infrastructure and DDoS protection plans. For more information, see Configure an Azure DDoS Protection Plan using Azure Firewall Manager.", - "type": "recommendation" + "type": "recommendation", + "guid": "6681988b-11df-4ea7-aee0-f7d5a1335ae0" }, { "waf": "Security", "service": "Azure Firewall", "text": "Use an Enterprise PKI to generate certificates for TLS Inspection.", "description": "With Azure Firewall Premium, if TLS Inspection feature is used, it is recommended to leverage an internal Enterprise Certification Authority (CA) for production environment. Self-signed certificates should be used for testing/PoC purposes only.", - "type": "recommendation" + "type": "recommendation", + "guid": "d6f023f6-dd16-4f48-9da7-18d0e0b0ef5b" }, { "waf": "Security", "service": "Azure Firewall", "text": "Review Zero-Trust configuration guide for Azure Firewall and Application Gateway", "description": "If your security requirements necessitate implementing a Zero-Trust approach for web applications (inspection and encryption), it is recommended to follow this guide. In this document, how to integrate together Azure Firewall and Application Gateway will be explained, in both traditional Hub & Spoke and Virtual WAN scenarios.", - "type": "recommendation" + "type": "recommendation", + "guid": "72a05358-270e-4985-878d-3f638d2bfbf2" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Deploy the proper Azure Firewall SKU.", "description": "Azure Firewall can be deployed in three different SKUs: Basic, Standard and Premium. Azure Firewall Premium is recommended to secure highly sensitive applications (such as payment processing). Azure Firewall Standard is recommended for customers looking for Layer 3\u2013Layer 7 firewall and needs autoscaling to handle peak traffic periods of up to 30 Gbps. Azure Firewall Basic is recommended for SMB customers with throughput needs of 250 Mbps. If required, downgrade or upgrade is possible between Standard and Premium as documented here. For more information, see Choose the right Azure Firewall SKU to meet your needs.", - "type": "recommendation" + "type": "recommendation", + "guid": "32d1cc86-0c04-4c38-be59-14e6bbe3d020" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Stop Azure Firewall deployments that don't need to run for 24x7.", "description": "You might have development or testing environments that are used only during business hours. For more information, see Deallocate and allocate Azure Firewall.", - "type": "recommendation" + "type": "recommendation", + "guid": "27745055-45fb-4108-89af-a63b1170f7d6" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Share the same instance of Azure Firewall across multiple workloads and Azure Virtual Networks.", "description": "You can use a central instance of Azure Firewall in the hub virtual network or Virtual WAN secure hub and share the same firewall across many spoke virtual networks that are connected to the same hub from the same region. Ensure there's no unexpected cross-region traffic as part of the hub-spoke topology.", - "type": "recommendation" + "type": "recommendation", + "guid": "90ed4bf4-2371-4a63-bea1-c5c5005e4f08" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Regularly review traffic processed by Azure Firewall and look for originating workload optimizations", "description": "Top Flows log (known in the industry as Fat Flows), shows the top connections that are contributing to the highest throughput through the firewall. It is recommended to regularly review traffic processed by the Azure Firewall and search for possible optimizations to reduce the amount of traffic traversing the firewall.", - "type": "recommendation" + "type": "recommendation", + "guid": "1020c3ff-e072-4de9-98d8-7c38bce266b9" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Review under-utilized Azure Firewall instances. Identify and delete unused Azure Firewall deployments.", "description": "To identify unused Azure Firewall deployments, start by analyzing the monitoring metrics and UDRs associated with subnets pointing to the firewall's private IP. Combine that information with other validations, such as if your instance of Azure Firewall has any rules (classic) for NAT, Network and Application, or even if the DNS Proxy setting is configured to Disabled, and with internal documentation about your environment and deployments. You can detect deployments that are cost-effective over time. For more information about monitoring logs and metrics, see Monitor Azure Firewall logs and metrics and SNAT port utilization.", - "type": "recommendation" + "type": "recommendation", + "guid": "b4581201-7d7a-41b0-ab7d-cacdb77d6cfa" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Use Azure Firewall Manager and its Policies to reduce operational costs, increase efficiency, and reduce management overhead.", "description": "Review your Firewall Manager policies, associations, and inheritance carefully. Policies are billed based on firewall associations. A policy with zero or one firewall association is free of charge. A policy with multiple firewall associations is billed at a fixed rate.For more information, see Pricing - Azure Firewall Manager.", - "type": "recommendation" + "type": "recommendation", + "guid": "4f9685b1-7f7e-413b-a5c8-03b734e9eade" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Delete unused public IP addresses.", "description": "Validate whether all the associated public IP addresses are in use. If they aren't in use, disassociate and delete them. Evaluate SNAT port utilization before removing any IP addresses.You'll only use the number of public IPs your firewall needs. For more information, see Monitor Azure Firewall logs and metrics and SNAT port utilization.", - "type": "recommendation" + "type": "recommendation", + "guid": "7f7ce673-1cff-42f8-8deb-7f018d7ceb20" }, { "waf": "Cost", "service": "Azure Firewall", "text": "Review logging requirements.", "description": "Azure Firewall has the ability to comprehensively log metadata of all traffic it sees, to Log Analytics Workspaces, Storage or third party solutions through Event Hubs. However, all logging solutions incur costs for data processing and storage. At very large volumes these costs can be significant, a cost effective approach and alternative to Log Analytics should be considered and cost estimated. Consider whether it is required to log traffic metadata for all logging categories and modify in Diagnostic Settings if needed.", - "type": "recommendation" + "type": "recommendation", + "guid": "e0e0d21e-8a8c-4a88-b714-b7eff11570c7" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Do not use Azure Firewall for intra-VNet traffic control.", "description": "Azure Firewall should be used to control traffic across VNets, between VNets and on-premises networks, outbound traffic to the Internet and incoming non-HTTP/s traffic. For intra-VNet traffic control, it is recommended to use Network Security Groups.", - "type": "recommendation" + "type": "recommendation", + "guid": "e94d1a6f-cfb1-4fd9-8f48-ad6cb7065081" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Maintain regular backups of Azure Policy artifacts.", "description": "If Infrastructure-as-Code (IaC) approach is used to maintain Azure Firewall and all dependencies then backup and versioning of Azure Firewall Policies should be already in place. If not, a companion mechanism based on external Logic App can be deployed to automate and provide an effective solution.", - "type": "recommendation" + "type": "recommendation", + "guid": "b0219e9d-82f0-4760-bc2a-4d8909636794" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Enable Diagnostic Logs for Azure Firewall.", "description": "Diagnostic Logs is a key component for many monitoring tools and strategies for Azure Firewall and should be enabled. You can monitor Azure Firewall by using firewall logs or workbooks. You can also use activity logs for auditing operations on Azure Firewall resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "3cffb79e-0a6b-4dad-b781-d17d1e270127" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Use Structured Firewall Logs format.", "description": "Structured Firewall Logs are a type of log data that are organized in a specific new format. They use a predefined schema to structure log data in a way that makes it easy to search, filter, and analyze. The latest monitoring tools are based on this type of logs hence it is often a pre-requisite. Use the previous Diagnostic Logs format only if there is an existing tool with a pre-requisite on that. Do not enable both logging formats at the same time.", - "type": "recommendation" + "type": "recommendation", + "guid": "a66b781d-3445-4076-8c69-4b9dcd2bded5" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Use the built-in Azure Firewall Monitoring Workbook.", "description": "Azure Firewall portal experience now includes a new workbook under the Monitoring section UI, a separate installation is no more required. With the Azure Firewall Workbook, you can extract valuable insights from Azure Firewall events, delve into your application and network rules, and examine statistics regarding firewall activities across URLs, ports, and addresses.", - "type": "recommendation" + "type": "recommendation", + "guid": "60a9b0b2-a45c-4012-a059-18430a4c7ad3" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Monitor key metrics and create alerts for indicators of the utilization of Azure Firewall capacity.", "description": "Alerts should be created to monitor at least Throughput, Firewall health state, SNAT port utilization and AZFW Latency Probe metrics.For information about monitoring logs and metrics, see Monitor Azure Firewall logs and metrics.", - "type": "recommendation" + "type": "recommendation", + "guid": "4c65a0f6-ea2d-46e8-bba3-9b8dea771bb8" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Configure Azure Firewall integration with Microsoft Defender for Cloud and Microsoft Sentinel.", "description": "If these tools are available in the environment, it is recommended to leverage integration with Microsoft Defender for Cloud and Microsoft Sentinel solutions. With Microsoft Defender for Cloud integration, you can visualize the all-up status of network infrastructure and network security in one place, including Azure Network Security across all VNets and Virtual Hubs spread across different regions in Azure. Integration with Microsoft Sentinel provides threat detection and prevention capabilities.", - "type": "recommendation" + "type": "recommendation", + "guid": "bba04e81-c422-427b-b203-350c1d3a724a" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Regularly review Policy Analytics dashboard to identify potential issues.", "description": "Policy Analytics is a new feature that provides insights into the impact of your Azure Firewall policies. It helps you identify potential issues (hitting policy limits, low utilization rules, redundant rules, rules too generic, IP Groups usage recommendation) in your policies and provides recommendations to improve your security posture and rule processing performance.", - "type": "recommendation" + "type": "recommendation", + "guid": "b171bd4a-f474-4249-b450-0f09e8fd9ded" }, { "waf": "Operations", "service": "Azure Firewall", "text": "Become familiar with KQL (Kusto Query Language) queries to allow quick analysis and troubleshooting using Azure Firewall logs.", "description": "Sample queries are provided for Azure Firewall. Those will enable you to quickly identify what's happening inside your firewall and check to see which rule was triggered, or which rule is allowing/blocking a request.", - "type": "recommendation" + "type": "recommendation", + "guid": "acfff57b-8cbb-4643-bb47-c8ada4c360cd" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Use Policy Analytics dashboard to identify potential optimizations for Firewall Policies.", "description": "Policy Analytics is a new feature that provides insights into the impact of your Azure Firewall policies. It helps you identify potential issues (hitting policy limits, low utilization rules, redundant rules, rules too generic, IP Groups usage recommendation) in your policies and provides recommendations to improve your security posture and rule processing performance.", - "type": "recommendation" + "type": "recommendation", + "guid": "5997898f-94eb-41bf-831c-64768c577d59" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Consider Web Categories to allow or deny outbound access in bulk.", "description": "Instead of explicitly building and maintaining a long list of public Internet sites, consider the usage of Azure Firewall Web Categories. This feature will dynamically categorize web content and will permit the creation of compact Application Rules.", - "type": "recommendation" + "type": "recommendation", + "guid": "a413ad7f-d747-401c-8b4d-f670e1a500fd" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Evaluate the performance impact of IDPS in Alert and deny mode.", "description": "If Azure Firewall is required to operate in IDPS mode Alert and deny, carefully consider the performance impact as documented in this page.", - "type": "recommendation" + "type": "recommendation", + "guid": "b3794bbc-ca9f-46c2-b857-e3c369b2a2ee" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Assess potential SNAT port exhaustion problem.", "description": "Azure Firewall currently supports 2496 ports per Public IP address per backend Virtual Machine Scale Set instance. By default, there are two Virtual Machine Scale Set instances. So, there are 4992 ports per flow destination IP, destination port and protocol (TCP or UDP). The firewall scales up to a maximum of 20 instances. You can work around the limits by configuring Azure Firewall deployments with a minimum of five public IP addresses for deployments susceptible to SNAT exhaustion.", - "type": "recommendation" + "type": "recommendation", + "guid": "8ebc6c2c-afad-475f-bf6f-87fb04a32cbb" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Properly warm up Azure Firewall before any performance test.", "description": "Create initial traffic that isn't part of your load tests 20 minutes before the test. Use diagnostics settings to capture scale-up and scale-down events. You can use the Azure Load Testing service to generate the initial traffic. Allows the Azure Firewall instance to scale up its instances to the maximum.", - "type": "recommendation" + "type": "recommendation", + "guid": "d4359622-ee34-46fe-84bd-c123458b7ddb" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Configure an Azure Firewall subnet (AzureFirewallSubnet) with a /26 address space.", "description": "Azure Firewall is a dedicated deployment in your virtual network. Within your virtual network, a dedicated subnet is required for the instance of Azure Firewall. Azure Firewall provisions more capacity as it scales.A /26 address space for its subnets ensures that the firewall has enough IP addresses available to accommodate the scaling. Azure Firewall doesn't need a subnet bigger than /26. The Azure Firewall subnet name must be AzureFirewallSubnet.", - "type": "recommendation" + "type": "recommendation", + "guid": "853d3967-f7e9-4019-bb9b-07957fb885b3" }, { "waf": "Performance", "service": "Azure Firewall", "text": "Do not enable advanced logging if not required", "description": "Azure Firewall provides some advanced logging capabilities that can be expensive to maintain always active. Instead, they should be used for troubleshooting purposes only, and limited in duration, then disabled when no more necessary. For example, Top flows and Flow trace logs are expensive can cause excessive CPU and storage usage on the Azure Firewall infrastructure.", - "type": "recommendation" + "type": "recommendation", + "guid": "62b90b2f-195d-4897-9537-e1164449b0d6" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -391,6 +437,6 @@ "name": "Azure Firewall Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azurefrontdoor_sg_checklist.en.json b/checklists-ext/azurefrontdoor_sg_checklist.en.json index 32f6d81d0..b4a83f638 100644 --- a/checklists-ext/azurefrontdoor_sg_checklist.en.json +++ b/checklists-ext/azurefrontdoor_sg_checklist.en.json @@ -6,187 +6,209 @@ "service": "Azure Front Door", "text": "Choose a routing method that supports your deployment strategy. The weighted method, which distributes traffic based on the configured weight coefficient, supports active-active models. A priority-based value that configures the primary region to receive all traffic and send traffic to the secondary region as a backup supports active-passive models. Combine the preceding methods with latency so that the origin with the lowest latency receives traffic.", "description": "You can select the best origin resource by using a series of decision steps and your design. The selected origin serves traffic within the allowable latency range in the specified ratio of weights.", - "type": "recommendation" + "type": "recommendation", + "guid": "12a2b704-aab5-49b9-b49f-d7b56d80611c" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Support redundancy by having multiple origins in one or more back-end pools. Always have redundant instances of your application and make sure each instance exposes an endpoint or origin. You can place those origins in one or more back-end pools.", "description": "Multiple origins support redundancy by distributing traffic across multiple instances of the application. If one instance is unavailable, then other back-end origins can still receive traffic.", - "type": "recommendation" + "type": "recommendation", + "guid": "dbcc6d21-7f71-42d8-b10b-00ba5c152bd6" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Set up health probes on the origin. Configure Azure Front Door to conduct health checks to determine if the back-end instance is available and ready to continue receiving requests.", "description": "Enabled health probes are part of the health monitoring pattern implementation. Health probes make sure that Azure Front Door only routes traffic to instances that are healthy enough to handle requests. For more information, see Best practices on health probes.", - "type": "recommendation" + "type": "recommendation", + "guid": "f08c4574-a85c-4d77-adbc-6c85fc0aad9f" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Set a timeout on forwarding requests to the back end. Adjust the timeout setting according to your endpoints' needs. If you don't, Azure Front Door might close the connection before the origin sends the response. You can also lower the default timeout for Azure Front Door if all of your origins have a shorter timeout. For more information, see Troubleshooting unresponsive requests.", "description": "Timeouts help prevent performance issues and availability issues by terminating requests that take longer than expected to complete.", - "type": "recommendation" + "type": "recommendation", + "guid": "a5ab698c-0a9f-4f84-b3db-513067920964" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Use the same host name on Azure Front Door and your origin. Azure Front Door can rewrite the host header of incoming requests, which is useful when you have multiple custom domain names that route to one origin. However, rewriting the host header might cause issues with request cookies and URL redirection.", "description": "Set the same host name to prevent malfunction with session affinity, authentication, and authorization. For more information, see Preserve the original HTTP host name between a reverse proxy and its back-end web application.", - "type": "recommendation" + "type": "recommendation", + "guid": "5efdb592-6276-45eb-a9d4-1cf161cb5c42" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Decide if your application requires session affinity. If you have high reliability requirements, we recommend that you disable session affinity.", "description": "With session affinity, user connections stay on the same origin during the user session. If that origin becomes unavailable, the user experience might be disrupted.", - "type": "recommendation" + "type": "recommendation", + "guid": "d494b3a0-08a0-4127-8376-1f5b6c37ecd2" }, { "waf": "Reliability", "service": "Azure Front Door", "text": "Take advantage of the rate-limiting rules that are included with a web application firewall (WAF).", "description": "Limit requests to prevent clients from sending too much traffic to your application. Rate limiting can help you avoid problems like a retry storm.", - "type": "recommendation" + "type": "recommendation", + "guid": "02733e65-a72a-4757-b58e-b9f1b3dbd900" }, { "waf": "Security", "service": "Azure Front Door", "text": "Enable WAF rule sets that detect and block potentially malicious traffic. This feature is available on the Premium tier. We recommend these rule sets: - Default- Bot protection- IP restriction- Geo-filtering- Rate limiting", "description": "Default rule sets are updated frequently based on OWASP top-10 attack types and information from Microsoft Threat Intelligence. The specialized rule sets detect certain use cases. For example, bot rules classify bots as good, bad, or unknown based on the client IP addresses. They also block bad bots and known IP addresses and restrict traffic based on geographical location of the callers. By using a combination of rule sets, you can detect and block attacks with various intents.", - "type": "recommendation" + "type": "recommendation", + "guid": "35b03d1d-e28e-4b7f-803b-6afb23c6133d" }, { "waf": "Security", "service": "Azure Front Door", "text": "Create exclusions for managed rule sets. Test a WAF policy in detection mode for a few weeks and adjust any false positives before you deploy it.", "description": "Reduce false positives and allow legitimate requests for your application.", - "type": "recommendation" + "type": "recommendation", + "guid": "e1cecbea-d7ab-4d0f-92e1-921716dac3ae" }, { "waf": "Security", "service": "Azure Front Door", "text": "Enable end-to-end TLS, HTTP to HTTPS redirection, and managed TLS certificates when applicable. Review the TLS best practices for Azure Front Door. Use TLS version 1.2 as the minimum allowed version with ciphers that are relevant for your application. Azure Front Door managed certificates should be your default choice for ease of operations. However, if you want to manage the lifecycle of the certificates, use your own certificates in Azure Front Door custom domain endpoints and store them in Key Vault.", "description": "TLS ensures that data exchanges between the browser, Azure Front Door, and the back-end origins are encrypted to prevent tampering. Key Vault offers managed certificate support and simple certificate renewal and rotation.", - "type": "recommendation" + "type": "recommendation", + "guid": "57b20099-1ae5-49de-8fe6-94af34380e64" }, { "waf": "Cost", "service": "Azure Front Door", "text": "Use caching for endpoints that support it.", "description": "Caching optimizes data transfer costs because it reduces the number of calls from your Azure Front Door instance to the origin.", - "type": "recommendation" + "type": "recommendation", + "guid": "8c52f54e-5d37-4213-aa1c-aaefbaeac682" }, { "waf": "Cost", "service": "Azure Front Door", "text": "Consider enabling file compression. For this configuration, the application must support compression and caching must be enabled.", "description": "Compression reduces bandwidth consumption and improves performance.", - "type": "recommendation" + "type": "recommendation", + "guid": "d040a66a-36ee-4dc5-b016-375e71dc937f" }, { "waf": "Cost", "service": "Azure Front Door", "text": "Disable health checks in single back-end pools.If you have only one origin configured in your Azure Front Door origin group, these calls are unnecessary.", "description": "You can save on bandwidth costs by disabling requests that aren't required to make routing decisions.", - "type": "recommendation" + "type": "recommendation", + "guid": "8a9a1107-82b2-4fad-b914-ef3348b41b29" }, { "waf": "Operations", "service": "Azure Front Door", "text": "Use HTTP to HTTPS redirection to support forward compatibility.", "description": "When redirection is enabled, Azure Front Door automatically redirects clients that are using older protocol to use HTTPS for a secure experience.", - "type": "recommendation" + "type": "recommendation", + "guid": "65b1c346-16af-4e5a-b465-f51094135758" }, { "waf": "Operations", "service": "Azure Front Door", "text": "Capture logs and metrics. Include resource activity logs, access logs, health probe logs, and WAF logs. Set up alerts.", "description": "Monitoring ingress flow is a crucial part of monitoring an application. You want to track requests and make performance and security improvements. You need data to debug your Azure Front Door configuration. With alerts in place, you can get instant notifications of any critical operational issues.", - "type": "recommendation" + "type": "recommendation", + "guid": "7d54b85e-638e-4a4b-b59e-e570a7cbf6bc" }, { "waf": "Operations", "service": "Azure Front Door", "text": "Review the built-in analytics reports.", "description": "A holistic view of your Azure Front Door profile helps drive improvements based on traffic and security reports through WAF metrics.", - "type": "recommendation" + "type": "recommendation", + "guid": "095f1b55-569d-4964-b9e3-81d8cadedf94" }, { "waf": "Operations", "service": "Azure Front Door", "text": "Use managed TLS certificates when possible.", "description": "Azure Front Door can issue and manage certificates for you. This feature eliminates the need for certificate renewals and minimizes the risk of an outage due to an invalid or expired TLS certificate.", - "type": "recommendation" + "type": "recommendation", + "guid": "e0f192c1-fd21-407f-a3c8-16bd275dabfe" }, { "waf": "Operations", "service": "Azure Front Door", "text": "Use wildcard TLS certificates.", "description": "You don't need to modify the configuration to add or specify each subdomain separately.", - "type": "recommendation" + "type": "recommendation", + "guid": "e54684f1-f16b-4ed4-bc10-e9a0e411939e" }, { "waf": "Performance", "service": "Azure Front Door", "text": "Enable caching. You can optimize query strings for caching. For purely static content, ignore query strings to maximize your use of the cache. If your application uses query strings, consider including them in the cache key. Including the query strings in the cache key allows Azure Front Door to serve cached responses or other responses, based on your configuration.", "description": "Azure Front Door offers a robust content delivery network solution that caches content at the edge of the network. Caching reduces the load on the back-end servers and reduces data movement across the network, which helps offload bandwidth usage.", - "type": "recommendation" + "type": "recommendation", + "guid": "aebbe719-6eac-4192-90d5-2b5de6e28861" }, { "waf": "Performance", "service": "Azure Front Door", "text": "Use file compression when you're accessing downloadable content.", "description": "Compression in Azure Front Door helps deliver content in the optimal format, has a smaller payload, and delivers content to the users faster.", - "type": "recommendation" + "type": "recommendation", + "guid": "eabc1f38-71e5-4af6-b31b-5b60508460f6" }, { "waf": "Performance", "service": "Azure Front Door", "text": "When you configure health probes in Azure Front Door, consider using `HEAD` requests instead of `GET` requests. The health probe reads only the status code, not the content.", "description": "`HEAD` requests let you query a state change without fetching its entire content.", - "type": "recommendation" + "type": "recommendation", + "guid": "e1b9b5a3-569c-4dc2-a2dc-a453879eeadf" }, { "waf": "Performance", "service": "Azure Front Door", "text": "Evaluate whether you should enable session affinity when requests from the same user should be directed to the same back-end server. From a reliability perspective, we don't recommend this approach. If you use this option, the application should gracefully recover without disrupting user sessions. There's also a tradeoff on load balancing because it restricts the flexibility of distributing traffic across multiple back ends evenly.", "description": "Optimize performance and maintain continuity for user sessions, especially when applications rely on maintaining state information locally.", - "type": "recommendation" + "type": "recommendation", + "guid": "908b9efc-df91-432a-ad42-0babc1316896" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -223,6 +245,6 @@ "name": "Azure Front Door Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azurekubernetesservice_sg_checklist.en.json b/checklists-ext/azurekubernetesservice_sg_checklist.en.json index 568262eb5..7aba70a60 100644 --- a/checklists-ext/azurekubernetesservice_sg_checklist.en.json +++ b/checklists-ext/azurekubernetesservice_sg_checklist.en.json @@ -6,390 +6,441 @@ "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Control pod scheduling using node selectors and affinity.", "description": "Allows the Kubernetes scheduler to logically isolate workloads by hardware in the node. Unlike tolerations, pods without a matching node selector can be scheduled on labeled nodes, which allows unused resources on the nodes to consume, but gives priority to pods that define the matching node selector. Use node affinity for more flexibility, which allows you to define what happens if the pod can't be matched with a node.", - "type": "recommendation" + "type": "recommendation", + "guid": "97e853ae-0f0c-4af9-9efd-bd97419c00e0" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Ensure proper selection of network plugin based on network requirements and cluster sizing.", "description": "Azure CNI is required for specific scenarios, for example, Windows-based node pools, specific networking requirements and Kubernetes Network Policies. Reference Kubenet versus Azure CNI for more information.", - "type": "recommendation" + "type": "recommendation", + "guid": "5c5d171c-e58a-430d-a2cc-38b46f773646" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Use the AKS Uptime SLA for production grade clusters.", "description": "The AKS Uptime SLA guarantees: - `99.95%` availability of the Kubernetes API server endpoint for AKS Clusters that use Azure Availability Zones, or - `99.9%` availability for AKS Clusters that don't use Azure Availability Zones.", - "type": "recommendation" + "type": "recommendation", + "guid": "5a34db1f-70ba-41df-89ff-8dcac4e78fd9" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Configure monitoring of cluster with Container insights.", "description": "Container insights help monitor the health and performance of controllers, nodes, and containers that are available in Kubernetes through the Metrics API. Integration with Prometheus enables collection of application and workload metrics.", - "type": "recommendation" + "type": "recommendation", + "guid": "685d2330-e8f1-4201-bc45-fd74617cc28b" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use availability zones to maximize resilience within an Azure region by distributing AKS agent nodes across physically separate data centers.", "description": "By spreading node pools across multiple zones, nodes in one node pool will continue running even if another zone has gone down. If colocality requirements exist, either a regular VMSS-based AKS deployment into a single zone or proximity placement groups can be used to minimize internode latency.", - "type": "recommendation" + "type": "recommendation", + "guid": "0d5115bc-7fbb-4fdb-a645-fee3c75d91a4" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Adopt a multiregion strategy by deploying AKS clusters deployed across different Azure regions to maximize availability and provide business continuity.", "description": "Internet facing workloads should leverage Azure Front Door or Azure Traffic Manager to route traffic globally across AKS clusters.", - "type": "recommendation" + "type": "recommendation", + "guid": "006656dc-4514-447f-8472-40590ba7d6ad" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Define Pod resource requests and limits in application deployment manifests, and enforce with Azure Policy.", "description": "Container CPU and memory resource limits are necessary to prevent resource exhaustion in your Kubernetes cluster.", - "type": "recommendation" + "type": "recommendation", + "guid": "daae16b3-339a-4f9c-a2e1-16437f2b39b0" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Keep the System node pool isolated from application workloads.", "description": "System node pools require a VM SKU of at least 2 vCPUs and 4 GB memory, but 4 vCPU or more is recommended. Reference System and user node pools for detailed requirements.", - "type": "recommendation" + "type": "recommendation", + "guid": "8482ef12-2aa4-41ac-a90f-a41988abef7e" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Separate applications to dedicated node pools based on specific requirements.", "description": "Applications may share the same configuration and need GPU-enabled VMs, CPU or memory optimized VMs, or the ability to scale-to-zero. Avoid large number of node pools to reduce extra management overhead.", - "type": "recommendation" + "type": "recommendation", + "guid": "d7fe91f7-0a16-43cc-9306-dc3c8f435698" }, { "waf": "Reliability", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use a NAT gateway for clusters that run workloads that make many concurrent outbound connections.", "description": "To avoid reliability issues with Azure Load Balancer limitations with high concurrent outbound traffic, us a NAT Gateway instead to support reliable egress traffic at scale.", - "type": "recommendation" + "type": "recommendation", + "guid": "39c79408-332f-449d-8c22-308c4eee21d2" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use Microsoft Entra integration.", "description": "Using Microsoft Entra ID centralizes the identity management component. Any change in user account or group status is automatically updated in access to the AKS cluster. The developers and application owners of your Kubernetes cluster need access to different resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "50fb3fc8-14f2-4856-bb4e-4af6cadfeabe" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Authenticate with Microsoft Entra ID to Azure Container Registry.", "description": "AKS and Microsoft Entra ID enables authentication with Azure Container Registry without the use of `imagePullSecrets` secrets. Review Authenticate with Azure Container Registry from Azure Kubernetes Service for more information.", - "type": "recommendation" + "type": "recommendation", + "guid": "743a94f9-3a7e-4b04-9766-f4895e826914" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Secure network traffic to your API server with private AKS cluster.", "description": "By default, network traffic between your node pools and the API server travels the Microsoft backbone network; by using a private cluster, you can ensure network traffic to your API server remains on the private network only.", - "type": "recommendation" + "type": "recommendation", + "guid": "4ba645c2-e73c-4d64-b122-afdf0b45243a" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: For non-private AKS clusters, use API server authorized IP ranges.", "description": "When using public clusters, you can still limit the traffic that can reach your clusters API server by using the authorized IP range feature. Include sources like the public IPs of your deployment build agents, operations management, and node pools' egress point (such as Azure Firewall).", - "type": "recommendation" + "type": "recommendation", + "guid": "46d7f245-f07f-4e88-bb2d-faca191bd7f6" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Protect the API server with Microsoft Entra RBAC.", "description": "Securing access to the Kubernetes API Server is one of the most important things you can do to secure your cluster. Integrate Kubernetes role-based access control (RBAC) with Microsoft Entra ID to control access to the API server. Disable local accounts to enforce all cluster access using Microsoft Entra ID-based identities.", - "type": "recommendation" + "type": "recommendation", + "guid": "70a1f14b-2493-467a-baaa-0082ad3e6e66" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use Azure network policies or Calico.", "description": "Secure and control network traffic between pods in a cluster.", - "type": "recommendation" + "type": "recommendation", + "guid": "9c861a46-6ed6-46c4-a407-d3a540731c4f" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Secure clusters and pods with Azure Policy.", "description": "Azure Policy can help to apply at-scale enforcement and safeguards on your clusters in a centralized, consistent manner. It can also control what functions pods are granted and if anything is running against company policy.", - "type": "recommendation" + "type": "recommendation", + "guid": "4aca3024-722c-4aa0-b727-d38adfcc2a46" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Secure container access to resources.", "description": "Limit access to actions that containers can perform. Provide the least number of permissions, and avoid the use of root or privileged escalation.", - "type": "recommendation" + "type": "recommendation", + "guid": "37e193d8-d9b1-4444-8f2f-4186242f88cb" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use a Web Application Firewall to secure HTTP(S) traffic.", "description": "To scan incoming traffic for potential attacks, use a web application firewall such as Azure Web Application Firewall (WAF) on Azure Application Gateway or Azure Front Door.", - "type": "recommendation" + "type": "recommendation", + "guid": "ecb6538c-45f3-46a8-ac7d-ef09e28905d9" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Control cluster egress traffic.", "description": "Ensure your cluster's outbound traffic is passing through a network security point such as Azure Firewall or an HTTP proxy.", - "type": "recommendation" + "type": "recommendation", + "guid": "8b978cf0-6f57-4b16-8ff4-c21cb24f9fda" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use the open-source Microsoft Entra Workload ID and Secrets Store CSI Driver with Azure Key Vault.", "description": "Protect and rotate secrets, certificates, and connection strings in Azure Key Vault with strong encryption. Provides an access audit log, and keeps core secrets out of the deployment pipeline.", - "type": "recommendation" + "type": "recommendation", + "guid": "1287d8a6-3b9b-4cad-af36-efb95fb960ec" }, { "waf": "Security", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Use Microsoft Defender for Containers.", "description": "Monitor and maintain the security of your clusters, containers, and their applications.", - "type": "recommendation" + "type": "recommendation", + "guid": "ca24b98e-95aa-4250-9020-35f835aa8141" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Align SKU selection and managed disk size with workload requirements.", "description": "Matching your selection to your workload demands ensures you don't pay for unneeded resources.", - "type": "recommendation" + "type": "recommendation", + "guid": "c318e6a0-4795-49ec-9911-6f0ecb79d7a6" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Select the right virtual machine instance type.", "description": "Selecting the right virtual machine instance type is critical as it directly impacts the cost of running applications on AKS. Choosing a high-performance instance without proper utilization can lead to wasteful spending, while choosing a powerful instance can lead to performance issues and increased downtime. To determine the right virtual machine instance type, consider workload characteristics, resource requirements, and availability needs.", - "type": "recommendation" + "type": "recommendation", + "guid": "87bb48b7-2f60-40f8-b5d5-a97e06baafc4" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Select virtual machines based on the Arm architecture.", "description": "AKS supports creating ARM64 Ubuntu agent nodes, as well as a of mix Intel and ARM architecture nodes within a cluster that can bring better performance at a lower cost.", - "type": "recommendation" + "type": "recommendation", + "guid": "761503f3-f91b-47dc-b732-ed2079836237" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Select Azure Spot Virtual Machines.", "description": "Spot VMs allow you to take advantage of unutilized Azure capacity with significant discounts (up to 90% as compared to pay-as-you-go prices). If Azure needs capacity back, the Azure infrastructure evicts the Spot nodes.", - "type": "recommendation" + "type": "recommendation", + "guid": "54565ad7-0937-4126-bdd9-d242dcde1dc7" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Select the appropriate region.", "description": "Due to many factors, cost of resources varies per region in Azure. Evaluate the cost, latency, and compliance requirements to ensure you are running your workload cost-effectively and it doesn't affect your end-users or create extra networking charges.", - "type": "recommendation" + "type": "recommendation", + "guid": "850c4199-ce25-4f8b-be6a-dbcb2009cf4a" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Workload architecture: Maintain small and optimized images.", "description": "Streamlining your images helps reduce costs since new nodes need to download these images. Build images in a way that allows the container start as soon as possible to help avoid user request failures or timeouts while the application is starting up, potentially leading to overprovisioning.", - "type": "recommendation" + "type": "recommendation", + "guid": "b17c40ac-02c7-4fbb-b804-7e246c89d073" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Enable Cluster Autoscaler to automatically reduce the number of agent nodes in response to excess resource capacity.", "description": "Automatically scaling down the number of nodes in your AKS cluster lets you run an efficient cluster when demand is low and scale up when demand returns.", - "type": "recommendation" + "type": "recommendation", + "guid": "35c3f143-8af5-4064-bff7-5cfee9b3de2b" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Enable Node Autoprovision to automate VM SKU selection.", "description": "Node Autoprovision simplifies the SKU selection process and decides, based on pending pod resource requirements, the optimal VM configuration to run workloads in the most efficient and cost effective manner.", - "type": "recommendation" + "type": "recommendation", + "guid": "b671b868-82a9-4e67-b695-2a231daa98a9" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use the Horizontal Pod Autoscaler.", "description": "Adjust the number of pods in a deployment depending on CPU utilization or other select metrics, which support cluster scale-in operations.", - "type": "recommendation" + "type": "recommendation", + "guid": "67bba4f2-32da-4816-adba-26cdd8416310" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use Vertical Pod Autoscaler (preview).", "description": "Rightsize your pods and dynamically set requests and limits based on historic usage.", - "type": "recommendation" + "type": "recommendation", + "guid": "4727a766-8d04-4609-b397-dd7ae2e1a6eb" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use Kubernetes Event Driven Autoscaling (KEDA).", "description": "Scale based on the number of events being processed. Choose from a rich catalogue of 50+ KEDA scalers.", - "type": "recommendation" + "type": "recommendation", + "guid": "47d91c51-224c-4d38-877a-f54d8c8b513c" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Adopt a cloud financial discipline and cultural practice to drive ownership of cloud usage.", "description": "The foundation of enabling cost optimization is the spread of a cost saving cluster. A financial operations approach (FinOps) is often used to help organizations reduce cloud costs. It is a practice involving collaboration between finance, operations, and engineering teams to drive alignment on cost saving goals and bring transparency to cloud costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "519b4bb1-9a1a-41a6-b445-498f858c700f" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Sign up for Azure Reservations or Azure Savings Plan.", "description": "If you properly planned for capacity, your workload is predictable and exists for an extended period of time, sign up for an Azure Reservation or a savings plan to further reduce your resource costs.", - "type": "recommendation" + "type": "recommendation", + "guid": "268e3171-4a88-4ee1-9096-7956cf6a7009" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Configure monitoring of cluster with Container insights.", "description": "Container insights help provides actionable insights into your clusters idle and unallocated resources. Container insights also supports collecting Prometheus metrics and integrates with Azure Managed Grafana to get a holistic view of your application and infrastructure.", - "type": "recommendation" + "type": "recommendation", + "guid": "b0c6d2ab-4cee-4e81-be4e-b26b466c049d" }, { "waf": "Cost", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Configure the AKS Cost Analysis add-on.", "description": "The cost analysis cluster extension enables you to obtain granular insight into costs associated with various Kubernetes resources in your clusters or namespaces.", - "type": "recommendation" + "type": "recommendation", + "guid": "f783ed2e-e0b7-494e-8b6c-03a7c7f0a521" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Review AKS best practices documentation.", "description": "To build and run applications successfully in AKS, there are key considerations to understand and implement. These areas include multi-tenancy and scheduler features, cluster, and pod security, or business continuity and disaster recovery.", - "type": "recommendation" + "type": "recommendation", + "guid": "34538d1b-a5ff-4ec6-9312-eaeb1dcbacf1" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Review Azure Chaos Studio.", "description": "Azure Chaos Studio can help simulate faults and trigger disaster recovery situations.", - "type": "recommendation" + "type": "recommendation", + "guid": "73ed49fe-4b44-4bbc-b8ee-59bb6e602187" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Configure monitoring of cluster with Container insights.", "description": "Container insights help monitor the performance of containers by collecting memory and processor metrics from controllers, nodes, and containers that are available in Kubernetes through the Metrics API and container logs.", - "type": "recommendation" + "type": "recommendation", + "guid": "2760ddd2-3f7b-4a74-a742-602c4b2b1ee0" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Workload architecture: Monitor application performance with Azure Monitor.", "description": "Configure Application Insights for code-based monitoring of applications running in an AKS cluster.", - "type": "recommendation" + "type": "recommendation", + "guid": "41a1cac4-ce0f-44c8-b0b6-d7e36aeace4d" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Workload architecture: Configure scraping of Prometheus metrics with Container insights.", "description": "Container insights, which are part of Azure Monitor, provide a seamless onboarding experience to collect Prometheus metrics. Reference Configure scraping of Prometheus metrics for more information.", - "type": "recommendation" + "type": "recommendation", + "guid": "95e28189-fdd7-4679-aeea-2070436acbd4" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Adopt a multiregion strategy by deploying AKS clusters deployed across different Azure regions to maximize availability and provide business continuity.", "description": "Internet facing workloads should leverage Azure Front Door or Azure Traffic Manager to route traffic globally across AKS clusters.", - "type": "recommendation" + "type": "recommendation", + "guid": "fbac9fd5-6811-4c97-8664-a598a206679c" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Operationalize clusters and pods configuration standards with Azure Policy.", "description": "Azure Policy can help to apply at-scale enforcement and safeguards on your clusters in a centralized, consistent manner. It can also control what functions pods are granted and if anything is running against company policy.", - "type": "recommendation" + "type": "recommendation", + "guid": "3531bc0d-e5ef-4513-bec0-4fe92182f3f0" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use platform capabilities in your release engineering process.", "description": "Kubernetes and ingress controllers support many advanced deployment patterns for inclusion in your release engineering process. Consider patterns like blue-green deployments or canary releases.", - "type": "recommendation" + "type": "recommendation", + "guid": "6c472ee9-9c78-482a-bb39-bfd85de6e7a9" }, { "waf": "Operations", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: For mission-critical workloads, use stamp-level blue/green deployments.", "description": "Automate your mission-critical design areas, including deployment and testing.", - "type": "recommendation" + "type": "recommendation", + "guid": "be17bb53-96e5-4295-96fb-ba078126befe" }, { "waf": "Performance", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Develop a detailed capacity plan and continually review and revise.", "description": "After formalizing your capacity plan, it should be frequently updated by continuously observing the resource utilization of the cluster.", - "type": "recommendation" + "type": "recommendation", + "guid": "c45e82d7-78ac-4dac-af7d-6b9fa46201ce" }, { "waf": "Performance", "service": "Azure Kubernetes Service", "text": "Cluster architecture: Enable cluster autoscaler to automatically adjust the number of agent nodes in response to resource constraints.", "description": "The ability to automatically scale up or down the number of nodes in your AKS cluster lets you run an efficient, cost-effective cluster.", - "type": "recommendation" + "type": "recommendation", + "guid": "2bc67a06-669d-4576-9ff7-467d440cd601" }, { "waf": "Performance", "service": "Azure Kubernetes Service", "text": "Cluster and workload architectures: Separate workloads into different node pools and consider scaling user node pools.", "description": "Unlike System node pools that always require running nodes, user node pools allow you to scale up or down.", - "type": "recommendation" + "type": "recommendation", + "guid": "14d66ba7-8381-4a2e-99f9-b52d42877bb7" }, { "waf": "Performance", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use AKS advanced scheduler features.", "description": "Helps control balancing of resources for workloads that require them.", - "type": "recommendation" + "type": "recommendation", + "guid": "69aadc69-d7f2-49a7-a8c0-948d950104d2" }, { "waf": "Performance", "service": "Azure Kubernetes Service", "text": "Workload architecture: Use meaningful workload scaling metrics.", "description": "Not all scale decisions can be derived from CPU or memory metrics. Often scale considerations will come from more complex or even external data points. Use KEDA to build a meaningful auto scale ruleset based on signals that are specific to your workload.", - "type": "recommendation" + "type": "recommendation", + "guid": "e5abfe2f-c669-42a3-9a0a-bdf9570208bc" } ], "categories": [], "waf": [ { - "name": "cost" + "name": "Performance" }, { - "name": "Cost" + "name": "Operations" }, { - "name": "reliability" + "name": "operations" }, { - "name": "Security" + "name": "Cost" }, { - "name": "operations" + "name": "Reliability" }, { - "name": "Operations" + "name": "reliability" }, { - "name": "Reliability" + "name": "cost" }, { - "name": "Performance" + "name": "security" }, { "name": "performance" }, { - "name": "security" + "name": "Security" } ], "yesno": [ @@ -426,6 +477,6 @@ "name": "Azure Kubernetes Service Service Guide", "waf": "all", "state": "preview", - "timestamp": "July 07, 2024" + "timestamp": "July 24, 2024" } } \ No newline at end of file diff --git a/checklists-ext/azuremachinelearning_sg_checklist.en.json b/checklists-ext/azuremachinelearning_sg_checklist.en.json index e4c863d85..873179e6c 100644 --- a/checklists-ext/azuremachinelearning_sg_checklist.en.json +++ b/checklists-ext/azuremachinelearning_sg_checklist.en.json @@ -6,264 +6,297 @@ "service": "Azure Machine Learning", "text": "Multi-region model deployment: For enhanced reliability and availability, consider a multi-region deployment environment when possible.", "description": "A multi-region deployment ensures that your Machine Learning workloads continue to run even if one region experiences an outage. Multi-region deployment improves load distribution across regions, potentially enhancing performance for users located in different geographical areas. For more information, see Failover for business continuity and disaster recovery.", - "type": "recommendation" + "type": "recommendation", + "guid": "9fc5b64b-1e1a-4078-8d89-ee58f1c4e711" }, { "waf": "Reliability", "service": "Azure Machine Learning", "text": "Model training resiliency: Use checkpointing features supported by Machine Learning including Azure Container for PyTorch, the TensorFlow Estimator class, or the Run object and the FileDataset class that support model checkpointing.", "description": "Model checkpointing periodically saves the state of your machine learning model during training, so that it can be restored in case of interruption, failure, or termination. For more information, see Boost checkpoint speed and reduce cost with Nebula.", - "type": "recommendation" + "type": "recommendation", + "guid": "4b5f3574-97aa-4f5e-beb5-1fae3c9f8b95" }, { "waf": "Reliability", "service": "Azure Machine Learning", "text": "Use the Dedicated virtual machine tier for compute clusters: Use the Dedicated virtual machine tier for compute clusters for batch inferencing to ensure your batch job isn't preempted.", "description": "Low-priority virtual machines come at a reduced price but are preemptible. Clusters that use the Dedicated virtual machine tier aren't preempted.", - "type": "recommendation" + "type": "recommendation", + "guid": "d66e2a26-ae5f-4991-bbde-4b0760677b7d" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Security baseline: To enhance the security and compliance of your Machine Learning Service, apply the Azure security baseline for Machine Learning.", "description": "The security baseline provides tailored guidance on crucial security aspects such as network security, identity management, data protection, and privileged access. For optimal security, use Microsoft Defender for Cloud to monitor these aspects.", - "type": "recommendation" + "type": "recommendation", + "guid": "4815b47d-64a5-4010-9a17-89f91790e23d" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Managed virtual network isolation: Configure managed virtual network isolation for Machine Learning. When you enable managed virtual network isolation, a managed virtual network is created for the workspace. Managed compute resources you create for the workspace automatically use this managed virtual network. If you can't implement managed virtual network isolation, then you must follow the network topology recommendations to separate compute into a dedicated subnet away from the rest of the resources in the solution, including the private endpoints for workspace resources.", "description": "Managed virtual network isolation enhances security by isolating your workspace from other networks, reducing the risk of unauthorized access. In a scenario in which a breach occurs in another network within your organization, the isolated network of your Machine Learning workspace remains unaffected, protecting your machine learning workloads.", - "type": "recommendation" + "type": "recommendation", + "guid": "eb4000ea-0aa2-4dc8-918e-0ea9dad778c3" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Machine Learning network isolation: Configure a private endpoint for your Machine Learning workspace and connect to the workspace over that private endpoint.", "description": "Machine Learning network isolation enhances security by ensuring that access to your workspace is secure and controlled. With a private endpoint configured for your workspace, you can then limit access to your workspace to only occur over the private IP addresses.", - "type": "recommendation" + "type": "recommendation", + "guid": "dde6ce0a-6734-4e47-9860-47305641f3c8" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Allow only approved outbound access: Configure the outbound mode on the Machine Learning workspace managed outbound access to `Allow only approved outbound` to minimize the risk of data exfiltration. Configure private endpoints, service tags, or fully qualified domain names (FQDNs) for resources that you need to access.", "description": "This configuration minimizes the risk of data exfiltration, improving data security. With this configuration enabled, a malicious actor who gains access to your system can\u2019t send your data to an unapproved external destination.", - "type": "recommendation" + "type": "recommendation", + "guid": "e7dc0d3b-de94-4d51-9deb-283c90ac955e" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Virtual network isolation for dependent services: Configure dependent services, such as Storage, Key Vault, and Container Registry with private endpoints and disable public access.", "description": "Network isolation bolsters security by restricting access to Azure platform as a service (PaaS) solutions to private IP addresses only.", - "type": "recommendation" + "type": "recommendation", + "guid": "d5299777-93bb-4233-8420-f617c700e51a" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Managed identity: Use managed identities for authentication between Machine Learning and other services.", "description": "Managed identities improve security by eliminating the need to store credentials and manually manage and rotate service principals.", - "type": "recommendation" + "type": "recommendation", + "guid": "1320acc1-2453-4af7-a484-232c7f487672" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Disable local authentication: Disable local authentication for Machine Learning compute clusters and instances.", "description": "Disabling local authentication increases the security of your Machine Learning compute and provides centralized control and management of identities and resource credentials.", - "type": "recommendation" + "type": "recommendation", + "guid": "5163e567-cf02-4db1-aa8c-13335d5913e3" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Disable the public SSH port: Ensure the public Secure Shell (SSH) port is closed on the Machine Learning compute cluster by setting `remoteLoginPortPublicAccess` to `Disabled`. Apply a similar configuration if you use a different compute.", "description": "Disabling SSH access helps prevent unauthorized individuals from gaining access and potentially causing harm to your system and protects you against brute force attacks.", - "type": "recommendation" + "type": "recommendation", + "guid": "5d0b43bc-7588-43cd-9a34-11d779cce318" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Don't provision public IP addresses for Machine Learning compute: Set enableNodePublicIp to `false` when provisioning Machine Learning compute clusters or compute instances. Apply a similar configuration if you use a different compute.", "description": "Refrain from provisioning public IP addresses to enhance security by limiting the potential for unauthorized access to your compute instance or clusters.", - "type": "recommendation" + "type": "recommendation", + "guid": "e70322de-d5c9-409d-9524-f495fd04071b" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Get the latest operating system image: Recreate compute instances to get the latest operating system image.", "description": "Using the latest images ensures you're maintaining a consistent, stable, and secure environment, including ensuring you have the latest security patches.", - "type": "recommendation" + "type": "recommendation", + "guid": "b93a0e63-6d54-4065-9b94-4ffea5a81cc3" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Strict Machine Learning workspace access controls: Use Microsoft Entra ID groups to manage workspace access and adhere to the principle of least privilege for RBAC.", "description": "Strict workspace access controls enhance security by ensuring that individuals have only the necessary permissions for their role. A data scientist, for instance, might have access to run experiments but not to modify security settings, minimizing potential security risks.", - "type": "recommendation" + "type": "recommendation", + "guid": "7c1de0a4-ae28-464e-aaf2-1d8e162d1194" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Restrict model catalog deployments: Restrict model deployments to specific registries.", "description": "Restricting the deployments from the model catalog to specific registries ensures you only deploy models to approved registries. This approach helps regulate access to the open-source foundational models.", - "type": "recommendation" + "type": "recommendation", + "guid": "fc675a42-35e6-4db4-a881-bcb68485993b" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Encrypt data at rest: Consider using customer-managed keys with Machine Learning.", "description": "Encrypting data at rest enhances data security by ensuring that sensitive data is encrypted by using keys directly managed by you. If you have a regulatory requirement to manage your own encryption keys, use this feature to comply with that requirement.", - "type": "recommendation" + "type": "recommendation", + "guid": "0fd5a8dc-c8aa-4203-b60a-c4c3b29cdded" }, { "waf": "Security", "service": "Azure Machine Learning", "text": "Minimize the risk of data exfiltration: Implement data exfiltration prevention. For example, create a service endpoint policy to filter egress virtual network traffic and permit data exfiltration only to specific Azure Storage accounts.", "description": "Minimize the risk of data exfiltration by limiting inbound and outbound requirements.", - "type": "recommendation" + "type": "recommendation", + "guid": "140eeaf5-b8e9-4f38-ac81-23709d3505a4" }, { "waf": "Cost", "service": "Azure Machine Learning", "text": "Optimize compute resources: Optimize your compute resources based on the requirements of your workload. Choose the SKU that best suits your workload: