From 297ef911ad8ed6622de0e78821190df0f9a1f0f8 Mon Sep 17 00:00:00 2001 From: erjosito Date: Tue, 19 Sep 2023 14:21:18 +0000 Subject: [PATCH] [create-pull-request] automated change --- checklists/aro_checklist.en.json | 2 +- checklists/aro_checklist.es.json | 18 +- checklists/aro_checklist.ja.json | 18 +- checklists/aro_checklist.ko.json | 18 +- checklists/aro_checklist.pt.json | 18 +- spreadsheet/macrofree/aro_checklist.en.xlsx | Bin 25138 -> 25221 bytes spreadsheet/macrofree/aro_checklist.es.xlsx | Bin 25686 -> 25786 bytes spreadsheet/macrofree/aro_checklist.ja.xlsx | Bin 26845 -> 26982 bytes spreadsheet/macrofree/aro_checklist.ko.xlsx | Bin 26398 -> 26511 bytes spreadsheet/macrofree/aro_checklist.pt.xlsx | Bin 25741 -> 25842 bytes .../alz_checklist.en_network_counters.json | 496 ++-- ...hecklist.en_network_counters_template.json | 2 +- .../alz_checklist.en_network_tabcounters.json | 2186 ++++++++--------- ...klist.en_network_tabcounters_template.json | 2 +- .../alz_checklist.en_network_workbook.json | 498 ++-- ...hecklist.en_network_workbook_template.json | 2 +- 16 files changed, 1662 insertions(+), 1598 deletions(-) diff --git a/checklists/aro_checklist.en.json b/checklists/aro_checklist.en.json index 46f9afec6..8d6943bd6 100644 --- a/checklists/aro_checklist.en.json +++ b/checklists/aro_checklist.en.json @@ -546,4 +546,4 @@ "state": " ", "timestamp": "September 19, 2023" } -} +} \ No newline at end of file diff --git a/checklists/aro_checklist.es.json b/checklists/aro_checklist.es.json index 60b013502..1c9b8b31c 100644 --- a/checklists/aro_checklist.es.json +++ b/checklists/aro_checklist.es.json @@ -1,5 +1,21 @@ { - "categories": [], + "categories": [ + { + "name": "Gestión de identidades y accesos" + }, + { + "name": "Topología y conectividad de red" + }, + { + "name": "Gestión de operaciones" + }, + { + "name": "Automatización de plataformas" + }, + { + "name": "Seguridad" + } + ], "items": [ { "category": "Gestión de identidades y accesos", diff --git a/checklists/aro_checklist.ja.json b/checklists/aro_checklist.ja.json index a76f1097e..dfea0e391 100644 --- a/checklists/aro_checklist.ja.json +++ b/checklists/aro_checklist.ja.json @@ -1,5 +1,21 @@ { - "categories": [], + "categories": [ + { + "name": "ID およびアクセス管理" + }, + { + "name": "ネットワーク トポロジと接続性" + }, + { + "name": "運用管理" + }, + { + "name": "プラットフォームの自動化" + }, + { + "name": "安全" + } + ], "items": [ { "category": "ID およびアクセス管理", diff --git a/checklists/aro_checklist.ko.json b/checklists/aro_checklist.ko.json index 6a4ce3fc2..bff44792b 100644 --- a/checklists/aro_checklist.ko.json +++ b/checklists/aro_checklist.ko.json @@ -1,5 +1,21 @@ { - "categories": [], + "categories": [ + { + "name": "ID 및 액세스 관리" + }, + { + "name": "네트워크 토폴로지 및 연결" + }, + { + "name": "운영 관리" + }, + { + "name": "플랫폼 자동화" + }, + { + "name": "안전" + } + ], "items": [ { "category": "ID 및 액세스 관리", diff --git a/checklists/aro_checklist.pt.json b/checklists/aro_checklist.pt.json index 88b658d05..14410d5f0 100644 --- a/checklists/aro_checklist.pt.json +++ b/checklists/aro_checklist.pt.json @@ -1,5 +1,21 @@ { - "categories": [], + "categories": [ + { + "name": "Gerenciamento de identidades e acesso" + }, + { + "name": "Topologia de rede e conectividade" + }, + { + "name": "Gestão de operações" + }, + { + "name": "Automação de Plataformas" + }, + { + "name": "Segurança" + } + ], "items": [ { "category": "Gerenciamento de identidades e acesso", diff --git a/spreadsheet/macrofree/aro_checklist.en.xlsx b/spreadsheet/macrofree/aro_checklist.en.xlsx index f233bee5e67b629143dadc54244f883291f7edde..cc093850bef26ab5d72c47d63deb7e1a27aeec79 100644 GIT binary patch delta 1661 zcmZ9Ndpy%?9LImZxkPTsXfm8huDN6pQbM(jbB=Kw)3VHR=^`E5DBX4mb(CCw%ApG* zYdJP2o1)NJhjk?4P=pa%Zc92fIi=dMUa!vSoac|{dA*<4=k>S2?GFQ2qeQ9nfYNMzq!LRRl!q7O1RQ&J(6|A z(PesUt=5})L;G8~x^3r@Rm0V3Qi-NDt+Qcd3JgRPK(*@^IWY*%s^eZQpYyUPGSSkJW&MqL&)VY)+3{Tz;SwbWTBIP7Ir z?kk%42Ir=v5>?L3?7Pd)F40r`C2yQC%I)|rI)0A?dmnovDN6i$biDh0@ zQjyA-Rv^&X;h7{xOSY#3_<>a((E<}I1rAZ~AI+F}Y*nY&MezT!W5PF}SR2Np3LA8+ zaE9vMmEyQ2Pc;C*L?3zdXw9^ge8?$h)o(}6zLCIlD8CuHj8>t-~I<->s?sqGnJH(AU!UphqB8Y~ zgyi4dr8*pPPPx{{p!Ex;?wTYJiK+|y+nrZWWbl6-%b7I0TxXWr6knd^(re3U>wVv< zN`TTQ7tE*x3{!bWy%S zz7Z4mYRJ!u+hN=n!w(??R?z8ls`ibC1CJBjim=Y zsTWfPRx?-MOsz2RzlTKIM5hX=yzRKRFWx0DCmt{kB*LhQzOshJER0o@2Ix_psREOIXob7$;$fcu9BQ`p|yVoA8s$Gbt+h z5~bhloL}yv`kg0R{N^bi%|WTCz$PH;=e1tTXPBd#dL~61@ENZWVhiWP7B48Hj1wc) zN?+Q$uo6>#%FHqGj796#u7>M>mMXzYx3u7xoyfw@_+nNJ-#vED)uw(nqW?v%9*}z6Mu0CTJA=PI}rLl`O(zy z#!gcDY`vq_Ic5esO52`c`+!css=iK}E1l72k zG_A&no%m14jq%g{N4$_C#>-kw;uXu93$y`1^3|eF7H#}_F~KQlGuh@-Mn}8Cbs7r* z86hwL@j0+~GFjCSi){ZX^RJSC|79LP_sI6@|GXq4!7<1n7O4j3SfuY95ddPS@kul{ zSM`n$0by{B&vODzSP`*=dS!7!*e{yS=*zO;FvNq)oBY JR>Y{|e*<85;#B|u delta 1635 zcmY+FdpOg39LIkfWA68rOQcRN&8^g$yC(M?p;_cMMhJ~1bd1TN(=m#E=(OxGhNFwj zlqr!AwbP`ObDpMBvYJwu>q*Ymc{=6u&-ZzMp7-bZexA?sd|sb|K1fS1MA_e0MphdD z05~8flqxq-#RS{^OMWL%N)SmB3IH0CCx%4yCzDc+SQAO)SgXwBq=M2&-yR$7zAm4) zS#;KDy;8Ulj-sxV2kUDq5hV9bsCl!Vw(YtY-d6L1$hTX_*vqYJ#;%vQ<_D)RVO0jW z1}Cj_aLTP&nP@#<%^i%!cpgctd}-`Fs!9#Da$ZtR@f%P?!oy~6O)H#yw+HLV($;#I z(|#E6I?j}V*=J&H3$6bK{FYqg<>Gt{DGqhZorBBK1AQLaT_b~6+>Q+&GU6gi@O9c) z^owq;=x(N$=r8cz6RQ91i`6U24?5-Xi^X?K## z>vp7`zhJ{T#E$I7q9B9D#7V(bM5eB*&%~>t_%leWG*s0Iwo!#neLg9y+v3K;X5w;; zeHn%-lbyy06f{}8(jQwm@UO{a)Eu@^9-mF%C358{@d~b^lpe>b3e55J+wljP^jKkk z6#~qK+kQqglO2*LURxF)6Emz|Tj(!^=jB74U=3BKTv_v96R-|TkHJ%%v+hphwwrZb zs;3^zR|vZ6N>@*6o)4KfCT_uXfSGalUDW2GGz45}bNJ#Qer5bsz@3U09}kFc)A-B) zeG?Iq8K;}iVG?s&pOj&n&QO06Dy)qX9|%&AUkCs@psre5-RV(Smw2=oUQ) z1Fel|>OGPlKkZ@eR6Kd%c|2M1zOi$^8>JpjG7E{`Z8x=$TA7<|J3!g9A9^pCQdcos zzz?Y7P>$l1lCH-JZy`K3$2(HD7Tp_MowOK7{BHLCxyq0bbCs8|%(lT^UUn^|sWiW% z9V&J=F}F3VkwO}0ymo7Vb~UI1bsi)t4{S=c%`oL7J^gkgHz}}CY-{zE-K3|Caxn4mH-@T?()7Y z7JcmLCOs0Wk?Y0Ao~YF2M<;?9b1UIp0%Xsg9r(aW7rK)NBf0oG`sqc1u%jT7(VRLR zcbAtxLpN04qISqWJdoKNBsFmrCvQ#NYU46e(Tqrx4Rfa3yhE9tx%nj!i8R@kClS1J9IfCWE=1I)4 zY5P^9H9I^NqydxcFbD}1N>^DFItY=<8{s0UY>4pxB9|f^75;}M=uAKvNmchc_0BVL z0B~m`0BA|j`89GOA`m2O`r?7h)mn+X03hENDnY`x$US};94454@vOzh_n!NpUetdc ze90T!8(9D_vjG5=Zx$dIavCH=8AyB1i86rHfajz1!lccu!^x9b60Vy{c%-(bfEEe> znMu|eBywUjiIga1yuU95sx9;NG}!LH7(upbl@t|Aj)LBr;xJGn+FbgZW3&Op3k-=i Kk^3!D>i8F~F~A-G diff --git a/spreadsheet/macrofree/aro_checklist.es.xlsx b/spreadsheet/macrofree/aro_checklist.es.xlsx index 1de88df108587ba9be08514c9bcd633f2894ad31..1428810af92d4cb165b0501bddd951b16fb733f3 100644 GIT binary patch delta 1742 zcmZXVe>~Is9>>4)>lkChO0>4h&vHZgkt@-Wjvt$2jcZHO*yhKM&5uoyXj>Q8=^%Vj zx_&F%ID2?x#4$&7?V=rwn(|vIV~6S}q_S&09^HF;+|NIs$LsxgzuvFMq8b1gY=87P8lD{&&#|M$u_J7gSekS^O1hi)1Pgh2_hWOGF@Y2lSKf-qv?89)X3~Dg%9!`+T zg`M6~Y*quo*LIJ#qaei@UF|Ad_V=}W%MMZ6@UHe4=6<8A*q9eBz_0xlNRD8LeFl75 znWXMj3(E1yH1rwbYE-53ohhNxfKwpQKI_Enb`YOQ_|^?_=LlI~gjV>rd62maGIWcA zM)dgK1valiy0z5m+0E_RHdsT|DkTRH3)&h0z<~k4E&%+UYRb(avN#jYuq_+6<=BeW zKD&f*r`A`fI>xxLvuu=E5e_YQg0J@TOqis2;P39Bc#pp~1d(qL$*&P!wYynp7T@Pt zdr(o?Db3TLY;#$JFz6a?jP&L@?(c?Kb(YsyEX0VcKIl!feOneb?=OxOtufr)`Eq2J z=a0?u>7TPVxL~YLzs~y_)_|d8O{ZvDQXMX&korZH7xtA0#Pq#EFIGjWmy3_hzjrLM z2o7HI+a-yVQa4sss#~IyKAI)a;NqT)d$LWbzk6+S^sLA$1Nvv}*$OLiH6h!P8gMzW zvPS*_A9c}X`oWAayXjI)Q`@5@N(tfcPt)J+?}eFiPuX;~_lDxYo%Yg!R&H zno}H0H%=ZQjl9tRap87jq`|Sk9?l0v>C%Z1V*x+R-6_Q^dtz`nwkf{wkJ5FAJB_I2 zb^1m#{p8J==SHT!6AT<|LH3Lum2!TdkY}nmOfI)4tAz`4UP%;2wKkIBu%gPaQfI&`VvA%{SbLXY9`K$L z50zFrl$=;cb*mKK|_{l8?G91zq%LWj4)0y z_TbI)G^zP7`?cJ$i6(ZJowaCx4Iuk${r-+Qv1x*lr1j{RZQf7f>ma57x+}{}f7T&R zy5;@ca1@cyVs?lvSdD!Z3tyEL6Uv~7GNRoD_l(TcLU9lTg~CdrjOp-R8O#D(d^jO3b*gkW=+C zLQ#ZcyD-g_X^oLtcpZ2x#jqDnW2(4!>y$sR3%|EbC%2Q>(cQ^Ax=Pc9)A2J9b1pi* zd+ssWs*?3dG@m&f+y|o;p?Ose`~#G94-G5avEcRGE3Z}J>%W&acZ7dZ*Wliv8gEC}y%B>74Glz5jgA^PcznyyraUJfGTDpyw?hV2?-a5{JQHe6S@_ zqCgpKiKOcSfx{~(VCNDJgNf`6N+4t(6nHLJ3knQ6g$)g$UQ6`CHysdfX|S0Lf0Q>= zfFfd?B7{*_kS)~-g8?lcg{<=istunIt8+%64&&8JcFg<=f;6vIhwHg)WG33F@Sxa5 z`iy0T0Hn2&#blE$aKZj*ql#ujf;4xm*}C94+qeAcd>#ug=Xc+jK0?6diHmhd)trSL zi^)bHO+pE}aa#Q_+jVnZp3^o85vKWH>)Bt)Z(FRy8+zI0mSOMwFign==X`O3(MTh6 zsx|c3RG)LIsMq8;a|;JcX$CdWn$+&fMdv|ty?EawdYY1jLp^mOP6E#`V{RHf^;wk4 z(s?$-*cL$@>A6uR_eeLWNpdVMl*j25%i~RC5$^qr(RN2*c<0AAW%a=S6RcbY8hPML zq)H~AI$n^QWrW-1++4&?z9{uNc1P*aMRVEEdsMl`V*pZ`1+1RXXNj}x8A$eH$c zMPUU881T_DVqqDBFAVkA$wXFQpD)r;WzpAk<deDWe|b0;rR%x5YWTF0*WRD)R^mv| ztOuE~jJe6u+hGgocIz54YpM?3RvGZMS($PNH6PjY%H}5B4hyx#I0eS)Qgx{k`X7F@ zr`&RNdvO{#E1C!acXGljX}^tP3(w;p%8YZoo=!>%@!oXJ&UNnxGxYBgs-V#*a9QI$ zX@98icBH+$wcM*c!tI4U)T_&FDI7ydPsf?X%RWh*wyi_Sg&@LrE1G=<3@B97PRHOY z<(H{g_hKJd4KbH3?ck zPMu*vcNeo@4RidDp6N~FsZE)^9;!NuC+^l7{VvkyvX_;ON;$0XYPfl2F{$Hxab<?Q5hl9K0&BIIux-s-ZN zYdRxx*IGIfXJZlCX|2kqI~*bVvIOO)FY22_tg)A^u}X95YYI+dIVZ;=OC}6XmQv;h zG$GTYX5&8;(ebk99ekY3gmD3V|!kSgLQ!hNgU7ib_ zpJi#0dL2!(D@e(W{ed?thU$s~=*0t)x2kkJ^ktqzmXEopx($DTT%;`{KP?0O?_RmK z4hw8V8sj5ct9~gC$1leZuQ&YE>b$ n8eUGM^Hb!xN{xbsM|<5Pp#^{TqMxUr0V@42WgidAo9py1SNO)t diff --git a/spreadsheet/macrofree/aro_checklist.ja.xlsx b/spreadsheet/macrofree/aro_checklist.ja.xlsx index 7e15f783c2edbee6b597c8afe1c8293ff3fe16b2..87a7e280b5308a24a7844ee9e6b261469282fb61 100644 GIT binary patch delta 1878 zcmY*aX*e6`8ck3HgAjD=Rm2ucm0~PKDMBf&HMS8+Xj()?ZB1${k6NaYma!GN$P{H< zE-{p7L@iaN4Jyje!M@K7`YQA6$7opf`5!MqbYCW~y zz(GvKb=tR-dK$!6q`TWuB$oTkV1|}61qA;y-MzAyf*N=&FkMP(73}oUH3wRiZ#;Il zj z7Lpjm4%YHg9EM$zAGEsEa_j?;N!L)6kR9I`NElI3E}_x}$8tyyN%fe?{FPI|R?{iU zem-013e(z|mJ@JneuHp;3AV?$&o9Q-5?Ff<(IBn7?o6{m5LU*O|Fa(EWApzDY~BU- z2=Y;J&F#Xc-NkvU+zM|hdLaM+&?U*UJ}LxXHjZs7c_brlOl~Wt{ax%-+_dy3z7&5B zKW+U6qTZwlk`aJ)1kW-ZboILNxOj8m|><@2hugsAdb}%M$leb^O9^~ z=Ccx#`h4o|8N}+ZA?$qgQt=wT)^8l+WF*rTDqaosmFH}CL_OEt%Q+%VU_Z{*5iST= zZ(Q*XXUv7MS#kP72ENRRFqMN6x%j1@wRf^Z&iOBi;zt%4B4QN^zKa7G@A3Kw`1?Dl z!!M4_k8dm75Vcwu$$!dzhIWU2A#Fif?M1mMRh>u~-Ky07$^?{`_jTeWI+-A*wGmI& z89G||;qXzOFpcwD8+Nd+d$0&W$UAz=L17=qKkEEz{RV0R5>*MsOQ)OBnlAemBI@)f@wTCE26;t;2>eq2d@=R%1f*Dv_y|l9Yu|1WG8%oHrhXnqsmaaB48CM>?^GXSW%*sg^)RVCZn!RxvjakT#~L*{ZL;gk(o8M8ZjB3Ww+&vKaTcJk={;y z+G91l>nZ0V{5q62%S?o{+}j>f8OaX93Jdh|hC*|UD?k?B|7_6MV6m%=| z8L%X0m;Z4wf$l)8W=CHpG+qFNJ^h4!p|f2G(AQ`3nrP}jVZ>2v`s4v%PuofuQE)I9dtbdEfheAykz_aX|6+=VEEeTXe5nQg4{e6 z1CkWq#Y`5R&qsNu{;ixvL>6hf6=+1vmX|xIed4&Qa~z#e)9NYv7(+@9ayE+e=Y}0&emyYGt=wJ&;qq+6xnmE}~te z>m0!=5|oCujQ+R#wLr-I-;vUVWDc#0YMnt-|7DQ1HFjLAMwz%G`EHW4*)&|J#9{2W zE8QP(QC9Wt)bPgUrD1%7C?4g4PBe4IDE6JG^TNVlER?UrEhMFL%|I zYXpCQI(<2tX^edK0p@2NX15b!QxdD+RyM=z4oE;ejNTk(S)o7HF`o3pBRQhyb7BW*^xvbcGjzc0Z2*c~Ba;#)BtFkN?7}C`-`)I)+?;GUahzp%j51$m=LI z9*{sQ0_(|oXsF8f0SW+|=62DyL%i2V#-X7+K?zsDAk)x_Kk)=@m)Gypxhz?3d5L~w zb0-lv9tr>i#xZg|@LIgfVUGGSxvt(~;O~Yb~jz*Wg-H31Ki%rWHdIQ&gi>;n&t$ zqe#`bVjF~7FF}h?Ri&x6mS!}Tdy81AI0~710+Drh z*)N3z0N?OL$$!!r>My8`7kv0g^;gbGe&f+k#LKvT&Z65n(q&W+2iA*jk=_&(A1 zpueI#%Po~Ify;I^vLwuUF?TrF_DpO<;f$8mlsv=lxYd??v}^w%{R93ho$n7`TeK&f zDMKoa(wlz-9DljDA8JM;VAC;^fa{jEj5NhrJ<*)~p?&y6a6j)fvg7%1wO#z!4;ow* zmKPgIz`yC@iXPD%MH5~Hib3z*a(B)Ec|B+Ylwss({i@eX>yw$`x4}YfTaWh0`E+HM zMl0?od~N9JSH&mlrW$tD|al*Z0IrN8jI)%LzoW#RY6+zfnw0h>(+X30<2B&de-D3}* z>L3}`OxN#QAs;6$T^yPlfO-aF#kN%Q=z$#l5b2MTDeDF25(rKM!vWkSJJeh*;8uL&MyxvE=@V)%+^x1Dte>%+o3GI(<_-! z_N#@G7qJ_cVY@uCRCfZ=&_7*-vGT60$VnhG)kw>(}Kc$Rg{xD;Q%_iEv&2Zhm zo4uJ=TADxArR2y7{HEO&Zz;^-i)V5xgMW*VL18lSfhV9YT5030W-~v-V62f_r`#D? zZ%I7AkaMof)DDHtPl-~?kF)KN-paC@4AYrinOl{oJ%b;e*F$umF6{F2L(*QTue4bm z+t#aYyp>o5wMbc68k1{fL93I9#+c1jU}T8tS8Ej2w5f3;b97PclyLbbg#Hn(9F9ud z+0-iY$fm0+>NOarmcmbF*vTQF4h)uvqFBy@k3I8IZGkjSK+u9h!)D)$3IVV>WX6@# zcW;-h5AQDNZYmblsC^u(totrt}1kBwEly11sIr$N0gTy4(?ma^$)J zx?k~OL(zheXj*VpPbCF$Td+SVw>RB(7&fb8r?{tDDB`^jR|NQl~G@IN4qY z?WcEIQ(Cy^aKngSTf`t^V!8vJXoSO&nzstnG|iToHx=M&&^02+l|NYb){wBH{5?JNYn4$sLq=pYctZCbqu48Qzkk1^g%~6 z=XsMmpdhNzo9$)r`>E7|i={;beXARtJvL1{38wS0bHXX~ABRi-;G0~8yuCL(j+0p>es|f%~dz}Ark{}}RCyKTtCzpbPRDlhYqn{uA zA7%ic`o+CBlYZ#~xBu($V$FNb?*UKG2ms{%?17kpHeo19Xiyjmau!SsJN)^FFqE}P zFaXdZF>%zGh+rx;LQ*mAE|7i5{a>01>s=WbbNu(cxQx9{I{cSd88Y|}G73}(mzBh+ Sg`@VZl0oxuw6tBQ#P=Ucvms>w diff --git a/spreadsheet/macrofree/aro_checklist.ko.xlsx b/spreadsheet/macrofree/aro_checklist.ko.xlsx index e5a95aa54ecebe92888713fa62c45f14c1eab295..9de9b0464dbbe467e21e74a97ca78d519f39fddf 100644 GIT binary patch delta 1819 zcmY*aX*3&X8%=CU?6I|DH1=9*tDT^V+O?^@mIe_TCx%HrVr;R6VTx2F9m{CSwASh< ziZ*CaU#+RpjwL9nR6|c{2)ghkb57@ceSf^qx$pbjd!FwegL62rNp+SiysCtY%?m02IQHZ-wYq!B~Z`-haS(e8@A%yNP#?1HtDPY=ucj(msd z54RF3|NVJ(KFl5ssoOBfnLc7=PgPLTUQISeo-9*W#ovb3sqT%jgKIi^-KM;LZua#s zIt4awO|^v8+IDRFco^^ELXOX56%ELhfFw8vYm5z<(h0vXG-lX+)cqkgnEAIh(taTW zb|vWVSh{7?V#hHQU)Bl^wZJmXhOhj1-VWGg8rCWg<9KwR3nOm)1?%LXg3kT_0^4~& zrkGFzuDu6L@{ty-k^#?G%oPCukTMkSKsDl&FUL~$i()Z+x-04m4gIMsTFgnWoDC1>*=OKfxzG~cRvc@NYCh+=H`_{j{0?qgoA63ef6XcVb?2{QgmsDReqwZe z^8+Y1mi^Kq$atf+jE#{MeJs=UChp#LL89dxm)b4=F;iH~L^5q{F8cCcwHU8CHEr7T zvcX5(U<>KD4?%hlx0!I$u{83|lw|9PX+V|k1#R(oHEX+?p)h|%HR#W4NRVevQ2p=@ zHv>e(mis%Wu8RqA+~l+Nzd#QePXP_L+^T|1D#gv@#(ifE&-CC znygckr@uF*^#TyvN4k)ZnmO)|U+jbp9zq9gW}>vItc|D8>CiR>Pje#4k^XG8O+Pf= zujG9~f9i6ky%1sL+4)B=sN7j3tnJuOf#Vv83lK+YWWuA4s8-F=9oy}_9}&FsSL1Jw z7DNA#d9z@Jm8t@FRr%~9!Rr}IOSk!N{;L9 zSRX8eO&rW^yKj=uSaLSp>~v%%_1^HT6OU7j!alV8Na3v=h+&%VBJ*SSB%TVo<0kAvOv61Gpn?Ax72U1x@~>I ztd^T{pPLfAa-~}C1fG_n2n!{}4i*j=pixYg8$;*pM9Y5ly!VO$VQQ#w?8jT9d2((} z%5Szz?tpe;iOK5pMcg&(ek*3ov;PpX4L+ilBSmugH^dD2>JlJn?;&(2cs;zYJm zDx@tU#-mpI*k@&3lgl5OF5Ng*M!IZ%zXQ?a$rPb>h#nSM`>e)DT~H~`MQY@t)W!(Z zHL@O0CAH5wL{by-{Xyd zbf7;C8f=lji16m=_W+Stj8{7hH^T`J)GfxZ?*Uf_643k1^pA>(tCS}QY0Fd>A*?ZQ zeUhl3l6U&%3F}>#&C+H&^7bF#S@%VqFUju9o3B%bc=qbgv%(t6$>UW-u3XP&_C<^C z?}!@5&L4Wu*+2eV03vAMGd|}w2h4Re$ay(3bud}wk4xqVhE_Z&_e^qPUn8N;BJ2l} zsphOK&G+4x<-M!(@nnDP>d|hS{7b_4L|-Mwi}ytj`~6r)pl@ueAOtGPw=GH~azo%= zxe+X&0QyJ06F^54;vZNRZ3p=`9w;->mVzD`v+^bj{&;^_B5+AJSRIdp zD8oS@kSb`2#8$6nERpQ|$QF_nHL(0q2?WxXhwwNuo)#BRw;{*TD5&HZ>IHTvuFV$S z-r_x(T6k};OfA@ma9&F-6WY$dHW1S;)jW3ZZ~no`VE)}ZxM@X+*1CEG7{)r zBXZ$B4#TYiSy!@`tdCfVH zE`kjQUc}SpkN zCs@A>ZdFlQBGn62FZgOGW~o~?F4a~Bf!JRFIHEBlm_D^zYh&+KOfTO<)x=!VSJLI# zJ0NZ7Jyy7KvopHLV+YDLp(j)VrFJy3-;Euu&2hGl)ZB{>iC*kOfvr=jE6aX%$3^>v zz7g!>;GeCy*W7MBNRNs7?j`z)Ab8g`yIF$Y*QJEVzY~1Xh97uX^*zh#>6`;TcO4Ht zn#-SIP`O_UIWd0Xo~B|qt{C|0asz}P#rrMYxFpYy22LW)`b}g+G#x3)i@bla?DPW@ z6)7-by+$)@x^!!vlllEav1M$kW*`Ef^osWZytMfmgZ`<0IK@q z)Y(yrI50Tw+KcMbc9(4n0$o15g6bYVugd9pI@vdI;Okh7>%;DwrSOl2<-y{K9 zHM*GBlZH;rlPeU&nQS^ap)tW3D~;k#zeaXkG0WT8^T@TR`G5^eF!Ttaj<(Pugs=HC zetGr7)2@waK2mUtB@Dherd3IWI&b=Ue%#8Y^-p-)z?Zb=pJ}hg)deJ0OuI;?G$JYvugacxy{cu3s~FbsHowkDJu~;_I_XjbA$!}^m8yh8@LQEv_ucR?6I-fL zID>BD%st!f z`P{euM=;U6f&gDV|0jb3e6%-fDAb7bi5th5)D%>m{Bg!P^xH4}LcnDq8SS2I+2!P;D#1!LP$3pgUopaMV%-orPtMCfYU$v(_ZwOHRNg|Erlsk=l z^ldI6Z9>cUdM zcw$3jSes_%?ss3T1|qUNzmFya7xS&D;$x?1WCDVu8-IXFn3`gJemJv%OpYcgXudZK&KKfEsCBp^_z% z2&};NFqr~*Wc(+DP@J~?D{H`uVz0=_pdi39;Ae`d0$Sxz1q@LvjsGtq5J+Dx_0K1R zi6#Okh+hKO2z5o3Zv+CI3PeR96p#~vFw6@DfkJ5%D%}R9xbZl!5*+e*WdN=6^dw*? x0;x#fl!F&w5V_}5NA8G$zma^6kmUN)`P@z(Gr(vv&`QDjJ%WC<>TcOm2h4lnWM4ZfF^5DB==`O6jG*acLQ}Q7iX^EE}(D zBvRURLruj;Ekeo0HT7De<&u`!YC2Pz1NGed+_~?E_xGIlJ?DHlAI>jN4!oBGIsrsA zbwdycqzMwTFX+^Bg={DC0$X=l8&E!iK_GqQh-T3P*sNn52Re(*uun;d&%AJuc+b%= zbKUpF$t%|s+0bxQ&?!CW8OZ&n!tsRr*R_`alWqG7U{sazLrhn+^yBS4NoOK*uLG+}G>`m* z{RF4CwpqtzsAlBRefHoy)e$^*iu@zpTy_oMR&R)Y1>&uPM!$~F|tJm)O&Oll+Q*gDZ8&}d` zJB|ByOqlms*KVuC5`z6aaCy(yV97?kciY}IrPZZ=AG4ftRDfKZp*!cD7$FuGR%CLY zE;XfFdHZ;)y`PDNI-lG4E2ZbswA*R}J!3qKqeiq^*T-xbnm;Wib*ESy7c@5g<}%a` zSo@l+^fWH^tVKviqTW)(8xENKA{sXzkQff{*c$8mW#&s=pxrsnvm%RffAM2%LZnTc z%jGa%=KePZBBAZ#itxoPv`4Apo`#s)G3S%39y>Y}9ow>tk!^~Y{+?RqNM&bGnUiIg zZ2ZWD=~>?ap4om#f#dwPSlIPGn&nQ2?!B^a+-SbPv z;8J1`{@_N6`zPS`&GvO1T!Pph!}#a+2v_U@c4n+4~@DB%6)MTN)uHU-N*a1pwO%I@Sj~a4$`+d4Fd2l99PYX3x z>BfC)5nY}fUB2O=5!E%-;M4fKRq}j&+ye@fyXkCWi@DjGRCJ7xIdGOWpQ9v*r2;eroe|ai#iWNk@a}?fo<81$-Jq`Lozg2DToWy+t&Vq-iM_MInv+XUt zq5gJ)O25xznil=oTwNo)&1=H`M=2RoIr&pL%f2r&cjeFFkq&3fLMP%P8s?TUQ@H3c z2yc{RX=i{a%-!BHIt;6zv33{YwF#GRas&eO&jZIFKMz=ijy9t+iQSrlma^NdQq4kK=X^bw|WqfyN`AzRqDRqyFA5 zWPOOTU3gmIbE=YgAKnM3;JwI~DtI$0;41`Zu3GBr;9LK+7gt@Vd(P$AzT}2EbrIg5Aq2)(@Z+?_5KbDyM7@;dk_(qqMWco!S zYTwFP#27JaRD{N^{FoHxx{0{fIo(_L`Qv%c>v`VK^LftaocDXS4R)aors#r~hNA!g zkOSrdauutPa{)LHlAd550bAXa0sth~NJP=obN%s6+fnRijuY`kjKP}-Uo0U(8F5C2 z&CD4%!5&pQ$mnP8sPJXp7$R{k|BgKbl~+5duQB3!MwZHyXcBJiQi%aS?yFWL8O>jZ zx`?*+C&|S^?cIZGy$yFStc`T$C>Y53%r?x(XMEW2WY0jU@RJ^g0}d&r(lS;wCps?E zs1I;nuvsG;>bN0cXZaUa*B2s(eE{|BP1pT>aXn#JNG->`9OYy&)Ch^%Xbz%Y_bcoC zC*DKL_CR5?-d4?R6n?GPeZa=_;_-a2SjX0tMH$aj#Xo|+TGWJy(br8L3_e;xBKE(| zsKONCs7-1knKW5KaJ^4!;%$44;g1$8+=zJIXloS<_G8Ox|AIBjO3ek-LUP{twUXuu z)A22Lr2*g|0@Nm8>F)j1eskros){?iZ#DO@-T0pTtP%WGtG4J5P~usR-Z^!&tmn~~ zXDo!lc7^`*Xyb}F`Pk&Y%`9^Y!*kKKKAU;Y>YZCr;vmbVNZg5CZ?#tBdLi_uj>}B* z(MAkb9A`4^btX-57yMT1rsC8~X{I-vSh3g3g0MaDtOP-$|HCYo)8vms101?t_ABeS zl4?zbcMkPt^eg1v*QUo|xJ|x`FU$u=hc^b2BWZe1p4YaNx_awA$mfaE@?4khBz|F7 z<(Q`3F>u^P?P z#GoUsZGE4xIP_}^COv8n%~A_hAEG1W-rs+tHr=71o#Ki^3%3B#;&wMH z^*5+z4Gi5*zmhV)661#Q{VMC;-+n<-k6N5vj3|5g6xUQ=iO8L?PNO2vi^i^&rGzew zGEkm$v&oi}&a4AGTAoI};R<;xLv6#IMZvsI^b`;8->Yrba^oGCTq9MGKzLZg(KVBk ze`;U$n75IiVcX=mo}2V3Mk&9KYjb!z_ete^lC~F{3Pp3``5DbK(-eEXBLydK#)bsK z|13HTTodOIh}wIwF3pffvxRWEFVt-J3p@Je@vs4rFwyBZvH>L{+q0VNKQ)qNmMIUn zOKeFBVOxUod^A#tYsW#%sGMK8fE^mE8yhnfvV_7dy(YJ|nbDhXMwNvboH;?&LY&gL z$2?*$h;Q!j+wrQv&1&gh)HV01wKF2?8k5`Ao_;oW3%Z z$JF6;>z?*`$pJ*yuy}^u`nozp>hf9cNv8fpYe4ak+TLdrH!cdohccV~24h87-Ls zEF^9|M1CO?bGc@DzWy`zCv$syB4t+14Tk%UNj&c1*9DW{<^YidQGqVsFob9=|8H!9 z6-0Bagc{MxtUOr&XxRt=Dyv!geI&y~c_f{0l6!2EA$>dmtPrFC_3!7aYjVmxa4$*! zo94eb0sf~^0DmXxOTJT0(v%W;fLszrLX#xTqhEahz@HjSIca1lnO*QODU|g0l*f6X z32Uf~)qK}qjVYxc>%vBT0f0s^ijAO>i4hTGL)r<-&zHf#AWbQzKS&SSEGc$pmC6FZ N)*wAuaiHX-e*kMs;iUio diff --git a/workbooks/alz_checklist.en_network_counters.json b/workbooks/alz_checklist.en_network_counters.json index fffcb3e00..e51611e8e 100644 --- a/workbooks/alz_checklist.en_network_counters.json +++ b/workbooks/alz_checklist.en_network_counters.json @@ -861,7 +861,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}" + "resultVal": "{Query27Stats:$.Success}" } } ] @@ -880,7 +880,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}" + "resultVal": "{Query27Stats:$.Total}" } } ] @@ -918,7 +918,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query14Stats:$.Success}+{Query15Stats:$.Success}" + "resultVal": "{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}" } } ] @@ -937,7 +937,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query14Stats:$.Total}+{Query15Stats:$.Total}" + "resultVal": "{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}" } } ] @@ -975,7 +975,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Success}" + "resultVal": "{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}" } } ] @@ -994,7 +994,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Total}" + "resultVal": "{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}" } } ] @@ -1089,7 +1089,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" + "resultVal": "{Query14Stats:$.Success}+{Query15Stats:$.Success}" } } ] @@ -1108,7 +1108,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" + "resultVal": "{Query14Stats:$.Total}+{Query15Stats:$.Total}" } } ] @@ -1146,7 +1146,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}" + "resultVal": "{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}" } } ] @@ -1165,7 +1165,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}" + "resultVal": "{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}" } } ] @@ -1203,7 +1203,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query27Stats:$.Success}" + "resultVal": "{Query22Stats:$.Success}" } } ] @@ -1222,7 +1222,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query27Stats:$.Total}" + "resultVal": "{Query22Stats:$.Total}" } } ] @@ -1260,7 +1260,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}" + "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" } } ] @@ -1279,7 +1279,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}" + "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" } } ] @@ -1317,7 +1317,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query22Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query27Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}" + "resultVal": "{Query27Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}+{Query22Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" } } ] @@ -1336,7 +1336,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query22Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query27Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}" + "resultVal": "{Query27Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}+{Query22Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" } } ] @@ -1410,34 +1410,34 @@ "style": "tabs", "links": [ { - "id": "f815adb2-b043-43ea-8399-44dd82e86af1", + "id": "ad23d952-d03a-4a40-9e11-a8e21290e6a5", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet ({Tab0Success:value}/{Tab0Total:value})", + "linkLabel": "Virtual WAN ({Tab0Success:value}/{Tab0Total:value})", "subTarget": "tab0", - "preText": "Internet", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "e362f099-b02e-4ca4-9874-65fb7e9ae26d", + "id": "02871c81-b79c-4a0e-ae55-3c7972d6f8ed", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan ({Tab1Success:value}/{Tab1Total:value})", + "linkLabel": "Hybrid ({Tab1Success:value}/{Tab1Total:value})", "subTarget": "tab1", - "preText": "IP plan", + "preText": "Hybrid", "style": "primary" }, { - "id": "f5228cec-e133-4020-bb9c-68294d17b1be", + "id": "709cbf8a-6bae-4c7a-95ae-72cdab59af6e", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS ({Tab2Success:value}/{Tab2Total:value})", + "linkLabel": "Internet ({Tab2Success:value}/{Tab2Total:value})", "subTarget": "tab2", - "preText": "PaaS", + "preText": "Internet", "style": "primary" }, { - "id": "a9e86b0f-72be-46ff-97dd-8540b3fc5ba7", + "id": "87d682aa-de16-4e9d-b625-fc1cce672221", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Hub and spoke ({Tab3Success:value}/{Tab3Total:value})", @@ -1446,39 +1446,39 @@ "style": "primary" }, { - "id": "a76d1d20-a186-4bad-a99f-adbe0b2ca709", + "id": "d1d7ea9b-e839-4c1e-9450-e756e0929b07", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App delivery ({Tab4Success:value}/{Tab4Total:value})", + "linkLabel": "IP plan ({Tab4Success:value}/{Tab4Total:value})", "subTarget": "tab4", - "preText": "App delivery", + "preText": "IP plan", "style": "primary" }, { - "id": "87785007-6ca1-4baf-8697-78670988597e", + "id": "c7e3cd92-c6bb-49b6-a2a2-39ba6994e297", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid ({Tab5Success:value}/{Tab5Total:value})", + "linkLabel": "Segmentation ({Tab5Success:value}/{Tab5Total:value})", "subTarget": "tab5", - "preText": "Hybrid", + "preText": "Segmentation", "style": "primary" }, { - "id": "55fce76a-2805-47e2-a0f7-c828784121b4", + "id": "66814f4e-402f-45ef-95ee-6e5db5944274", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN ({Tab6Success:value}/{Tab6Total:value})", + "linkLabel": "PaaS ({Tab6Success:value}/{Tab6Total:value})", "subTarget": "tab6", - "preText": "Virtual WAN", + "preText": "PaaS", "style": "primary" }, { - "id": "297605f6-da89-4008-9a76-294087edaf09", + "id": "5da00eb8-cb47-4176-9577-751aa4235908", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation ({Tab7Success:value}/{Tab7Total:value})", + "linkLabel": "App delivery ({Tab7Success:value}/{Tab7Total:value})", "subTarget": "tab7", - "preText": "Segmentation", + "preText": "App delivery", "style": "primary" } ] @@ -1494,22 +1494,22 @@ { "type": 1, "content": { - "json": "## Internet" + "json": "## Virtual WAN" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext16" + "name": "querytext27" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1558,20 +1558,42 @@ ] } }, - "name": "query16" + "name": "query27" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext17" + "name": "querytext9" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1620,20 +1642,20 @@ ] } }, - "name": "query17" + "name": "query9" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." }, - "name": "querytext18" + "name": "querytext10" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1682,20 +1704,20 @@ ] } }, - "name": "query18" + "name": "query10" }, { "type": 1, "content": { - "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." }, - "name": "querytext19" + "name": "querytext11" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1744,20 +1766,20 @@ ] } }, - "name": "query19" + "name": "query11" }, { "type": 1, "content": { - "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." + "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext12" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1806,20 +1828,20 @@ ] } }, - "name": "query20" + "name": "query12" }, { "type": 1, "content": { - "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." }, - "name": "querytext21" + "name": "querytext13" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1868,16 +1890,16 @@ ] } }, - "name": "query21" + "name": "query13" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab0" + "value": "tab1" }, - "name": "tab0" + "name": "tab1" }, { "type": 12, @@ -1888,22 +1910,22 @@ { "type": 1, "content": { - "json": "## IP plan" + "json": "## Internet" }, - "name": "tab1title" + "name": "tab2title" }, { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." }, - "name": "querytext14" + "name": "querytext16" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1952,20 +1974,20 @@ ] } }, - "name": "query14" + "name": "query16" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." }, - "name": "querytext15" + "name": "querytext17" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2014,42 +2036,20 @@ ] } }, - "name": "query15" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab1" - }, - "name": "tab1" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## PaaS" - }, - "name": "tab2title" + "name": "query17" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext22" + "name": "querytext18" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2098,42 +2098,20 @@ ] } }, - "name": "query22" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab2" - }, - "name": "tab2" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hub and spoke" - }, - "name": "tab3title" + "name": "query18" }, { "type": 1, "content": { - "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." + "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext5" + "name": "querytext19" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2182,20 +2160,20 @@ ] } }, - "name": "query5" + "name": "query19" }, { "type": 1, "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." }, - "name": "querytext6" + "name": "querytext20" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2244,20 +2222,20 @@ ] } }, - "name": "query6" + "name": "query20" }, { "type": 1, "content": { - "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." }, - "name": "querytext7" + "name": "querytext21" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2306,20 +2284,42 @@ ] } }, - "name": "query7" + "name": "query21" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab2" + }, + "name": "tab2" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hub and spoke" + }, + "name": "tab3title" }, { "type": 1, "content": { - "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." + "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." }, - "name": "querytext8" + "name": "querytext5" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2368,42 +2368,20 @@ ] } }, - "name": "query8" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## App delivery" - }, - "name": "tab4title" + "name": "query5" }, { "type": 1, "content": { - "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." }, - "name": "querytext0" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2452,20 +2430,20 @@ ] } }, - "name": "query0" + "name": "query6" }, { "type": 1, "content": { - "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." + "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." }, - "name": "querytext1" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2514,20 +2492,20 @@ ] } }, - "name": "query1" + "name": "query7" }, { "type": 1, "content": { - "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." }, - "name": "querytext2" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2576,20 +2554,42 @@ ] } }, - "name": "query2" + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## IP plan" + }, + "name": "tab4title" }, { "type": 1, "content": { - "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext3" + "name": "querytext14" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2638,20 +2638,20 @@ ] } }, - "name": "query3" + "name": "query14" }, { "type": 1, "content": { - "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext4" + "name": "querytext15" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2700,7 +2700,7 @@ ] } }, - "name": "query4" + "name": "query15" } ] }, @@ -2720,22 +2720,22 @@ { "type": 1, "content": { - "json": "## Hybrid" + "json": "## Segmentation" }, "name": "tab5title" }, { "type": 1, "content": { - "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." }, - "name": "querytext9" + "name": "querytext23" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2784,20 +2784,20 @@ ] } }, - "name": "query9" + "name": "query23" }, { "type": 1, "content": { - "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." + "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." }, - "name": "querytext10" + "name": "querytext24" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2846,20 +2846,20 @@ ] } }, - "name": "query10" + "name": "query24" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." + "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." }, - "name": "querytext11" + "name": "querytext25" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2908,20 +2908,20 @@ ] } }, - "name": "query11" + "name": "query25" }, { "type": 1, "content": { - "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext12" + "name": "querytext26" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2970,20 +2970,42 @@ ] } }, - "name": "query12" + "name": "query26" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "name": "tab6title" }, { "type": 1, "content": { - "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext13" + "name": "querytext22" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3032,16 +3054,16 @@ ] } }, - "name": "query13" + "name": "query22" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab5" + "value": "tab6" }, - "name": "tab5" + "name": "tab6" }, { "type": 12, @@ -3052,22 +3074,22 @@ { "type": 1, "content": { - "json": "## Virtual WAN" + "json": "## App delivery" }, - "name": "tab6title" + "name": "tab7title" }, { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext27" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3116,42 +3138,20 @@ ] } }, - "name": "query27" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab6" - }, - "name": "tab6" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Segmentation" - }, - "name": "tab7title" + "name": "query0" }, { "type": 1, "content": { - "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." + "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." }, - "name": "querytext23" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3200,20 +3200,20 @@ ] } }, - "name": "query23" + "name": "query1" }, { "type": 1, "content": { - "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." + "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext24" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3262,20 +3262,20 @@ ] } }, - "name": "query24" + "name": "query2" }, { "type": 1, "content": { - "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." + "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." }, - "name": "querytext25" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3324,20 +3324,20 @@ ] } }, - "name": "query25" + "name": "query3" }, { "type": 1, "content": { - "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." }, - "name": "querytext26" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3386,7 +3386,7 @@ ] } }, - "name": "query26" + "name": "query4" } ] }, diff --git a/workbooks/alz_checklist.en_network_counters_template.json b/workbooks/alz_checklist.en_network_counters_template.json index 7faa8c4e1..e4b6fc0ef 100644 --- a/workbooks/alz_checklist.en_network_counters_template.json +++ b/workbooks/alz_checklist.en_network_counters_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Success}+{Query15Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Total}+{Query15Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query22Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query27Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query22Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query27Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"f815adb2-b043-43ea-8399-44dd82e86af1\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e362f099-b02e-4ca4-9874-65fb7e9ae26d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f5228cec-e133-4020-bb9c-68294d17b1be\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a9e86b0f-72be-46ff-97dd-8540b3fc5ba7\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a76d1d20-a186-4bad-a99f-adbe0b2ca709\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery ({Tab4Success:value}/{Tab4Total:value})\",\n \"subTarget\": \"tab4\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"87785007-6ca1-4baf-8697-78670988597e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid ({Tab5Success:value}/{Tab5Total:value})\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"55fce76a-2805-47e2-a0f7-c828784121b4\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"297605f6-da89-4008-9a76-294087edaf09\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab7Success:value}/{Tab7Total:value})\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Success}+{Query15Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Total}+{Query15Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}+{Query22Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}+{Query22Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"ad23d952-d03a-4a40-9e11-a8e21290e6a5\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"02871c81-b79c-4a0e-ae55-3c7972d6f8ed\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"709cbf8a-6bae-4c7a-95ae-72cdab59af6e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"87d682aa-de16-4e9d-b625-fc1cce672221\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d1d7ea9b-e839-4c1e-9450-e756e0929b07\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan ({Tab4Success:value}/{Tab4Total:value})\",\n \"subTarget\": \"tab4\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"c7e3cd92-c6bb-49b6-a2a2-39ba6994e297\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab5Success:value}/{Tab5Total:value})\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"66814f4e-402f-45ef-95ee-6e5db5944274\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"5da00eb8-cb47-4176-9577-751aa4235908\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery ({Tab7Success:value}/{Tab7Total:value})\",\n \"subTarget\": \"tab7\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/alz_checklist.en_network_tabcounters.json b/workbooks/alz_checklist.en_network_tabcounters.json index d82393c99..b5c154c90 100644 --- a/workbooks/alz_checklist.en_network_tabcounters.json +++ b/workbooks/alz_checklist.en_network_tabcounters.json @@ -70,75 +70,75 @@ "style": "tabs", "links": [ { - "id": "b21daf1c-e40d-42ac-8839-4f510606f83b", + "id": "8ef646c5-323c-49db-862a-83b58686a5fb", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "Hub and spoke", "subTarget": "tab0", - "preText": "Virtual WAN", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "e7bcb15f-0691-4818-9b4b-0ce78babebed", + "id": "ba16207d-826a-442d-a644-232313f92057", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet", + "linkLabel": "PaaS", "subTarget": "tab1", - "preText": "Internet", + "preText": "PaaS", "style": "primary" }, { - "id": "11763190-3921-45e3-8519-d18f1f2d5a2a", + "id": "153c1f3f-3820-4ddd-8abc-b60f25031e67", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid", + "linkLabel": "Virtual WAN", "subTarget": "tab2", - "preText": "Hybrid", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "20493c56-2b5b-41ae-b989-21ecfb73bbbc", + "id": "eefe307c-919c-4617-8559-c73f120c2c8a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "App delivery", "subTarget": "tab3", - "preText": "PaaS", + "preText": "App delivery", "style": "primary" }, { - "id": "a97c9297-bf86-48db-9bea-90b0a60d0c1d", + "id": "b66a4578-0228-46f8-84c3-3b266d31380a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan", + "linkLabel": "Internet", "subTarget": "tab4", - "preText": "IP plan", + "preText": "Internet", "style": "primary" }, { - "id": "f8da1f7c-9c85-48d8-9f29-0f5355b4c3ee", + "id": "b5481edf-5561-4ce1-a82a-73175ba7b3f2", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "IP plan", "subTarget": "tab5", - "preText": "Hub and spoke", + "preText": "IP plan", "style": "primary" }, { - "id": "b0e86262-9fe2-46ab-93be-cf85ef6a5e4a", + "id": "4028c596-4898-46fa-9094-4dbedf19cc3a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation", + "linkLabel": "Hybrid", "subTarget": "tab6", - "preText": "Segmentation", + "preText": "Hybrid", "style": "primary" }, { - "id": "67a0cc13-c123-4614-8434-d77b7d21a9bf", + "id": "2906e345-fd8a-455a-912d-fc3e0535bc36", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App delivery", + "linkLabel": "Segmentation", "subTarget": "tab7", - "preText": "App delivery", + "preText": "Segmentation", "style": "primary" } ] @@ -162,9 +162,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query27Stats", + "name": "Query5Stats", "type": 1, - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -178,9 +178,93 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query27FullyCompliant", + "name": "Query5FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query27Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query5Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query6Stats", + "type": 1, + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query6FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query6Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query7Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query7FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query7Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query8Stats", + "type": 1, + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query8FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query8Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -201,7 +285,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query27Stats:$.Success}" + "resultVal": "{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" } } ] @@ -220,7 +304,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query27Stats:$.Total}" + "resultVal": "{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" } } ] @@ -254,7 +338,7 @@ { "type": 1, "content": { - "json": "## Virtual WAN" + "json": "## Hub and spoke" }, "customWidth": "50", "name": "tab0title" @@ -295,15 +379,15 @@ { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." }, - "name": "querytext27" + "name": "querytext5" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -352,333 +436,37 @@ ] } }, - "name": "query27" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab0" - }, - "name": "tab0" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ + "name": "query5" + }, { - "type": 9, + "type": 1, "content": { - "version": "KqlParameterItem/1.0", + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + }, + "name": "querytext6" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ "{Subscription}" ], - "parameters": [ - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query16Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query16FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query16Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query17Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query17FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query17Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query18Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query18FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query18Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query19Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query19FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query19Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query20Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query20FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query20Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query21Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query21FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query21Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab1Success", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab1Total", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab1Percent", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "round(100*{Tab1Success}/{Tab1Total})" - } - } - ] - } - ], - "style": "pills", - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - "name": "TabInvisibleParameters" - }, - { - "type": 1, - "content": { - "json": "## Internet" - }, - "customWidth": "50", - "name": "tab1title" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab1Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", - "size": 3, - "queryType": 8, - "visualization": "tiles", - "tileSettings": { - "titleContent": { - "columnMatch": "Column1", - "formatter": 4, - "formatOptions": { - "min": 0, - "max": 100, - "palette": "redGreen" - }, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - "subtitleContent": { - "columnMatch": "Column2" - }, - "showBorder": true - } - }, - "customWidth": "50", - "name": "TabPercentTile" - }, - { - "type": 1, - "content": { - "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." - }, - "name": "querytext16" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "crossComponentResources": [ - "{Subscription}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } }, { "columnMatch": "compliant", @@ -710,20 +498,20 @@ ] } }, - "name": "query16" + "name": "query6" }, { "type": 1, "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." }, - "name": "querytext17" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -772,20 +560,20 @@ ] } }, - "name": "query17" + "name": "query7" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." }, - "name": "querytext18" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -834,82 +622,176 @@ ] } }, - "name": "query18" - }, - { - "type": 1, - "content": { - "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." - }, - "name": "querytext19" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", "crossComponentResources": [ "{Subscription}" ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" + "parameters": [ + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query22Stats", + "type": 1, + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query22FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query22Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab1Success", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query22Stats:$.Success}" } } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab1Total", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query22Stats:$.Total}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab1Percent", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "round(100*{Tab1Success}/{Tab1Total})" + } + } + ] + } + ], + "style": "pills", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + "name": "TabInvisibleParameters" + }, + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "customWidth": "50", + "name": "tab1title" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab1Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", + "size": 3, + "queryType": 8, + "visualization": "tiles", + "tileSettings": { + "titleContent": { + "columnMatch": "Column1", + "formatter": 4, + "formatOptions": { + "min": 0, + "max": 100, + "palette": "redGreen" + }, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" } } - ] + }, + "subtitleContent": { + "columnMatch": "Column2" + }, + "showBorder": true } }, - "name": "query19" + "customWidth": "50", + "name": "TabPercentTile" }, { "type": 1, "content": { - "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext22" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -958,20 +840,176 @@ ] } }, - "name": "query20" + "name": "query22" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab1" + }, + "name": "tab1" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "crossComponentResources": [ + "{Subscription}" + ], + "parameters": [ + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query27Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query27FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query27Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab2Success", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query27Stats:$.Success}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab2Total", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query27Stats:$.Total}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab2Percent", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "round(100*{Tab2Success}/{Tab2Total})" + } + } + ] + } + ], + "style": "pills", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + "name": "TabInvisibleParameters" }, { "type": 1, "content": { - "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + "json": "## Virtual WAN" }, - "name": "querytext21" + "customWidth": "50", + "name": "tab2title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab2Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", + "size": 3, + "queryType": 8, + "visualization": "tiles", + "tileSettings": { + "titleContent": { + "columnMatch": "Column1", + "formatter": 4, + "formatOptions": { + "min": 0, + "max": 100, + "palette": "redGreen" + }, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } + }, + "subtitleContent": { + "columnMatch": "Column2" + }, + "showBorder": true + } + }, + "customWidth": "50", + "name": "TabPercentTile" + }, + { + "type": 1, + "content": { + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + }, + "name": "querytext27" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1020,16 +1058,16 @@ ] } }, - "name": "query21" + "name": "query27" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab1" + "value": "tab2" }, - "name": "tab1" + "name": "tab2" }, { "type": 12, @@ -1048,9 +1086,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query9Stats", + "name": "Query0Stats", "type": 1, - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1064,9 +1102,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query9FullyCompliant", + "name": "Query0FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query9Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query0Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1076,9 +1114,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query10Stats", + "name": "Query1Stats", "type": 1, - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1092,9 +1130,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query10FullyCompliant", + "name": "Query1FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query10Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query1Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1104,9 +1142,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query11Stats", + "name": "Query2Stats", "type": 1, - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1120,9 +1158,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query11FullyCompliant", + "name": "Query2FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query11Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query2Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1132,9 +1170,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query12Stats", + "name": "Query3Stats", "type": 1, - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1148,9 +1186,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query12FullyCompliant", + "name": "Query3FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query12Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query3Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1160,9 +1198,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query13Stats", + "name": "Query4Stats", "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1176,9 +1214,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query13FullyCompliant", + "name": "Query4FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query13Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query4Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1188,7 +1226,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Success", + "name": "Tab3Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1199,7 +1237,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}" + "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" } } ] @@ -1207,7 +1245,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Total", + "name": "Tab3Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1218,7 +1256,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}" + "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" } } ] @@ -1226,7 +1264,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Percent", + "name": "Tab3Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1237,7 +1275,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab2Success}/{Tab2Total})" + "resultVal": "round(100*{Tab3Success}/{Tab3Total})" } } ] @@ -1252,16 +1290,16 @@ { "type": 1, "content": { - "json": "## Hybrid" + "json": "## App delivery" }, "customWidth": "50", - "name": "tab2title" + "name": "tab3title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab2Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab3Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -1293,15 +1331,15 @@ { "type": 1, "content": { - "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext9" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1350,20 +1388,20 @@ ] } }, - "name": "query9" + "name": "query0" }, { "type": 1, "content": { - "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." + "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." }, - "name": "querytext10" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1412,20 +1450,20 @@ ] } }, - "name": "query10" + "name": "query1" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." + "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext11" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1474,20 +1512,20 @@ ] } }, - "name": "query11" + "name": "query2" }, { "type": 1, "content": { - "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." }, - "name": "querytext12" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1536,20 +1574,20 @@ ] } }, - "name": "query12" + "name": "query3" }, { "type": 1, "content": { - "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." }, - "name": "querytext13" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1568,67 +1606,207 @@ } } }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] - } - } - ] - } - }, - "name": "query13" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab2" - }, - "name": "tab2" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 9, - "content": { - "version": "KqlParameterItem/1.0", - "crossComponentResources": [ - "{Subscription}" - ], - "parameters": [ + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] + } + } + ] + } + }, + "name": "query4" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "crossComponentResources": [ + "{Subscription}" + ], + "parameters": [ + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query16Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query16FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query16Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query17Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query17FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query17Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query18Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query18FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query18Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query19Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query19FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query19Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query20Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query22Stats", + "name": "Query20FullyCompliant", "type": 1, - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query20Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query21Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -1642,9 +1820,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query22FullyCompliant", + "name": "Query21FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query22Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query21Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1654,7 +1832,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Success", + "name": "Tab4Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1665,7 +1843,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Success}" + "resultVal": "{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}" } } ] @@ -1673,7 +1851,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Total", + "name": "Tab4Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1684,7 +1862,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Total}" + "resultVal": "{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}" } } ] @@ -1692,7 +1870,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Percent", + "name": "Tab4Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1703,7 +1881,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab3Success}/{Tab3Total})" + "resultVal": "round(100*{Tab4Success}/{Tab4Total})" } } ] @@ -1718,16 +1896,16 @@ { "type": 1, "content": { - "json": "## PaaS" + "json": "## Internet" }, "customWidth": "50", - "name": "tab3title" + "name": "tab4title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab3Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab4Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -1759,15 +1937,15 @@ { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." }, - "name": "querytext22" + "name": "querytext16" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1816,204 +1994,144 @@ ] } }, - "name": "query22" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ + "name": "query16" + }, { - "type": 9, + "type": 1, "content": { - "version": "KqlParameterItem/1.0", + "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + }, + "name": "querytext17" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ "{Subscription}" ], - "parameters": [ - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query14Stats", - "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query14FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query14Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query15Stats", - "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query15FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query15Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab4Success", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query14Stats:$.Success}+{Query15Stats:$.Success}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab4Total", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query14Stats:$.Total}+{Query15Stats:$.Total}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab4Percent", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "round(100*{Tab4Success}/{Tab4Total})" + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" } } - ] - } - ], - "style": "pills", - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" + }, + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] + } + } + ] + } }, - "name": "TabInvisibleParameters" + "name": "query17" }, { "type": 1, "content": { - "json": "## IP plan" + "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "customWidth": "50", - "name": "tab4title" + "name": "querytext18" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab4Percent}\\\", \\\"Column2\\\": \\\"Percent of succesful checks\\\"}\",\"transformers\":null}", - "size": 3, - "queryType": 8, - "visualization": "tiles", - "tileSettings": { - "titleContent": { - "columnMatch": "Column1", - "formatter": 4, - "formatOptions": { - "min": 0, - "max": 100, - "palette": "redGreen" + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "crossComponentResources": [ + "{Subscription}" + ], + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } }, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] } } - }, - "subtitleContent": { - "columnMatch": "Column2" - }, - "showBorder": true + ] } }, - "customWidth": "50", - "name": "TabPercentTile" + "name": "query18" }, { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext14" + "name": "querytext19" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2062,20 +2180,20 @@ ] } }, - "name": "query14" + "name": "query19" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." }, - "name": "querytext15" + "name": "querytext20" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2124,93 +2242,99 @@ ] } }, - "name": "query15" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ + "name": "query20" + }, { - "type": 9, + "type": 1, "content": { - "version": "KqlParameterItem/1.0", + "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + }, + "name": "querytext21" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ "{Subscription}" ], - "parameters": [ - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query5Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query5FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query5Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query6Stats", - "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query6FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query6Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } }, - "queryType": 8 - }, + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] + } + } + ] + } + }, + "name": "query21" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab4" + }, + "name": "tab4" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "crossComponentResources": [ + "{Subscription}" + ], + "parameters": [ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query7Stats", + "name": "Query14Stats", "type": 1, - "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2224,9 +2348,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query7FullyCompliant", + "name": "Query14FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query7Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query14Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2236,9 +2360,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query8Stats", + "name": "Query15Stats", "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2252,9 +2376,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query8FullyCompliant", + "name": "Query15FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query8Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query15Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2275,7 +2399,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" + "resultVal": "{Query14Stats:$.Success}+{Query15Stats:$.Success}" } } ] @@ -2294,7 +2418,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" + "resultVal": "{Query14Stats:$.Total}+{Query15Stats:$.Total}" } } ] @@ -2328,7 +2452,7 @@ { "type": 1, "content": { - "json": "## Hub and spoke" + "json": "## IP plan" }, "customWidth": "50", "name": "tab5title" @@ -2369,139 +2493,15 @@ { "type": 1, "content": { - "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." - }, - "name": "querytext5" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "crossComponentResources": [ - "{Subscription}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] - } - } - ] - } - }, - "name": "query5" - }, - { - "type": 1, - "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." - }, - "name": "querytext6" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "crossComponentResources": [ - "{Subscription}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] - } - } - ] - } - }, - "name": "query6" - }, - { - "type": 1, - "content": { - "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext7" + "name": "querytext14" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2550,20 +2550,20 @@ ] } }, - "name": "query7" + "name": "query14" }, { "type": 1, "content": { - "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext8" + "name": "querytext15" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2612,7 +2612,7 @@ ] } }, - "name": "query8" + "name": "query15" } ] }, @@ -2640,9 +2640,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query23Stats", + "name": "Query9Stats", "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2656,9 +2656,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query23FullyCompliant", + "name": "Query9FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query23Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query9Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2668,9 +2668,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query24Stats", + "name": "Query10Stats", "type": 1, - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2684,9 +2684,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query24FullyCompliant", + "name": "Query10FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query24Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query10Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2696,9 +2696,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query25Stats", + "name": "Query11Stats", "type": 1, - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2712,9 +2712,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query25FullyCompliant", + "name": "Query11FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query25Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query11Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2724,9 +2724,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query26Stats", + "name": "Query12Stats", "type": 1, - "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2740,9 +2740,37 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query26FullyCompliant", + "name": "Query12FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query26Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query12Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query13Stats", + "type": 1, + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query13FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query13Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2763,7 +2791,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}" + "resultVal": "{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}" } } ] @@ -2782,7 +2810,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}" + "resultVal": "{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}" } } ] @@ -2816,7 +2844,7 @@ { "type": 1, "content": { - "json": "## Segmentation" + "json": "## Hybrid" }, "customWidth": "50", "name": "tab6title" @@ -2857,15 +2885,15 @@ { "type": 1, "content": { - "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." + "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext23" + "name": "querytext9" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2914,20 +2942,20 @@ ] } }, - "name": "query23" + "name": "query9" }, { "type": 1, "content": { - "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." + "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." }, - "name": "querytext24" + "name": "querytext10" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2976,20 +3004,20 @@ ] } }, - "name": "query24" + "name": "query10" }, { "type": 1, "content": { - "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." }, - "name": "querytext25" + "name": "querytext11" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3038,20 +3066,20 @@ ] } }, - "name": "query25" + "name": "query11" }, { "type": 1, "content": { - "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext26" + "name": "querytext12" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3100,7 +3128,69 @@ ] } }, - "name": "query26" + "name": "query12" + }, + { + "type": 1, + "content": { + "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + }, + "name": "querytext13" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "crossComponentResources": [ + "{Subscription}" + ], + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } + }, + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] + } + } + ] + } + }, + "name": "query13" } ] }, @@ -3128,37 +3218,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query0Stats", - "type": 1, - "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query0FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query0Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query1Stats", + "name": "Query23Stats", "type": 1, - "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -3172,9 +3234,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query1FullyCompliant", + "name": "Query23FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query1Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query23Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -3184,9 +3246,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query2Stats", + "name": "Query24Stats", "type": 1, - "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -3200,9 +3262,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query2FullyCompliant", + "name": "Query24FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query2Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query24Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -3212,9 +3274,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query3Stats", + "name": "Query25Stats", "type": 1, - "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -3228,9 +3290,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query3FullyCompliant", + "name": "Query25FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query3Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query25Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -3240,9 +3302,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query4Stats", + "name": "Query26Stats", "type": 1, - "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -3256,9 +3318,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query4FullyCompliant", + "name": "Query26FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query4Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query26Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -3279,7 +3341,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" + "resultVal": "{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}" } } ] @@ -3298,7 +3360,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" + "resultVal": "{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}" } } ] @@ -3332,7 +3394,7 @@ { "type": 1, "content": { - "json": "## App delivery" + "json": "## Segmentation" }, "customWidth": "50", "name": "tab7title" @@ -3373,77 +3435,15 @@ { "type": 1, "content": { - "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." - }, - "name": "querytext0" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "crossComponentResources": [ - "{Subscription}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] - } - } - ] - } - }, - "name": "query0" - }, - { - "type": 1, - "content": { - "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." + "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." }, - "name": "querytext1" + "name": "querytext23" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3492,20 +3492,20 @@ ] } }, - "name": "query1" + "name": "query23" }, { "type": 1, "content": { - "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." }, - "name": "querytext2" + "name": "querytext24" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3554,20 +3554,20 @@ ] } }, - "name": "query2" + "name": "query24" }, { "type": 1, "content": { - "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." + "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." }, - "name": "querytext3" + "name": "querytext25" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3616,20 +3616,20 @@ ] } }, - "name": "query3" + "name": "query25" }, { "type": 1, "content": { - "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." + "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext4" + "name": "querytext26" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3678,7 +3678,7 @@ ] } }, - "name": "query4" + "name": "query26" } ] }, diff --git a/workbooks/alz_checklist.en_network_tabcounters_template.json b/workbooks/alz_checklist.en_network_tabcounters_template.json index 1c8f5f8ad..841720369 100644 --- a/workbooks/alz_checklist.en_network_tabcounters_template.json +++ b/workbooks/alz_checklist.en_network_tabcounters_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"b21daf1c-e40d-42ac-8839-4f510606f83b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e7bcb15f-0691-4818-9b4b-0ce78babebed\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"11763190-3921-45e3-8519-d18f1f2d5a2a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"20493c56-2b5b-41ae-b989-21ecfb73bbbc\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab3\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a97c9297-bf86-48db-9bea-90b0a60d0c1d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab4\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f8da1f7c-9c85-48d8-9f29-0f5355b4c3ee\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"b0e86262-9fe2-46ab-93be-cf85ef6a5e4a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"67a0cc13-c123-4614-8434-d77b7d21a9bf\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery\",\n \"subTarget\": \"tab7\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab0title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab0Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab1title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab1Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab2title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab2Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab3title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab3Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Success}+{Query15Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Total}+{Query15Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab4title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab4Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab5title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab5Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab6title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab6Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab7title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab7Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"8ef646c5-323c-49db-862a-83b58686a5fb\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ba16207d-826a-442d-a644-232313f92057\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab1\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"153c1f3f-3820-4ddd-8abc-b60f25031e67\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"eefe307c-919c-4617-8559-c73f120c2c8a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery\",\n \"subTarget\": \"tab3\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"b66a4578-0228-46f8-84c3-3b266d31380a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"b5481edf-5561-4ce1-a82a-73175ba7b3f2\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab5\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"4028c596-4898-46fa-9094-4dbedf19cc3a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"2906e345-fd8a-455a-912d-fc3e0535bc36\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab0title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab0Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab1title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab1Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query27Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab2title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab2Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab3title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab3Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab4title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab4Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Success}+{Query15Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query14Stats:$.Total}+{Query15Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab5title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab5Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab6title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab6Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab7title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab7Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of succesful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/alz_checklist.en_network_workbook.json b/workbooks/alz_checklist.en_network_workbook.json index 9c439be04..96472bcd2 100644 --- a/workbooks/alz_checklist.en_network_workbook.json +++ b/workbooks/alz_checklist.en_network_workbook.json @@ -70,75 +70,75 @@ "style": "tabs", "links": [ { - "id": "3947f6f6-dacf-406b-b813-6ee084bf929d", + "id": "1d406f6b-168f-4c8d-93d4-2819a2900e36", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App delivery", + "linkLabel": "Hub and spoke", "subTarget": "tab0", - "preText": "App delivery", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "06f9b5a5-7707-4ce3-86cb-50e135720d8c", + "id": "6c8040ec-e3a1-4f1b-9ab9-9ba09ba30bd5", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "IP plan", "subTarget": "tab1", - "preText": "Hub and spoke", + "preText": "IP plan", "style": "primary" }, { - "id": "8285bfb6-b49a-4a99-a155-bc9cf54a0eda", + "id": "ea8ed44d-41cb-4d2e-90bd-ac19a327a5f7", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "Segmentation", "subTarget": "tab2", - "preText": "Virtual WAN", + "preText": "Segmentation", "style": "primary" }, { - "id": "d7debaaa-6bbc-4db5-953b-70a70b135fa0", + "id": "ad03162a-ea2a-42db-a62c-0853773704e9", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan", + "linkLabel": "App delivery", "subTarget": "tab3", - "preText": "IP plan", + "preText": "App delivery", "style": "primary" }, { - "id": "55860051-a9f2-4d8d-87ab-f7b8f9d4e34c", + "id": "9d414136-7bbe-4d33-b88a-0dfbef8c8893", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid", + "linkLabel": "Internet", "subTarget": "tab4", - "preText": "Hybrid", + "preText": "Internet", "style": "primary" }, { - "id": "d25817c3-76eb-4485-97ef-65e3545059c4", + "id": "577d4a8b-e2fe-4db4-a262-f27ff0a32d99", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet", + "linkLabel": "PaaS", "subTarget": "tab5", - "preText": "Internet", + "preText": "PaaS", "style": "primary" }, { - "id": "7dae6de8-7463-4900-962b-b5b625c6c12b", + "id": "51010a75-0db3-41f5-b2c9-aecba1fb2841", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation", + "linkLabel": "Hybrid", "subTarget": "tab6", - "preText": "Segmentation", + "preText": "Hybrid", "style": "primary" }, { - "id": "4ca04348-6105-4a9d-bff2-70e77c815a6c", + "id": "31c37464-d06e-443d-ac63-4bfddd39fd7a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "Virtual WAN", "subTarget": "tab7", - "preText": "PaaS", + "preText": "Virtual WAN", "style": "primary" } ] @@ -154,22 +154,22 @@ { "type": 1, "content": { - "json": "## App delivery" + "json": "## Hub and spoke" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." }, - "name": "querytext0" + "name": "querytext5" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -218,20 +218,20 @@ ] } }, - "name": "query0" + "name": "query5" }, { "type": 1, "content": { - "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." }, - "name": "querytext1" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -280,20 +280,20 @@ ] } }, - "name": "query1" + "name": "query6" }, { "type": 1, "content": { - "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." }, - "name": "querytext2" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -342,20 +342,20 @@ ] } }, - "name": "query2" + "name": "query7" }, { "type": 1, "content": { - "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." + "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." }, - "name": "querytext3" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -404,20 +404,42 @@ ] } }, - "name": "query3" + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## IP plan" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext4" + "name": "querytext14" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -466,42 +488,20 @@ ] } }, - "name": "query4" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab0" - }, - "name": "tab0" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hub and spoke" - }, - "name": "tab1title" + "name": "query14" }, { "type": 1, "content": { - "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext5" + "name": "querytext15" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -550,20 +550,42 @@ ] } }, - "name": "query5" + "name": "query15" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab1" + }, + "name": "tab1" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Segmentation" + }, + "name": "tab2title" }, { "type": 1, "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." }, - "name": "querytext6" + "name": "querytext23" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -612,20 +634,20 @@ ] } }, - "name": "query6" + "name": "query23" }, { "type": 1, "content": { - "json": "Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information." + "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." }, - "name": "querytext7" + "name": "querytext24" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -674,20 +696,20 @@ ] } }, - "name": "query7" + "name": "query24" }, { "type": 1, "content": { - "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information." + "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." }, - "name": "querytext8" + "name": "querytext25" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -736,42 +758,20 @@ ] } }, - "name": "query8" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab1" - }, - "name": "tab1" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Virtual WAN" - }, - "name": "tab2title" + "name": "query25" }, { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext27" + "name": "querytext26" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -820,7 +820,7 @@ ] } }, - "name": "query27" + "name": "query26" } ] }, @@ -840,22 +840,22 @@ { "type": 1, "content": { - "json": "## IP plan" + "json": "## App delivery" }, "name": "tab3title" }, { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext14" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -904,20 +904,20 @@ ] } }, - "name": "query14" + "name": "query0" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." }, - "name": "querytext15" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -966,42 +966,20 @@ ] } }, - "name": "query15" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hybrid" - }, - "name": "tab4title" + "name": "query1" }, { "type": 1, "content": { - "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext9" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1050,20 +1028,20 @@ ] } }, - "name": "query9" + "name": "query2" }, { "type": 1, "content": { - "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." + "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." }, - "name": "querytext10" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1112,20 +1090,20 @@ ] } }, - "name": "query10" + "name": "query3" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." + "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." }, - "name": "querytext11" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1174,20 +1152,42 @@ ] } }, - "name": "query11" + "name": "query4" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Internet" + }, + "name": "tab4title" }, { "type": 1, "content": { - "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." }, - "name": "querytext12" + "name": "querytext16" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1236,20 +1236,20 @@ ] } }, - "name": "query12" + "name": "query16" }, { "type": 1, "content": { - "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." }, - "name": "querytext13" + "name": "querytext17" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1298,42 +1298,20 @@ ] } }, - "name": "query13" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Internet" - }, - "name": "tab5title" + "name": "query17" }, { "type": 1, "content": { - "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." + "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext16" + "name": "querytext18" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1382,20 +1360,20 @@ ] } }, - "name": "query16" + "name": "query18" }, { "type": 1, "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext17" + "name": "querytext19" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1444,20 +1422,20 @@ ] } }, - "name": "query17" + "name": "query19" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." }, - "name": "querytext18" + "name": "querytext20" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1506,20 +1484,20 @@ ] } }, - "name": "query18" + "name": "query20" }, { "type": 1, "content": { - "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." }, - "name": "querytext19" + "name": "querytext21" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1568,20 +1546,42 @@ ] } }, - "name": "query19" + "name": "query21" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab4" + }, + "name": "tab4" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "name": "tab5title" }, { "type": 1, "content": { - "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext22" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1630,20 +1630,42 @@ ] } }, - "name": "query20" + "name": "query22" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab6title" }, { "type": 1, "content": { - "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext21" + "name": "querytext9" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1692,42 +1714,20 @@ ] } }, - "name": "query21" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab5" - }, - "name": "tab5" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Segmentation" - }, - "name": "tab6title" + "name": "query9" }, { "type": 1, "content": { - "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information." + "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information." }, - "name": "querytext23" + "name": "querytext10" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1776,20 +1776,20 @@ ] } }, - "name": "query23" + "name": "query10" }, { "type": 1, "content": { - "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information." }, - "name": "querytext24" + "name": "querytext11" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1838,20 +1838,20 @@ ] } }, - "name": "query24" + "name": "query11" }, { "type": 1, "content": { - "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." + "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext25" + "name": "querytext12" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1900,20 +1900,20 @@ ] } }, - "name": "query25" + "name": "query12" }, { "type": 1, "content": { - "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." }, - "name": "querytext26" + "name": "querytext13" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1962,7 +1962,7 @@ ] } }, - "name": "query26" + "name": "query13" } ] }, @@ -1982,22 +1982,22 @@ { "type": 1, "content": { - "json": "## PaaS" + "json": "## Virtual WAN" }, "name": "tab7title" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext22" + "name": "querytext27" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2046,7 +2046,7 @@ ] } }, - "name": "query22" + "name": "query27" } ] }, diff --git a/workbooks/alz_checklist.en_network_workbook_template.json b/workbooks/alz_checklist.en_network_workbook_template.json index 6b2890ff4..8327a11a5 100644 --- a/workbooks/alz_checklist.en_network_workbook_template.json +++ b/workbooks/alz_checklist.en_network_workbook_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"3947f6f6-dacf-406b-b813-6ee084bf929d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery\",\n \"subTarget\": \"tab0\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"06f9b5a5-7707-4ce3-86cb-50e135720d8c\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8285bfb6-b49a-4a99-a155-bc9cf54a0eda\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d7debaaa-6bbc-4db5-953b-70a70b135fa0\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab3\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"55860051-a9f2-4d8d-87ab-f7b8f9d4e34c\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d25817c3-76eb-4485-97ef-65e3545059c4\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"7dae6de8-7463-4900-962b-b5b625c6c12b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"4ca04348-6105-4a9d-bff2-70e77c815a6c\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab7\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"1d406f6b-168f-4c8d-93d4-2819a2900e36\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"6c8040ec-e3a1-4f1b-9ab9-9ba09ba30bd5\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab1\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ea8ed44d-41cb-4d2e-90bd-ac19a327a5f7\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ad03162a-ea2a-42db-a62c-0853773704e9\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App delivery\",\n \"subTarget\": \"tab3\",\n \"preText\": \"App delivery\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"9d414136-7bbe-4d33-b88a-0dfbef8c8893\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"577d4a8b-e2fe-4db4-a262-f27ff0a32d99\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab5\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"51010a75-0db3-41f5-b2c9-aecba1fb2841\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"31c37464-d06e-443d-ac63-4bfddd39fd7a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Consider the limit of routes per route table (400). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App delivery\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your application gateways should be deployed in subnets with IP prefixes equal or larger than /26. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetId = tostring(subnets.id), subnetPrefixLength = split(subnets.properties.addressPrefix, '/')[1]) on subnetId | extend compliant = (subnetPrefixLength <= 26) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use VPN gateways to connect branches or remote locations to Azure. For higher resilience, deploy zone-redundant gateways (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]"