mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(azure): Add new checks related to Network service (#3402)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
This commit is contained in:
41
poetry.lock
generated
41
poetry.lock
generated
@@ -388,6 +388,22 @@ azure-common = ">=1.1,<2.0"
|
||||
azure-mgmt-core = ">=1.3.2,<2.0.0"
|
||||
isodate = ">=0.6.1,<1.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-network"
|
||||
version = "25.2.0"
|
||||
description = "Microsoft Azure Network Management Client Library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "azure-mgmt-network-25.2.0.tar.gz", hash = "sha256:114c4292d223b1d1e247b41af65b8d5a3793567e6adbfa230772055223f4182a"},
|
||||
{file = "azure_mgmt_network-25.2.0-py3-none-any.whl", hash = "sha256:c76181e79d689df40b8160c4ffa8dd2bbf6ba064ed4d164fdefd8fb53b781641"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
azure-common = ">=1.1,<2.0"
|
||||
azure-mgmt-core = ">=1.3.2,<2.0.0"
|
||||
isodate = ">=0.6.1,<1.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-rdbms"
|
||||
version = "10.1.0"
|
||||
@@ -3119,7 +3135,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
||||
@@ -3127,16 +3142,8 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
||||
@@ -3153,7 +3160,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
||||
@@ -3161,7 +3167,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||
@@ -3551,24 +3556,24 @@ python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"},
|
||||
@@ -3576,7 +3581,7 @@ files = [
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"},
|
||||
@@ -3584,7 +3589,7 @@ files = [
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"},
|
||||
@@ -3592,7 +3597,7 @@ files = [
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"},
|
||||
@@ -4230,4 +4235,4 @@ docs = ["mkdocs", "mkdocs-material"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.13"
|
||||
content-hash = "9fa7e3474b8c6ae351dc10eeb5d396f9f7f38b6a4eb402993ec72c5cbdafe9c7"
|
||||
content-hash = "cb76dd1a0fafbfa685bca46d1f214b7fb5158fa76bbcec46159a1b68add29456"
|
||||
|
||||
@@ -2,6 +2,7 @@ import asyncio
|
||||
import sys
|
||||
from os import getenv
|
||||
|
||||
import requests
|
||||
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential
|
||||
from azure.mgmt.subscription import SubscriptionClient
|
||||
from msgraph import GraphServiceClient
|
||||
@@ -212,3 +213,31 @@ class Azure_Provider:
|
||||
|
||||
def get_region_config(self):
|
||||
return self.region_config
|
||||
|
||||
def get_locations(self, credentials, region_config):
|
||||
locations = None
|
||||
if credentials and region_config:
|
||||
subscriptions_client = SubscriptionClient(
|
||||
credential=credentials,
|
||||
base_url=region_config["base_url"],
|
||||
credential_scopes=region_config["credential_scopes"],
|
||||
)
|
||||
list_subscriptions = subscriptions_client.subscriptions.list()
|
||||
list_subscriptions_ids = [
|
||||
subscription.subscription_id for subscription in list_subscriptions
|
||||
]
|
||||
locations = {}
|
||||
token = credentials.get_token("https://management.azure.com/.default").token
|
||||
for subscription_id in list_subscriptions_ids:
|
||||
locations.update({subscription_id: []})
|
||||
url = f"https://management.azure.com/subscriptions/{subscription_id}/locations?api-version=2022-12-01"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
for location in data["value"]:
|
||||
locations[subscription_id].append(location["name"])
|
||||
return locations
|
||||
|
||||
@@ -11,4 +11,5 @@ azure_audit_info = Azure_Audit_Info(
|
||||
audit_metadata=None,
|
||||
audit_config=None,
|
||||
azure_region_config=Azure_Region_Config(),
|
||||
locations=None,
|
||||
)
|
||||
|
||||
@@ -28,6 +28,7 @@ class Azure_Audit_Info:
|
||||
audit_metadata: Optional[Any]
|
||||
audit_config: dict
|
||||
azure_region_config: Azure_Region_Config
|
||||
locations: list[str]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -37,6 +38,7 @@ class Azure_Audit_Info:
|
||||
audit_resources,
|
||||
audit_config,
|
||||
azure_region_config,
|
||||
locations,
|
||||
):
|
||||
self.credentials = credentials
|
||||
self.identity = identity
|
||||
@@ -44,3 +46,4 @@ class Azure_Audit_Info:
|
||||
self.audit_resources = audit_resources
|
||||
self.audit_config = audit_config
|
||||
self.azure_region_config = azure_region_config
|
||||
self.locations = locations
|
||||
|
||||
@@ -16,6 +16,7 @@ class AzureService:
|
||||
)
|
||||
|
||||
self.subscriptions = audit_info.identity.subscriptions
|
||||
self.locations = audit_info.locations
|
||||
|
||||
def __set_clients__(self, subscriptions, credentials, service, region_config):
|
||||
clients = {}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_bastion_host_exists",
|
||||
"CheckTitle": "Ensure an Azure Bastion Host Exists",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "Network",
|
||||
"Description": "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service.",
|
||||
"Risk": "The Azure Bastion service allows organizations a more secure means of accessing Azure Virtual Machines over the Internet without assigning public IP addresses to those Virtual Machines. The Azure Bastion service provides Remote Desktop Protocol (RDP) and Secure Shell (SSH) access to Virtual Machines using TLS within a web browser, thus preventing organizations from opening up 3389/TCP and 22/TCP to the Internet on Azure Virtual Machines. Additional benefits of the Bastion service includes Multi-Factor Authentication, Conditional Access Policies, and any other hardening measures configured within Azure Active Directory using a central point of access.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/bastion/bastion-overview#sku",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az network bastion create --location <location> --name <name of bastion host> --public-ip-address <public IP address name or ID> --resource-group <resource group name or ID> --vnet-name <virtual network containing subnet called 'AzureBastionSubnet'> --scale-units <integer> --sku Standard [--disable-copy- paste true|false] [--enable-ip-connect true|false] [--enable-tunneling true|false]",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/bastion-host-exists.html",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "From Azure Portal* 1. Click on Bastions 2. Select the Subscription 3. Select the Resource group 4. Type a Name for the new Bastion host 5. Select a Region 6. Choose Standard next to Tier 7. Use the slider to set the Instance count 8. Select the Virtual network or Create new 9. Select the Subnet named AzureBastionSubnet. Create a Subnet named AzureBastionSubnet using a /26 CIDR range if it doesn't already exist. 10. Selct the appropriate Public IP address option. 11. If Create new is selected for the Public IP address option, provide a Public IP address name. 12. If Use existing is selected for Public IP address option, select an IP address from Choose public IP address 13. Click Next: Tags > 14. Configure the appropriate Tags 15. Click Next: Advanced > 16. Select the appropriate Advanced options 17. Click Next: Review + create > 18. Click Create From Azure CLI az network bastion create --location <location> --name <name of bastion host> --public-ip-address <public IP address name or ID> --resource-group <resource group name or ID> --vnet-name <virtual network containing subnet called 'AzureBastionSubnet'> --scale-units <integer> --sku Standard [--disable-copy- paste true|false] [--enable-ip-connect true|false] [--enable-tunneling true|false] From PowerShell Create the appropriate Virtual network settings and Public IP Address settings. $subnetName = 'AzureBastionSubnet' $subnet = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix <IP address range in CIDR notation making sure to use a /26> $virtualNet = New-AzVirtualNetwork -Name <virtual network name> - ResourceGroupName <resource group name> -Location <location> -AddressPrefix <IP address range in CIDR notation> -Subnet $subnet $publicip = New-AzPublicIpAddress -ResourceGroupName <resource group name> - Name <public IP address name> -Location <location> -AllocationMethod Dynamic -Sku Standard",
|
||||
"Url": "https://learn.microsoft.com/en-us/powershell/module/az.network/get-azbastion?view=azps-9.2.0"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "The Azure Bastion service incurs additional costs and requires a specific virtual network configuration. The Standard tier offers additional configuration options compared to the Basic tier and may incur additional costs for those added features."
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_bastion_host_exists(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, bastion_hosts in network_client.bastion_hosts.items():
|
||||
if not bastion_hosts:
|
||||
status = "FAIL"
|
||||
status_extended = (
|
||||
f"Bastion Host from subscription {subscription} does not exist"
|
||||
)
|
||||
resource_id = "N/A"
|
||||
else:
|
||||
bastion_names = ", ".join(
|
||||
[bastion_host.name for bastion_host in bastion_hosts]
|
||||
)
|
||||
resource_id = ", ".join(
|
||||
[bastion_host.id for bastion_host in bastion_hosts]
|
||||
)
|
||||
status = "PASS"
|
||||
status_extended = f"Bastion Host from subscription {subscription} available are: {bastion_names}"
|
||||
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = "Bastion Host"
|
||||
report.resource_id = resource_id
|
||||
report.status = status
|
||||
report.status_extended = status_extended
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,4 @@
|
||||
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
|
||||
from prowler.providers.azure.services.network.network_service import Network
|
||||
|
||||
network_client = Network(azure_audit_info)
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_flow_log_more_than_90_days",
|
||||
"CheckTitle": "Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days.",
|
||||
"Risk": "Flow logs enable capturing information about IP traffic flowing in and out of network security groups. Logs can be used to check for anomalies and give insight into suspected breaches.",
|
||||
"RelatedUrl": " https://docs.microsoft.com/en-us/azure/network-watcher/network-watcher-nsg-flow-logging-overview",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az network watcher flow-log configure --nsg <NameorID of the Network Security Group> --enabled true --resource-group <resourceGroupName> --retention 91 -- storage-account <NameorID of the storage account to save flow logs>",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/sufficient-nsg-flow-log-retention-period.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_azr_logging_1#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "From Azure Portal 1. Go to Network Watcher 2. Select NSG flow logs blade in the Logs section 3. Select each Network Security Group from the list 4. Ensure Status is set to On 5. Ensure Retention (days) setting greater than 90 days 6. Select your storage account in the Storage account field 7. Select Save From Azure CLI Enable the NSG flow logs and set the Retention (days) to greater than or equal to 90 days. az network watcher flow-log configure --nsg <NameorID of the Network Security Group> --enabled true --resource-group <resourceGroupName> --retention 91 --storage-account <NameorID of the storage account to save flow logs>",
|
||||
"Url": "https://docs.microsoft.com/en-us/cli/azure/network/watcher/flow-log?view=azure-cli-latest"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This will keep IP traffic logs for longer than 90 days. As a level 2, first determine your need to retain data, then apply your selection here. As this is data stored for longer, your monthly storage costs will increase depending on your data use."
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_flow_log_more_than_90_days(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, network_watchers in network_client.network_watchers.items():
|
||||
for network_watcher in network_watchers:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = network_watcher.name
|
||||
report.resource_id = network_watcher.id
|
||||
if network_watcher.flow_logs:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has flow logs enabled for more than 90 days"
|
||||
has_failed = False
|
||||
for flow_log in network_watcher.flow_logs:
|
||||
if not has_failed:
|
||||
if not flow_log.enabled:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has flow logs disabled"
|
||||
has_failed = True
|
||||
elif flow_log.retention_policy.days < 90 and not has_failed:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} flow logs retention policy is less than 90 days"
|
||||
has_failed = True
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has no flow logs"
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_http_internet_access_restricted",
|
||||
"CheckTitle": "Ensure that HTTP(S) access from the Internet is evaluated and restricted",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured.",
|
||||
"Risk": "The potential security problem with using HTTP(S) over the Internet is that attackers can use various brute force techniques to gain access to Azure resources. Once the attackers gain access, they can use the resource as a launch point for compromising other resources within the Azure tenant.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-network-security#ns-1-establish-network-segmentation-boundaries",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/unrestricted-http-access.html",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Where HTTP(S) is not explicitly required and narrowly configured for resources attached to the Network Security Group, Internet-level access to your Azure resources should be restricted or eliminated. For internal access to relevant resources, configure an encrypted network tunnel such as: ExpressRoute Site-to-site VPN Point-to-site VPN",
|
||||
"Url": ""
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_http_internet_access_restricted(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, security_groups in network_client.security_groups.items():
|
||||
for security_group in security_groups:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = security_group.name
|
||||
report.resource_id = security_group.id
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has HTTP internet access restricted."
|
||||
rule_fail_condition = any(
|
||||
(
|
||||
rule.destination_port_range == "80"
|
||||
or (
|
||||
"-" in rule.destination_port_range
|
||||
and int(rule.destination_port_range.split("-")[0]) <= 80
|
||||
and int(rule.destination_port_range.split("-")[1]) >= 80
|
||||
)
|
||||
)
|
||||
and rule.protocol in ["TCP", "*"]
|
||||
and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"]
|
||||
and rule.access == "Allow"
|
||||
and rule.direction == "Inbound"
|
||||
for rule in security_group.security_rules
|
||||
)
|
||||
if rule_fail_condition:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has HTTP internet access allowed."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_rdp_internet_access_restricted",
|
||||
"CheckTitle": "Ensure that RDP access from the Internet is evaluated and restricted",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
|
||||
"Risk": "The potential security problem with using RDP over the Internet is that attackers can use various brute force techniques to gain access to Azure Virtual Machines. Once the attackers gain access, they can use a virtual machine as a launch point for compromising other machines on an Azure Virtual Network or even attack networked devices outside of Azure.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/security/azure-security-network-security-best-practices#disable-rdpssh-access-to-azure-virtual-machines",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/unrestricted-rdp-access.html#",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_azr_networking_2#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Where RDP is not explicitly required and narrowly configured for resources attached to the Network Security Group, Internet-level access to your Azure resources should be restricted or eliminated. For internal access to relevant resources, configure an encrypted network tunnel such as: ExpressRoute Site-to-site VPN Point-to-site VPN",
|
||||
"Url": "https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-network-security#ns-1-establish-network-segmentation-boundaries"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_rdp_internet_access_restricted(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, security_groups in network_client.security_groups.items():
|
||||
for security_group in security_groups:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = security_group.name
|
||||
report.resource_id = security_group.id
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has RDP internet access restricted."
|
||||
rule_fail_condition = any(
|
||||
(
|
||||
rule.destination_port_range == "3389"
|
||||
or (
|
||||
"-" in rule.destination_port_range
|
||||
and int(rule.destination_port_range.split("-")[0]) <= 3389
|
||||
and int(rule.destination_port_range.split("-")[1]) >= 3389
|
||||
)
|
||||
)
|
||||
and rule.protocol in ["TCP", "*"]
|
||||
and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"]
|
||||
and rule.access == "Allow"
|
||||
and rule.direction == "Inbound"
|
||||
for rule in security_group.security_rules
|
||||
)
|
||||
if rule_fail_condition:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has RDP internet access allowed."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
116
prowler/providers/azure/services/network/network_service.py
Normal file
116
prowler/providers/azure/services/network/network_service.py
Normal file
@@ -0,0 +1,116 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from azure.mgmt.network import NetworkManagementClient
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.azure.lib.service.service import AzureService
|
||||
|
||||
|
||||
########################## SQLServer
|
||||
class Network(AzureService):
|
||||
def __init__(self, audit_info):
|
||||
super().__init__(NetworkManagementClient, audit_info)
|
||||
self.security_groups = self.__get_security_groups__()
|
||||
self.bastion_hosts = self.__get_bastion_hosts__()
|
||||
self.network_watchers = self.__get_network_watchers__()
|
||||
|
||||
def __get_security_groups__(self):
|
||||
logger.info("Network - Getting Network Security Groups...")
|
||||
security_groups = {}
|
||||
for subscription, client in self.clients.items():
|
||||
try:
|
||||
security_groups.update({subscription: []})
|
||||
security_groups_list = client.network_security_groups.list_all()
|
||||
for security_group in security_groups_list:
|
||||
security_groups[subscription].append(
|
||||
SecurityGroup(
|
||||
id=security_group.id,
|
||||
name=security_group.name,
|
||||
location=security_group.location,
|
||||
security_rules=security_group.security_rules,
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return security_groups
|
||||
|
||||
def __get_network_watchers__(self):
|
||||
logger.info("Network - Getting Network Watchers...")
|
||||
network_watchers = {}
|
||||
for subscription, client in self.clients.items():
|
||||
try:
|
||||
network_watchers.update({subscription: []})
|
||||
network_watchers_list = client.network_watchers.list_all()
|
||||
for network_watcher in network_watchers_list:
|
||||
flow_logs = self.__get_flow_logs__(
|
||||
subscription, network_watcher.name
|
||||
)
|
||||
network_watchers[subscription].append(
|
||||
NetworkWatcher(
|
||||
id=network_watcher.id,
|
||||
name=network_watcher.name,
|
||||
location=network_watcher.location,
|
||||
flow_logs=flow_logs,
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return network_watchers
|
||||
|
||||
def __get_flow_logs__(self, subscription, network_watcher_name):
|
||||
logger.info("Network - Getting Flow Logs...")
|
||||
client = self.clients[subscription]
|
||||
resource_group = "NetworkWatcherRG"
|
||||
flow_logs = client.flow_logs.list(resource_group, network_watcher_name)
|
||||
return flow_logs
|
||||
|
||||
def __get_bastion_hosts__(self):
|
||||
logger.info("Network - Getting Bastion Hosts...")
|
||||
bastion_hosts = {}
|
||||
for subscription, client in self.clients.items():
|
||||
try:
|
||||
bastion_hosts.update({subscription: []})
|
||||
bastion_hosts_list = client.bastion_hosts.list()
|
||||
for bastion_host in bastion_hosts_list:
|
||||
bastion_hosts[subscription].append(
|
||||
BastionHost(
|
||||
id=bastion_host.id,
|
||||
name=bastion_host.name,
|
||||
location=bastion_host.location,
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return bastion_hosts
|
||||
|
||||
|
||||
@dataclass
|
||||
class BastionHost:
|
||||
id: str
|
||||
name: str
|
||||
location: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkWatcher:
|
||||
id: str
|
||||
name: str
|
||||
location: str
|
||||
flow_logs: list
|
||||
|
||||
|
||||
@dataclass
|
||||
class SecurityGroup:
|
||||
id: str
|
||||
name: str
|
||||
location: str
|
||||
security_rules: list
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_ssh_internet_access_restricted",
|
||||
"CheckTitle": "Ensure that SSH access from the Internet is evaluated and restricted",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
|
||||
"Risk": "The potential security problem with using SSH over the Internet is that attackers can use various brute force techniques to gain access to Azure Virtual Machines. Once the attackers gain access, they can use a virtual machine as a launch point for compromising other machines on the Azure Virtual Network or even attack networked devices outside of Azure.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/security/azure-security-network-security-best-practices#disable-rdpssh-access-to-azure-virtual-machines",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/unrestricted-ssh-access.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_azr_networking_3#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Where SSH is not explicitly required and narrowly configured for resources attached to the Network Security Group, Internet-level access to your Azure resources should be restricted or eliminated. For internal access to relevant resources, configure an encrypted network tunnel such as: ExpressRoute Site-to-site VPN Point-to-site VPN",
|
||||
"Url": "https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-network-security#ns-1-establish-network-segmentation-boundaries"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_ssh_internet_access_restricted(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, security_groups in network_client.security_groups.items():
|
||||
for security_group in security_groups:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = security_group.name
|
||||
report.resource_id = security_group.id
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has SSH internet access restricted."
|
||||
rule_fail_condition = any(
|
||||
(
|
||||
rule.destination_port_range == "22"
|
||||
or (
|
||||
"-" in rule.destination_port_range
|
||||
and int(rule.destination_port_range.split("-")[0]) <= 22
|
||||
and int(rule.destination_port_range.split("-")[1]) >= 22
|
||||
)
|
||||
)
|
||||
and rule.protocol in ["TCP", "*"]
|
||||
and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"]
|
||||
and rule.access == "Allow"
|
||||
and rule.direction == "Inbound"
|
||||
for rule in security_group.security_rules
|
||||
)
|
||||
if rule_fail_condition:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has SSH internet access allowed."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_udp_internet_access_restricted",
|
||||
"CheckTitle": "Ensure that UDP access from the Internet is evaluated and restricted",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
|
||||
"Risk": "The potential security problem with broadly exposing UDP services over the Internet is that attackers can use DDoS amplification techniques to reflect spoofed UDP traffic from Azure Virtual Machines. The most common types of these attacks use exposed DNS, NTP, SSDP, SNMP, CLDAP and other UDP-based services as amplification sources for disrupting services of other machines on the Azure Virtual Network or even attack networked devices outside of Azure.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices#secure-your-critical-azure-service-resources-to-only-your-virtual-networks",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/unrestricted-udp-access.html#",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-that-udp-services-are-restricted-from-the-internet#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Where UDP is not explicitly required and narrowly configured for resources attached tothe Network Security Group, Internet-level access to your Azure resources should be restricted or eliminated. For internal access to relevant resources, configure an encrypted network tunnel such as: ExpressRouteSite-to-site VPN Point-to-site VPN",
|
||||
"Url": "https://docs.microsoft.com/en-us/azure/security/fundamentals/ddos-best-practices"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_udp_internet_access_restricted(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, security_groups in network_client.security_groups.items():
|
||||
for security_group in security_groups:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = security_group.name
|
||||
report.resource_id = security_group.id
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has UDP internet access restricted."
|
||||
rule_fail_condition = any(
|
||||
rule.protocol in ["UDP"]
|
||||
and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"]
|
||||
and rule.access == "Allow"
|
||||
and rule.direction == "Inbound"
|
||||
for rule in security_group.security_rules
|
||||
)
|
||||
if rule_fail_condition:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has UDP internet access allowed."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_watcher_enabled",
|
||||
"CheckTitle": "Ensure that Network Watcher is 'Enabled'",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Enable Network Watcher for Azure subscriptions.",
|
||||
"Risk": "Network diagnostic and visualization tools available with Network Watcher help users understand, diagnose, and gain insights to the network in Azure.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/network-watcher/network-watcher-monitoring-overview",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Network/enable-network-watcher.html#",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Opting out of Network Watcher automatic enablement is a permanent change. Once you opt-out you cannot opt-in without contacting support.",
|
||||
"Url": "https://docs.azure.cn/zh-cn/cli/network/watcher?view=azure-cli-latest#az_network_watcher_list"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "There are additional costs per transaction to run and store network data. For high-volume networks these charges will add up quickly."
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_watcher_enabled(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
nw_locations = []
|
||||
for subscription, network_watchers in network_client.network_watchers.items():
|
||||
for network_watcher in network_watchers:
|
||||
nw_locations.append(network_watcher.location)
|
||||
for subscription, locations in network_client.locations.items():
|
||||
for location in locations:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = "Network Watcher"
|
||||
report.resource_id = f"/subscriptions/{subscription}/providers/Microsoft.Network/networkWatchers/{location}"
|
||||
if location not in nw_locations:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher is not enabled for the location {location} in subscription {subscription}."
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Network Watcher is enabled for the location {location} in subscription {subscription}."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -330,6 +330,9 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
|
||||
base_url=region_config["base_url"],
|
||||
credential_scopes=region_config["credential_scopes"],
|
||||
)
|
||||
azure_audit_info.locations = azure_provider.get_locations(
|
||||
azure_audit_info.credentials, region_config
|
||||
)
|
||||
|
||||
if not arguments.get("only_logs"):
|
||||
self.print_azure_credentials(azure_audit_info)
|
||||
@@ -386,7 +389,7 @@ def set_provider_audit_info(provider: str, arguments: dict):
|
||||
|
||||
def set_provider_execution_parameters(provider: str, audit_info):
|
||||
"""
|
||||
set_provider_audit_info configures automatically the audit execution based on the selected provider and returns the checks that are going to be executed.
|
||||
set_provider_execution_parameters" configures automatically the audit execution based on the selected provider and returns the checks that are going to be executed.
|
||||
"""
|
||||
try:
|
||||
set_provider_execution_parameters_function = (
|
||||
|
||||
@@ -32,6 +32,7 @@ azure-mgmt-applicationinsights = "4.0.0"
|
||||
azure-mgmt-authorization = "4.0.0"
|
||||
azure-mgmt-rdbms = "10.1.0"
|
||||
azure-mgmt-cosmosdb = "9.4.0"
|
||||
azure-mgmt-network = "25.2.0"
|
||||
azure-mgmt-security = "6.0.0"
|
||||
azure-mgmt-sql = "3.0.1"
|
||||
azure-mgmt-storage = "21.1.0"
|
||||
|
||||
@@ -78,6 +78,7 @@ class Test_Slack_Integration:
|
||||
audit_metadata=None,
|
||||
audit_config=None,
|
||||
azure_region_config=Azure_Region_Config(),
|
||||
locations=None,
|
||||
)
|
||||
assert create_message_identity("aws", aws_audit_info) == (
|
||||
f"AWS Account *{aws_audit_info.audited_account}*",
|
||||
|
||||
@@ -29,6 +29,7 @@ def set_mocked_azure_audit_info(
|
||||
),
|
||||
audit_config: dict = None,
|
||||
azure_region_config: Azure_Region_Config = Azure_Region_Config(),
|
||||
locations: list = None,
|
||||
):
|
||||
audit_info = Azure_Audit_Info(
|
||||
credentials=credentials,
|
||||
@@ -37,5 +38,6 @@ def set_mocked_azure_audit_info(
|
||||
audit_resources=None,
|
||||
audit_config=audit_config,
|
||||
azure_region_config=azure_region_config,
|
||||
locations=locations,
|
||||
)
|
||||
return audit_info
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import BastionHost
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_bastion_host_exists:
|
||||
def test_no_bastion_hosts(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.bastion_hosts = {AZURE_SUBSCRIPTION: []}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_bastion_host_exists.network_bastion_host_exists import (
|
||||
network_bastion_host_exists,
|
||||
)
|
||||
|
||||
check = network_bastion_host_exists()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Bastion Host from subscription {AZURE_SUBSCRIPTION} does not exist"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == "Bastion Host"
|
||||
assert result[0].resource_id == "N/A"
|
||||
|
||||
def test_network_bastion_host_exists(self):
|
||||
network_client = mock.MagicMock
|
||||
bastion_host_name = "Bastion Host Name"
|
||||
bastion_host_id = str(uuid4())
|
||||
|
||||
network_client.bastion_hosts = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
BastionHost(
|
||||
id=bastion_host_id,
|
||||
name=bastion_host_name,
|
||||
location="location",
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_bastion_host_exists.network_bastion_host_exists import (
|
||||
network_bastion_host_exists,
|
||||
)
|
||||
|
||||
check = network_bastion_host_exists()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Bastion Host from subscription {AZURE_SUBSCRIPTION} available are: {bastion_host_name}"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == "Bastion Host"
|
||||
assert result[0].resource_id == bastion_host_id
|
||||
@@ -0,0 +1,200 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import FlowLog, RetentionPolicyParameters
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import NetworkWatcher
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_flow_log_more_than_90_days:
|
||||
def test_no_network_watchers(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.network_watchers = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_more_than_90_days.network_flow_log_more_than_90_days import (
|
||||
network_flow_log_more_than_90_days,
|
||||
)
|
||||
|
||||
check = network_flow_log_more_than_90_days()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_network_watchers_no_flow_logs(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_more_than_90_days.network_flow_log_more_than_90_days import (
|
||||
network_flow_log_more_than_90_days,
|
||||
)
|
||||
|
||||
check = network_flow_log_more_than_90_days()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has no flow logs"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_network_watchers_flow_logs_disabled(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[
|
||||
FlowLog(
|
||||
enabled=False,
|
||||
retention_policy=RetentionPolicyParameters(days=90),
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_more_than_90_days.network_flow_log_more_than_90_days import (
|
||||
network_flow_log_more_than_90_days,
|
||||
)
|
||||
|
||||
check = network_flow_log_more_than_90_days()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has flow logs disabled"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_network_watchers_flow_logs_retention_days_80(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[
|
||||
FlowLog(
|
||||
enabled=True,
|
||||
retention_policy=RetentionPolicyParameters(days=80),
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_more_than_90_days.network_flow_log_more_than_90_days import (
|
||||
network_flow_log_more_than_90_days,
|
||||
)
|
||||
|
||||
check = network_flow_log_more_than_90_days()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} flow logs retention policy is less than 90 days"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_network_watchers_flow_logs_well_configured(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[
|
||||
FlowLog(
|
||||
enabled=True,
|
||||
retention_policy=RetentionPolicyParameters(days=90),
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_more_than_90_days.network_flow_log_more_than_90_days import (
|
||||
network_flow_log_more_than_90_days,
|
||||
)
|
||||
|
||||
check = network_flow_log_more_than_90_days()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has flow logs enabled for more than 90 days"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
@@ -0,0 +1,209 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import SecurityRule
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import SecurityGroup
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_http_internet_access_restricted:
|
||||
def test_no_security_groups(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.security_groups = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import (
|
||||
network_http_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_http_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_security_groups_no_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import (
|
||||
network_http_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_http_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has HTTP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="80",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import (
|
||||
network_http_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_http_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has HTTP internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules_range(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="20-100",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import (
|
||||
network_http_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_http_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has HTTP internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_valid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="23",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import (
|
||||
network_http_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_http_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has HTTP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
@@ -0,0 +1,162 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import SecurityRule
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import SecurityGroup
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_rdp_internet_access_restricted:
|
||||
def test_no_security_groups(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.security_groups = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_rdp_internet_access_restricted.network_rdp_internet_access_restricted import (
|
||||
network_rdp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_rdp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_security_groups_no_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_rdp_internet_access_restricted.network_rdp_internet_access_restricted import (
|
||||
network_rdp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_rdp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has RDP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_valid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="3388",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_rdp_internet_access_restricted.network_rdp_internet_access_restricted import (
|
||||
network_rdp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_rdp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has RDP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules_range(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="33-6000",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_rdp_internet_access_restricted.network_rdp_internet_access_restricted import (
|
||||
network_rdp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_rdp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has RDP internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
129
tests/providers/azure/services/network/network_service_test.py
Normal file
129
tests/providers/azure/services/network/network_service_test.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from azure.mgmt.network.models import FlowLog
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import (
|
||||
BastionHost,
|
||||
Network,
|
||||
NetworkWatcher,
|
||||
SecurityGroup,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION,
|
||||
set_mocked_azure_audit_info,
|
||||
)
|
||||
|
||||
|
||||
def mock_network_get_security_groups(_):
|
||||
return {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id="id",
|
||||
name="name",
|
||||
location="location",
|
||||
security_rules=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def mock_network_get_bastion_hosts(_):
|
||||
return {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
BastionHost(
|
||||
id="id",
|
||||
name="name",
|
||||
location="location",
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def mock_network_get_network_watchers(_):
|
||||
return {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id="id",
|
||||
name="name",
|
||||
location="location",
|
||||
flow_logs=[FlowLog(enabled=True, retention_policy=90)],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network.__get_security_groups__",
|
||||
new=mock_network_get_security_groups,
|
||||
)
|
||||
@patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network.__get_bastion_hosts__",
|
||||
new=mock_network_get_bastion_hosts,
|
||||
)
|
||||
@patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network.__get_network_watchers__",
|
||||
new=mock_network_get_network_watchers,
|
||||
)
|
||||
class Test_Network_Service:
|
||||
def test__get_client__(self):
|
||||
network = Network(set_mocked_azure_audit_info())
|
||||
assert (
|
||||
network.clients[AZURE_SUBSCRIPTION].__class__.__name__
|
||||
== "NetworkManagementClient"
|
||||
)
|
||||
|
||||
def test__get_security_groups__(self):
|
||||
network = Network(set_mocked_azure_audit_info())
|
||||
assert (
|
||||
network.security_groups[AZURE_SUBSCRIPTION][0].__class__.__name__
|
||||
== "SecurityGroup"
|
||||
)
|
||||
assert network.security_groups[AZURE_SUBSCRIPTION][0].id == "id"
|
||||
assert network.security_groups[AZURE_SUBSCRIPTION][0].name == "name"
|
||||
assert network.security_groups[AZURE_SUBSCRIPTION][0].location == "location"
|
||||
assert network.security_groups[AZURE_SUBSCRIPTION][0].security_rules == []
|
||||
|
||||
def test__get_network_watchers__(self):
|
||||
network = Network(set_mocked_azure_audit_info())
|
||||
assert (
|
||||
network.network_watchers[AZURE_SUBSCRIPTION][0].__class__.__name__
|
||||
== "NetworkWatcher"
|
||||
)
|
||||
assert network.network_watchers[AZURE_SUBSCRIPTION][0].id == "id"
|
||||
assert network.network_watchers[AZURE_SUBSCRIPTION][0].name == "name"
|
||||
assert network.network_watchers[AZURE_SUBSCRIPTION][0].location == "location"
|
||||
assert network.network_watchers[AZURE_SUBSCRIPTION][0].flow_logs == [
|
||||
FlowLog(enabled=True, retention_policy=90)
|
||||
]
|
||||
|
||||
def __get_flow_logs__(self):
|
||||
network = Network(set_mocked_azure_audit_info())
|
||||
nw_name = "name"
|
||||
assert (
|
||||
network.network_watchers[AZURE_SUBSCRIPTION][0]
|
||||
.flow_logs[nw_name][0]
|
||||
.__class__.__name__
|
||||
== "FlowLog"
|
||||
)
|
||||
assert network.network_watchers[AZURE_SUBSCRIPTION][0].flow_logs == [
|
||||
FlowLog(enabled=True, retention_policy=90)
|
||||
]
|
||||
assert (
|
||||
network.network_watchers[AZURE_SUBSCRIPTION][0].flow_logs[0].enabled is True
|
||||
)
|
||||
assert (
|
||||
network.network_watchers[AZURE_SUBSCRIPTION][0]
|
||||
.flow_logs[0]
|
||||
.retention_policy
|
||||
== 90
|
||||
)
|
||||
|
||||
def __get_bastion_hosts__(self):
|
||||
network = Network(set_mocked_azure_audit_info())
|
||||
assert (
|
||||
network.bastion_hosts[AZURE_SUBSCRIPTION][0].__class__.__name__
|
||||
== "BastionHost"
|
||||
)
|
||||
assert network.bastion_hosts[AZURE_SUBSCRIPTION][0].id == "id"
|
||||
assert network.bastion_hosts[AZURE_SUBSCRIPTION][0].name == "name"
|
||||
assert network.bastion_hosts[AZURE_SUBSCRIPTION][0].location == "location"
|
||||
@@ -0,0 +1,209 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import SecurityRule
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import SecurityGroup
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_ssh_internet_access_restricted:
|
||||
def test_no_security_groups(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.security_groups = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_ssh_internet_access_restricted.network_ssh_internet_access_restricted import (
|
||||
network_ssh_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_ssh_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_security_groups_no_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_ssh_internet_access_restricted.network_ssh_internet_access_restricted import (
|
||||
network_ssh_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_ssh_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has SSH internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="22",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_ssh_internet_access_restricted.network_ssh_internet_access_restricted import (
|
||||
network_ssh_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_ssh_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has SSH internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules_range(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="20-25",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_ssh_internet_access_restricted.network_ssh_internet_access_restricted import (
|
||||
network_ssh_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_ssh_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has SSH internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_valid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
destination_port_range="23",
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_ssh_internet_access_restricted.network_ssh_internet_access_restricted import (
|
||||
network_ssh_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_ssh_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has SSH internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
@@ -0,0 +1,160 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import SecurityRule
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import SecurityGroup
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_udp_internet_access_restricted:
|
||||
def test_no_security_groups(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.security_groups = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_udp_internet_access_restricted.network_udp_internet_access_restricted import (
|
||||
network_udp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_udp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_security_groups_no_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_udp_internet_access_restricted.network_udp_internet_access_restricted import (
|
||||
network_udp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_udp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has UDP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_invalid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
protocol="UDP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_udp_internet_access_restricted.network_udp_internet_access_restricted import (
|
||||
network_udp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_udp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has UDP internet access allowed."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
|
||||
def test_network_security_groups_valid_security_rules(self):
|
||||
network_client = mock.MagicMock
|
||||
security_group_name = "Security Group Name"
|
||||
security_group_id = str(uuid4())
|
||||
|
||||
network_client.security_groups = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
SecurityGroup(
|
||||
id=security_group_id,
|
||||
name=security_group_name,
|
||||
location="location",
|
||||
security_rules=[
|
||||
SecurityRule(
|
||||
protocol="TCP",
|
||||
source_address_prefix="Internet",
|
||||
access="Allow",
|
||||
direction="Inbound",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_udp_internet_access_restricted.network_udp_internet_access_restricted import (
|
||||
network_udp_internet_access_restricted,
|
||||
)
|
||||
|
||||
check = network_udp_internet_access_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION} has UDP internet access restricted."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == security_group_name
|
||||
assert result[0].resource_id == security_group_id
|
||||
@@ -0,0 +1,112 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import NetworkWatcher
|
||||
|
||||
AZURE_SUBSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_network_watcher_enabled:
|
||||
def test_no_network_watchers(self):
|
||||
network_client = mock.MagicMock
|
||||
locations = []
|
||||
network_client.locations = {AZURE_SUBSCRIPTION: locations}
|
||||
network_client.security_groups = {}
|
||||
network_client.network_watchers = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_watcher_enabled.network_watcher_enabled import (
|
||||
network_watcher_enabled,
|
||||
)
|
||||
|
||||
check = network_watcher_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_invalid_network_watchers(self):
|
||||
network_client = mock.MagicMock
|
||||
locations = ["location"]
|
||||
network_client.locations = {AZURE_SUBSCRIPTION: locations}
|
||||
network_watcher_name = "Network Watcher"
|
||||
network_watcher_id = f"/subscriptions/{AZURE_SUBSCRIPTION}/providers/Microsoft.Network/networkWatchers/{locations[0]}"
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location=None,
|
||||
flow_logs=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_watcher_enabled.network_watcher_enabled import (
|
||||
network_watcher_enabled,
|
||||
)
|
||||
|
||||
check = network_watcher_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher is not enabled for the location {locations[0]} in subscription {AZURE_SUBSCRIPTION}."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_valid_network_watchers(self):
|
||||
network_client = mock.MagicMock
|
||||
locations = ["location"]
|
||||
network_client.locations = {AZURE_SUBSCRIPTION: locations}
|
||||
network_watcher_name = "Network Watcher"
|
||||
network_watcher_id = f"/subscriptions/{AZURE_SUBSCRIPTION}/providers/Microsoft.Network/networkWatchers/{locations[0]}"
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_watcher_enabled.network_watcher_enabled import (
|
||||
network_watcher_enabled,
|
||||
)
|
||||
|
||||
check = network_watcher_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher is enabled for the location {locations[0]} in subscription {AZURE_SUBSCRIPTION}."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
@@ -34,6 +34,7 @@ mock_azure_audit_info = Azure_Audit_Info(
|
||||
audit_resources=None,
|
||||
audit_config=None,
|
||||
azure_region_config=Azure_Region_Config(),
|
||||
locations=None,
|
||||
)
|
||||
|
||||
mock_set_audit_info = Audit_Info()
|
||||
|
||||
@@ -36,6 +36,7 @@ class Test_Common_Output_Options:
|
||||
audit_resources=None,
|
||||
audit_config=None,
|
||||
azure_region_config=Azure_Region_Config(),
|
||||
locations=None,
|
||||
)
|
||||
return audit_info
|
||||
|
||||
|
||||
Reference in New Issue
Block a user