├── CODEOWNERS
├── docs
├── content
│ └── en
│ │ ├── search.md
│ │ ├── docs
│ │ ├── Recommendations
│ │ │ └── _index.md
│ │ ├── _index.md
│ │ ├── Install
│ │ │ └── _index.md
│ │ ├── Troubleshooting
│ │ │ └── _index.md
│ │ ├── Reference
│ │ │ └── _index.md
│ │ └── Contributing
│ │ │ └── _index.md
│ │ └── _index.md
├── static
│ ├── favicons
│ │ ├── favicon.ico
│ │ └── site.webmanifest
│ └── logo
│ │ └── azqr_readme.png
├── layouts
│ ├── shortcodes
│ │ └── include.html
│ └── 404.html
├── go.mod
├── assets
│ ├── scss
│ │ └── _variables_project.scss
│ └── icons
│ │ └── logo.svg
├── config.yaml
├── go.sum
└── package.json
├── internal
├── embeded
│ ├── azqr.png
│ ├── embeded.go
│ └── embeded_test.go
├── viewer
│ ├── static
│ │ └── fonts
│ │ │ ├── bootstrap-icons.woff
│ │ │ └── bootstrap-icons.woff2
│ └── server_test.go
├── to
│ ├── ptr.go
│ ├── string.go
│ ├── string_test.go
│ └── ptr_test.go
├── graph
│ └── azure-orphan-resources
│ │ ├── Network
│ │ └── kql
│ │ │ ├── 8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e.kql
│ │ │ ├── 3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d.kql
│ │ │ ├── 9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f.kql
│ │ │ ├── 1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b.kql
│ │ │ ├── 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e.kql
│ │ │ ├── 6d7e8f9a-0b1c-2d3e-4f5a-6b7c8d9e0f1a.kql
│ │ │ ├── 5c6d7e8f-9a0b-1c2d-3e4f-5a6b7c8d9e0f.kql
│ │ │ ├── 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d.kql
│ │ │ ├── 7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b.kql
│ │ │ ├── 0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a.kql
│ │ │ ├── 5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b.kql
│ │ │ ├── 6f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c.kql
│ │ │ ├── 4b5c6d7e-8f9a-0b1c-2d3e-4f5a6b7c8d9e.kql
│ │ │ ├── 9a0b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d.kql
│ │ │ ├── 8f9a0b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c.kql
│ │ │ └── 2f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c.kql
│ │ ├── Web
│ │ ├── kql
│ │ │ ├── 3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b.kql
│ │ │ ├── 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d.kql
│ │ │ └── 2d3e4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a.kql
│ │ └── queries.yaml
│ │ ├── Compute
│ │ ├── kql
│ │ │ ├── 2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e.kql
│ │ │ └── 3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f.kql
│ │ └── queries.yaml
│ │ ├── Resources
│ │ ├── kql
│ │ │ └── 1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f.kql
│ │ └── queries.yaml
│ │ └── Sql
│ │ ├── queries.yaml
│ │ └── kql
│ │ └── 4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a.kql
├── scanners
│ ├── plugins
│ │ └── zone
│ │ │ └── types.go
│ ├── sap
│ │ ├── sap.go
│ │ └── sap_test.go
│ ├── nic
│ │ ├── nic.go
│ │ └── nic_test.go
│ ├── disk
│ │ ├── disk.go
│ │ └── disk_test.go
│ ├── iot
│ │ ├── iot.go
│ │ └── iot_test.go
│ ├── gal
│ │ ├── gal.go
│ │ └── gal_test.go
│ ├── netapp
│ │ ├── netapp.go
│ │ └── netapp_test.go
│ ├── avs
│ │ ├── avs.go
│ │ └── avs_test.go
│ ├── conn
│ │ ├── conn.go
│ │ └── conn_test.go
│ ├── ba
│ │ ├── ba.go
│ │ └── ba_test.go
│ ├── rg
│ │ ├── rg.go
│ │ └── rg_test.go
│ ├── rsv
│ │ ├── rsv.go
│ │ └── rsv_test.go
│ ├── avail
│ │ ├── avail.go
│ │ └── avail_test.go
│ ├── aa
│ │ ├── aa.go
│ │ └── aa_test.go
│ ├── avd
│ │ ├── avd.go
│ │ └── avd_test.go
│ ├── erc
│ │ ├── erc.go
│ │ └── erc_test.go
│ ├── odb
│ │ ├── odb.go
│ │ └── odb_test.go
│ ├── fdfp
│ │ ├── fdfp.go
│ │ └── fdfp_test.go
│ ├── hpc
│ │ ├── hpc.go
│ │ └── hpc_test.go
│ ├── pdnsz
│ │ ├── pdnsz.go
│ │ └── pdnsz_test.go
│ ├── vdpool
│ │ ├── vdpool.go
│ │ └── vdpool_test.go
│ ├── arc
│ │ ├── arc.go
│ │ └── arc_test.go
│ ├── it
│ │ └── rules.go
│ ├── nsg
│ │ └── rules_test.go
│ ├── appi
│ │ └── rules_test.go
│ ├── pip
│ │ └── rules_test.go
│ ├── vm
│ │ └── rules_test.go
│ ├── ng
│ │ └── rules_test.go
│ ├── rt
│ │ └── rules_test.go
│ ├── pip.go
│ ├── log
│ │ └── rules_test.go
│ └── nw
│ │ └── rules_test.go
├── renderers
│ ├── types.go
│ └── excel
│ │ ├── advisor.go
│ │ ├── cost.go
│ │ ├── arc_sql.go
│ │ ├── impacted.go
│ │ ├── azure_policy.go
│ │ ├── resourceTypes.go
│ │ ├── recommendations.go
│ │ └── resources.go
├── throttling
│ ├── limiter.go
│ └── policy.go
├── plugins
│ ├── loader.go
│ └── internal.go
└── models
│ └── base_scanner.go
├── scripts
├── update_aprl.sh
├── install.sh
├── install.ps1
├── test_graph_queries.sh
└── verify-checksum.sh
├── .gitmodules
├── .github
├── ISSUE_TEMPLATE
│ ├── discussion.md
│ ├── config.yml
│ ├── proposal.md
│ ├── question.md
│ ├── feature_request.md
│ └── bug_report.md
├── pull_request_template.md
├── workflows
│ ├── stale.yml
│ ├── dependency-review.yml
│ └── bump-winget.yml
└── dependabot.yml
├── cmd
├── server
│ ├── main.go
│ └── commands
│ │ └── root.go
└── azqr
│ ├── commands
│ ├── hpc.go
│ ├── nic.go
│ ├── nsg.go
│ ├── sap.go
│ ├── disk.go
│ ├── pip.go
│ ├── rt.go
│ ├── conn.go
│ ├── it.go
│ ├── st.go
│ ├── afw.go
│ ├── iot.go
│ ├── kv.go
│ ├── netapp.go
│ ├── nw.go
│ ├── rg.go
│ ├── vm.go
│ ├── ba.go
│ ├── dbw.go
│ ├── evh.go
│ ├── gal.go
│ ├── lb.go
│ ├── ng.go
│ ├── pep.go
│ ├── rsv.go
│ ├── sb.go
│ ├── sigr.go
│ ├── wps.go
│ ├── adf.go
│ ├── asp.go
│ ├── ca.go
│ ├── dec.go
│ ├── sql.go
│ ├── srch.go
│ ├── aa.go
│ ├── amg.go
│ ├── as.go
│ ├── avd.go
│ ├── avs.go
│ ├── logic.go
│ ├── odb.go
│ ├── pdnsz.go
│ ├── vwan.go
│ ├── aks.go
│ ├── apim.go
│ ├── avail.go
│ ├── ci.go
│ ├── cosmos.go
│ ├── cr.go
│ ├── erc.go
│ ├── log.go
│ ├── traf.go
│ ├── vgw.go
│ ├── vnet.go
│ ├── agw.go
│ ├── arc.go
│ ├── evgd.go
│ ├── psql.go
│ ├── redis.go
│ ├── synw.go
│ ├── appcs.go
│ ├── appi.go
│ ├── mysql.go
│ ├── vdpool.go
│ ├── vmss.go
│ ├── maria.go
│ ├── cae.go
│ ├── aif.go
│ ├── fdfp.go
│ ├── hub.go
│ ├── afd.go
│ ├── types.go
│ ├── rules.go
│ └── root.go
│ └── main.go
├── examples
├── filters
│ └── containers-filters.yml
├── plugins
│ └── yaml-example
│ │ └── kql
│ │ └── unused-public-ips.kql
└── cicd
│ ├── github-actions.yml
│ └── azdo-pipeline.yml
├── .pre-commit-config.yaml
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── .dockerignore
├── CONTRIBUTING.md
├── .vscode
└── launch.json
├── .gitignore
├── LICENSE
├── jumpstart_drops
└── azqr-tutorial.json
├── .devcontainer
└── devcontainer.json
└── SECURITY_VERIFICATION.md
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners are the maintainers and approvers of this repo
2 | * @cmendible
--------------------------------------------------------------------------------
/docs/content/en/search.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Search Results
3 | layout: search
4 | ---
5 |
--------------------------------------------------------------------------------
/internal/embeded/azqr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/azqr/HEAD/internal/embeded/azqr.png
--------------------------------------------------------------------------------
/scripts/update_aprl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | git submodule init
4 | git submodule update --remote
--------------------------------------------------------------------------------
/docs/static/favicons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/azqr/HEAD/docs/static/favicons/favicon.ico
--------------------------------------------------------------------------------
/docs/static/logo/azqr_readme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/azqr/HEAD/docs/static/logo/azqr_readme.png
--------------------------------------------------------------------------------
/docs/layouts/shortcodes/include.html:
--------------------------------------------------------------------------------
1 | {{ $file := .Get 0 }} {{ if strings.HasSuffix $file ".txt" }} {{ $file | readFile | safeHTML }} {{ end }}
--------------------------------------------------------------------------------
/internal/viewer/static/fonts/bootstrap-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/azqr/HEAD/internal/viewer/static/fonts/bootstrap-icons.woff
--------------------------------------------------------------------------------
/internal/viewer/static/fonts/bootstrap-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/azqr/HEAD/internal/viewer/static/fonts/bootstrap-icons.woff2
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "internal/graph/aprl"]
2 | path = internal/graph/aprl
3 | url = https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2.git
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/discussion.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Discussion
3 | about: Start a discussion for azqr
4 | title: ''
5 | labels: kind/discussion
6 | assignees: ''
7 |
8 | ---
9 |
--------------------------------------------------------------------------------
/internal/to/ptr.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package to
5 |
6 | func Ptr[E any](e E) *E {
7 | return &e
8 | }
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: azqr Repo
4 | url: https://github.com/Azure/azqr
5 | about: Please see our community docs here.
6 |
--------------------------------------------------------------------------------
/docs/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/google/docsy-example
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/google/docsy v0.11.0 // indirect
7 | github.com/google/docsy/dependencies v0.7.2 // indirect
8 | )
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/proposal.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Proposal
3 | about: Create a proposal for azqr
4 | title: ''
5 | labels: kind/proposal
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the proposal
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask a question about azqr
4 | title: ''
5 | labels: kind/question
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Ask your question here
--------------------------------------------------------------------------------
/cmd/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/Azure/azqr/cmd/server/commands"
5 | )
6 |
7 | // main is the entry point for the serve executable.
8 | func main() {
9 | commands.Execute()
10 | }
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Create a Feature Request for azqr
4 | title: ''
5 | labels: kind/enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the feature
11 |
12 |
--------------------------------------------------------------------------------
/docs/static/favicons/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/examples/filters/containers-filters.yml:
--------------------------------------------------------------------------------
1 | # Including only Azure Kubernetes Service (aks), Container Apps (ca), Container App Environments (cae), Container Instances (ci) and Container Registry (cr) resources.
2 | azqr:
3 | include:
4 | resourceTypes:
5 | - aks
6 | - ca
7 | - cae
8 | - ci
9 | - cr
10 |
--------------------------------------------------------------------------------
/docs/content/en/docs/Recommendations/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Recommendations
3 | description: Recommendations
4 | weight: 4
5 | ---
6 |
7 | Azure Quick Review checks the following recommendations for Azure resources. The recommendations are categorized based on their impact and category:
8 |
9 | {{% include "./static/rules.txt" %}}
10 |
--------------------------------------------------------------------------------
/docs/layouts/404.html:
--------------------------------------------------------------------------------
1 | {{ define "main" -}}
2 |
3 |
Not found
4 |
Oops! This page doesn't exist. Try going back to the home page.
5 |
You can learn how to make a 404 page like this in Custom 404 Pages.
6 |
7 | {{- end }}
8 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all route tables without subnets
3 | resources
4 | | where type == "microsoft.network/routetables"
5 | | where isnull(properties.subnets)
6 | | project recommendationId="8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all virtual networks without subnets
3 | resources
4 | | where type == "microsoft.network/virtualnetworks"
5 | | where properties.subnets == "[]"
6 | | project recommendationId="3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all load balancers without backend pools
3 | resources
4 | | where type == "microsoft.network/loadbalancers"
5 | | where properties.backendAddressPools == "[]"
6 | | project recommendationId="9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all Traffic Manager profiles without endpoints
3 | resources
4 | | where type == "microsoft.network/trafficmanagerprofiles"
5 | | where properties.endpoints == "[]"
6 | | project recommendationId="1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Web/kql/3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all expired App Service Certificates
3 | resources
4 | | where type == 'microsoft.web/certificates'
5 | | extend expiresOn = todatetime(properties.expirationDate)
6 | | where expiresOn <= now()
7 | | project recommendationId="3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b", name, id, tags
8 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/gitleaks/gitleaks
3 | rev: v8.16.3
4 | hooks:
5 | - id: gitleaks
6 | - repo: https://github.com/golangci/golangci-lint
7 | rev: v1.63.4
8 | hooks:
9 | - id: golangci-lint
10 | - repo: https://github.com/pre-commit/pre-commit-hooks
11 | rev: v4.4.0
12 | hooks:
13 | - id: end-of-file-fixer
14 | - id: trailing-whitespace
15 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all DDoS protection plans that are not associated with any virtual networks
3 | resources
4 | | where type == "microsoft.network/ddosprotectionplans"
5 | | where isnull(properties.virtualNetworks)
6 | | project recommendationId="0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/6d7e8f9a-0b1c-2d3e-4f5a-6b7c8d9e0f1a.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all IP groups without firewalls or firewall policies
3 | resources
4 | | where type == "microsoft.network/ipgroups"
5 | | where properties.firewalls == "[]" and properties.firewallPolicies == "[]"
6 | | project recommendationId="6d7e8f9a-0b1c-2d3e-4f5a-6b7c8d9e0f1a", name, id, tags
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/5c6d7e8f-9a0b-1c2d-3e4f-5a6b7c8d9e0f.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all NAT gateways without subnets
3 | resources
4 | | where type == "microsoft.network/natgateways"
5 | | where isnull(properties.subnets)
6 | | project recommendationId="5c6d7e8f-9a0b-1c2d-3e4f-5a6b7c8d9e0f", name, id, tags, param1=strcat("Sku: ", sku.name), param2=strcat("Tier: ", sku.tier)
7 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all network security groups without associated network interfaces or subnets
3 | resources
4 | | where type == "microsoft.network/networksecuritygroups" and isnull(properties.networkInterfaces) and isnull(properties.subnets)
5 | | project recommendationId="7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d", name, id, tags
6 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Compute/kql/2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all availability sets that are not associated with any virtual machines
3 | resources
4 | | where type =~ 'Microsoft.Compute/availabilitySets'
5 | | where properties.virtualMachines == "[]"
6 | | where not(name endswith "-asr")
7 | | project recommendationId="2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e", name, id, tags
8 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Web/kql/1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all App Service Plans that have no sites associated with them
3 | resources
4 | | where type =~ "microsoft.web/serverfarms"
5 | | where properties.numberOfSites == 0
6 | | project recommendationId="1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", name, id, tags, param1=strcat("Sku: ", sku.name), param2=strcat("Tier: ", sku.name)
7 |
--------------------------------------------------------------------------------
/docs/assets/scss/_variables_project.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Add styles or override variables from the theme here.
3 | */
4 |
5 | $primary: #004589;
6 | $secondary: #0080ff;
7 |
8 | $light: #89c4ff;
9 | $dark: #001e3b;
10 |
11 | // UI element colors
12 | $td-sidebar-bg-color: rgba($primary, 0.15);
13 |
14 | /*
15 | AZURE COLOR PALETTE
16 | #d8ebff (216,235,255)
17 | #89c4ff (137,196,255)
18 | #0080ff (0,128,255)
19 | #004589 (0,69,137)
20 | #001e3b (0,30,59)
21 | */
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all private DNS zones without virtual network links
3 | resources
4 | | where type == "microsoft.network/privatednszones"
5 | | where properties.numberOfVirtualNetworkLinks == 0
6 | | project recommendationId="7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b", name, id, tags, param1=strcat("NumberOfRecordSets: ", properties.numberOfRecordSets)
7 |
--------------------------------------------------------------------------------
/internal/scanners/plugins/zone/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package zone
5 |
6 | // zoneMappingResult represents a single logical-to-physical zone mapping for a location
7 | type zoneMappingResult struct {
8 | subscriptionID string
9 | subscriptionName string
10 | location string
11 | displayName string
12 | logicalZone string
13 | physicalZone string
14 | }
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report a bug in azqr
4 | title: ''
5 | labels: kind/bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Expected Behavior
11 |
12 |
13 |
14 | ## Actual Behavior
15 |
16 |
17 |
18 | ## Steps to Reproduce the Problem
19 |
20 |
21 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
--------------------------------------------------------------------------------
/internal/embeded/embeded.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package embeded
5 |
6 | import (
7 | "embed"
8 | )
9 |
10 | //go:embed *.png
11 | var embededFiles embed.FS
12 |
13 | // GetTemplates - Returns the template for the given name
14 | func GetTemplates(templateName string) []byte {
15 | data, err := embededFiles.ReadFile(templateName)
16 | if err != nil {
17 | return nil
18 | }
19 | return data
20 | }
21 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/hpc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(hpcCmd)
12 | }
13 |
14 | var hpcCmd = &cobra.Command{
15 | Use: "hpc",
16 | Short: "Scan HPC",
17 | Long: "Scan HPC",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"hpc"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/nic.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(nicCmd)
12 | }
13 |
14 | var nicCmd = &cobra.Command{
15 | Use: "nic",
16 | Short: "Scan NICs",
17 | Long: "Scan NICs",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"nic"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/nsg.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(nsgCmd)
12 | }
13 |
14 | var nsgCmd = &cobra.Command{
15 | Use: "nsg",
16 | Short: "Scan NSG",
17 | Long: "Scan NSG",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"nsg"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/sap.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(sapCmd)
12 | }
13 |
14 | var sapCmd = &cobra.Command{
15 | Use: "sap",
16 | Short: "Scan SAP",
17 | Long: "Scan SAP",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"sap"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/disk.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(diskCmd)
12 | }
13 |
14 | var diskCmd = &cobra.Command{
15 | Use: "disk",
16 | Short: "Scan Disk",
17 | Long: "Scan Disk",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"disk"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/main.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package main
5 |
6 | import (
7 | "github.com/Azure/azqr/cmd/azqr/commands"
8 |
9 | // Import internal plugins to register them
10 | _ "github.com/Azure/azqr/internal/scanners/plugins/carbon"
11 | _ "github.com/Azure/azqr/internal/scanners/plugins/openai"
12 | _ "github.com/Azure/azqr/internal/scanners/plugins/zone"
13 | )
14 |
15 | func main() {
16 | commands.Execute()
17 | }
18 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/pip.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(pipCmd)
12 | }
13 |
14 | var pipCmd = &cobra.Command{
15 | Use: "pip",
16 | Short: "Scan Public IP",
17 | Long: "Scan Public IP",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"pip"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/rt.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(rtCmd)
12 | }
13 |
14 | var rtCmd = &cobra.Command{
15 | Use: "rt",
16 | Short: "Scan Route Table",
17 | Long: "Scan Route Table",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"rt"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/conn.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(conCmd)
12 | }
13 |
14 | var conCmd = &cobra.Command{
15 | Use: "con",
16 | Short: "Scan Connection",
17 | Long: "Scan Connection",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"con"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/it.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(itCmd)
12 | }
13 |
14 | var itCmd = &cobra.Command{
15 | Use: "it",
16 | Short: "Scan Image Template",
17 | Long: "Scan Image Template",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"it"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/st.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(stCmd)
12 | }
13 |
14 | var stCmd = &cobra.Command{
15 | Use: "st",
16 | Short: "Scan Azure Storage",
17 | Long: "Scan Azure Storage",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"st"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all Front Door WAF policies that are not associated without associations
3 | resources
4 | | where type == "microsoft.network/frontdoorwebapplicationfirewallpolicies"
5 | | where properties.frontendEndpointLinks== "[]" and properties.securityPolicyLinks == "[]"
6 | | project recommendationId="0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a", name, id, tags, param1=strcat("Sku: ", sku.name)
7 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/afw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(afwCmd)
12 | }
13 |
14 | var afwCmd = &cobra.Command{
15 | Use: "afw",
16 | Short: "Scan Azure Firewall",
17 | Long: "Scan Azure Firewall",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"afw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/iot.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(iotCmd)
12 | }
13 |
14 | var iotCmd = &cobra.Command{
15 | Use: "iot",
16 | Short: "Scan Azure IoT Hub",
17 | Long: "Scan Azure IoT Hub",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"iot"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/kv.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(kvCmd)
12 | }
13 |
14 | var kvCmd = &cobra.Command{
15 | Use: "kv",
16 | Short: "Scan Azure Key Vault",
17 | Long: "Scan Azure Key Vault",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"kv"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/netapp.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(netappCmd)
12 | }
13 |
14 | var netappCmd = &cobra.Command{
15 | Use: "netapp",
16 | Short: "Scan NetApp",
17 | Long: "Scan NetApp",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"netapp"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/nw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(nwCmd)
12 | }
13 |
14 | var nwCmd = &cobra.Command{
15 | Use: "nw",
16 | Short: "Scan Network Watcher",
17 | Long: "Scan Network Watcher",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"nw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/rg.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(rgCmd)
12 | }
13 |
14 | var rgCmd = &cobra.Command{
15 | Use: "rg",
16 | Short: "Scan Resource Groups",
17 | Long: "Scan Resource Groups",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"rg"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vm.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vmCmd)
12 | }
13 |
14 | var vmCmd = &cobra.Command{
15 | Use: "vm",
16 | Short: "Scan Virtual Machine",
17 | Long: "Scan Virtual Machine",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vm"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/ba.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(baCmd)
12 | }
13 |
14 | var baCmd = &cobra.Command{
15 | Use: "ba",
16 | Short: "Scan Azure Batch Account",
17 | Long: "Scan Azure Batch Account",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"ba"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/dbw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(dbwCmd)
12 | }
13 |
14 | var dbwCmd = &cobra.Command{
15 | Use: "dbw",
16 | Short: "Scan Azure Databricks",
17 | Long: "Scan Azure Databricks",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"dbw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/evh.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(evhCmd)
12 | }
13 |
14 | var evhCmd = &cobra.Command{
15 | Use: "evh",
16 | Short: "Scan Azure Event Hubs",
17 | Long: "Scan Azure Event Hubs",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"evh"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/gal.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(galCmd)
12 | }
13 |
14 | var galCmd = &cobra.Command{
15 | Use: "gal",
16 | Short: "Scan Azure Galleries",
17 | Long: "Scan Azure Galleries",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"gal"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/lb.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(lbCmd)
12 | }
13 |
14 | var lbCmd = &cobra.Command{
15 | Use: "lb",
16 | Short: "Scan Azure Load Balancer",
17 | Long: "Scan Azure Load Balancer",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"lb"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/ng.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(ngCmd)
12 | }
13 |
14 | var ngCmd = &cobra.Command{
15 | Use: "ng",
16 | Short: "Scan Azure NAT Gateway",
17 | Long: "Scan Azure NAT Gateway",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"ng"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/pep.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(pepCmd)
12 | }
13 |
14 | var pepCmd = &cobra.Command{
15 | Use: "pep",
16 | Short: "Scan Private Endpoint",
17 | Long: "Scan Private Endpoint",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"pep"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/rsv.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(rsvCmd)
12 | }
13 |
14 | var rsvCmd = &cobra.Command{
15 | Use: "rsv",
16 | Short: "Scan Recovery Service",
17 | Long: "Scan Recovery Service",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"rsv"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/sb.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(sbCmd)
12 | }
13 |
14 | var sbCmd = &cobra.Command{
15 | Use: "sb",
16 | Short: "Scan Azure Service Bus",
17 | Long: "Scan Azure Service Bus",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"sb"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/sigr.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(sigrCmd)
12 | }
13 |
14 | var sigrCmd = &cobra.Command{
15 | Use: "sigr",
16 | Short: "Scan Azure SignalR",
17 | Long: "Scan Azure SignalR",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"sigr"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/wps.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(wpsCmd)
12 | }
13 |
14 | var wpsCmd = &cobra.Command{
15 | Use: "wps",
16 | Short: "Scan Azure Web PubSub",
17 | Long: "Scan Azure Web PubSub",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"wps"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/adf.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(adfCmd)
12 | }
13 |
14 | var adfCmd = &cobra.Command{
15 | Use: "adf",
16 | Short: "Scan Azure Data Factory",
17 | Long: "Scan Azure Data Factory",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"adf"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/asp.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(planCmd)
12 | }
13 |
14 | var planCmd = &cobra.Command{
15 | Use: "asp",
16 | Short: "Scan Azure App Service",
17 | Long: "Scan Azure App Service",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"asp"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/ca.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(caCmd)
12 | }
13 |
14 | var caCmd = &cobra.Command{
15 | Use: "ca",
16 | Short: "Scan Azure Container Apps",
17 | Long: "Scan Azure Container Apps",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"ca"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/dec.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(decCmd)
12 | }
13 |
14 | var decCmd = &cobra.Command{
15 | Use: "dec",
16 | Short: "Scan Azure Data Explorer",
17 | Long: "Scan Azure Data Explorer",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"dec"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/sql.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(sqlCmd)
12 | }
13 |
14 | var sqlCmd = &cobra.Command{
15 | Use: "sql",
16 | Short: "Scan Azure SQL Database",
17 | Long: "Scan Azure SQL Database",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"sql"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/srch.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(srchCmd)
12 | }
13 |
14 | var srchCmd = &cobra.Command{
15 | Use: "srch",
16 | Short: "Scan Azure AI Search",
17 | Long: "Scan Azure AI Search",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"srch"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/aa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(aaCmd)
12 | }
13 |
14 | var aaCmd = &cobra.Command{
15 | Use: "aa",
16 | Short: "Scan Azure Automation Account",
17 | Long: "Scan Azure Automation Account",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"aa"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/amg.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(amgCmd)
12 | }
13 |
14 | var amgCmd = &cobra.Command{
15 | Use: "amg",
16 | Short: "Scan Azure Managed Grafana",
17 | Long: "Scan Azure Managed Grafana",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"amg"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/as.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(asCmd)
12 | }
13 |
14 | var asCmd = &cobra.Command{
15 | Use: "as",
16 | Short: "Scan Azure Analysis Service",
17 | Long: "Scan Azure Analysis Service",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"as"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/avd.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(avdCmd)
12 | }
13 |
14 | var avdCmd = &cobra.Command{
15 | Use: "avd",
16 | Short: "Scan Azure Virtual Desktop",
17 | Long: "Scan Azure Virtual Desktop",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"avd"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/avs.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(avsCmd)
12 | }
13 |
14 | var avsCmd = &cobra.Command{
15 | Use: "avs",
16 | Short: "Scan Azure VMware Solution",
17 | Long: "Scan Azure VMware Solution",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"avs"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/logic.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(logicCmd)
12 | }
13 |
14 | var logicCmd = &cobra.Command{
15 | Use: "logic",
16 | Short: "Scan Azure Logic Apps",
17 | Long: "Scan Azure Logic Apps",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"logic"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/odb.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(odbCmd)
12 | }
13 |
14 | var odbCmd = &cobra.Command{
15 | Use: "odb",
16 | Short: "Scan Oracle Database@Azure",
17 | Long: "Scan Oracle Database@Azure",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"odb"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/pdnsz.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(pdnszCmd)
12 | }
13 |
14 | var pdnszCmd = &cobra.Command{
15 | Use: "pdnsz",
16 | Short: "Scan Private DNS Zone",
17 | Long: "Scan Private DNS Zone",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"pdnsz"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vwan.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vwanCmd)
12 | }
13 |
14 | var vwanCmd = &cobra.Command{
15 | Use: "vwan",
16 | Short: "Scan Azure Virtual WAN",
17 | Long: "Scan Azure Virtual WAN",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vwan"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/aks.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(aksCmd)
12 | }
13 |
14 | var aksCmd = &cobra.Command{
15 | Use: "aks",
16 | Short: "Scan Azure Kubernetes Service",
17 | Long: "Scan Azure Kubernetes Service",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"aks"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/apim.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(apimCmd)
12 | }
13 |
14 | var apimCmd = &cobra.Command{
15 | Use: "apim",
16 | Short: "Scan Azure API Management",
17 | Long: "Scan Azure API Management",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"apim"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/avail.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(availCmd)
12 | }
13 |
14 | var availCmd = &cobra.Command{
15 | Use: "avail",
16 | Short: "Scan Availability Sets",
17 | Long: "Scan Availability Sets",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"avail"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/ci.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(ciCmd)
12 | }
13 |
14 | var ciCmd = &cobra.Command{
15 | Use: "ci",
16 | Short: "Scan Azure Container Instances",
17 | Long: "Scan Azure Container Instances",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"ci"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/cosmos.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(cosmosCmd)
12 | }
13 |
14 | var cosmosCmd = &cobra.Command{
15 | Use: "cosmos",
16 | Short: "Scan Azure Cosmos DB",
17 | Long: "Scan Azure Cosmos DB",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"cosmos"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/cr.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(crCmd)
12 | }
13 |
14 | var crCmd = &cobra.Command{
15 | Use: "cr",
16 | Short: "Scan Azure Container Registries",
17 | Long: "Scan Azure Container Registries",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"cr"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/erc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(ercCmd)
12 | }
13 |
14 | var ercCmd = &cobra.Command{
15 | Use: "erc",
16 | Short: "Scan Express Route Circuits",
17 | Long: "Scan Express Route Circuits",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"erc"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/log.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(logCmd)
12 | }
13 |
14 | var logCmd = &cobra.Command{
15 | Use: "log",
16 | Short: "Scan Log Analytics workspace",
17 | Long: "Scan Log Analytics workspace",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"log"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/traf.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(trafCmd)
12 | }
13 |
14 | var trafCmd = &cobra.Command{
15 | Use: "traf",
16 | Short: "Scan Azure Traffic Manager",
17 | Long: "Scan Azure Traffic Manager",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"traf"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vgw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vgwCmd)
12 | }
13 |
14 | var vgwCmd = &cobra.Command{
15 | Use: "vgw",
16 | Short: "Scan Virtual Network Gateway",
17 | Long: "Scan Virtual Network Gateway",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vgw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vnet.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vnetCmd)
12 | }
13 |
14 | var vnetCmd = &cobra.Command{
15 | Use: "vnet",
16 | Short: "Scan Azure Virtual Network",
17 | Long: "Scan Azure Virtual Network",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vnet"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/docs/config.yaml:
--------------------------------------------------------------------------------
1 | # THIS IS A TEST CONFIG ONLY!
2 | # FOR THE CONFIGURATION OF YOUR SITE USE hugo.yaml.
3 | #
4 | # As of Docsy 0.7.0, Hugo 0.110.0 or later must be used.
5 | #
6 | # The sole purpose of this config file is to detect Hugo-module builds that use
7 | # an older version of Hugo.
8 | #
9 | # DO NOT add any config parameters to this file. You can safely delete this file
10 | # if your project is using the required Hugo version.
11 |
12 | module:
13 | hugoVersion:
14 | extended: true
15 | min: 0.110.0
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Dockerfile for kubelogin
2 | # This Dockerfile copies a pre-built binary into a minimal scratch image.
3 | # The binary should be built before running docker build
4 | ARG BUILDPLATFORM=linux/amd64
5 | FROM --platform=$BUILDPLATFORM scratch
6 |
7 | # Build arguments for multi-architecture support
8 | ARG TARGETARCH=amd64
9 |
10 | # Copy the pre-built binary from local build to /usr/local/bin
11 | COPY bin/linux_${TARGETARCH}/azqr /usr/local/bin/azqr
12 |
13 | # Set the entrypoint
14 | ENTRYPOINT ["/usr/local/bin/azqr"]
--------------------------------------------------------------------------------
/cmd/azqr/commands/agw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(agwCmd)
12 | }
13 |
14 | var agwCmd = &cobra.Command{
15 | Use: "agw",
16 | Short: "Scan Azure Application Gateway",
17 | Long: "Scan Azure Application Gateway",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"agw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/arc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(arcCmd)
12 | }
13 |
14 | var arcCmd = &cobra.Command{
15 | Use: "arc",
16 | Short: "Scan Azure Arc-enabled machines",
17 | Long: "Scan Azure Arc-enabled machines",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"arc"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/evgd.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(evgdCmd)
12 | }
13 |
14 | var evgdCmd = &cobra.Command{
15 | Use: "evgd",
16 | Short: "Scan Azure Event Grid Domains",
17 | Long: "Scan Azure Event Grid Domains",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"evgd"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/psql.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(psqlCmd)
12 | }
13 |
14 | var psqlCmd = &cobra.Command{
15 | Use: "psql",
16 | Short: "Scan Azure Database for psql",
17 | Long: "Scan Azure Database for psql",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"psql"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/redis.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(redisCmd)
12 | }
13 |
14 | var redisCmd = &cobra.Command{
15 | Use: "redis",
16 | Short: "Scan Azure Cache for Redis",
17 | Long: "Scan Azure Cache for Redis",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"redis"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/synw.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(synwCmd)
12 | }
13 |
14 | var synwCmd = &cobra.Command{
15 | Use: "synw",
16 | Short: "Scan Azure Synapse Workspace",
17 | Long: "Scan Azure Synapse Workspace",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"synw"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/appcs.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(appcsCmd)
12 | }
13 |
14 | var appcsCmd = &cobra.Command{
15 | Use: "appcs",
16 | Short: "Scan Azure App Configuration",
17 | Long: "Scan Azure App Configuration",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"appcs"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/appi.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(appiCmd)
12 | }
13 |
14 | var appiCmd = &cobra.Command{
15 | Use: "appi",
16 | Short: "Scan Azure Application Insights",
17 | Long: "Scan Azure Application Insights",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"appi"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/mysql.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(mysqlCmd)
12 | }
13 |
14 | var mysqlCmd = &cobra.Command{
15 | Use: "mysql",
16 | Short: "Scan Azure Database for MySQL",
17 | Long: "Scan Azure Database for MySQL",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"mysql"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vdpool.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vdPoolCmd)
12 | }
13 |
14 | var vdPoolCmd = &cobra.Command{
15 | Use: "vdpool",
16 | Short: "Scan Azure Virtual Desktop",
17 | Long: "Scan Azure Virtual Desktop",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vdpool"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/vmss.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(vmssCmd)
12 | }
13 |
14 | var vmssCmd = &cobra.Command{
15 | Use: "vmss",
16 | Short: "Scan Virtual Machine Scale Set",
17 | Long: "Scan Virtual Machine Scale Set",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"vmss"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/maria.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(mariaCmd)
12 | }
13 |
14 | var mariaCmd = &cobra.Command{
15 | Use: "maria",
16 | Short: "Scan Azure Database for MariaDB",
17 | Long: "Scan Azure Database for MariaDB",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"maria"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/cae.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(caeCmd)
12 | }
13 |
14 | var caeCmd = &cobra.Command{
15 | Use: "cae",
16 | Short: "Scan Azure Container Apps Environment",
17 | Long: "Scan Azure Container Apps Environment",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"cae"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/aif.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(cogCmd)
12 | }
13 |
14 | var cogCmd = &cobra.Command{
15 | Use: "aif",
16 | Short: "Scan Azure AI Foundry and Cognitive Services",
17 | Long: "Scan Azure AI and Cognitive Services",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"aif"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/fdfp.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(fdfpCmd)
12 | }
13 |
14 | var fdfpCmd = &cobra.Command{
15 | Use: "fdfp",
16 | Short: "Scan Front Door Web Application Policy",
17 | Long: "Scan Front Door Web Application Policy",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"fdfp"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all public IP addresses that are not associated with any resources
3 | resources
4 | | where type == "microsoft.network/publicipaddresses"
5 | | where properties.ipConfiguration == "" and properties.natGateway == "" and properties.publicIPPrefix == ""
6 | | project recommendationId="5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b", name, id, tags, param1=strcat("Sku: ", sku.name), param2=strcat("AllocationMethod: ", properties.publicIPAllocationMethod)
7 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | _Please explain the changes you've made_
4 |
5 | ## Issue reference
6 |
7 | We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.
8 |
9 | Please reference the issue this PR will close: #_[issue number]_
10 |
11 | ## Checklist
12 |
13 | Please make sure you've completed the relevant tasks for this PR, out of the following list:
14 |
15 | * [ ] Code compiles correctly
16 | * [ ] Created/updated tests
17 | * [ ] Unit tests passing
18 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/hub.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | scanCmd.AddCommand(hubCmd)
12 | }
13 |
14 | var hubCmd = &cobra.Command{
15 | Use: "hub",
16 | Short: "Scan AI Foundry Hub and Azure Machine Learning Workspaces",
17 | Long: "Scan AI Foundry Hub and Azure Machine Learning Workspaces",
18 | Args: cobra.NoArgs,
19 | Run: func(cmd *cobra.Command, args []string) {
20 | scan(cmd, []string{"hub"})
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/examples/plugins/yaml-example/kql/unused-public-ips.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Find all public IP addresses that are not associated with any resource
3 | resources
4 | | where type =~ 'Microsoft.Network/publicIPAddresses'
5 | | where properties.ipConfiguration == "" or isnull(properties.ipConfiguration)
6 | | where properties.natGateway == "" or isnull(properties.natGateway)
7 | | project recommendationId="yaml-002-unused-public-ips", name, id, tags,
8 | param1=strcat("SKU: ", sku.name),
9 | param2=strcat("Allocation: ", properties.publicIPAllocationMethod)
10 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/6f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all network interfaces that are not associated with any virtual machines, private endpoints, or private link services
3 | resources
4 | | where type has "microsoft.network/networkinterfaces"
5 | | where isnull(properties.privateEndpoint)
6 | | where isnull(properties.privateLinkService)
7 | | where properties.hostedWorkloads == "[]"
8 | | where properties !has 'virtualmachine'
9 | | project recommendationId="6f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c", name, id, tags
10 |
--------------------------------------------------------------------------------
/internal/to/string.go:
--------------------------------------------------------------------------------
1 | package to
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/rs/zerolog/log"
8 | )
9 |
10 | func String(i interface{}) string {
11 | if i == nil {
12 | return ""
13 | }
14 |
15 | switch v := i.(type) {
16 | case string:
17 | return v
18 | case int:
19 | return fmt.Sprintf("%d", v)
20 | case bool:
21 | return fmt.Sprintf("%t", v)
22 | default:
23 | jsonStr, err := json.Marshal(i)
24 | if err != nil {
25 | log.Fatal().Err(err).Msg("Unsupported type found in ARG query result")
26 | }
27 | return string(jsonStr)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Resources/kql/1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all empty Resource Groups
3 | ResourceContainers
4 | | where type == "microsoft.resources/subscriptions/resourcegroups"
5 | | extend rgAndSub = strcat(resourceGroup, "--", subscriptionId)
6 | | join kind=leftouter (
7 | Resources
8 | | extend rgAndSub = strcat(resourceGroup, "--", subscriptionId)
9 | | summarize count() by rgAndSub
10 | ) on rgAndSub
11 | | where isnull(count_)
12 | | project recommendationId="1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f", name, id, tags
13 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 | on:
3 | schedule:
4 | - cron: '30 1 * * *'
5 |
6 | permissions:
7 | contents: read
8 |
9 | jobs:
10 | stale:
11 | runs-on: ubuntu-latest
12 | permissions:
13 | issues: write
14 | steps:
15 | - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
16 | with:
17 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
18 | days-before-stale: 30
19 | days-before-close: 5
--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if ! command -v jq &> /dev/null || ! command -v unzip &> /dev/null || ! command -v wget &> /dev/null
4 | then
5 | echo "jq, unzip or wget could not be found, please install them."
6 | exit
7 | fi
8 |
9 | arch=$(uname -m)
10 | if [ "$arch" == "aarch64" ]; then
11 | arch="arm64"
12 | else
13 | arch="amd64"
14 | fi
15 |
16 | latest_azqr=$(curl -sL https://api.github.com/repos/Azure/azqr/releases/latest | jq -r ".tag_name" | cut -c1-)
17 | wget https://github.com/Azure/azqr/releases/download/$latest_azqr/azqr-linux-$arch.zip -O azqr.zip
18 | unzip -uj -qq azqr.zip
19 | rm azqr.zip
20 | chmod +x azqr
21 | ./azqr --version
22 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/afd.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | // init initializes the afd command and adds it to the scan command.
11 | func init() {
12 | scanCmd.AddCommand(afdCmd)
13 | }
14 |
15 | // afdCmd represents the afd command.
16 | var afdCmd = &cobra.Command{
17 | Use: "afd",
18 | Short: "Scan Azure Front Door",
19 | Long: "Scan Azure Front Door",
20 | Args: cobra.NoArgs,
21 | Run: func(cmd *cobra.Command, args []string) {
22 | // Call the scan function with the "afd" argument.
23 | scan(cmd, []string{"afd"})
24 | },
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "fmt"
8 |
9 | "github.com/Azure/azqr/internal/renderers"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | func init() {
14 | rootCmd.AddCommand(typesCmd)
15 | }
16 |
17 | var typesCmd = &cobra.Command{
18 | Use: "types",
19 | Short: "Print all supported azure resource types",
20 | Long: "Print all supported azure resource types",
21 | Args: cobra.NoArgs,
22 | Run: func(cmd *cobra.Command, args []string) {
23 | st := renderers.SupportedTypes{}
24 | output := st.GetAll()
25 | fmt.Println(output)
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Sql/queries.yaml:
--------------------------------------------------------------------------------
1 | - description: SQL elastic pool without databases
2 | aprlGuid: 4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a
3 | recommendationTypeId: null
4 | recommendationControl: Governance
5 | recommendationImpact: Medium
6 | recommendationResourceType: Microsoft.Sql/servers/elasticpools
7 | recommendationMetadataState: Active
8 | longDescription: |
9 | SQL elastic pool without databases.
10 | potentialBenefits: Identifies unused resources
11 | pgVerified: false
12 | automationAvailable: false
13 | tags: []
14 | learnMoreLink:
15 | - name: SQL elastic pool
16 | url: "https://learn.microsoft.com/en-us/azure/azure-sql/database/elastic-pool-overview"
17 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Resources/queries.yaml:
--------------------------------------------------------------------------------
1 | - description: Resource Groups without resources
2 | aprlGuid: 1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f
3 | recommendationTypeId: null
4 | recommendationControl: Governance
5 | recommendationImpact: Medium
6 | recommendationResourceType: Microsoft.Resources/resourceGroups
7 | recommendationMetadataState: Active
8 | longDescription: |
9 | Resource Groups without resources.
10 | potentialBenefits: Identifies unused resources
11 | pgVerified: false
12 | automationAvailable: false
13 | tags: []
14 | learnMoreLink:
15 | - name: Resource Groups
16 | url: "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview"
17 |
--------------------------------------------------------------------------------
/docs/content/en/docs/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Azure Quick Review
3 | linkTitle: Documentation
4 | menu: {main: {weight: 20}}
5 | weight: 20
6 | ---
7 |
8 | {{% pageinfo %}}
9 | **Azure Quick Review!** — Analyze Azure resources and identify whether they comply with Azure's best practices and recommendations.
10 | {{% /pageinfo %}}
11 |
12 | **Azure Quick Review (azqr)** is a command-line interface (CLI) tool specifically designed to analyze Azure resources and identify whether they comply with Azure's best practices and recommendations. Its primary purpose is to provide users with a detailed overview of their Azure resources, enabling them to easily identify any non-compliant configurations or potential areas for improvement.
13 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Docker ignore file for kubelogin
2 | # Ignore development and build files that are not needed in Docker context
3 |
4 | # Version control
5 | .git
6 | .gitignore
7 | .gitmodules
8 | .precommit-config.yaml
9 |
10 | # Documentation
11 | docs/
12 | CODE_OF_CONDUCT.md
13 | CODEOWNERS
14 | CONTRIBUTING.md
15 | LICENSE
16 | README.md
17 | SECURITY.md
18 | jumpstart_drops/
19 |
20 | # Examples
21 | examples/
22 |
23 | # Data
24 | data/
25 |
26 | # Scripts
27 | scripts/
28 |
29 | # Test files
30 | *_test.go
31 | **/*_test.go
32 | **/testdata/
33 | **/*VCR.yaml
34 |
35 | # Development files
36 | .github/
37 |
38 | # IDE files
39 | .vscode/
40 | .idea/
41 | *.swp
42 | *.swo
43 | *~
44 |
45 | # OS files
46 | .DS_Store
47 | Thumbs.db
--------------------------------------------------------------------------------
/internal/renderers/types.go:
--------------------------------------------------------------------------------
1 | package renderers
2 |
3 | import (
4 | "fmt"
5 | "sort"
6 |
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | type SupportedTypes struct{}
11 |
12 | func (t SupportedTypes) GetAll() string {
13 | output := fmt.Sprintln("Abbreviation | Resource Type ")
14 | output += fmt.Sprintln("---|---")
15 | keys := make([]string, 0, len(models.ScannerList))
16 | for key := range models.ScannerList {
17 | keys = append(keys, key)
18 | }
19 | sort.Strings(keys)
20 | for _, key := range keys {
21 | for _, t := range models.ScannerList[key] {
22 | for _, rt := range t.ResourceTypes() {
23 | output += fmt.Sprintf("%s | %s", key, rt)
24 | output += fmt.Sprintln()
25 | }
26 | }
27 | }
28 | return output
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/sap/sap.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package sap
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["sap"] = []models.IAzureScanner{NewSAPScanner()}
12 | }
13 |
14 | // NewSAPScanner creates a new SAPScanner
15 | func NewSAPScanner() *SAPScanner {
16 | return &SAPScanner{
17 | BaseScanner: models.NewBaseScanner("Specialized.Workload/SAP"),
18 | }
19 | }
20 |
21 | // SAPScanner - Scanner for SAP
22 | type SAPScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the SAP Scanner
27 | func (a *SAPScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/nic/nic.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package nic
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["nic"] = []models.IAzureScanner{NewNICScanner()}
12 | }
13 |
14 | // NewNICScanner creates a new NICScanner
15 | func NewNICScanner() *NICScanner {
16 | return &NICScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Network/networkInterfaces"),
18 | }
19 | }
20 |
21 | // NICScanner - Scanner for NIC
22 | type NICScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the NIC Scanner
27 | func (a *NICScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/disk/disk.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package disk
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["disk"] = []models.IAzureScanner{NewDiskScanner()}
12 | }
13 |
14 | // NewDiskScanner creates a new DiskScanner
15 | func NewDiskScanner() *DiskScanner {
16 | return &DiskScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Compute/disks"),
18 | }
19 | }
20 |
21 | // DiskScanner - Scanner for Disk
22 | type DiskScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Disk Scanner
27 | func (a *DiskScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/rules.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "fmt"
8 |
9 | "github.com/Azure/azqr/internal/renderers"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | func init() {
14 | rootCmd.PersistentFlags().BoolP("json", "j", false, "Output rules list in JSON format")
15 | rootCmd.AddCommand(rulesCmd)
16 | }
17 |
18 | var rulesCmd = &cobra.Command{
19 | Use: "rules",
20 | Short: "Print all recommendations",
21 | Long: "Print all recommendations as markdown table",
22 | Args: cobra.NoArgs,
23 | Run: func(cmd *cobra.Command, args []string) {
24 | oj, _ := cmd.Flags().GetBool("json")
25 | output := renderers.GetAllRecommendations(!oj)
26 | fmt.Println(output)
27 | },
28 | }
29 |
--------------------------------------------------------------------------------
/internal/scanners/iot/iot.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package iot
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["iot"] = []models.IAzureScanner{NewIoTHubScanner()}
12 | }
13 |
14 | // NewIoTHubScanner creates a new IoTHubScanner
15 | func NewIoTHubScanner() *IoTHubScanner {
16 | return &IoTHubScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Devices/IotHubs"),
18 | }
19 | }
20 |
21 | // IoTHubScanner - Scanner for IoT Hub
22 | type IoTHubScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the IoT Hub Scanner
27 | func (a *IoTHubScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/gal/gal.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package gal
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["gal"] = []models.IAzureScanner{NewGalleryScanner()}
12 | }
13 |
14 | // NewGalleryScanner creates a new GalleryScanner
15 | func NewGalleryScanner() *GalleryScanner {
16 | return &GalleryScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Compute/galleries"),
18 | }
19 | }
20 |
21 | // GalleryScanner - Scanner for Gallery
22 | type GalleryScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Gallery Scanner
27 | func (a *GalleryScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: github-actions
9 | directory: /
10 | schedule:
11 | interval: daily
12 |
13 | - package-ecosystem: gomod
14 | directory: /docs
15 | schedule:
16 | interval: daily
17 |
18 | - package-ecosystem: npm
19 | directory: /docs
20 | schedule:
21 | interval: daily
22 |
23 | - package-ecosystem: gomod
24 | directory: /
25 | schedule:
26 | interval: daily
27 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Sql/kql/4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all Elastic Pools that have no databases associated
3 | resources
4 | | where type =~ 'microsoft.sql/servers/elasticpools'
5 | | project elasticPoolId = tolower(id), name, Resource = id, resourceGroup, location, subscriptionId, tags, properties
6 | | join kind=leftouter (resources
7 | | where type =~ 'Microsoft.Sql/servers/databases'
8 | | project id, properties
9 | | extend elasticPoolId = tolower(properties.elasticPoolId)) on elasticPoolId
10 | | summarize databaseCount = countif(id != '') by Resource, name, resourceGroup, location, subscriptionId, tostring(tags)
11 | | where databaseCount == 0
12 | | project recommendationId="4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", name, id=Resource, tags
13 |
--------------------------------------------------------------------------------
/internal/scanners/netapp/netapp.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package netapp
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["netapp"] = []models.IAzureScanner{NewNetAppScanner()}
12 | }
13 |
14 | // NewNetAppScanner creates a new NetAppScanner
15 | func NewNetAppScanner() *NetAppScanner {
16 | return &NetAppScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.NetApp/netAppAccounts"),
18 | }
19 | }
20 |
21 | // NetAppScanner - Scanner for NetApp
22 | type NetAppScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the NetApp Scanner
27 | func (a *NetAppScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/install.ps1:
--------------------------------------------------------------------------------
1 | if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") {
2 | $arch = "amd64"
3 | } elseif ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
4 | $arch = "arm64"
5 | } else {
6 | Write-Host "Unsupported architecture: $($env:PROCESSOR_ARCHITECTURE)"
7 | exit
8 | }
9 |
10 | $latest_azqr=$(iwr https://api.github.com/repos/Azure/azqr/releases/latest).content | convertfrom-json | Select-Object -ExpandProperty tag_name
11 | iwr https://github.com/Azure/azqr/releases/download/$latest_azqr/azqr-win-$arch.zip -OutFile azqr.zip
12 | Expand-Archive -Path azqr.zip -DestinationPath ./azqr_bin
13 | Get-ChildItem -Path ./azqr_bin -Recurse -File | ForEach-Object { Move-Item -Path $_.FullName -Destination . -Force }
14 | Remove-Item -Path ./azqr_bin -Recurse -Force
15 | Remove-Item -Path azqr.zip
16 | .\azqr.exe --version
--------------------------------------------------------------------------------
/internal/scanners/avs/avs.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package avs
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["avs"] = []models.IAzureScanner{NewAVSScanner()}
12 | }
13 |
14 | // NewAVSScanner creates a new AVSScanner
15 | func NewAVSScanner() *AVSScanner {
16 | return &AVSScanner{
17 | BaseScanner: models.NewBaseScanner(
18 | "Microsoft.AVS/privateClouds",
19 | "Specialized.Workload/AVS",
20 | ),
21 | }
22 | }
23 |
24 | // AVSScanner - Scanner for AVS
25 | type AVSScanner struct {
26 | models.BaseScanner
27 | }
28 |
29 | // Init - Initializes the AVS Scanner
30 | func (a *AVSScanner) Init(config *models.ScannerConfig) error {
31 | return a.BaseScanner.Init(config)
32 | }
33 |
--------------------------------------------------------------------------------
/docs/go.sum:
--------------------------------------------------------------------------------
1 | github.com/FortAwesome/Font-Awesome v0.0.0-20230327165841-0698449d50f2/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo=
2 | github.com/FortAwesome/Font-Awesome v0.0.0-20240716171331-37eff7fa00de/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo=
3 | github.com/google/docsy v0.11.0 h1:QnV40cc28QwS++kP9qINtrIv4hlASruhC/K3FqkHAmM=
4 | github.com/google/docsy v0.11.0/go.mod h1:hGGW0OjNuG5ZbH5JRtALY3yvN8ybbEP/v2iaK4bwOUI=
5 | github.com/google/docsy/dependencies v0.7.2 h1:+t5ufoADQAj4XneFphz4A+UU0ICAxmNaRHVWtMYXPSI=
6 | github.com/google/docsy/dependencies v0.7.2/go.mod h1:gihhs5gmgeO+wuoay4FwOzob+jYJVyQbNaQOh788lD4=
7 | github.com/twbs/bootstrap v5.2.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0=
8 | github.com/twbs/bootstrap v5.3.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0=
9 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/4b5c6d7e-8f9a-0b1c-2d3e-4f5a6b7c8d9e.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all subnets without Connected Devices or Delegation
3 | resources
4 | | where type =~ "microsoft.network/virtualnetworks"
5 | | extend subnet = properties.subnets
6 | | mv-expand subnet
7 | | extend ipConfigurations = subnet.properties.ipConfigurations
8 | | extend delegations = subnet.properties.delegations
9 | | extend applicationGatewayIPConfigurations = subnet.properties.applicationGatewayIPConfigurations
10 | | where isnull(ipConfigurations) and delegations == "[]" and isnull(applicationGatewayIPConfigurations)
11 | | extend SubnetName = subnet.name, SubnetId = subnet.id
12 | | project recommendationId="4b5c6d7e-8f9a-0b1c-2d3e-4f5a6b7c8d9e", name=SubnetName, id=SubnetId, tags, param1=strcat("VNET Name: ", name)
13 |
--------------------------------------------------------------------------------
/internal/scanners/conn/conn.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package conn
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["conn"] = []models.IAzureScanner{NewConnectionScanner()}
12 | }
13 |
14 | // NewConnectionScanner creates a new ConnectionScanner
15 | func NewConnectionScanner() *ConnectionScanner {
16 | return &ConnectionScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Network/connections"),
18 | }
19 | }
20 |
21 | // ConnectionScanner - Scanner for Connection
22 | type ConnectionScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Connection Scanner
27 | func (a *ConnectionScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/ba/ba.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package ba
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["ba"] = []models.IAzureScanner{NewBatchAccountScanner()}
12 | }
13 |
14 | // NewBatchAccountScanner creates a new BatchAccountScanner
15 | func NewBatchAccountScanner() *BatchAccountScanner {
16 | return &BatchAccountScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Batch/batchAccounts"),
18 | }
19 | }
20 |
21 | // BatchAccountScanner - Scanner for Batch Account
22 | type BatchAccountScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Batch Account Scanner
27 | func (a *BatchAccountScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Compute/kql/3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all disks that are not attached
3 | resources
4 | | where type has "microsoft.compute/disks"
5 | | extend diskState = tostring(properties.diskState)
6 | | where (managedBy == "" and diskState != 'ActiveSAS') or (diskState == 'Unattached' and diskState != 'ActiveSAS')
7 | | where not(name endswith "-ASRReplica" or name startswith "ms-asr-" or name startswith "asrseeddisk-")
8 | | where (tags !contains "kubernetes.io-created-for-pvc") and tags !contains "ASR-ReplicaDisk" and tags !contains "asrseeddisk" and tags !contains "RSVaultBackup"
9 | | extend Details = pack_all()
10 | | project recommendationId="3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f", name, id, tags, param1=strcat("Sku: ", sku.name), param2=strcat("diskSizeGB: ", properties.diskSizeGB)
11 |
--------------------------------------------------------------------------------
/internal/scanners/rg/rg.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package rg
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["rg"] = []models.IAzureScanner{NewResourceGroupScanner()}
12 | }
13 |
14 | // NewResourceGroupScanner creates a new ResourceGroupScanner
15 | func NewResourceGroupScanner() *ResourceGroupScanner {
16 | return &ResourceGroupScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Resources/resourceGroups"),
18 | }
19 | }
20 |
21 | // ResourceGroupScanner - Scanner for Resource Groups
22 | type ResourceGroupScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Resource Groups Scanner
27 | func (a *ResourceGroupScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/cmd/server/commands/root.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "os"
8 | "time"
9 |
10 | "github.com/spf13/cobra"
11 |
12 | "github.com/rs/zerolog"
13 | "github.com/rs/zerolog/log"
14 | )
15 |
16 | var (
17 | version = "dev"
18 | )
19 |
20 | var rootCmd = &cobra.Command{
21 | Use: "azqr-server",
22 | Short: "Azure Quick Review (azqr) API and MCP server",
23 | Long: "Azure Quick Review (azqr) API and MCP server",
24 | Args: cobra.NoArgs,
25 | Version: version,
26 | Run: func(cmd *cobra.Command, args []string) {
27 | _ = cmd.Usage()
28 | },
29 | }
30 |
31 | func Execute() {
32 | output := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}
33 |
34 | log.Logger = zerolog.New(output).With().Timestamp().Logger()
35 |
36 | cobra.CheckErr(rootCmd.Execute())
37 | }
38 |
--------------------------------------------------------------------------------
/internal/scanners/rsv/rsv.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package rsv
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["rsv"] = []models.IAzureScanner{NewRecoveryServiceScanner()}
12 | }
13 |
14 | // NewRecoveryServiceScanner creates a new RecoveryServiceScanner
15 | func NewRecoveryServiceScanner() *RecoveryServiceScanner {
16 | return &RecoveryServiceScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.RecoveryServices/vaults"),
18 | }
19 | }
20 |
21 | // RecoveryServiceScanner - Scanner for Recovery Service
22 | type RecoveryServiceScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Recovery Service Scanner
27 | func (a *RecoveryServiceScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/avail/avail.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package avail
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["avail"] = []models.IAzureScanner{NewAvailabilitySetScanner()}
12 | }
13 |
14 | // NewAvailabilitySetScanner creates a new AvailabilitySetScanner
15 | func NewAvailabilitySetScanner() *AvailabilitySetScanner {
16 | return &AvailabilitySetScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Compute/availabilitySets"),
18 | }
19 | }
20 |
21 | // AvailabilitySetScanner - Scanner for Availability Set
22 | type AvailabilitySetScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Availability Set Scanner
27 | func (a *AvailabilitySetScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/aa/aa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package aa
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["aa"] = []models.IAzureScanner{NewAutomationAccountScanner()}
12 | }
13 |
14 | // NewAutomationAccountScanner creates a new AutomationAccountScanner
15 | func NewAutomationAccountScanner() *AutomationAccountScanner {
16 | return &AutomationAccountScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Automation/automationAccounts"),
18 | }
19 | }
20 |
21 | // AutomationAccountScanner - Scanner for Automation Account
22 | type AutomationAccountScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Automation Account Scanner
27 | func (a *AutomationAccountScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/avd/avd.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package avd
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["avd"] = []models.IAzureScanner{NewAzureVirtualDesktopScanner()}
12 | }
13 |
14 | // NewAzureVirtualDesktopScanner creates a new AzureVirtualDesktopScanner
15 | func NewAzureVirtualDesktopScanner() *AzureVirtualDesktopScanner {
16 | return &AzureVirtualDesktopScanner{
17 | BaseScanner: models.NewBaseScanner("Specialized.Workload/AVD"),
18 | }
19 | }
20 |
21 | // AzureVirtualDesktopScanner - Scanner for Azure Virtual Desktop
22 | type AzureVirtualDesktopScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Azure Virtual Desktop Scanner
27 | func (a *AzureVirtualDesktopScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/erc/erc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package erc
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["erc"] = []models.IAzureScanner{NewExpressRouteScanner()}
12 | }
13 |
14 | // NewExpressRouteScanner creates a new ExpressRouteScanner
15 | func NewExpressRouteScanner() *ExpressRouteScanner {
16 | return &ExpressRouteScanner{
17 | BaseScanner: models.NewBaseScanner(
18 | "Microsoft.Network/expressRouteCircuits",
19 | "Microsoft.Network/ExpressRoutePorts",
20 | ),
21 | }
22 | }
23 |
24 | // ExpressRouteScanner - Scanner for Express Route
25 | type ExpressRouteScanner struct {
26 | models.BaseScanner
27 | }
28 |
29 | // Init - Initializes the Express Route Scanner
30 | func (a *ExpressRouteScanner) Init(config *models.ScannerConfig) error {
31 | return a.BaseScanner.Init(config)
32 | }
33 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to
4 | agree to a Contributor License Agreement (CLA) declaring that you have the right to,
5 | and actually do, grant us the rights to use your contribution. For details, visit
6 | https://cla.microsoft.com.
7 |
8 | When you submit a pull request, a CLA-bot will automatically determine whether you need
9 | to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
10 | instructions provided by the bot. You will only need to do this once across all repositories using our CLA.
11 |
12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
14 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Web/kql/2d3e4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all API Connections not related to any Logic App
3 | resources
4 | | where type =~ 'Microsoft.Web/connections'
5 | | project subscriptionId, Resource = id , apiName = name, resourceGroup, tags, location
6 | | join kind = leftouter (
7 | resources
8 | | where type == 'microsoft.logic/workflows'
9 | | extend resourceGroup, location, subscriptionId, properties
10 | | extend varJson = properties["parameters"]["$connections"]["value"]
11 | | mvexpand varConnection = varJson
12 | | where notnull(varConnection)
13 | | extend connectionId = extract("connectionId\":\"(.*?)\"", 1, tostring(varConnection))
14 | | project connectionId, name
15 | )
16 | on $left.Resource == $right.connectionId
17 | | where connectionId == ""
18 | | project recommendationId="2d3e4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a", name, id=Resource, tags
19 |
--------------------------------------------------------------------------------
/internal/scanners/odb/odb.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package odb
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["odb"] = []models.IAzureScanner{NewOracleDatabaseScanner()}
12 | }
13 |
14 | // NewOracleDatabaseScanner creates a new OracleDatabaseScanner
15 | func NewOracleDatabaseScanner() *OracleDatabaseScanner {
16 | return &OracleDatabaseScanner{
17 | BaseScanner: models.NewBaseScanner(
18 | "Oracle.Database/cloudExadataInfrastructures",
19 | "Oracle.Database/cloudVmClusters",
20 | ),
21 | }
22 | }
23 |
24 | // OracleDatabaseScanner - Scanner for Oracle Database@Azure
25 | type OracleDatabaseScanner struct {
26 | models.BaseScanner
27 | }
28 |
29 | // Init - Initializes the Oracle Database Scanner
30 | func (a *OracleDatabaseScanner) Init(config *models.ScannerConfig) error {
31 | return a.BaseScanner.Init(config)
32 | }
33 |
--------------------------------------------------------------------------------
/docs/content/en/docs/Install/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Install
3 | weight: 2
4 | description: Learn how to install Azure Quick Review (azqr)
5 | ---
6 |
7 | ## Install on Linux or Azure Cloud Shell
8 |
9 | ```bash
10 | bash -c "$(curl -fsSL https://raw.githubusercontent.com/azure/azqr/main/scripts/install.sh)"
11 | ```
12 |
13 | ## Install on Windows
14 |
15 | Use `winget`:
16 |
17 | ``` console
18 | winget install azqr
19 | ```
20 |
21 | or download the executable file:
22 |
23 | ```
24 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/azure/azqr/main/scripts/install.ps1'))
25 | ```
26 |
27 | ## Install on Mac
28 |
29 | Use `homebrew`:
30 |
31 | ```console
32 | brew install azqr
33 | ```
34 |
35 | or download the latest release from [here](https://github.com/Azure/azqr/releases).
--------------------------------------------------------------------------------
/internal/scanners/fdfp/fdfp.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package fdfp
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["fdfp"] = []models.IAzureScanner{NewFrontDoorWAFPolicyScanner()}
12 | }
13 |
14 | // NewFrontDoorWAFPolicyScanner creates a new FrontDoorWAFPolicyScanner
15 | func NewFrontDoorWAFPolicyScanner() *FrontDoorWAFPolicyScanner {
16 | return &FrontDoorWAFPolicyScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Network/frontdoorWebApplicationFirewallPolicies"),
18 | }
19 | }
20 |
21 | // FrontDoorWAFPolicyScanner - Scanner for Front Door Web Application Policy
22 | type FrontDoorWAFPolicyScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Front Door Web Application Policy Scanner
27 | func (a *FrontDoorWAFPolicyScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/hpc/hpc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package hpc
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["hpc"] = []models.IAzureScanner{NewHighPerformanceComputingScanner()}
12 | }
13 |
14 | // NewHighPerformanceComputingScanner creates a new HighPerformanceComputingScanner
15 | func NewHighPerformanceComputingScanner() *HighPerformanceComputingScanner {
16 | return &HighPerformanceComputingScanner{
17 | BaseScanner: models.NewBaseScanner("Specialized.Workload/HPC"),
18 | }
19 | }
20 |
21 | // HighPerformanceComputingScanner - Scanner for High Performance Computing
22 | type HighPerformanceComputingScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the High Performance Computing Scanner
27 | func (a *HighPerformanceComputingScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/scanners/pdnsz/pdnsz.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package pdnsz
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["pdnsz"] = []models.IAzureScanner{NewPrivateDNSZoneScanner()}
12 | }
13 |
14 | // NewPrivateDNSZoneScanner creates a new PrivateDNSZoneScanner
15 | func NewPrivateDNSZoneScanner() *PrivateDNSZoneScanner {
16 | return &PrivateDNSZoneScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.Network/privateDnsZones"),
18 | }
19 | }
20 |
21 | // PrivateDNSZoneScanner - Scanner for Private DNS Zone
22 | type PrivateDNSZoneScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Private DNS Zone Scanner
27 | func (a *PrivateDNSZoneScanner) Init(config *models.ScannerConfig) error {
28 | return a.BaseScanner.Init(config)
29 | }
30 |
31 | // TODO: version 6.1.0 of armentowrk does not allow listing per subscription yet.
32 |
--------------------------------------------------------------------------------
/internal/graph/azure-orphan-resources/Network/kql/9a0b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d.kql:
--------------------------------------------------------------------------------
1 | // Azure Resource Graph Query
2 | // Get all virtual network gateways without Point-to-site configuration or Connections
3 | resources
4 | | where type =~ "microsoft.network/virtualnetworkgateways"
5 | | extend SKU = tostring(properties.sku.name)
6 | | extend Tier = tostring(properties.sku.tier)
7 | | extend GatewayType = tostring(properties.gatewayType)
8 | | extend vpnClientConfiguration = properties.vpnClientConfiguration
9 | | extend Resource = id
10 | | join kind=leftouter (
11 | resources
12 | | where type =~ "microsoft.network/connections"
13 | | mv-expand Resource = pack_array(properties.virtualNetworkGateway1.id, properties.virtualNetworkGateway2.id) to typeof(string)
14 | | project Resource, connectionId = id, ConnectionProperties=properties
15 | ) on Resource
16 | | where isempty(vpnClientConfiguration) and isempty(connectionId)
17 | | project recommendationId="9a0b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d", name, id, tags
18 |
--------------------------------------------------------------------------------
/internal/scanners/vdpool/vdpool.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package vdpool
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["vdpool"] = []models.IAzureScanner{NewVirtualDesktopScanner()}
12 | }
13 |
14 | // NewVirtualDesktopScanner creates a new VirtualDesktopScanner
15 | func NewVirtualDesktopScanner() *VirtualDesktopScanner {
16 | return &VirtualDesktopScanner{
17 | BaseScanner: models.NewBaseScanner(
18 | "Microsoft.DesktopVirtualization/hostPools",
19 | "Microsoft.DesktopVirtualization/scalingPlans",
20 | "Microsoft.DesktopVirtualization/workspaces",
21 | ),
22 | }
23 | }
24 |
25 | // VirtualDesktopScanner - Scanner for Virtual Desktop
26 | type VirtualDesktopScanner struct {
27 | models.BaseScanner
28 | }
29 |
30 | // Init - Initializes the Virtual Desktop Scanner
31 | func (a *VirtualDesktopScanner) Init(config *models.ScannerConfig) error {
32 | return a.BaseScanner.Init(config)
33 | }
34 |
--------------------------------------------------------------------------------
/examples/cicd/github-actions.yml:
--------------------------------------------------------------------------------
1 | # GitHub Actions workflow for azqr
2 |
3 | name: azqr-pipeline
4 |
5 | on:
6 | workflow_dispatch: # Trigger manually
7 | schedule: # Trigger every Friday at midnight
8 | - cron: "0 0 * * 5"
9 | push:
10 | branches:
11 | - main # Trigger on push to main
12 | pull_request:
13 | branches:
14 | - main # Trigger on pull request to main
15 |
16 | jobs:
17 | azqr:
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | # Checkout the repository
22 | - name: Checkout repository
23 | uses: actions/checkout@v2
24 |
25 | # Run azqr scan
26 | - name: Run Azure Quick Review
27 | uses: Azure/azqr/.github/actions/azqr-scan
28 | env:
29 | AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
30 | AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
31 | AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
32 | with:
33 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
34 | output-format: 'json'
35 |
--------------------------------------------------------------------------------
/docs/content/en/docs/Troubleshooting/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Troubleshooting & Support
3 | description: Troubleshooting & Support
4 | weight: 4
5 | ---
6 |
7 | If you encounter any issue while using **Azure Quick Review (azqr)**, please set the `AZURE_SDK_GO_LOGGING` environment variable to `all`, run the tool with the `--debug` flag and then share the console output with us by filing a new [issue](https://github.com/Azure/azqr/issues).
8 |
9 | ## Support
10 |
11 | This project uses GitHub Issues to track bugs and feature requests.
12 | Before logging an issue please check our [troubleshooting](#troubleshooting) guide.
13 |
14 | Please search the existing issues before filing new issues to avoid duplicates.
15 |
16 | - For new issues, file your bug or feature request as a new [issue](https://github.com/Azure/azqr/issues).
17 | - For help, discussion, and support questions about using this project, join or start a [discussion](https://github.com/Azure/azqr/discussions).
18 |
19 | Support for this project / product is limited to the resources listed above.
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch Scan",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "program": "${fileDirname}",
13 | "args": [
14 | "scan"
15 | ],
16 | "env": {
17 | "AZURE_SDK_GO_LOGGING": "all"
18 | }
19 | },
20 | {
21 | "name": "Launch Server",
22 | "type": "go",
23 | "request": "launch",
24 | "mode": "auto",
25 | "program": "${fileDirname}",
26 | "args": [
27 | "serve"
28 | ],
29 | "env": {
30 | "AZURE_SDK_GO_LOGGING": "all"
31 | }
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # If you prefer the allow list template instead of the deny list, see community template:
2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3 | #
4 | # Binaries for programs and plugins
5 | *.exe
6 | *.exe~
7 | *.dll
8 | *.so
9 | *.dylib
10 |
11 | # Test binary, built with `go test -c`
12 | *.test
13 | coverage.txt
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Jetbrains IDE
19 | .idea/
20 | # Dependency directories (remove the comment below to include it)
21 | # vendor/
22 |
23 | # Go workspace file
24 | go.work
25 |
26 | # Go profiling
27 | *.prof
28 | profiles/
29 |
30 | ## Hugo & Node
31 | public/
32 | resources/
33 | node_modules/
34 | package-lock.json
35 | .hugo_build.lock
36 |
37 | dist/
38 |
39 | # azqr build and runtime artifacts
40 | .azqr
41 | main
42 | main.exe
43 |
44 | # azqr binaries
45 | bin/
46 | /azqr
47 | azqr.exe
48 |
49 | # azqr outputs
50 | *.xlsx
51 | *.csv
52 |
53 | # Windows resource files (generated by make)
54 | cmd/azqr/winres/winres.json
55 | cmd/azqr/*.syso
56 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review.yml:
--------------------------------------------------------------------------------
1 | # Dependency Review Action
2 | #
3 | # This Action will scan dependency manifest files that change as part of a Pull Request,
4 | # surfacing known-vulnerable versions of the packages declared or updated in the PR.
5 | # Once installed, if the workflow run is marked as required,
6 | # PRs introducing known-vulnerable packages will be blocked from merging.
7 | #
8 | # Source repository: https://github.com/actions/dependency-review-action
9 | name: 'Dependency Review'
10 | on: [pull_request]
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | dependency-review:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Harden Runner
20 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
21 | with:
22 | egress-policy: audit
23 |
24 | - name: 'Checkout Repository'
25 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
26 | - name: 'Dependency Review'
27 | uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/internal/renderers/excel/advisor.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package excel
5 |
6 | import (
7 | _ "image/png"
8 |
9 | "github.com/Azure/azqr/internal/renderers"
10 | "github.com/rs/zerolog/log"
11 | "github.com/xuri/excelize/v2"
12 | )
13 |
14 | func renderAdvisor(f *excelize.File, data *renderers.ReportData) {
15 | _, err := f.NewSheet("Advisor")
16 | if err != nil {
17 | log.Fatal().Err(err).Msg("Failed to create Advisor sheet")
18 | }
19 |
20 | records := data.AdvisorTable()
21 | headers := records[0]
22 | createFirstRow(f, "Advisor", headers)
23 |
24 | if len(data.Advisor) > 0 {
25 | records = records[1:]
26 | currentRow := 4
27 | for _, row := range records {
28 | currentRow += 1
29 | cell, err := excelize.CoordinatesToCellName(1, currentRow)
30 | if err != nil {
31 | log.Fatal().Err(err).Msg("Failed to get cell")
32 | }
33 | err = f.SetSheetRow("Advisor", cell, &row)
34 | if err != nil {
35 | log.Fatal().Err(err).Msg("Failed to set row")
36 | }
37 | }
38 |
39 | configureSheet(f, "Advisor", headers, currentRow)
40 | } else {
41 | log.Info().Msg("Skipping Advisor. No data to render")
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/internal/renderers/excel/cost.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package excel
5 |
6 | import (
7 | _ "image/png"
8 |
9 | "github.com/Azure/azqr/internal/renderers"
10 | "github.com/rs/zerolog/log"
11 | "github.com/xuri/excelize/v2"
12 | )
13 |
14 | func renderCosts(f *excelize.File, data *renderers.ReportData) {
15 | _, err := f.NewSheet("Costs")
16 | if err != nil {
17 | log.Fatal().Err(err).Msg("Failed to create Costs sheet")
18 | }
19 |
20 | records := data.CostTable()
21 | headers := records[0]
22 | createFirstRow(f, "Costs", headers)
23 |
24 | if data.Cost != nil && len(data.Cost.Items) > 0 {
25 | records = records[1:]
26 | currentRow := 4
27 | for _, row := range records {
28 | currentRow += 1
29 | cell, err := excelize.CoordinatesToCellName(1, currentRow)
30 | if err != nil {
31 | log.Fatal().Err(err).Msg("Failed to get cell")
32 | }
33 | err = f.SetSheetRow("Costs", cell, &row)
34 | if err != nil {
35 | log.Fatal().Err(err).Msg("Failed to set row")
36 | }
37 | }
38 |
39 | configureSheet(f, "Costs", headers, currentRow)
40 | } else {
41 | log.Info().Msg("Skipping Costs. No data to render")
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/internal/throttling/limiter.go:
--------------------------------------------------------------------------------
1 | package throttling
2 |
3 | import (
4 | "context"
5 |
6 | "golang.org/x/time/rate"
7 | )
8 |
9 | // ARMLimiter rate limits Azure Resource Manager API calls
10 | // Allows 3 operations per second with burst capacity of 100
11 | // https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling#regional-throttling-and-token-bucket-algorithm
12 | var ARMLimiter = rate.NewLimiter(rate.Limit(3), 100)
13 |
14 | // GraphLimiter rate limits Azure Resource Graph API calls
15 | // Allows 3 operations per second with burst capacity of 10
16 | // With higher burst capacity to better utilize the 5-second window
17 | // https://learn.microsoft.com/en-us/azure/governance/resource-graph/concepts/guidance-for-throttled-requests#staggering-queries
18 | var GraphLimiter = rate.NewLimiter(rate.Limit(2), 10)
19 |
20 | // WaitARM waits for permission to make an ARM API call using the provided context
21 | func WaitARM(ctx context.Context) error {
22 | return ARMLimiter.Wait(ctx)
23 | }
24 |
25 | // WaitGraph waits for permission to make a Graph API call using the provided context
26 | func WaitGraph(ctx context.Context) error {
27 | return GraphLimiter.Wait(ctx)
28 | }
29 |
--------------------------------------------------------------------------------
/cmd/azqr/commands/root.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package commands
5 |
6 | import (
7 | "os"
8 | "time"
9 |
10 | "github.com/spf13/cobra"
11 |
12 | "github.com/Azure/azqr/internal/plugins"
13 | "github.com/rs/zerolog"
14 | "github.com/rs/zerolog/log"
15 | )
16 |
17 | var (
18 | version = "dev"
19 | )
20 |
21 | var rootCmd = &cobra.Command{
22 | Use: "azqr",
23 | Short: "Azure Quick Review (azqr) goal is to produce a high level assessment of an Azure Subscription or Resource Group",
24 | Long: `Azure Quick Review (azqr) goal is to produce a high level assessment of an Azure Subscription or Resource Group`,
25 | Args: cobra.NoArgs,
26 | Version: version,
27 | Run: func(cmd *cobra.Command, args []string) {
28 | _ = cmd.Usage()
29 | },
30 | }
31 |
32 | func Execute() {
33 | output := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}
34 |
35 | log.Logger = zerolog.New(output).With().Timestamp().Logger()
36 |
37 | // Load all YAML plugins after logger is configured
38 | if err := plugins.LoadAll(); err != nil {
39 | log.Warn().Err(err).Msg("Failed to load some plugins")
40 | }
41 |
42 | cobra.CheckErr(rootCmd.Execute())
43 | }
44 |
--------------------------------------------------------------------------------
/internal/scanners/arc/arc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package arc
5 |
6 | import (
7 | "github.com/Azure/azqr/internal/models"
8 | )
9 |
10 | func init() {
11 | models.ScannerList["arc"] = []models.IAzureScanner{NewArcScanner()}
12 | }
13 |
14 | // NewArcScanner creates a new ArcScanner
15 | func NewArcScanner() *ArcScanner {
16 | return &ArcScanner{
17 | BaseScanner: models.NewBaseScanner("Microsoft.AzureArcData/sqlServerInstances"),
18 | }
19 | }
20 |
21 | // ArcScanner - Scanner for Arc SQL
22 | type ArcScanner struct {
23 | models.BaseScanner
24 | }
25 |
26 | // Init - Initializes the Arc SQL Scanner
27 | func (c *ArcScanner) Init(config *models.ScannerConfig) error {
28 | return c.BaseScanner.Init(config)
29 | }
30 |
31 | // Scan - Scans all Azure Arc-enabled machines in a Resource Group
32 | func (c *ArcScanner) Scan(scanContext *models.ScanContext) ([]*models.AzqrServiceResult, error) {
33 | models.LogSubscriptionScan(c.BaseScanner.GetConfig().SubscriptionID, c.ResourceTypes()[0])
34 | // This scanner doesn't perform actual scans - it's here to register the resource type
35 | // Actual Arc SQL scanning is done by the graph-based ArcSQLScanner
36 | return []*models.AzqrServiceResult{}, nil
37 | }
38 |
--------------------------------------------------------------------------------
/internal/renderers/excel/arc_sql.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | package excel
5 |
6 | import (
7 | _ "image/png"
8 |
9 | "github.com/Azure/azqr/internal/renderers"
10 | "github.com/rs/zerolog/log"
11 | "github.com/xuri/excelize/v2"
12 | )
13 |
14 | // renderArcSQL creates and populates the Arc SQL sheet in the Excel report.
15 | func renderArcSQL(f *excelize.File, data *renderers.ReportData) {
16 | _, err := f.NewSheet("Arc SQL")
17 | if err != nil {
18 | log.Fatal().Err(err).Msg("Failed to create Arc SQL sheet")
19 | }
20 |
21 | records := data.ArcSQLTable()
22 | headers := records[0]
23 | createFirstRow(f, "Arc SQL", headers)
24 |
25 | if len(data.ArcSQL) > 0 {
26 | records = records[1:]
27 | currentRow := 4
28 | for _, row := range records {
29 | currentRow += 1
30 | cell, err := excelize.CoordinatesToCellName(1, currentRow)
31 | if err != nil {
32 | log.Fatal().Err(err).Msg("Failed to get cell")
33 | }
34 | err = f.SetSheetRow("Arc SQL", cell, &row)
35 | if err != nil {
36 | log.Fatal().Err(err).Msg("Failed to set row")
37 | }
38 | }
39 |
40 | configureSheet(f, "Arc SQL", headers, currentRow)
41 | } else {
42 | log.Info().Msg("Skipping Arc SQL. No data to render")
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jumpstart_drops/azqr-tutorial.json:
--------------------------------------------------------------------------------
1 | {
2 | "Title": " Azure Quick Review Tutorial",
3 | "Summary": "This Drop provides a tutorial on how to use the Azure Quick Review tool to assess your Azure environment.",
4 | "Description": "This Drop provides a tutorial on how to use the Azure Quick Review tool to assess your Azure environment. The Azure Quick Review tool is a free, open-source tool that helps you assess your Azure environment and identify areas for improvement. The tool provides a comprehensive report that includes recommendations for best practices, security, and cost optimization.",
5 | "Cover": "",
6 | "Authors": [
7 | {
8 | "Name": "Carlos Mendible",
9 | "Link": "https://linkedin.com/in/carlosmendible"
10 | }
11 | ],
12 | "Source": "https://github.com/Azure/azqr/tree/main/jumpstart_drops/azqr-tutorial",
13 | "Type": "tutorial_guide",
14 | "Difficulty": "Medium",
15 | "ProgrammingLanguage": [
16 | "Bash",
17 | "Powershell"
18 | ],
19 | "Products": [
20 | "Azure Kubernetes Service",
21 | "Azure Cosmos DB",
22 | "Azure Firewall"
23 | ],
24 | "LastModified": "2025-02-25T14:27:00.000Z",
25 | "CreatedDate": "2025-02-25T14:27:00.000Z",
26 | "Topics": []
27 | }
28 |
--------------------------------------------------------------------------------
/docs/assets/icons/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |