From c4b711f3aa0f2f55fe5452db0fd4eecbc4500be7 Mon Sep 17 00:00:00 2001 From: Vikramjeet Singh <58273802+vikramsinghvirdi@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:56:34 -0700 Subject: [PATCH 1/2] Release/v1.0.0 (#7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PLA-17940 updating constraints and fixing s3_enable_access_logging to… (#3) * PLA-17940 updating constraints and fixing s3_enable_access_logging to not remediate the logging target bucket * PLA-17940 fixing copyright info * Updated readme to have link for reporting issues (#4) Co-authored-by: svikramjeet * S3 access logs permissions (#6) * Update minimum permissions for the job * Add more logs when permission is missing Co-authored-by: Mohammad Zuber Khan Co-authored-by: Paul Allen Co-authored-by: svikramjeet Co-authored-by: Zuber Co-authored-by: Mohammad Zuber Khan --- .gitignore | 2 + README.md | 3 + .../jobs/ec2_close_port_22/constraints.txt | 30 +++++-- .../ec2_close_port_22/requirements-dev.txt | 6 ++ .../jobs/ec2_close_port_22/requirements.txt | 8 +- .../jobs/ec2_close_port_3389/constraints.txt | 30 +++++-- .../ec2_close_port_3389/requirements-dev.txt | 6 ++ .../jobs/ec2_close_port_3389/requirements.txt | 8 +- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- .../s3_enable_access_logging/constraints.txt | 30 +++++-- .../minimum_policy.json | 3 +- .../requirements-dev.txt | 6 ++ .../s3_enable_access_logging/requirements.txt | 8 +- .../s3_enable_access_logging.py | 15 +++- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- .../jobs/s3_list_buckets/constraints.txt | 30 +++++-- .../jobs/s3_list_buckets/requirements-dev.txt | 6 ++ .../jobs/s3_list_buckets/requirements.txt | 8 +- .../s3_remove_public_access/constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../s3_remove_public_access/requirements.txt | 8 +- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- .../constraints.txt | 30 +++++-- .../requirements-dev.txt | 6 ++ .../requirements.txt | 8 +- setup.py | 2 +- shared/worker_logging/setup.py | 21 +++++ test/unit/test_s3_enable_access_logging.py | 78 +++++++++++++++++++ tox.ini | 72 +++++++++++++++-- 41 files changed, 583 insertions(+), 97 deletions(-) create mode 100644 remediation_worker/jobs/ec2_close_port_22/requirements-dev.txt create mode 100644 remediation_worker/jobs/ec2_close_port_3389/requirements-dev.txt create mode 100644 remediation_worker/jobs/rds_backup_retention_30_days/requirements-dev.txt create mode 100644 remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt create mode 100644 remediation_worker/jobs/s3_enable_default_encryption/requirements-dev.txt create mode 100644 remediation_worker/jobs/s3_list_buckets/requirements-dev.txt create mode 100644 remediation_worker/jobs/s3_remove_public_access/requirements-dev.txt create mode 100644 remediation_worker/jobs/s3_remove_public_admin_acl/requirements-dev.txt create mode 100644 remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt create mode 100644 remediation_worker/jobs/security_group_close_port_3389/requirements-dev.txt create mode 100644 remediation_worker/jobs/security_group_close_port_5432/requirements-dev.txt create mode 100644 shared/worker_logging/setup.py diff --git a/.gitignore b/.gitignore index 63db5e0..444053d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ pip-selfcheck.json venv test/unit/__pycache__ remediation_worker.egg-info +.tox +__pycache__ diff --git a/README.md b/README.md index dad67ce..9e09942 100644 --- a/README.md +++ b/README.md @@ -94,5 +94,8 @@ Members: * [VMware Code](https://code.vmware.com/home) * [VMware Developer Community](https://communities.vmware.com/community/vmtn/developer) +## Feedback +If you find a bug, please open a [GitHub issue](https://github.com/vmware-samples/secure-state-remediation-jobs/issues). + [license-img]: https://img.shields.io/badge/License-Apache%202.0-blue.svg [license]: https://opensource.org/licenses/Apache-2.0 diff --git a/remediation_worker/jobs/ec2_close_port_22/constraints.txt b/remediation_worker/jobs/ec2_close_port_22/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/ec2_close_port_22/constraints.txt +++ b/remediation_worker/jobs/ec2_close_port_22/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/ec2_close_port_22/requirements-dev.txt b/remediation_worker/jobs/ec2_close_port_22/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/ec2_close_port_22/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/ec2_close_port_22/requirements.txt b/remediation_worker/jobs/ec2_close_port_22/requirements.txt index f938cb2..b239388 100644 --- a/remediation_worker/jobs/ec2_close_port_22/requirements.txt +++ b/remediation_worker/jobs/ec2_close_port_22/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/ec2_close_port_3389/constraints.txt b/remediation_worker/jobs/ec2_close_port_3389/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/ec2_close_port_3389/constraints.txt +++ b/remediation_worker/jobs/ec2_close_port_3389/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/ec2_close_port_3389/requirements-dev.txt b/remediation_worker/jobs/ec2_close_port_3389/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/ec2_close_port_3389/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/ec2_close_port_3389/requirements.txt b/remediation_worker/jobs/ec2_close_port_3389/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/ec2_close_port_3389/requirements.txt +++ b/remediation_worker/jobs/ec2_close_port_3389/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/rds_backup_retention_30_days/constraints.txt b/remediation_worker/jobs/rds_backup_retention_30_days/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/rds_backup_retention_30_days/constraints.txt +++ b/remediation_worker/jobs/rds_backup_retention_30_days/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/rds_backup_retention_30_days/requirements-dev.txt b/remediation_worker/jobs/rds_backup_retention_30_days/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/rds_backup_retention_30_days/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/rds_backup_retention_30_days/requirements.txt b/remediation_worker/jobs/rds_backup_retention_30_days/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/rds_backup_retention_30_days/requirements.txt +++ b/remediation_worker/jobs/rds_backup_retention_30_days/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/s3_enable_access_logging/constraints.txt b/remediation_worker/jobs/s3_enable_access_logging/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/constraints.txt +++ b/remediation_worker/jobs/s3_enable_access_logging/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/s3_enable_access_logging/minimum_policy.json b/remediation_worker/jobs/s3_enable_access_logging/minimum_policy.json index 6abf920..7f49d4c 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/minimum_policy.json +++ b/remediation_worker/jobs/s3_enable_access_logging/minimum_policy.json @@ -8,7 +8,8 @@ "s3:PutBucketLogging", "s3:PutBucketAcl", "s3:GetBucketAcl", - "s3:CreateBucket" + "s3:CreateBucket", + "s3:ListBucket" ], "Resource": "*" } diff --git a/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt b/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_enable_access_logging/requirements.txt b/remediation_worker/jobs/s3_enable_access_logging/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/requirements.txt +++ b/remediation_worker/jobs/s3_enable_access_logging/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py b/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py index 077f862..fcd360b 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py +++ b/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py @@ -25,6 +25,10 @@ logging.basicConfig(level=logging.INFO) +class SelfRemediationError(ValueError): + pass + + class S3EnableAccessLogging(object): def parse(self, payload): """Parse payload received from Remediation Service. @@ -97,7 +101,6 @@ def grant_log_delivery_permissions(self, client, bucket_name): def ensure_log_target_bucket(self, client, target_bucket, region): try: client.head_bucket(Bucket=target_bucket) - return None except ClientError as e: if e.response["Error"]["Code"] == "404": # The bucket does not exist @@ -108,6 +111,10 @@ def ensure_log_target_bucket(self, client, target_bucket, region): Bucket=target_bucket, CreateBucketConfiguration={"LocationConstraint": region}, ) + elif e.response["Error"]["Code"] == "403": + # The assumed role does not have the permission + logging.error("Not enough permissions to list buckets") + raise e else: raise e @@ -131,6 +138,12 @@ def remediate(self, region, client, source_bucket, target_bucket, target_prefix) :rtype: int :raises: botocore.exceptions.ClientError """ + if source_bucket == target_bucket: + raise SelfRemediationError( + f"Cannot remediate the logging bucket (i.e. write access logs to self). " + f"Consider suppressing the violation for this bucket ({source_bucket})." + ) + self.ensure_log_target_bucket(client, target_bucket, region) logging.info("ensuring logs can be delivered") self.grant_log_delivery_permissions(client, target_bucket) diff --git a/remediation_worker/jobs/s3_enable_default_encryption/constraints.txt b/remediation_worker/jobs/s3_enable_default_encryption/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/s3_enable_default_encryption/constraints.txt +++ b/remediation_worker/jobs/s3_enable_default_encryption/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/s3_enable_default_encryption/requirements-dev.txt b/remediation_worker/jobs/s3_enable_default_encryption/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/s3_enable_default_encryption/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_enable_default_encryption/requirements.txt b/remediation_worker/jobs/s3_enable_default_encryption/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/s3_enable_default_encryption/requirements.txt +++ b/remediation_worker/jobs/s3_enable_default_encryption/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/s3_list_buckets/constraints.txt b/remediation_worker/jobs/s3_list_buckets/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/s3_list_buckets/constraints.txt +++ b/remediation_worker/jobs/s3_list_buckets/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/s3_list_buckets/requirements-dev.txt b/remediation_worker/jobs/s3_list_buckets/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/s3_list_buckets/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_list_buckets/requirements.txt b/remediation_worker/jobs/s3_list_buckets/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/s3_list_buckets/requirements.txt +++ b/remediation_worker/jobs/s3_list_buckets/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/s3_remove_public_access/constraints.txt b/remediation_worker/jobs/s3_remove_public_access/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/s3_remove_public_access/constraints.txt +++ b/remediation_worker/jobs/s3_remove_public_access/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/s3_remove_public_access/requirements-dev.txt b/remediation_worker/jobs/s3_remove_public_access/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/s3_remove_public_access/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_remove_public_access/requirements.txt b/remediation_worker/jobs/s3_remove_public_access/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/s3_remove_public_access/requirements.txt +++ b/remediation_worker/jobs/s3_remove_public_access/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/s3_remove_public_admin_acl/constraints.txt b/remediation_worker/jobs/s3_remove_public_admin_acl/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/s3_remove_public_admin_acl/constraints.txt +++ b/remediation_worker/jobs/s3_remove_public_admin_acl/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/s3_remove_public_admin_acl/requirements-dev.txt b/remediation_worker/jobs/s3_remove_public_admin_acl/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/s3_remove_public_admin_acl/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_remove_public_admin_acl/requirements.txt b/remediation_worker/jobs/s3_remove_public_admin_acl/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/s3_remove_public_admin_acl/requirements.txt +++ b/remediation_worker/jobs/s3_remove_public_admin_acl/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/security_group_close_port_22/constraints.txt b/remediation_worker/jobs/security_group_close_port_22/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/security_group_close_port_22/constraints.txt +++ b/remediation_worker/jobs/security_group_close_port_22/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt b/remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/security_group_close_port_22/requirements.txt b/remediation_worker/jobs/security_group_close_port_22/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/security_group_close_port_22/requirements.txt +++ b/remediation_worker/jobs/security_group_close_port_22/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/security_group_close_port_3389/constraints.txt b/remediation_worker/jobs/security_group_close_port_3389/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/security_group_close_port_3389/constraints.txt +++ b/remediation_worker/jobs/security_group_close_port_3389/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/security_group_close_port_3389/requirements-dev.txt b/remediation_worker/jobs/security_group_close_port_3389/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/security_group_close_port_3389/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/security_group_close_port_3389/requirements.txt b/remediation_worker/jobs/security_group_close_port_3389/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/security_group_close_port_3389/requirements.txt +++ b/remediation_worker/jobs/security_group_close_port_3389/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/remediation_worker/jobs/security_group_close_port_5432/constraints.txt b/remediation_worker/jobs/security_group_close_port_5432/constraints.txt index 61279bb..6b211d2 100644 --- a/remediation_worker/jobs/security_group_close_port_5432/constraints.txt +++ b/remediation_worker/jobs/security_group_close_port_5432/constraints.txt @@ -1,9 +1,3 @@ -boto3==1.14.9 \ - --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ - --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 -botocore==1.17.9 \ - --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 \ - --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 docutils==0.15.2 \ --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ @@ -23,3 +17,27 @@ urllib3==1.25.9 \ six==1.15.0 \ --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +attrs==19.3.0 \ + --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ + --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b diff --git a/remediation_worker/jobs/security_group_close_port_5432/requirements-dev.txt b/remediation_worker/jobs/security_group_close_port_5432/requirements-dev.txt new file mode 100644 index 0000000..9412e93 --- /dev/null +++ b/remediation_worker/jobs/security_group_close_port_5432/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +-c constraints.txt + +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/security_group_close_port_5432/requirements.txt b/remediation_worker/jobs/security_group_close_port_5432/requirements.txt index f938cb2..7ca0574 100644 --- a/remediation_worker/jobs/security_group_close_port_5432/requirements.txt +++ b/remediation_worker/jobs/security_group_close_port_5432/requirements.txt @@ -1,2 +1,6 @@ -boto3==1.14.9 -botocore==1.17.9 +boto3==1.14.9 \ + --hash=sha256:185f7b36c16f76e501d8dfc5cd209113426e078e4968dd13cc355c916bc99597 \ + --hash=sha256:51243ba0e976343ca0b98bb4a15fc3d588526220f6ba45bfed7ea45472b1e033 +botocore==1.17.9 \ + --hash=sha256:7dd59bc766d567ca83bc6113aa139d92ba447738ccdfcd40788848553d329a52 + --hash=sha256:cd4bb2d96ff2ec6bf4fbcdb2f241d0fb6ba1e7955b4721cf1d81f13db02768b6 diff --git a/setup.py b/setup.py index 52a2e05..d71e655 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 VMware Corp +# Copyright (c) 2020 VMware Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/shared/worker_logging/setup.py b/shared/worker_logging/setup.py new file mode 100644 index 0000000..8b97fd2 --- /dev/null +++ b/shared/worker_logging/setup.py @@ -0,0 +1,21 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from setuptools import setup +from setuptools import find_packages + + +setup( + name="worker_logging", version="0.0.1", packages=find_packages(), +) diff --git a/test/unit/test_s3_enable_access_logging.py b/test/unit/test_s3_enable_access_logging.py index 63a73c9..5c0d8ca 100644 --- a/test/unit/test_s3_enable_access_logging.py +++ b/test/unit/test_s3_enable_access_logging.py @@ -19,6 +19,7 @@ from remediation_worker.jobs.s3_enable_access_logging.s3_enable_access_logging import ( S3EnableAccessLogging, + SelfRemediationError, ) @@ -112,6 +113,79 @@ def full_payload(): ) +@pytest.fixture +def self_payload(): + return json.dumps( + { + "cloudAccount": { + "provider": "", + "roleArn": "arn:aws:iam::530342348278:role/SecureStateRemediation", + }, + "notificationInfo": { + "RuleId": "5c6cc5cc03dcc90f3631468d", + "RuleName": "", + "RuleDisplayName": "", + "Level": "Low", + "Service": "s3", + "FindingInfo": { + "FindingId": "05eedc79-65b5-4774-8a6a-cfffb17a3a99", + "ObjectId": "vss-logging-target-530342348278-us-east-1", + "ObjectChain": "{" + ' "cloudAccountId": "530342348278",' + ' "creationTime": "2020-06-23T21:40:33.000Z",' + ' "depthCount": {' + ' "depth_0": 1,' + ' "depth_1": 1' + " }," + ' "entityId": "AWS.S3.530342348278.us-east-1.Bucket.rule-executor-s3-test-892fbb42-45ee-489b-bcc9-e9a4dc285ea0",' # noqa: E501 + ' "entityName": "rule-executor-s3-test-892fbb42-45ee-489b-bcc9-e9a4dc285ea0",' + ' "entityType": "AWS.S3.Bucket",' + ' "lastUpdateTime": "2020-06-23T21:40:33.000Z",' + ' "partitionKey": "530342348278",' + ' "properties": [{' + ' "name": "BucketName",' + ' "stringV": "rule-executor-s3-test-892fbb42-45ee-489b-bcc9-e9a4dc285ea0",' + ' "type": "string"' + " }, {" + ' "name": "VersioningStatus",' + ' "stringV": "Enabled",' + ' "type": "string"' + " }, {" + ' "name": "CreationDate",' + ' "stringV": "2020-06-22T20:48:49.000Z",' + ' "type": "datetime"' + " }, {" + ' "boolV": false,' + ' "name": "ReplicationEnabled",' + ' "type": "bool"' + " }, {" + ' "name": "VersioningMFADelete",' + ' "stringV": "Disabled",' + ' "type": "string"' + " }, {" + ' "name": "Location",' + ' "stringV": "us-east-1",' + ' "type": "string"' + " }, {" + ' "boolV": false,' + ' "name": "LoggingEnabled",' + ' "type": "bool"' + " }]," + ' "provider": "AWS",' + ' "region": "us-east-1",' + ' "service": "S3"' + "}", + "CloudTags": None, + "RiskScore": 10, + "Region": "us-east-1", + "Service": "s3", + }, + }, + "autoRemediate": False, + } + ) + + class TestS3EnableAccessLogging(object): def test_parse_payload_success(self, full_payload): obj = S3EnableAccessLogging() @@ -172,3 +246,7 @@ def put_bucket_logging(self, **kwargs): assert action.remediate( "region", client, "source_bucket", "target_bucket", "target_prefix" ) + + def test_dont_log_to_self(self, self_payload): + with pytest.raises(SelfRemediationError): + assert S3EnableAccessLogging().run([None, self_payload]) diff --git a/tox.ini b/tox.ini index 13d5773..bc2dd70 100644 --- a/tox.ini +++ b/tox.ini @@ -2,9 +2,16 @@ minversion = 3.6.0 skip_missing_interpreters = true envlist = - unit -toxworkdir = {env:TOX_WORK_DIR:{homedir}/envs/} - + unit-security-group-close-port-5432 + unit-s3-remove-public-admin-acl + unit-s3-enable-access-logging + unit-ec2-close-port-3389 + unit-s3-enable-default-encryption + unit-ec2-close-port-22 + unit-s3-list-buckets + unit-security-group-close-port-3389 + unit-rds-backup-retention-30-days + unit-security-group-close-port-22 [testenv] passenv = @@ -23,10 +30,63 @@ passenv = # Used to make tox (and python) work correctly on macOS OBJC_DISABLE_INITIALIZE_FORK_SAFETY -deps = -r requirements.txt +[testenv:unit-security-group-close-port-5432] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_security_group_close_port_5432.py +deps = -r remediation_worker/jobs/security_group_close_port_5432/requirements-dev.txt + +[testenv:unit-s3-remove-public-admin-acl] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_s3_remove_public_admin_acl.py +deps = -r remediation_worker/jobs/s3_remove_public_admin_acl/requirements-dev.txt + +[testenv:unit-s3-enable-access-logging] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_s3_enable_access_logging.py +deps = -r remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt + +[testenv:unit-ec2-close-port-3389] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_ec2_close_port_3389.py +deps = -r remediation_worker/jobs/ec2_close_port_3389/requirements-dev.txt + +[testenv:unit-s3-enable-default-encryption] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_s3_enable_default_encryption.py +deps = -r remediation_worker/jobs/s3_enable_default_encryption/requirements-dev.txt + +[testenv:unit-ec2-close-port-22] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_ec2_close_port_22.py +deps = -r remediation_worker/jobs/ec2_close_port_22/requirements-dev.txt + +[testenv:unit-s3-list-buckets] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_s3_list_buckets.py +deps = -r remediation_worker/jobs/s3_list_buckets/requirements-dev.txt + +[testenv:unit-security-group-close-port-3389] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_security_group_close_port_3389.py +deps = -r remediation_worker/jobs/security_group_close_port_3389/requirements-dev.txt + +[testenv:unit-rds-backup-retention-30-days] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_rds_backup_retention_30_days.py +deps = -r remediation_worker/jobs/rds_backup_retention_30_days/requirements-dev.txt -[testenv:unit] +[testenv:unit-security-group-close-port-22] description = Unit test the project changedir = test -commands = pytest --capture=no --basetemp="{envtmpdir}" {posargs} +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_security_group_close_port_22.py +deps = -r remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt From e928be01b46556b225d0bef9c394eba985d13920 Mon Sep 17 00:00:00 2001 From: Vikramjeet Singh <58273802+vikramsinghvirdi@users.noreply.github.com> Date: Fri, 18 Sep 2020 11:10:16 -0700 Subject: [PATCH 2/2] Release/v1.1.0 (#17) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PLA-17940 updating constraints and fixing s3_enable_access_logging to… (#3) * PLA-17940 updating constraints and fixing s3_enable_access_logging to not remediate the logging target bucket * PLA-17940 fixing copyright info * Updated readme to have link for reporting issues (#4) Co-authored-by: svikramjeet * S3 access logs permissions (#6) * Update minimum permissions for the job * Add more logs when permission is missing Co-authored-by: Mohammad Zuber Khan * change the way cloudAccountId is parsed from Job Paramaters (#9) Co-authored-by: Mohammad Zuber Khan * PLA-16779: Add remediation job for azure security group port 22 (#10) * PLA-16779: Add remediation job for azure security group port 22 * add test dependencies * update README.md * add deployment info to the README * add rule information Co-authored-by: Mohammad Zuber Khan * Add remediation job for closing port 22 for VM (#11) * PLA-18743: Add remediation job for closing port 22 for VM * add tests for azure_vm_close_port_22 to tox * add deployment details Co-authored-by: Mohammad Zuber Khan * Add remediation jobs for storage and RDP violations (#12) * add remediation job for closing RDP access * Add remediation job for remove public access for blob * Add remediation job to allow only https traffic to storage account * update READMEs to fix broken links Co-authored-by: Mohammad Zuber Khan * fix the parameters passed for remediation (#13) Co-authored-by: Mohammad Zuber Khan * add check for existing permissions before adding new (#15) Co-authored-by: Mohammad Zuber Khan * Fix ports range for network security groups (#19) (#20) * handle the case when the security rule port is a range * Add minimum permissions for each remediation jobs * add link to built in roles Co-authored-by: Mohammad Zuber Khan Co-authored-by: Zuber Co-authored-by: Mohammad Zuber Khan Co-authored-by: Paul Allen Co-authored-by: svikramjeet Co-authored-by: Zuber Co-authored-by: Mohammad Zuber Khan --- .../azure_blob_remove_public_access/README.md | 74 ++++++ .../__init__.py | 0 .../azure_blob_remove_public_access.py | 151 ++++++++++++ .../constraints.txt | 115 +++++++++ .../minimum_permissions.json | 19 ++ .../requirements-dev.txt | 33 +++ .../requirements.txt | 6 + .../README.md | 74 ++++++ .../__init__.py | 0 ...re_network_security_group_close_port_22.py | 217 +++++++++++++++++ .../constraints.txt | 109 +++++++++ .../minimum_permissions.json | 19 ++ .../requirements-dev.txt | 33 +++ .../requirements.txt | 6 + .../README.md | 75 ++++++ .../__init__.py | 0 ..._network_security_group_close_port_3389.py | 214 +++++++++++++++++ .../constraints.txt | 115 +++++++++ .../minimum_permissions.json | 19 ++ .../requirements-dev.txt | 33 +++ .../requirements.txt | 6 + .../README.md | 75 ++++++ .../__init__.py | 0 ...torage_account_allow_https_traffic_only.py | 132 +++++++++++ .../constraints.txt | 115 +++++++++ .../minimum_permissions.json | 19 ++ .../requirements-dev.txt | 33 +++ .../requirements.txt | 6 + .../jobs/azure_vm_close_port_22/README.md | 75 ++++++ .../jobs/azure_vm_close_port_22/__init__.py | 0 .../azure_vm_close_port_22.py | 223 ++++++++++++++++++ .../azure_vm_close_port_22/constraints.txt | 115 +++++++++ .../minimum_permissions.json | 21 ++ .../requirements-dev.txt | 33 +++ .../azure_vm_close_port_22/requirements.txt | 9 + .../jobs/ec2_close_port_22/README.md | 4 +- .../jobs/ec2_close_port_3389/README.md | 4 +- .../rds_backup_retention_30_days/README.md | 19 +- .../jobs/s3_enable_access_logging/README.md | 4 +- .../requirements-dev.txt | 3 + .../s3_enable_access_logging.py | 48 +++- .../s3_enable_default_encryption/README.md | 4 +- .../jobs/s3_list_buckets/README.md | 4 +- .../jobs/s3_remove_public_access/README.md | 4 +- .../jobs/s3_remove_public_admin_acl/README.md | 4 +- .../security_group_close_port_22/README.md | 18 +- .../security_group_close_port_3389/README.md | 18 +- .../security_group_close_port_5432/README.md | 18 +- .../test_azure_blob_remove_public_access.py | 68 ++++++ ...re_network_security_group_close_port_22.py | 105 +++++++++ ..._network_security_group_close_port_3389.py | 106 +++++++++ ...torage_account_allow_https_traffic_only.py | 64 +++++ test/unit/test_azure_vm_close_port_22.py | 129 ++++++++++ test/unit/test_s3_enable_access_logging.py | 80 ++++++- tox.ini | 35 +++ 55 files changed, 2878 insertions(+), 35 deletions(-) create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/README.md create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/__init__.py create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/azure_blob_remove_public_access.py create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/constraints.txt create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/minimum_permissions.json create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/requirements-dev.txt create mode 100644 remediation_worker/jobs/azure_blob_remove_public_access/requirements.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/README.md create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/__init__.py create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/azure_network_security_group_close_port_22.py create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/constraints.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/minimum_permissions.json create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/requirements-dev.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_22/requirements.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/README.md create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/__init__.py create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/azure_network_security_group_close_port_3389.py create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/constraints.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/minimum_permissions.json create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements-dev.txt create mode 100644 remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements.txt create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/README.md create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/__init__.py create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/azure_storage_account_allow_https_traffic_only.py create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/constraints.txt create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/minimum_permissions.json create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements-dev.txt create mode 100644 remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements.txt create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/README.md create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/__init__.py create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/azure_vm_close_port_22.py create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/constraints.txt create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/minimum_permissions.json create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/requirements-dev.txt create mode 100644 remediation_worker/jobs/azure_vm_close_port_22/requirements.txt create mode 100644 test/unit/test_azure_blob_remove_public_access.py create mode 100644 test/unit/test_azure_network_security_group_close_port_22.py create mode 100644 test/unit/test_azure_network_security_group_close_port_3389.py create mode 100644 test/unit/test_azure_storage_account_allow_https_traffic_only.py create mode 100644 test/unit/test_azure_vm_close_port_22.py diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/README.md b/remediation_worker/jobs/azure_blob_remove_public_access/README.md new file mode 100644 index 0000000..1eee4c2 --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/README.md @@ -0,0 +1,74 @@ +# Remove Blob public access + +This job removes public access to the blobs in a container for a storage account + +### Applicable Rule + +##### Rule ID: +5c8c26997a550e1fb6560cd9 + +##### Rule Name: +Public read access is enabled for blob storage + +## Getting Started + +### Prerequisites + +The provided Azure service principal must have the following permissions: +`Microsoft.Storage/storageAccounts/blobServices/containers/read` +`Microsoft.Storage/storageAccounts/blobServices/containers/write` + +A sample role with requisite permissions can be found [here](minimum_permissions.json) + +More information about already builtin roles and permissions can be found +[here](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) + +### Running the script + +You may run this script using following commands: +```shell script + pip install -r requirements.txt + python3 azure_remove_blob_public_access.py +``` + +## Running the tests +You may run test using following command under vss-remediation-worker-job-code-python directory: +```shell script + pip install -r requirements-dev.txt + python3 -m pytest test +``` + +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + +## Contributing +The Secure State team welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). +All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. + +For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING.md). + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). + +## Authors + +* **VMware Secure State** - *Initial work* + +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. + +## License + +This project is licensed under the Apache License - see the [LICENSE](https://github.com/vmware-samples/secure-state-remediation-jobs/blob/master/LICENSE.txt) file for details diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/__init__.py b/remediation_worker/jobs/azure_blob_remove_public_access/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/azure_blob_remove_public_access.py b/remediation_worker/jobs/azure_blob_remove_public_access/azure_blob_remove_public_access.py new file mode 100644 index 0000000..804f0f9 --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/azure_blob_remove_public_access.py @@ -0,0 +1,151 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import logging + +from azure.mgmt.storage import StorageManagementClient +from azure.common.credentials import ServicePrincipalCredentials +from azure.mgmt.storage.models import PublicAccess + +logging.basicConfig(level=logging.INFO) + + +def logcall(f, *args, **kwargs): + logging.info( + "%s(%s)", + f.__name__, + ", ".join(list(args) + [f"{k}={repr(v)}" for k, v in kwargs.items()]), + ) + logging.info(f(*args, **kwargs)) + + +class StorageBlobRemovePublicAccess(object): + def parse(self, payload): + """Parse payload received from Remediation Service. + + :param payload: JSON string containing parameters received from the remediation service. + :type payload: str. + :returns: Dictionary of parsed parameters + :rtype: dict + :raises: KeyError, JSONDecodeError + """ + remediation_entry = json.loads(payload) + + object_id = remediation_entry["notificationInfo"]["FindingInfo"]["ObjectId"] + object_components = object_id.split(".") + account_name = object_components[0] + container_name = object_components[-1] + + region = remediation_entry["notificationInfo"]["FindingInfo"]["Region"] + + object_chain = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectChain" + ] + object_chain_dict = json.loads(object_chain) + subscription_id = object_chain_dict["cloudAccountId"] + + properties = object_chain_dict["properties"] + resource_group_name = "" + for property in properties: + if property["name"] == "ResourceGroup" and property["type"] == "string": + resource_group_name = property["stringV"] + break + + logging.info("parsed params") + logging.info(f" resource_group_name: {resource_group_name}") + logging.info(f" account_name: {account_name}") + logging.info(f" container_name: {container_name}") + logging.info(f" subscription_id: {subscription_id}") + logging.info(f" region: {region}") + + return { + "resource_group_name": resource_group_name, + "account_name": account_name, + "container_name": container_name, + "subscription_id": subscription_id, + "region": region, + } + + def remediate(self, client, resource_group_name, account_name, container_name): + """Block public access to blob container + + :param client: Instance of the Azure NetworkManagementClient. + :param resource_group_name: The name of the resource group to which the storage account belongs + :param account_name: The name of the storage account. You must specify the + security group name in the request. + :param container_name: The name of the container having the violation + :type resource_group_name: str. + :type account_name: str. + :type container_name: str. + :returns: Integer signaling success or failure + :rtype: int + :raises: msrestazure.azure_exceptions.CloudError + """ + + container = client.blob_containers.get( + resource_group_name=resource_group_name, + account_name=account_name, + container_name=container_name, + ) + + container.public_access = PublicAccess.none + + # Revoke public access permissions for container + logging.info("revoking public access for container") + try: + logging.info(" executing client.blob_containers.update") + logging.info(f" resource_group_name={resource_group_name}") + logging.info(f" account_name={account_name}") + logging.info(f" container_name={container_name}") + client.blob_containers.update( + resource_group_name=resource_group_name, + account_name=account_name, + container_name=container_name, + blob_container=container, + ) + except Exception as e: + logging.error(f"{str(e)}") + raise + + return 0 + + def run(self, args): + """Run the remediation job. + + :param args: List of arguments provided to the job. + :type args: list. + :returns: int + """ + params = self.parse(args[1]) + + credentials = ServicePrincipalCredentials( + client_id=os.environ.get("AZURE_CLIENT_ID"), + secret=os.environ.get("AZURE_CLIENT_SECRET"), + tenant=os.environ.get("AZURE_TENANT_ID"), + ) + + client = StorageManagementClient(credentials, params["subscription_id"]) + return self.remediate( + client, + params["resource_group_name"], + params["account_name"], + params["container_name"], + ) + + +if __name__ == "__main__": + sys.exit(StorageBlobRemovePublicAccess().run(sys.argv)) diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/constraints.txt b/remediation_worker/jobs/azure_blob_remove_public_access/constraints.txt new file mode 100644 index 0000000..3ab47a3 --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/constraints.txt @@ -0,0 +1,115 @@ +adal==1.2.4 \ + --hash=sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0 \ + --hash=sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc +azure-common==1.1.25 \ + --hash=sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054 \ + --hash=sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a +azure-core==1.8.0 \ + --hash=sha256:84bff2b05ce989942e7ca3a13237441fbd8ff6855aaf2979b2bc94b74a02be5f \ + --hash=sha256:c89bbdcdc13ad45fe57d775ed87b15baf6d0b039a1ecd0a1bc91d2f713cb1f08 +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc +certifi==2020.6.20 \ + --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ + --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 +cffi==1.14.2 \ + --hash=sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e \ + --hash=sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c \ + --hash=sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e \ + --hash=sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1 \ + --hash=sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4 \ + --hash=sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2 \ + --hash=sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c \ + --hash=sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0 \ + --hash=sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798 \ + --hash=sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1 \ + --hash=sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4 \ + --hash=sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731 \ + --hash=sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4 \ + --hash=sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c \ + --hash=sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487 \ + --hash=sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e \ + --hash=sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f \ + --hash=sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123 \ + --hash=sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c \ + --hash=sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b \ + --hash=sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650 \ + --hash=sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad \ + --hash=sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75 \ + --hash=sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82 \ + --hash=sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7 \ + --hash=sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15 \ + --hash=sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa \ + --hash=sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +cryptography==3.0 \ + --hash=sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b \ + --hash=sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd \ + --hash=sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a \ + --hash=sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07 \ + --hash=sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71 \ + --hash=sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756 \ + --hash=sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559 \ + --hash=sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f \ + --hash=sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261 \ + --hash=sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053 \ + --hash=sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2 \ + --hash=sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f \ + --hash=sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b \ + --hash=sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77 \ + --hash=sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83 \ + --hash=sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f \ + --hash=sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67 \ + --hash=sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c \ + --hash=sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6 +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 +isodate==0.6.0 \ + --hash=sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8 \ + --hash=sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81 +msal-extensions==0.2.2 \ + --hash=sha256:31414753c484679bb3b6c6401623eb4c3ccab630af215f2f78c1d5c4f8e1d1a9 \ + --hash=sha256:f092246787145ec96d6c3c9f7bedfb837830fe8a79b56180e531fbf28b8de532 +msal==1.4.3 \ + --hash=sha256:51b8e8e0d918d9b4813f006324e7c4e21eb76268dd4c1a06d811a3475ad4ac57 \ + --hash=sha256:82c0ca1103f4a040f3fa5325bfd6fb6c8273fbd1d6f7c1ea92bbc94fcc360c46 +msrest==0.6.18 \ + --hash=sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d \ + --hash=sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96 +msrestazure==0.6.4 \ + --hash=sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9 \ + --hash=sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189 +oauthlib==3.1.0 \ + --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ + --hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea +portalocker==1.7.1 \ + --hash=sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a \ + --hash=sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a +pycparser==2.20 \ + --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \ + --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 +pyjwt==1.7.1 \ + --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ + --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 +python-dateutil==2.8.1 \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +requests-oauthlib==1.3.0 \ + --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ + --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a +requests==2.24.0 \ + --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ + --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/minimum_permissions.json b/remediation_worker/jobs/azure_blob_remove_public_access/minimum_permissions.json new file mode 100644 index 0000000..8c203f8 --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/minimum_permissions.json @@ -0,0 +1,19 @@ +{ + "properties": { + "roleName": "remediate_blob_public_access", + "description": "This role has required permissions to make changes to the blob containers", + "assignableScopes": [ + ], + "permissions": [ + { + "actions": [ + "Microsoft.Storage/storageAccounts/blobServices/containers/read", + "Microsoft.Storage/storageAccounts/blobServices/containers/write" + ], + "notActions": [], + "dataActions": [], + "notDataActions": [] + } + ] + } +} \ No newline at end of file diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/requirements-dev.txt b/remediation_worker/jobs/azure_blob_remove_public_access/requirements-dev.txt new file mode 100644 index 0000000..1143bce --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/requirements-dev.txt @@ -0,0 +1,33 @@ +-r requirements.txt +-c constraints.txt + +attrs==20.1.0 \ + --hash=sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a \ + --hash=sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 diff --git a/remediation_worker/jobs/azure_blob_remove_public_access/requirements.txt b/remediation_worker/jobs/azure_blob_remove_public_access/requirements.txt new file mode 100644 index 0000000..50850c0 --- /dev/null +++ b/remediation_worker/jobs/azure_blob_remove_public_access/requirements.txt @@ -0,0 +1,6 @@ +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-storage==11.1.0 \ + --hash=sha256:62a6a8c1c359026ec560856da25221b66b6f1e0a84763a04e863c6e911bc1a5e \ + --hash=sha256:ef23587c1b6dc0866ebf0e91e83ba05d7f7e4fea7951b704781b9cd9f5f27f1c diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/README.md b/remediation_worker/jobs/azure_network_security_group_close_port_22/README.md new file mode 100644 index 0000000..50a7223 --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/README.md @@ -0,0 +1,74 @@ +# Close Port 22 for a Network Security Group + +This job blocks public access to port 22. + +### Applicable Rule + +#### Rule ID: +5c8c26847a550e1fb6560cab + +#### Rule Name: +The security group allows access to SSH port (22) + +## Getting Started + +### Prerequisites + +The provided Azure service principal must have the following permissions: +`Microsoft.Network/networkSecurityGroups/read` +`Microsoft.Network/networkSecurityGroups/write` + +A sample role with requisite permissions can be found [here](minimum_permissions.json) + +More information about already builtin roles and permissions can be found +[here](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) + +### Running the script + +You may run this script using following commands: +```shell script + pip install -r requirements.txt + python3 azure_network_security_group_close_port_22.py +``` + +## Running the tests +You may run test using following command under vss-remediation-worker-job-code-python directory: +```shell script + pip install -r requirements-dev.txt + python3 -m pytest test +``` +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + +## Contributing +The Secure State team welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). +All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. + +For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING.md). + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). + +## Authors + +* **VMware Secure State** - *Initial work* + +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who + participated in this project. + +## License + +This project is licensed under the Apache License - see the [LICENSE](https://github.com/vmware-samples/secure-state-remediation-jobs/blob/master/LICENSE.txt) file for details diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/__init__.py b/remediation_worker/jobs/azure_network_security_group_close_port_22/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/azure_network_security_group_close_port_22.py b/remediation_worker/jobs/azure_network_security_group_close_port_22/azure_network_security_group_close_port_22.py new file mode 100644 index 0000000..f4c98cc --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/azure_network_security_group_close_port_22.py @@ -0,0 +1,217 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import logging + +from azure.mgmt.network import NetworkManagementClient +from azure.common.credentials import ServicePrincipalCredentials + +logging.basicConfig(level=logging.INFO) + + +def logcall(f, *args, **kwargs): + logging.info( + "%s(%s)", + f.__name__, + ", ".join(list(args) + [f"{k}={repr(v)}" for k, v in kwargs.items()]), + ) + logging.info(f(*args, **kwargs)) + + +class NetworkSecurityGroupClosePort22(object): + def parse(self, payload): + """Parse payload received from Remediation Service. + + :param payload: JSON string containing parameters received from the remediation service. + :type payload: str. + :returns: Dictionary of parsed parameters + :rtype: dict + :raises: KeyError, JSONDecodeError + """ + remediation_entry = json.loads(payload) + + security_group_name = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectId" + ] + region = remediation_entry["notificationInfo"]["FindingInfo"]["Region"] + object_chain = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectChain" + ] + object_chain_dict = json.loads(object_chain) + subscription_id = object_chain_dict["cloudAccountId"] + + properties = object_chain_dict["properties"] + resource_group_name = "" + for property in properties: + if property["name"] == "ResourceGroup" and property["type"] == "string": + resource_group_name = property["stringV"] + break + + logging.info("parsed params") + logging.info(f" security_group: {security_group_name}") + logging.info(f" subscription_id: {subscription_id}") + logging.info(f" resource_group_name: {resource_group_name}") + logging.info(f" region: {region}") + + return { + "security_group_name": security_group_name, + "resource_group_name": resource_group_name, + "subscription_id": subscription_id, + "region": region, + } + + def remediate(self, client, resource_group_name, security_group_name): + """Block public access to port 22 + + :param client: Instance of the Azure NetworkManagementClient. + :param resource_group_name: The name of the resource group to which the security_group belongs + :param security_group_name: The name of the security group. You must specify the + security group name in the request. + :type security_group_name: str. + :type resource_group_name: str. + :returns: Integer signaling success or failure + :rtype: int + :raises: msrestazure.azure_exceptions.CloudError + """ + + port = 22 + + network_security_group = client.network_security_groups.get( + resource_group_name=resource_group_name, + network_security_group_name=security_group_name, + ) + + security_rules = network_security_group.security_rules + + for rule in security_rules: + if ( + rule.access != "Allow" + or rule.direction != "Inbound" + or rule.source_address_prefix != "*" + ): + continue + if rule.destination_port_range is not None: + port_range = rule.destination_port_range + if "-" in port_range: + new_ranges = self._find_and_remove_port([port_range], port) + if len(new_ranges) == 1: + rule.destination_port_range = new_ranges[0] + else: + rule.destination_port_range = None + rule.destination_port_ranges = new_ranges + elif int(rule.destination_port_range) == port: + security_rules.remove(rule) + else: + port_ranges = rule.destination_port_ranges + new_ranges = self._find_and_remove_port(port_ranges, port) + rule.destination_port_ranges = new_ranges + + network_security_group.security_rules = security_rules + + # Revoke permission for port 22 + logging.info("revoking permissions for port 22") + try: + logging.info( + " executing client.network_security_groups.create_or_update" + ) + logging.info(f" resource_group_name={resource_group_name}") + logging.info(f" network_security_group_name={security_group_name}") + client.network_security_groups.create_or_update( + resource_group_name, security_group_name, network_security_group + ) + except Exception as e: + logging.error(f"{str(e)}") + raise + + return 0 + + def _find_and_remove_port(self, port_ranges, port): + """Remove the port from the port range. + + :param port_ranges: port ranges to be updated. + :param port: port to be removed + :type port_ranges: list. + :type port: int + :returns: list of port_ranges + """ + result = [] + for port_range in port_ranges: + if "-" in port_range: + boundaries = port_range.split("-") + if int(boundaries[0]) <= port and int(boundaries[1]) >= port: + if int(boundaries[0]) == port: + new_range_start = port + 1 + new_range_end = int(boundaries[1]) + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + elif int(boundaries[1]) == port: + new_range_start = int(boundaries[0]) + new_range_end = port - 1 + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + else: + range1_start = int(boundaries[0]) + range1_end = port - 1 + range2_start = port + 1 + range2_end = int(boundaries[1]) + + if range1_start != range1_end: + result.append(str(range1_start) + "-" + str(range1_end)) + else: + result.append(str(range1_start)) + + if range2_start != range2_end: + result.append(str(range2_start) + "-" + str(range2_end)) + else: + result.append(str(range2_start)) + else: + result.append(port_range) + elif int(port_range) != port: + result.append(port_range) + return result + + def run(self, args): + """Run the remediation job. + + :param args: List of arguments provided to the job. + :type args: list. + :returns: int + """ + params = self.parse(args[1]) + + credentials = ServicePrincipalCredentials( + client_id=os.environ.get("AZURE_CLIENT_ID"), + secret=os.environ.get("AZURE_CLIENT_SECRET"), + tenant=os.environ.get("AZURE_TENANT_ID"), + ) + + client = NetworkManagementClient(credentials, params["subscription_id"]) + return self.remediate( + client, params["resource_group_name"], params["security_group_name"] + ) + + +if __name__ == "__main__": + sys.exit(NetworkSecurityGroupClosePort22().run(sys.argv)) diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/constraints.txt b/remediation_worker/jobs/azure_network_security_group_close_port_22/constraints.txt new file mode 100644 index 0000000..42600dd --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/constraints.txt @@ -0,0 +1,109 @@ +adal==1.2.4 \ + --hash=sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0 \ + --hash=sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc +azure-common==1.1.25 \ + --hash=sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054 \ + --hash=sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a +azure-core==1.8.0 \ + --hash=sha256:84bff2b05ce989942e7ca3a13237441fbd8ff6855aaf2979b2bc94b74a02be5f \ + --hash=sha256:c89bbdcdc13ad45fe57d775ed87b15baf6d0b039a1ecd0a1bc91d2f713cb1f08 +certifi==2020.6.20 \ + --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ + --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 +cffi==1.14.2 \ + --hash=sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e \ + --hash=sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c \ + --hash=sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e \ + --hash=sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1 \ + --hash=sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4 \ + --hash=sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2 \ + --hash=sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c \ + --hash=sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0 \ + --hash=sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798 \ + --hash=sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1 \ + --hash=sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4 \ + --hash=sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731 \ + --hash=sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4 \ + --hash=sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c \ + --hash=sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487 \ + --hash=sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e \ + --hash=sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f \ + --hash=sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123 \ + --hash=sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c \ + --hash=sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b \ + --hash=sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650 \ + --hash=sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad \ + --hash=sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75 \ + --hash=sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82 \ + --hash=sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7 \ + --hash=sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15 \ + --hash=sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa \ + --hash=sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +cryptography==3.0 \ + --hash=sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b \ + --hash=sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd \ + --hash=sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a \ + --hash=sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07 \ + --hash=sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71 \ + --hash=sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756 \ + --hash=sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559 \ + --hash=sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f \ + --hash=sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261 \ + --hash=sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053 \ + --hash=sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2 \ + --hash=sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f \ + --hash=sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b \ + --hash=sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77 \ + --hash=sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83 \ + --hash=sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f \ + --hash=sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67 \ + --hash=sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c \ + --hash=sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6 +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 +isodate==0.6.0 \ + --hash=sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8 \ + --hash=sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81 +msal-extensions==0.2.2 \ + --hash=sha256:31414753c484679bb3b6c6401623eb4c3ccab630af215f2f78c1d5c4f8e1d1a9 \ + --hash=sha256:f092246787145ec96d6c3c9f7bedfb837830fe8a79b56180e531fbf28b8de532 +msal==1.4.3 \ + --hash=sha256:51b8e8e0d918d9b4813f006324e7c4e21eb76268dd4c1a06d811a3475ad4ac57 \ + --hash=sha256:82c0ca1103f4a040f3fa5325bfd6fb6c8273fbd1d6f7c1ea92bbc94fcc360c46 +msrest==0.6.18 \ + --hash=sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d \ + --hash=sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96 +msrestazure==0.6.4 \ + --hash=sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9 \ + --hash=sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189 +oauthlib==3.1.0 \ + --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ + --hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea +portalocker==1.7.1 \ + --hash=sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a \ + --hash=sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a +pycparser==2.20 \ + --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \ + --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 +pyjwt==1.7.1 \ + --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ + --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 +python-dateutil==2.8.1 \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +requests-oauthlib==1.3.0 \ + --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ + --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a +requests==2.24.0 \ + --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ + --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/minimum_permissions.json b/remediation_worker/jobs/azure_network_security_group_close_port_22/minimum_permissions.json new file mode 100644 index 0000000..0c2654a --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/minimum_permissions.json @@ -0,0 +1,19 @@ +{ + "properties": { + "roleName": "remediate_network_security_group", + "description": "This role has required permissions to make changes in the network security groups", + "assignableScopes": [ + ], + "permissions": [ + { + "actions": [ + "Microsoft.Network/networkSecurityGroups/read", + "Microsoft.Network/networkSecurityGroups/write" + ], + "notActions": [], + "dataActions": [], + "notDataActions": [] + } + ] + } +} \ No newline at end of file diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements-dev.txt b/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements-dev.txt new file mode 100644 index 0000000..1143bce --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements-dev.txt @@ -0,0 +1,33 @@ +-r requirements.txt +-c constraints.txt + +attrs==20.1.0 \ + --hash=sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a \ + --hash=sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements.txt b/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements.txt new file mode 100644 index 0000000..3c68ef7 --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_22/requirements.txt @@ -0,0 +1,6 @@ +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/README.md b/remediation_worker/jobs/azure_network_security_group_close_port_3389/README.md new file mode 100644 index 0000000..5a0eb2b --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/README.md @@ -0,0 +1,75 @@ +# Close Port 3389 for a Network Security Group + +This job blocks public access to port 3389 + +### Applicable Rule + +#### Rule ID: +5c8c267e7a550e1fb6560c9c + +#### Rule Name: +The security group allows access to Remote Desktop port (3389) + +## Getting Started + +### Prerequisites + +The provided Azure service principal must have the following permissions: +`Microsoft.Network/networkSecurityGroups/read` +`Microsoft.Network/networkSecurityGroups/write` + +A sample role with requisite permissions can be found [here](minimum_permissions.json) + +More information about already builtin roles and permissions can be found +[here](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) + + +### Running the script + +You may run this script using following commands: +```shell script + pip install -r requirements.txt + python3 azure_network_security_group_close_port_22.py +``` + +## Running the tests +You may run test using following command under vss-remediation-worker-job-code-python directory: +```shell script + pip install -r requirements-dev.txt + python3 -m pytest test +``` + +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + +## Contributing +The Secure State team welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). +All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. + +For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING.md). + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). + +## Authors + +* **VMware Secure State** - *Initial work* + +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. + +## License + +This project is licensed under the Apache License - see the [LICENSE](https://github.com/vmware-samples/secure-state-remediation-jobs/blob/master/LICENSE.txt) file for details diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/__init__.py b/remediation_worker/jobs/azure_network_security_group_close_port_3389/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/azure_network_security_group_close_port_3389.py b/remediation_worker/jobs/azure_network_security_group_close_port_3389/azure_network_security_group_close_port_3389.py new file mode 100644 index 0000000..bd0c7ea --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/azure_network_security_group_close_port_3389.py @@ -0,0 +1,214 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import logging + +from azure.mgmt.network import NetworkManagementClient +from azure.common.credentials import ServicePrincipalCredentials + +logging.basicConfig(level=logging.INFO) + + +def logcall(f, *args, **kwargs): + logging.info( + "%s(%s)", + f.__name__, + ", ".join(list(args) + [f"{k}={repr(v)}" for k, v in kwargs.items()]), + ) + logging.info(f(*args, **kwargs)) + + +class NetworkSecurityGroupClosePort3389(object): + def parse(self, payload): + """Parse payload received from Remediation Service. + + :param payload: JSON string containing parameters received from the remediation service. + :type payload: str. + :returns: Dictionary of parsed parameters + :rtype: dict + :raises: KeyError, JSONDecodeError + """ + remediation_entry = json.loads(payload) + + security_group_name = remediation_entry["notificationInfo"]["FindingInfo"]["ObjectId"] + region = remediation_entry["notificationInfo"]["FindingInfo"]["Region"] + + object_chain = remediation_entry["notificationInfo"]["FindingInfo"]["ObjectChain"] + object_chain_dict = json.loads(object_chain) + subscription_id = object_chain_dict["cloudAccountId"] + + properties = object_chain_dict["properties"] + resource_group_name = "" + for property in properties: + if property["name"] == "ResourceGroup" and property["type"] == "string": + resource_group_name = property["stringV"] + break + + logging.info("parsed params") + logging.info(f" resource_group_name: {resource_group_name}") + logging.info(f" security_group: {security_group_name}") + logging.info(f" subscription_id: {subscription_id}") + logging.info(f" region: {region}") + + return { + "security_group_name": security_group_name, + "resource_group_name": resource_group_name, + "subscription_id": subscription_id, + "region": region, + } + + def remediate(self, client, resource_group_name, security_group_name): + """Block public access to port 3389 + + :param client: Instance of the Azure NetworkManagementClient. + :param resource_group_name: The name of the resource group to which the security_group belongs + :param security_group_name: The name of the security group. You must specify the + security group name in the request. + :type security_group_name: str. + :type resource_group_name: str. + :returns: Integer signaling success or failure + :rtype: int + :raises: msrestazure.azure_exceptions.CloudError + """ + + port = 3389 + + network_security_group = client.network_security_groups.get( + resource_group_name=resource_group_name, + network_security_group_name=security_group_name, + ) + + security_rules = network_security_group.security_rules + + for rule in security_rules: + if ( + rule.access != "Allow" + or rule.direction != "Inbound" + or rule.source_address_prefix != "*" + ): + continue + if rule.destination_port_range is not None: + port_range = rule.destination_port_range + if "-" in port_range: + new_ranges = self._find_and_remove_port([port_range], port) + if len(new_ranges) == 1: + rule.destination_port_range = new_ranges[0] + else: + rule.destination_port_range = None + rule.destination_port_ranges = new_ranges + elif int(rule.destination_port_range) == port: + security_rules.remove(rule) + else: + port_ranges = rule.destination_port_ranges + new_ranges = self._find_and_remove_port(port_ranges, port) + rule.destination_port_ranges = new_ranges + + network_security_group.security_rules = security_rules + + # Revoke permission for port 3389 + logging.info("revoking permissions for port 3389") + try: + logging.info( + " executing client.network_security_groups.create_or_update" + ) + logging.info(f" resource_group_name={resource_group_name}") + logging.info(f" network_security_group_name={security_group_name}") + client.network_security_groups.create_or_update( + resource_group_name, security_group_name, network_security_group + ) + except Exception as e: + logging.error(f"{str(e)}") + raise + + return 0 + + def _find_and_remove_port(self, port_ranges, port): + """Remove the port from the port range. + + :param port_ranges: port ranges to be updated. + :param port: port to be removed + :type port_ranges: list. + :type port: int + :returns: list of port_ranges + """ + result = [] + for port_range in port_ranges: + if "-" in port_range: + boundaries = port_range.split("-") + if int(boundaries[0]) <= port and int(boundaries[1]) >= port: + if int(boundaries[0]) == port: + new_range_start = port + 1 + new_range_end = int(boundaries[1]) + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + elif int(boundaries[1]) == port: + new_range_start = int(boundaries[0]) + new_range_end = port - 1 + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + else: + range1_start = int(boundaries[0]) + range1_end = port - 1 + range2_start = port + 1 + range2_end = int(boundaries[1]) + + if range1_start != range1_end: + result.append(str(range1_start) + "-" + str(range1_end)) + else: + result.append(str(range1_start)) + + if range2_start != range2_end: + result.append(str(range2_start) + "-" + str(range2_end)) + else: + result.append(str(range2_start)) + else: + result.append(port_range) + elif int(port_range) != port: + result.append(port_range) + return result + + def run(self, args): + """Run the remediation job. + + :param args: List of arguments provided to the job. + :type args: list. + :returns: int + """ + params = self.parse(args[1]) + + credentials = ServicePrincipalCredentials( + client_id=os.environ.get("AZURE_CLIENT_ID"), + secret=os.environ.get("AZURE_CLIENT_SECRET"), + tenant=os.environ.get("AZURE_TENANT_ID"), + ) + + client = NetworkManagementClient(credentials, params["subscription_id"]) + return self.remediate( + client, params["resource_group_name"], params["security_group_name"] + ) + + +if __name__ == "__main__": + sys.exit(NetworkSecurityGroupClosePort3389().run(sys.argv)) diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/constraints.txt b/remediation_worker/jobs/azure_network_security_group_close_port_3389/constraints.txt new file mode 100644 index 0000000..3ab47a3 --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/constraints.txt @@ -0,0 +1,115 @@ +adal==1.2.4 \ + --hash=sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0 \ + --hash=sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc +azure-common==1.1.25 \ + --hash=sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054 \ + --hash=sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a +azure-core==1.8.0 \ + --hash=sha256:84bff2b05ce989942e7ca3a13237441fbd8ff6855aaf2979b2bc94b74a02be5f \ + --hash=sha256:c89bbdcdc13ad45fe57d775ed87b15baf6d0b039a1ecd0a1bc91d2f713cb1f08 +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc +certifi==2020.6.20 \ + --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ + --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 +cffi==1.14.2 \ + --hash=sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e \ + --hash=sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c \ + --hash=sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e \ + --hash=sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1 \ + --hash=sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4 \ + --hash=sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2 \ + --hash=sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c \ + --hash=sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0 \ + --hash=sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798 \ + --hash=sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1 \ + --hash=sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4 \ + --hash=sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731 \ + --hash=sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4 \ + --hash=sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c \ + --hash=sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487 \ + --hash=sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e \ + --hash=sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f \ + --hash=sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123 \ + --hash=sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c \ + --hash=sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b \ + --hash=sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650 \ + --hash=sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad \ + --hash=sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75 \ + --hash=sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82 \ + --hash=sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7 \ + --hash=sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15 \ + --hash=sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa \ + --hash=sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +cryptography==3.0 \ + --hash=sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b \ + --hash=sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd \ + --hash=sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a \ + --hash=sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07 \ + --hash=sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71 \ + --hash=sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756 \ + --hash=sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559 \ + --hash=sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f \ + --hash=sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261 \ + --hash=sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053 \ + --hash=sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2 \ + --hash=sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f \ + --hash=sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b \ + --hash=sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77 \ + --hash=sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83 \ + --hash=sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f \ + --hash=sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67 \ + --hash=sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c \ + --hash=sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6 +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 +isodate==0.6.0 \ + --hash=sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8 \ + --hash=sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81 +msal-extensions==0.2.2 \ + --hash=sha256:31414753c484679bb3b6c6401623eb4c3ccab630af215f2f78c1d5c4f8e1d1a9 \ + --hash=sha256:f092246787145ec96d6c3c9f7bedfb837830fe8a79b56180e531fbf28b8de532 +msal==1.4.3 \ + --hash=sha256:51b8e8e0d918d9b4813f006324e7c4e21eb76268dd4c1a06d811a3475ad4ac57 \ + --hash=sha256:82c0ca1103f4a040f3fa5325bfd6fb6c8273fbd1d6f7c1ea92bbc94fcc360c46 +msrest==0.6.18 \ + --hash=sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d \ + --hash=sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96 +msrestazure==0.6.4 \ + --hash=sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9 \ + --hash=sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189 +oauthlib==3.1.0 \ + --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ + --hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea +portalocker==1.7.1 \ + --hash=sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a \ + --hash=sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a +pycparser==2.20 \ + --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \ + --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 +pyjwt==1.7.1 \ + --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ + --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 +python-dateutil==2.8.1 \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +requests-oauthlib==1.3.0 \ + --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ + --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a +requests==2.24.0 \ + --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ + --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/minimum_permissions.json b/remediation_worker/jobs/azure_network_security_group_close_port_3389/minimum_permissions.json new file mode 100644 index 0000000..6d33c22 --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/minimum_permissions.json @@ -0,0 +1,19 @@ +{ + "properties": { + "roleName": "remediate_network_security_group", + "description": "This role has required permission to make changes in the network security groups", + "assignableScopes": [ + ], + "permissions": [ + { + "actions": [ + "Microsoft.Network/networkSecurityGroups/read", + "Microsoft.Network/networkSecurityGroups/write" + ], + "notActions": [], + "dataActions": [], + "notDataActions": [] + } + ] + } +} \ No newline at end of file diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements-dev.txt b/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements-dev.txt new file mode 100644 index 0000000..1143bce --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements-dev.txt @@ -0,0 +1,33 @@ +-r requirements.txt +-c constraints.txt + +attrs==20.1.0 \ + --hash=sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a \ + --hash=sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 diff --git a/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements.txt b/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements.txt new file mode 100644 index 0000000..3c68ef7 --- /dev/null +++ b/remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements.txt @@ -0,0 +1,6 @@ +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/README.md b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/README.md new file mode 100644 index 0000000..f3d6281 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/README.md @@ -0,0 +1,75 @@ +# Allow only https traffic to the storage account + +This job enables only secure traffic to the storage account + +### Applicable Rule + +#### Rule ID: +5c8c269a7a550e1fb6560cdb + +#### Rule Name: +Secure connections are not enabled for storage transactions + + +## Getting Started + +### Prerequisites + +The provided Azure service principal must have the following permissions: +`Microsoft.Storage/storageAccounts/read` +`Microsoft.Storage/storageAccounts/write` + +A sample role with requisite permissions can be found [here](minimum_permissions.json) + +More information about already builtin roles and permissions can be found +[here](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) + +### Running the script + +You may run this script using following commands: +```shell script + pip install -r requirements.txt + python3 azure_storage_account_allow_https_traffic_only.py +``` + +## Running the tests +You may run test using following command under vss-remediation-worker-job-code-python directory: +```shell script + pip install -r requirements-dev.txt + python3 -m pytest test +``` + +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + +## Contributing +The Secure State team welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). +All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. + +For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING.md). + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). + +## Authors + +* **VMware Secure State** - *Initial work* + +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. + +## License + +This project is licensed under the Apache License - see the [LICENSE](https://github.com/vmware-samples/secure-state-remediation-jobs/blob/master/LICENSE.txt) file for details diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/__init__.py b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/azure_storage_account_allow_https_traffic_only.py b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/azure_storage_account_allow_https_traffic_only.py new file mode 100644 index 0000000..1ece258 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/azure_storage_account_allow_https_traffic_only.py @@ -0,0 +1,132 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import logging + +from azure.mgmt.storage import StorageManagementClient +from azure.common.credentials import ServicePrincipalCredentials +from azure.mgmt.storage.models import StorageAccountUpdateParameters + +logging.basicConfig(level=logging.INFO) + + +def logcall(f, *args, **kwargs): + logging.info( + "%s(%s)", + f.__name__, + ", ".join(list(args) + [f"{k}={repr(v)}" for k, v in kwargs.items()]), + ) + logging.info(f(*args, **kwargs)) + + +class StorageAccountAllowHttpsTrafficOnly(object): + def parse(self, payload): + """Parse payload received from Remediation Service. + + :param payload: JSON string containing parameters received from the remediation service. + :type payload: str. + :returns: Dictionary of parsed parameters + :rtype: dict + :raises: KeyError, JSONDecodeError + """ + remediation_entry = json.loads(payload) + + account_name = remediation_entry["notificationInfo"]["FindingInfo"]["ObjectId"] + region = remediation_entry["notificationInfo"]["FindingInfo"]["Region"] + + object_chain = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectChain" + ] + object_chain_dict = json.loads(object_chain) + subscription_id = object_chain_dict["cloudAccountId"] + + properties = object_chain_dict["properties"] + resource_group_name = "" + for property in properties: + if property["name"] == "ResourceGroup" and property["type"] == "string": + resource_group_name = property["stringV"] + break + + logging.info("parsed params") + logging.info(f" resource_group_name: {resource_group_name}") + logging.info(f" account_name: {account_name}") + logging.info(f" subscription_id: {subscription_id}") + logging.info(f" region: {region}") + + return { + "resource_group_name": resource_group_name, + "account_name": account_name, + "subscription_id": subscription_id, + "region": region, + } + + def remediate(self, client, resource_group_name, account_name): + """Block public access to blob container + + :param client: Instance of the Azure NetworkManagementClient. + :param resource_group_name: The name of the resource group to which the storage account belongs + :param account_name: The name of the storage account. You must specify the + account name in the request. + :type resource_group_name: str. + :type account_name: str. + :returns: Integer signaling success or failure + :rtype: int + :raises: msrestazure.azure_exceptions.CloudError + """ + + update_params = StorageAccountUpdateParameters(enable_https_traffic_only=True) + + # Allow only https traffic for the storage account + logging.info("Enabling HTTPS only traffic for storage account") + try: + logging.info(" executing client.storage_accounts.update") + logging.info(f" resource_group_name={resource_group_name}") + logging.info(f" account_name={account_name}") + client.storage_accounts.update( + resource_group_name=resource_group_name, + account_name=account_name, + parameters=update_params, + ) + except Exception as e: + logging.error(f"{str(e)}") + raise + + return 0 + + def run(self, args): + """Run the remediation job. + + :param args: List of arguments provided to the job. + :type args: list. + :returns: int + """ + params = self.parse(args[1]) + + credentials = ServicePrincipalCredentials( + client_id=os.environ.get("AZURE_CLIENT_ID"), + secret=os.environ.get("AZURE_CLIENT_SECRET"), + tenant=os.environ.get("AZURE_TENANT_ID"), + ) + + client = StorageManagementClient(credentials, params["subscription_id"]) + return self.remediate( + client, params["resource_group_name"], params["account_name"] + ) + + +if __name__ == "__main__": + sys.exit(StorageAccountAllowHttpsTrafficOnly().run(sys.argv)) diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/constraints.txt b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/constraints.txt new file mode 100644 index 0000000..3ab47a3 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/constraints.txt @@ -0,0 +1,115 @@ +adal==1.2.4 \ + --hash=sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0 \ + --hash=sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc +azure-common==1.1.25 \ + --hash=sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054 \ + --hash=sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a +azure-core==1.8.0 \ + --hash=sha256:84bff2b05ce989942e7ca3a13237441fbd8ff6855aaf2979b2bc94b74a02be5f \ + --hash=sha256:c89bbdcdc13ad45fe57d775ed87b15baf6d0b039a1ecd0a1bc91d2f713cb1f08 +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc +certifi==2020.6.20 \ + --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ + --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 +cffi==1.14.2 \ + --hash=sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e \ + --hash=sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c \ + --hash=sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e \ + --hash=sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1 \ + --hash=sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4 \ + --hash=sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2 \ + --hash=sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c \ + --hash=sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0 \ + --hash=sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798 \ + --hash=sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1 \ + --hash=sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4 \ + --hash=sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731 \ + --hash=sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4 \ + --hash=sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c \ + --hash=sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487 \ + --hash=sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e \ + --hash=sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f \ + --hash=sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123 \ + --hash=sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c \ + --hash=sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b \ + --hash=sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650 \ + --hash=sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad \ + --hash=sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75 \ + --hash=sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82 \ + --hash=sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7 \ + --hash=sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15 \ + --hash=sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa \ + --hash=sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +cryptography==3.0 \ + --hash=sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b \ + --hash=sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd \ + --hash=sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a \ + --hash=sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07 \ + --hash=sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71 \ + --hash=sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756 \ + --hash=sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559 \ + --hash=sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f \ + --hash=sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261 \ + --hash=sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053 \ + --hash=sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2 \ + --hash=sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f \ + --hash=sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b \ + --hash=sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77 \ + --hash=sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83 \ + --hash=sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f \ + --hash=sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67 \ + --hash=sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c \ + --hash=sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6 +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 +isodate==0.6.0 \ + --hash=sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8 \ + --hash=sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81 +msal-extensions==0.2.2 \ + --hash=sha256:31414753c484679bb3b6c6401623eb4c3ccab630af215f2f78c1d5c4f8e1d1a9 \ + --hash=sha256:f092246787145ec96d6c3c9f7bedfb837830fe8a79b56180e531fbf28b8de532 +msal==1.4.3 \ + --hash=sha256:51b8e8e0d918d9b4813f006324e7c4e21eb76268dd4c1a06d811a3475ad4ac57 \ + --hash=sha256:82c0ca1103f4a040f3fa5325bfd6fb6c8273fbd1d6f7c1ea92bbc94fcc360c46 +msrest==0.6.18 \ + --hash=sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d \ + --hash=sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96 +msrestazure==0.6.4 \ + --hash=sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9 \ + --hash=sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189 +oauthlib==3.1.0 \ + --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ + --hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea +portalocker==1.7.1 \ + --hash=sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a \ + --hash=sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a +pycparser==2.20 \ + --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \ + --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 +pyjwt==1.7.1 \ + --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ + --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 +python-dateutil==2.8.1 \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +requests-oauthlib==1.3.0 \ + --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ + --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a +requests==2.24.0 \ + --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ + --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/minimum_permissions.json b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/minimum_permissions.json new file mode 100644 index 0000000..56ff5e5 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/minimum_permissions.json @@ -0,0 +1,19 @@ +{ + "properties": { + "roleName": "remediate_storage_account", + "description": "This role has required permissions to make changes to the storage account", + "assignableScopes": [ + ], + "permissions": [ + { + "actions": [ + "Microsoft.Storage/storageAccounts/write", + "Microsoft.Storage/storageAccounts/read" + ], + "notActions": [], + "dataActions": [], + "notDataActions": [] + } + ] + } +} \ No newline at end of file diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements-dev.txt b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements-dev.txt new file mode 100644 index 0000000..c7e0d39 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements-dev.txt @@ -0,0 +1,33 @@ +-r requirements.txt +-c constraints.txt + +attrs==20.1.0 \ + --hash=sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a \ + --hash=sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 \ No newline at end of file diff --git a/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements.txt b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements.txt new file mode 100644 index 0000000..50850c0 --- /dev/null +++ b/remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements.txt @@ -0,0 +1,6 @@ +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-storage==11.1.0 \ + --hash=sha256:62a6a8c1c359026ec560856da25221b66b6f1e0a84763a04e863c6e911bc1a5e \ + --hash=sha256:ef23587c1b6dc0866ebf0e91e83ba05d7f7e4fea7951b704781b9cd9f5f27f1c diff --git a/remediation_worker/jobs/azure_vm_close_port_22/README.md b/remediation_worker/jobs/azure_vm_close_port_22/README.md new file mode 100644 index 0000000..edc9aee --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/README.md @@ -0,0 +1,75 @@ +# Close Port 22 for a VM + +This job blocks public access to port 22 for the VM. + +### Applicable Rule + +##### Rule ID: +d7a3ad03-860c-4928-9ba8-789e84a835be + +##### Rule Name: +A virtual machine is publicly accessible to the internet via port 22 + +## Getting Started + +### Prerequisites + +The provided Azure service principal must have the following permissions: +`Microsoft.Compute/virtualMachines/read` +`Microsoft.Network/networkInterfaces/read` +`Microsoft.Network/networkSecurityGroups/read` +`Microsoft.Network/networkSecurityGroups/write` + +A sample role with requisite permissions can be found [here](minimum_permissions.json) + +More information about already builtin roles and permissions can be found +[here](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) + +### Running the script + +You may run this script using following commands: +```shell script + pip install -r requirements.txt + python3 azure_vm_close_port_22.py +``` + +## Running the tests +You may run test using following command under vss-remediation-worker-job-code-python directory: +```shell script + python3 -m pytest test +``` + +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + +## Contributing +The Secure State team welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). +All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. + +For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING.md). + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). + +## Authors + +* **VMware Secure State** - *Initial work* + +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. + +## License + +This project is licensed under the Apache License - see the [LICENSE](https://github.com/vmware-samples/secure-state-remediation-jobs/blob/master/LICENSE.txt) file for details diff --git a/remediation_worker/jobs/azure_vm_close_port_22/__init__.py b/remediation_worker/jobs/azure_vm_close_port_22/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remediation_worker/jobs/azure_vm_close_port_22/azure_vm_close_port_22.py b/remediation_worker/jobs/azure_vm_close_port_22/azure_vm_close_port_22.py new file mode 100644 index 0000000..88f1d2e --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/azure_vm_close_port_22.py @@ -0,0 +1,223 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import logging + +from azure.mgmt.compute import ComputeManagementClient +from azure.mgmt.network import NetworkManagementClient +from azure.common.credentials import ServicePrincipalCredentials + +logging.basicConfig(level=logging.INFO) + + +def logcall(f, *args, **kwargs): + logging.info( + "%s(%s)", + f.__name__, + ", ".join(list(args) + [f"{k}={repr(v)}" for k, v in kwargs.items()]), + ) + logging.info(f(*args, **kwargs)) + + +class VMSecurityGroupClosePort22(object): + def parse(self, payload): + """Parse payload received from Remediation Service. + + :param payload: JSON string containing parameters received from the remediation service. + :type payload: str. + :returns: Dictionary of parsed parameters + :rtype: dict + :raises: KeyError, JSONDecodeError + """ + remediation_entry = json.loads(payload) + + vm_name = remediation_entry["notificationInfo"]["FindingInfo"]["ObjectId"] + region = remediation_entry["notificationInfo"]["FindingInfo"]["Region"] + + object_chain = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectChain" + ] + object_chain_dict = json.loads(object_chain) + subscription_id = object_chain_dict["cloudAccountId"] + + properties = object_chain_dict["properties"] + resource_group_name = "" + for property in properties: + if property["name"] == "ResourceGroup" and property["type"] == "string": + resource_group_name = property["stringV"] + break + + logging.info("parsed params") + logging.info(f" resource_group_name: {resource_group_name}") + logging.info(f" vm_name: {vm_name}") + logging.info(f" subscription_id: {subscription_id}") + logging.info(f" region: {region}") + + return { + "vm_name": vm_name, + "resource_group_name": resource_group_name, + "subscription_id": subscription_id, + "region": region, + } + + def remediate(self, compute_client, network_client, resource_group_name, vm_name): + """Block public access to port 22 of the VM + + :param compute_client: Instance of the Azure ComputeManagementClient. + :param network_client: Instance of the Azure NetworkManagementClient. + :param resource_group_name: The name of the resource group to which the security_group belongs + :param vm_name: The name of the VM. You must specify the VM name in the request. + :type vm_name: str. + :type resource_group_name: str. + :returns: Integer signaling success or failure + :rtype: int + :raises: msrestazure.azure_exceptions.CloudError + """ + + port = 22 + vm = compute_client.virtual_machines.get(resource_group_name, vm_name) + nw_interfaces = vm.network_profile.network_interfaces + + for nw_interface in nw_interfaces: + nw_interface_name = self._get_name_from_id(nw_interface.id) + nw_interface_details = network_client.network_interfaces.get( + resource_group_name, nw_interface_name + ) + security_group_name = self._get_name_from_id( + nw_interface_details.network_security_group.id + ) + network_security_group = network_client.network_security_groups.get( + resource_group_name=resource_group_name, + network_security_group_name=security_group_name, + ) + + security_rules = network_security_group.security_rules + + for rule in security_rules: + if ( + rule.access != "Allow" + or rule.direction != "Inbound" + or rule.source_address_prefix != "*" + ): + continue + if rule.destination_port_range is not None: + if int(rule.destination_port_range) == port: + security_rules.remove(rule) + else: + port_ranges = rule.destination_port_ranges + new_ranges = self._find_and_remove_port(port_ranges, port) + rule.destination_port_ranges = new_ranges + + network_security_group.security_rules = security_rules + + # Revoke permission for port 22 + logging.info("revoking permissions for port 22") + try: + logging.info( + " executing client.network_security_groups.create_or_update" + ) + logging.info(f" resource_group_name={resource_group_name}") + logging.info(f" network_security_group_name={security_group_name}") + network_client.network_security_groups.create_or_update( + resource_group_name, security_group_name, network_security_group + ) + except Exception as e: + logging.error(f"{str(e)}") + raise + + return 0 + + def _get_name_from_id(self, id): + return id.split("/")[-1] + + def _find_and_remove_port(self, port_ranges, port): + """Remove the port from the port range. + + :param port_ranges: port ranges to be updated. + :param port: port to be removed + :type port_ranges: list. + :type port: int + :returns: list of port_ranges + """ + result = [] + for port_range in port_ranges: + if "-" in port_range: + boundaries = port_range.split("-") + if int(boundaries[0]) <= port and int(boundaries[1]) >= port: + if int(boundaries[0]) == port: + new_range_start = port + 1 + new_range_end = int(boundaries[1]) + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + elif int(boundaries[1]) == port: + new_range_start = int(boundaries[0]) + new_range_end = port - 1 + if new_range_start != new_range_end: + result.append( + str(new_range_start) + "-" + str(new_range_end) + ) + else: + result.append(str(new_range_start)) + else: + range1_start = int(boundaries[0]) + range1_end = port - 1 + range2_start = port + 1 + range2_end = int(boundaries[1]) + + if range1_start != range1_end: + result.append(str(range1_start) + "-" + str(range1_end)) + else: + result.append(str(range1_start)) + + if range2_start != range2_end: + result.append(str(range2_start) + "-" + str(range2_end)) + else: + result.append(str(range2_start)) + else: + result.append(port_range) + elif int(port_range) != port: + result.append(port_range) + return result + + def run(self, args): + """Run the remediation job. + + :param args: List of arguments provided to the job. + :type args: list. + :returns: int + """ + params = self.parse(args[1]) + + credentials = ServicePrincipalCredentials( + client_id=os.environ.get("AZURE_CLIENT_ID"), + secret=os.environ.get("AZURE_CLIENT_SECRET"), + tenant=os.environ.get("AZURE_TENANT_ID"), + ) + + compute_client = ComputeManagementClient(credentials, params["subscription_id"]) + nw_client = NetworkManagementClient(credentials, params["subscription_id"]) + return self.remediate( + compute_client, nw_client, params["resource_group_name"], params["vm_name"], + ) + + +if __name__ == "__main__": + sys.exit(VMSecurityGroupClosePort22().run(sys.argv)) diff --git a/remediation_worker/jobs/azure_vm_close_port_22/constraints.txt b/remediation_worker/jobs/azure_vm_close_port_22/constraints.txt new file mode 100644 index 0000000..3ab47a3 --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/constraints.txt @@ -0,0 +1,115 @@ +adal==1.2.4 \ + --hash=sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0 \ + --hash=sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc +azure-common==1.1.25 \ + --hash=sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054 \ + --hash=sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a +azure-core==1.8.0 \ + --hash=sha256:84bff2b05ce989942e7ca3a13237441fbd8ff6855aaf2979b2bc94b74a02be5f \ + --hash=sha256:c89bbdcdc13ad45fe57d775ed87b15baf6d0b039a1ecd0a1bc91d2f713cb1f08 +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc +certifi==2020.6.20 \ + --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \ + --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 +cffi==1.14.2 \ + --hash=sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e \ + --hash=sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c \ + --hash=sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e \ + --hash=sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1 \ + --hash=sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4 \ + --hash=sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2 \ + --hash=sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c \ + --hash=sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0 \ + --hash=sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798 \ + --hash=sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1 \ + --hash=sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4 \ + --hash=sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731 \ + --hash=sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4 \ + --hash=sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c \ + --hash=sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487 \ + --hash=sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e \ + --hash=sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f \ + --hash=sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123 \ + --hash=sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c \ + --hash=sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b \ + --hash=sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650 \ + --hash=sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad \ + --hash=sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75 \ + --hash=sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82 \ + --hash=sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7 \ + --hash=sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15 \ + --hash=sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa \ + --hash=sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +cryptography==3.0 \ + --hash=sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b \ + --hash=sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd \ + --hash=sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a \ + --hash=sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07 \ + --hash=sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71 \ + --hash=sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756 \ + --hash=sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559 \ + --hash=sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f \ + --hash=sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261 \ + --hash=sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053 \ + --hash=sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2 \ + --hash=sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f \ + --hash=sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b \ + --hash=sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77 \ + --hash=sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83 \ + --hash=sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f \ + --hash=sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67 \ + --hash=sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c \ + --hash=sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6 +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 +isodate==0.6.0 \ + --hash=sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8 \ + --hash=sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81 +msal-extensions==0.2.2 \ + --hash=sha256:31414753c484679bb3b6c6401623eb4c3ccab630af215f2f78c1d5c4f8e1d1a9 \ + --hash=sha256:f092246787145ec96d6c3c9f7bedfb837830fe8a79b56180e531fbf28b8de532 +msal==1.4.3 \ + --hash=sha256:51b8e8e0d918d9b4813f006324e7c4e21eb76268dd4c1a06d811a3475ad4ac57 \ + --hash=sha256:82c0ca1103f4a040f3fa5325bfd6fb6c8273fbd1d6f7c1ea92bbc94fcc360c46 +msrest==0.6.18 \ + --hash=sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d \ + --hash=sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96 +msrestazure==0.6.4 \ + --hash=sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9 \ + --hash=sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189 +oauthlib==3.1.0 \ + --hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889 \ + --hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea +portalocker==1.7.1 \ + --hash=sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a \ + --hash=sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a +pycparser==2.20 \ + --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \ + --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 +pyjwt==1.7.1 \ + --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ + --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 +python-dateutil==2.8.1 \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +requests-oauthlib==1.3.0 \ + --hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \ + --hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a +requests==2.24.0 \ + --hash=sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b \ + --hash=sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898 +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 diff --git a/remediation_worker/jobs/azure_vm_close_port_22/minimum_permissions.json b/remediation_worker/jobs/azure_vm_close_port_22/minimum_permissions.json new file mode 100644 index 0000000..ab1625d --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/minimum_permissions.json @@ -0,0 +1,21 @@ +{ + "properties": { + "roleName": "remediate_vm", + "description": "This role has required permissions Role with permissions to remediate VM violations for port 22", + "assignableScopes": [ + ], + "permissions": [ + { + "actions": [ + "Microsoft.Compute/virtualMachines/read", + "Microsoft.Network/networkInterfaces/read", + "Microsoft.Network/networkSecurityGroups/read", + "Microsoft.Network/networkSecurityGroups/write" + ], + "notActions": [], + "dataActions": [], + "notDataActions": [] + } + ] + } +} \ No newline at end of file diff --git a/remediation_worker/jobs/azure_vm_close_port_22/requirements-dev.txt b/remediation_worker/jobs/azure_vm_close_port_22/requirements-dev.txt new file mode 100644 index 0000000..1143bce --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/requirements-dev.txt @@ -0,0 +1,33 @@ +-r requirements.txt +-c constraints.txt + +attrs==20.1.0 \ + --hash=sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a \ + --hash=sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff +iniconfig==1.0.1 \ + --hash=sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437 \ + --hash=sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69 +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 +more-itertools==8.4.0 \ + --hash=sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5 \ + --hash=sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2 +packaging==20.4 \ + --hash=sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8 \ + --hash=sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181 +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d +py==1.9.0 \ + --hash=sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2 \ + --hash=sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342 +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b +pytest==6.0.1 \ + --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ + --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad +toml==0.10.1 \ + --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ + --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 diff --git a/remediation_worker/jobs/azure_vm_close_port_22/requirements.txt b/remediation_worker/jobs/azure_vm_close_port_22/requirements.txt new file mode 100644 index 0000000..9307e77 --- /dev/null +++ b/remediation_worker/jobs/azure_vm_close_port_22/requirements.txt @@ -0,0 +1,9 @@ +azure-identity==1.4.0 \ + --hash=sha256:820e1f3e21f90d36063239c6cb7ca9a6bb644cb120a6b1ead3081cafdf6ceaf8 \ + --hash=sha256:92ccea6c6ac7724d186cb73422d1ad8f525202dce2bdc17f35c695948fadf222 +azure-mgmt-compute==13.0.0 \ + --hash=sha256:0848fe37b4b6e49bed07d3969789072da7c259e8a8d21458251c3912f695e7c2 \ + --hash=sha256:7f331bafcbedf25d65aa42038f7553747dab18d7f10a5af3297192d31c45339e +azure-mgmt-network==11.0.0 \ + --hash=sha256:0a4bda7341e33b2cfa567928f4374fe4e0c5710a328174f780813359ef15786b \ + --hash=sha256:7fdfc631c660cb173eee88abbb7b8be7742f91b522be6017867f217409cd69bc diff --git a/remediation_worker/jobs/ec2_close_port_22/README.md b/remediation_worker/jobs/ec2_close_port_22/README.md index 585bc1d..bdc9436 100644 --- a/remediation_worker/jobs/ec2_close_port_22/README.md +++ b/remediation_worker/jobs/ec2_close_port_22/README.md @@ -32,13 +32,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/ec2_close_port_3389/README.md b/remediation_worker/jobs/ec2_close_port_3389/README.md index 8ff488b..130f5f6 100644 --- a/remediation_worker/jobs/ec2_close_port_3389/README.md +++ b/remediation_worker/jobs/ec2_close_port_3389/README.md @@ -32,13 +32,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/rds_backup_retention_30_days/README.md b/remediation_worker/jobs/rds_backup_retention_30_days/README.md index 503909b..f013160 100644 --- a/remediation_worker/jobs/rds_backup_retention_30_days/README.md +++ b/remediation_worker/jobs/rds_backup_retention_30_days/README.md @@ -26,6 +26,21 @@ You may run test using following command under vss-remediation-worker-job-code-p python3 -m pytest test ``` +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + + ## Contributing The Secure State team welcomes welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. @@ -34,13 +49,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/s3_enable_access_logging/README.md b/remediation_worker/jobs/s3_enable_access_logging/README.md index f3a03cc..f8f32b1 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/README.md +++ b/remediation_worker/jobs/s3_enable_access_logging/README.md @@ -47,13 +47,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt b/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt index 9412e93..cf03a93 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt +++ b/remediation_worker/jobs/s3_enable_access_logging/requirements-dev.txt @@ -1,6 +1,9 @@ -r requirements.txt -c constraints.txt +mock==4.0.2 \ + --hash=sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0 \ + --hash=sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72 pytest==6.0.1 \ --hash=sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4 \ --hash=sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad diff --git a/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py b/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py index fcd360b..dd57755 100644 --- a/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py +++ b/remediation_worker/jobs/s3_enable_access_logging/s3_enable_access_logging.py @@ -44,9 +44,11 @@ def parse(self, payload): finding_info = notification_info.get("FindingInfo", None) source_bucket = finding_info.get("ObjectId", None) - cloud_account = remediation_entry.get("cloudAccount") - role_arn = cloud_account.get("roleArn") - cloud_account_id = role_arn.split(":")[4] + object_chain = remediation_entry["notificationInfo"]["FindingInfo"][ + "ObjectChain" + ] + object_chain_dict = json.loads(object_chain) + cloud_account_id = object_chain_dict["cloudAccountId"] region = finding_info.get("Region") logging.info(f"cloud_account_id: {cloud_account_id}") @@ -73,10 +75,44 @@ def parse(self, payload): logging.info(return_dict) return return_dict + def check_log_delivery_permissions(self, acl): + write_grant = False + read_acp_grant = False + + grants = acl.get("Grants") + + if grants is None: + return write_grant, read_acp_grant + + for grant in grants: + grantee = grant.get("Grantee") + if grantee is None: + continue + grantee_type = grantee.get("Type") + grantee_uri = grantee.get("URI") + if grantee_type is None or grantee_uri is None: + continue + if ( + grantee_type == "Group" + and grantee_uri == "http://acs.amazonaws.com/groups/s3/LogDelivery" + ): + if grant["Permission"] == "WRITE": + write_grant = True + elif grant["Permission"] == "READ_ACP": + read_acp_grant = True + + return write_grant, read_acp_grant + def grant_log_delivery_permissions(self, client, bucket_name): # Give the group log-delievery WRITE and READ_ACP permisions to the # target bucket acl = client.get_bucket_acl(Bucket=bucket_name) + + # check if the required permissions are already granted, and if present return + write_granted, read_acp_granted = self.check_log_delivery_permissions(acl) + if write_granted and read_acp_granted: + return + write_grant = { "Grantee": { "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery", @@ -94,8 +130,10 @@ def grant_log_delivery_permissions(self, client, bucket_name): del acl["ResponseMetadata"] modified_acl = copy.deepcopy(acl) - modified_acl["Grants"].append(write_grant) - modified_acl["Grants"].append(read_acp_grant) + if not write_granted: + modified_acl["Grants"].append(write_grant) + if not read_acp_granted: + modified_acl["Grants"].append(read_acp_grant) client.put_bucket_acl(Bucket=bucket_name, AccessControlPolicy=modified_acl) def ensure_log_target_bucket(self, client, target_bucket, region): diff --git a/remediation_worker/jobs/s3_enable_default_encryption/README.md b/remediation_worker/jobs/s3_enable_default_encryption/README.md index 8f04f6f..e8165db 100644 --- a/remediation_worker/jobs/s3_enable_default_encryption/README.md +++ b/remediation_worker/jobs/s3_enable_default_encryption/README.md @@ -47,13 +47,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/s3_list_buckets/README.md b/remediation_worker/jobs/s3_list_buckets/README.md index b005e42..6751699 100644 --- a/remediation_worker/jobs/s3_list_buckets/README.md +++ b/remediation_worker/jobs/s3_list_buckets/README.md @@ -47,13 +47,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/s3_remove_public_access/README.md b/remediation_worker/jobs/s3_remove_public_access/README.md index b3bc697..602599a 100644 --- a/remediation_worker/jobs/s3_remove_public_access/README.md +++ b/remediation_worker/jobs/s3_remove_public_access/README.md @@ -47,13 +47,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/s3_remove_public_admin_acl/README.md b/remediation_worker/jobs/s3_remove_public_admin_acl/README.md index a854223..3e46299 100644 --- a/remediation_worker/jobs/s3_remove_public_admin_acl/README.md +++ b/remediation_worker/jobs/s3_remove_public_admin_acl/README.md @@ -47,13 +47,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/security_group_close_port_22/README.md b/remediation_worker/jobs/security_group_close_port_22/README.md index 7d9f0c5..671f0bf 100644 --- a/remediation_worker/jobs/security_group_close_port_22/README.md +++ b/remediation_worker/jobs/security_group_close_port_22/README.md @@ -24,6 +24,20 @@ You may run test using following command under vss-remediation-worker-job-code-p python3 -m pytest test ``` +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + ## Contributing The Secure State team welcomes welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. @@ -32,13 +46,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/security_group_close_port_3389/README.md b/remediation_worker/jobs/security_group_close_port_3389/README.md index a07df49..41d3865 100644 --- a/remediation_worker/jobs/security_group_close_port_3389/README.md +++ b/remediation_worker/jobs/security_group_close_port_3389/README.md @@ -24,6 +24,20 @@ You may run test using following command under vss-remediation-worker-job-code-p python3 -m pytest test ``` +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + ## Contributing The Secure State team welcomes welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. @@ -32,13 +46,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/remediation_worker/jobs/security_group_close_port_5432/README.md b/remediation_worker/jobs/security_group_close_port_5432/README.md index 9eb5c02..41c68af 100644 --- a/remediation_worker/jobs/security_group_close_port_5432/README.md +++ b/remediation_worker/jobs/security_group_close_port_5432/README.md @@ -24,6 +24,20 @@ You may run test using following command under vss-remediation-worker-job-code-p python3 -m pytest ``` +## Deployment +1. Provision a Virtual Machine +Create an EC2 instance to use for the worker. The minimum required specifications are 128 MB memory and 1/2 Core CPU. +2. Setup Docker +Install Docker on the newly provisioned EC2 instance. You can refer to the [docs here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html) for more information. +3. Deploy the worker image +SSH into the EC2 instance and run the command below to deploy the worker image: +```shell script + docker run --rm -it --name worker \ + -e VSS_CLIENT_ID={ENTER CLIENT ID} + -e VSS_CLIENT_SECRET={ENTER CLIENT SECRET} \ + vmware/vss-remediation-worker:latest-python +``` + ## Contributing The Secure State team welcomes welcomes contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a Pull Request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. @@ -32,13 +46,13 @@ For more detailed information, refer to [CONTRIBUTING.md](../../../CONTRIBUTING. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vmware-samples/secure-state-remediation-jobs/tags). ## Authors * **VMware Secure State** - *Initial work* -See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. +See also the list of [contributors](https://github.com/vmware-samples/secure-state-remediation-jobs/contributors) who participated in this project. ## License diff --git a/test/unit/test_azure_blob_remove_public_access.py b/test/unit/test_azure_blob_remove_public_access.py new file mode 100644 index 0000000..1c40787 --- /dev/null +++ b/test/unit/test_azure_blob_remove_public_access.py @@ -0,0 +1,68 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from mock import Mock + +from remediation_worker.jobs.azure_blob_remove_public_access.azure_blob_remove_public_access import ( + StorageBlobRemovePublicAccess, +) + + +@pytest.fixture +def valid_payload(): + return """ +{ + "notificationInfo": { + "RuleId": "5c6cc5e103dcc90f363146cd", + "Service": "Storage", + "FindingInfo": { + "FindingId": "d0431afd-b82e-4021-8aa6-ba3cf5c60ef7", + "ObjectId": "storage_account_name.default.container_name", + "ObjectChain": "{\\"cloudAccountId\\":\\"subscription_id\\",\\"entityId\\":\\"Azure.Storage.d687b1a3-9b78-43b1-a17b-7de297fd1fce.resource_group_name.BlobContainer.storage_account_name.default.container_name\\",\\"entityName\\":\\"storage_account_name.default.container_name\\",\\"entityType\\":\\"Azure.Storage.BlobContainer\\",\\"lastUpdateTime\\":\\"2020-09-09T00:36:35.000Z\\",\\"partitionKey\\":\\"d687b1a3-9b78-43b1-a17b-7de297fd1fce\\",\\"provider\\":\\"Azure\\",\\"region\\":\\"eastus\\",\\"service\\":\\"Storage\\", \\"properties\\":[{\\"name\\":\\"ResourceGroup\\",\\"stringV\\":\\"resource_group_name\\",\\"type\\":\\"string\\"}]}", + "Region": "region" + } + } +} +""" + + +class TestBlobRemovePublicAccess(object): + def test_parse_payload(self, valid_payload): + params = StorageBlobRemovePublicAccess().parse(valid_payload) + assert params["account_name"] == "storage_account_name" + assert params["container_name"] == "container_name" + assert params["resource_group_name"] == "resource_group_name" + assert params["subscription_id"] == "subscription_id" + assert params["region"] == "region" + + def test_remediate_success(self): + client = Mock() + action = StorageBlobRemovePublicAccess() + assert ( + action.remediate(client, "resource_group", "account_name", "container_name") + == 0 + ) + assert client.blob_containers.update.call_count == 1 + + call_args = client.blob_containers.update.call_args + updated_container = call_args[1]["blob_container"] + assert updated_container.public_access == "None" + + def test_remediate_with_exception(self): + client = Mock() + client.blob_containers.update.side_effect = Exception + action = StorageBlobRemovePublicAccess() + with pytest.raises(Exception): + assert action.remediate(client, "security_group_id", "resource_group") diff --git a/test/unit/test_azure_network_security_group_close_port_22.py b/test/unit/test_azure_network_security_group_close_port_22.py new file mode 100644 index 0000000..1e3ee5f --- /dev/null +++ b/test/unit/test_azure_network_security_group_close_port_22.py @@ -0,0 +1,105 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from azure.mgmt.network.models import NetworkSecurityGroup +from azure.mgmt.network.models import SecurityRule +from mock import Mock + +from remediation_worker.jobs.azure_network_security_group_close_port_22.azure_network_security_group_close_port_22 import ( + NetworkSecurityGroupClosePort22, +) + + +@pytest.fixture +def valid_payload1(): + return """ +{ + "notificationInfo": { + "RuleId": "5c6cc5d903dcc90f363146b6", + "Service": "Network", + "FindingInfo": { + "FindingId": "e1606076-d55c-42c5-9ca7-93e933b1e672", + "ObjectId": "security_group_name", + "ObjectChain": "{\\"cloudAccountId\\":\\"subscription_id\\", \\"properties\\":[{\\"name\\":\\"ResourceGroup\\",\\"stringV\\":\\"resource_group_name\\",\\"type\\":\\"string\\"}]}", + "Region": "region" + } + } +} +""" + + +class TestNetworkSecurityGroupClosePort22(object): + def test_parse_payload(self, valid_payload1): + params = NetworkSecurityGroupClosePort22().parse(valid_payload1) + assert params["security_group_name"] == "security_group_name" + assert params["resource_group_name"] == "resource_group_name" + assert params["subscription_id"] == "subscription_id" + assert params["region"] == "region" + + def test_remediate_success(self): + client = Mock() + client.network_security_groups.get.return_value = NetworkSecurityGroup( + id="nsg", + security_rules=[ + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_ranges=["22-30", "3389"], + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="20-30", + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="22", + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="35", + ), + ], + ) + + action = NetworkSecurityGroupClosePort22() + assert action.remediate(client, "security_group_name", "resource_group") == 0 + assert client.network_security_groups.create_or_update.call_count == 1 + + call_args = client.network_security_groups.create_or_update.call_args + updated_sg = call_args.args[2] + security_rules = updated_sg.security_rules + assert len(security_rules) == 3 + assert security_rules[0].destination_port_ranges == ["23-30","3389"] + assert security_rules[1].destination_port_ranges == ["20-21", "23-30"] + assert security_rules[1].destination_port_range is None + assert security_rules[2].destination_port_range == "35" + + def test_remediate_with_exception(self): + client = Mock() + client.network_security_groups.create_or_update.side_effect = Exception + action = NetworkSecurityGroupClosePort22() + with pytest.raises(Exception): + assert action.remediate(client, "security_group_id", "resource_group") diff --git a/test/unit/test_azure_network_security_group_close_port_3389.py b/test/unit/test_azure_network_security_group_close_port_3389.py new file mode 100644 index 0000000..7e5de7e --- /dev/null +++ b/test/unit/test_azure_network_security_group_close_port_3389.py @@ -0,0 +1,106 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from azure.mgmt.network.models import NetworkSecurityGroup +from azure.mgmt.network.models import SecurityRule +from mock import Mock + +from remediation_worker.jobs.azure_network_security_group_close_port_3389.azure_network_security_group_close_port_3389 \ + import ( + NetworkSecurityGroupClosePort3389, +) + + +@pytest.fixture +def valid_payload1(): + return """ +{ + "notificationInfo": { + "RuleId": "5c6cc5d903dcc90f363146b6", + "Service": "Network", + "FindingInfo": { + "FindingId": "e1606076-d55c-42c5-9ca7-93e933b1e672", + "ObjectId": "security_group_name", + "ObjectChain": "{\\"cloudAccountId\\":\\"subscription_id\\", \\"properties\\":[{\\"name\\":\\"ResourceGroup\\",\\"stringV\\":\\"resource_group_name\\",\\"type\\":\\"string\\"}]}", + "Region": "region" + } + } +} +""" + + +class TestNetworkSecurityGroupClosePort22(object): + def test_parse_payload(self, valid_payload1): + params = NetworkSecurityGroupClosePort3389().parse(valid_payload1) + assert params["security_group_name"] == "security_group_name" + assert params["resource_group_name"] == "resource_group_name" + assert params["subscription_id"] == "subscription_id" + assert params["region"] == "region" + + def test_remediate_success(self): + client = Mock() + client.network_security_groups.get.return_value = NetworkSecurityGroup( + id="nsg", + security_rules=[ + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_ranges=["22-30", "3380-3390"], + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="3380-3395", + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="3389", + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="35", + ), + ], + ) + + action = NetworkSecurityGroupClosePort3389() + assert action.remediate(client, "security_group_name", "resource_group") == 0 + assert client.network_security_groups.create_or_update.call_count == 1 + + call_args = client.network_security_groups.create_or_update.call_args + updated_sg = call_args.args[2] + security_rules = updated_sg.security_rules + assert len(security_rules) == 3 + assert security_rules[0].destination_port_ranges == ["22-30", "3380-3388", "3390"] + assert security_rules[1].destination_port_ranges == ["3380-3388", "3390-3395"] + assert security_rules[1].destination_port_range is None + assert security_rules[2].destination_port_range == "35" + + def test_remediate_with_exception(self): + client = Mock() + client.network_security_groups.create_or_update.side_effect = Exception + action = NetworkSecurityGroupClosePort3389() + with pytest.raises(Exception): + assert action.remediate(client, "security_group_id", "resource_group") diff --git a/test/unit/test_azure_storage_account_allow_https_traffic_only.py b/test/unit/test_azure_storage_account_allow_https_traffic_only.py new file mode 100644 index 0000000..ba677a6 --- /dev/null +++ b/test/unit/test_azure_storage_account_allow_https_traffic_only.py @@ -0,0 +1,64 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from mock import Mock + +from remediation_worker.jobs.azure_storage_account_allow_https_traffic_only.azure_storage_account_allow_https_traffic_only import ( + StorageAccountAllowHttpsTrafficOnly, +) + + +@pytest.fixture +def valid_payload(): + return """ +{ + "notificationInfo": { + "RuleId": "5c8c269a7a550e1fb6560cdb", + "Service": "Storage", + "FindingInfo": { + "FindingId": "e1606076-d55c-42c5-9ca7-93e933b1e672", + "ObjectId": "storage_account_name", + "ObjectChain": "{\\"cloudAccountId\\":\\"subscription_id\\",\\"entityId\\":\\"Azure.Storage.d687b1a3-9b78-43b1-a17b-7de297fd1fce.resource_group_name.StorageAccount.testingresourcename\\",\\"entityName\\":\\"testingresourcename\\",\\"entityType\\":\\"Azure.Storage.StorageAccount\\",\\"lastUpdateTime\\":\\"2020-09-09T00:36:35.000Z\\",\\"partitionKey\\":\\"d687b1a3-9b78-43b1-a17b-7de297fd1fce\\",\\"provider\\":\\"Azure\\",\\"region\\":\\"eastus\\",\\"service\\":\\"Storage\\", \\"properties\\":[{\\"name\\":\\"ResourceGroup\\",\\"stringV\\":\\"resource_group_name\\",\\"type\\":\\"string\\"}]}", + "Region": "region" + } + } +} +""" + + +class TestStorageAccountAllowHttpsTrafficOnly(object): + def test_parse_payload(self, valid_payload): + params = StorageAccountAllowHttpsTrafficOnly().parse(valid_payload) + assert params["account_name"] == "storage_account_name" + assert params["resource_group_name"] == "resource_group_name" + assert params["subscription_id"] == "subscription_id" + assert params["region"] == "region" + + def test_remediate_success(self): + client = Mock() + action = StorageAccountAllowHttpsTrafficOnly() + assert action.remediate(client, "security_group_name", "resource_group") == 0 + assert client.storage_accounts.update.call_count == 1 + + call_args = client.storage_accounts.update.call_args + update_param = call_args[1]["parameters"] + assert update_param.enable_https_traffic_only == True + + def test_remediate_with_exception(self): + client = Mock() + client.network_security_groups.create_or_update.side_effect = Exception + action = StorageAccountAllowHttpsTrafficOnly() + with pytest.raises(Exception): + assert action.remediate(client, "security_group_id", "resource_group") diff --git a/test/unit/test_azure_vm_close_port_22.py b/test/unit/test_azure_vm_close_port_22.py new file mode 100644 index 0000000..0b5bf4f --- /dev/null +++ b/test/unit/test_azure_vm_close_port_22.py @@ -0,0 +1,129 @@ +# Copyright (c) 2020 VMware Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from azure.mgmt.network.models import NetworkSecurityGroup, NetworkInterface +from azure.mgmt.network.models import SecurityRule +from azure.mgmt.compute.models import ( + VirtualMachine, + NetworkProfile, + NetworkInterfaceReference, +) +from mock import Mock + +from remediation_worker.jobs.azure_vm_close_port_22.azure_vm_close_port_22 import ( + VMSecurityGroupClosePort22, +) + + +@pytest.fixture +def valid_payload1(): + return """ +{ + "notificationInfo": { + "RuleId": "5c6cc5e203dcc90f363146ce", + "Service": "Network", + "FindingInfo": { + "FindingId": "e1606076-d55c-42c5-9ca7-93e933b1e672", + "ObjectId": "vm_name", + "ObjectChain": "{\\"cloudAccountId\\":\\"subscription_id\\",\\"entityId\\":\\"Azure.Storage.d687b1a3-9b78-43b1-a17b-7de297fd1fce.khanz-test.StorageAccount.testingresourcename\\",\\"entityName\\":\\"testingresourcename\\",\\"entityType\\":\\"Azure.Storage.StorageAccount\\",\\"lastUpdateTime\\":\\"2020-09-09T00:36:35.000Z\\",\\"partitionKey\\":\\"d687b1a3-9b78-43b1-a17b-7de297fd1fce\\",\\"provider\\":\\"Azure\\",\\"region\\":\\"eastus\\",\\"service\\":\\"Storage\\", \\"properties\\":[{\\"name\\":\\"ResourceGroup\\",\\"stringV\\":\\"resource_group_name\\",\\"type\\":\\"string\\"}]}", + "Region": "region" + } + } +} +""" + + +class TestStorageAccountAllowHttpsTrafficOnly(object): + def test_parse_payload(self, valid_payload1): + params = VMSecurityGroupClosePort22().parse(valid_payload1) + assert params["vm_name"] == "vm_name" + assert params["resource_group_name"] == "resource_group_name" + assert params["subscription_id"] == "subscription_id" + assert params["region"] == "region" + + def test_remediate_success(self): + compute_client = Mock() + nw_profile = NetworkProfile( + network_interfaces=[ + NetworkInterfaceReference( + id="/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network" + "/networkInterfaces/vm_nameVMNic " + ) + ] + ) + + compute_client.virtual_machines.get.return_value = VirtualMachine( + id="/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Compute" + "/virtualMachines/vm_name", + location="eastus", + network_profile=nw_profile, + ) + nw_client = Mock() + nw_client.network_interfaces.get.return_value = NetworkInterface( + id="/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network" + "/networkInterfaces/vm_nameVMNic", + network_security_group=NetworkSecurityGroup( + id="/subscriptions/subscription_id/resourceGroups/resource_name/providers/Microsoft.Network" + "/networkSecurityGroups/vm_nameNSG " + ), + ) + + nw_client.network_security_groups.get.return_value = NetworkSecurityGroup( + id="/subscriptions/subscription_id/resourceGroups/resource_name/providers/Microsoft.Network" + "/networkSecurityGroups/vm_nameNSG", + security_rules=[ + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_ranges=["22", "3389"], + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_ranges=["20-30", "3389"], + ), + SecurityRule( + protocol="All", + access="Allow", + direction="Inbound", + source_address_prefix="*", + destination_port_range="22", + ), + ], + ) + + action = VMSecurityGroupClosePort22() + assert ( + action.remediate(compute_client, nw_client, "resource_name", "vm_name") == 0 + ) + assert nw_client.network_security_groups.create_or_update.call_count == 1 + call_args = nw_client.network_security_groups.create_or_update.call_args + updated_sg = call_args.args[2] + security_rules = updated_sg.security_rules + assert len(security_rules) == 2 + assert security_rules[0].destination_port_ranges == ["3389"] + assert security_rules[1].destination_port_ranges == ["20-21", "23-30", "3389"] + + # + def test_remediate_with_exception(self): + client = Mock() + client.network_security_groups.create_or_update.side_effect = Exception + action = VMSecurityGroupClosePort22() + with pytest.raises(Exception): + assert action.remediate(client, "security_group_id", "resource_group") diff --git a/test/unit/test_s3_enable_access_logging.py b/test/unit/test_s3_enable_access_logging.py index 5c0d8ca..9918c84 100644 --- a/test/unit/test_s3_enable_access_logging.py +++ b/test/unit/test_s3_enable_access_logging.py @@ -15,6 +15,7 @@ import json import pytest +from mock import Mock from botocore.exceptions import ClientError from remediation_worker.jobs.s3_enable_access_logging.s3_enable_access_logging import ( @@ -37,10 +38,6 @@ def invalid_payload(): def full_payload(): return json.dumps( { - "cloudAccount": { - "provider": "", - "roleArn": "arn:aws:iam::530342348278:role/SecureStateRemediation", - }, "notificationInfo": { "RuleId": "5c6cc5cc03dcc90f3631468d", "RuleName": "", @@ -117,10 +114,6 @@ def full_payload(): def self_payload(): return json.dumps( { - "cloudAccount": { - "provider": "", - "roleArn": "arn:aws:iam::530342348278:role/SecureStateRemediation", - }, "notificationInfo": { "RuleId": "5c6cc5cc03dcc90f3631468d", "RuleName": "", @@ -250,3 +243,74 @@ def put_bucket_logging(self, **kwargs): def test_dont_log_to_self(self, self_payload): with pytest.raises(SelfRemediationError): assert S3EnableAccessLogging().run([None, self_payload]) + + def test_check_log_delivery(self): + acl = { + "Grants": [ + { + "Grantee": { + "Type": "Group", + "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery", + }, + "Permission": "WRITE", + } + ] + } + + action = S3EnableAccessLogging() + write_enabled, read_acp_enabled = action.check_log_delivery_permissions(acl) + assert write_enabled + assert not read_acp_enabled + + def test_grant_log_delivery_permissions(self): + client = Mock() + client.get_bucket_acl.return_value = { + "ResponseMetadata": { + "RequestId": "6B0F579EDDCCAB3C", + "HostId": "9Csk0PXuRLyPhcKimBPbhfEmwQywAXPiWVWdpZPV+rjwVZO1DJMEKD/M65RJL+GguB3UMhOmpAQ=", + "HTTPStatusCode": 200, + "HTTPHeaders": { + "x-amz-id-2": "9Csk0PXuRLyPhcKimBPbhfEmwQywAXPiWVWdpZPV+rjwVZO1DJMEKD/M65RJL+GguB3UMhOmpAQ=", + "x-amz-request-id": "6B0F579EDDCCAB3C", + "date": "Wed, 16 Sep 2020 16:57:36 GMT", + }, + "RetryAttempts": 0, + }, + "Owner": { + "DisplayName": "awsmasteremail", + "ID": "b101f924005dbb04273644ca983ef2ea93d43ad46757f21f65c40d48d75368c3", + }, + "Grants": [ + { + "Grantee": { + "DisplayName": "awsmasteremail", + "ID": "b101f924005dbb04273644ca983ef2ea93d43ad46757f21f65c40d48d75368c3", + "Type": "CanonicalUser", + }, + "Permission": "FULL_CONTROL", + }, + { + "Grantee": { + "Type": "Group", + "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery", + }, + "Permission": "READ_ACP", + }, + ], + } + + bucket_name = "my_bucket" + action = S3EnableAccessLogging() + action.grant_log_delivery_permissions(client, bucket_name) + assert client.put_bucket_acl.call_count == 1 + call_args = client.put_bucket_acl.call_args.kwargs + + assert len(call_args) == 2 + assert call_args.get("Bucket") == bucket_name + + acp = call_args.get("AccessControlPolicy") + assert acp is not None + assert len(acp["Grants"]) >= 2 + write_granted, read_granted = action.check_log_delivery_permissions(acp) + assert write_granted + assert read_granted diff --git a/tox.ini b/tox.ini index bc2dd70..45dcf7e 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,11 @@ envlist = unit-security-group-close-port-3389 unit-rds-backup-retention-30-days unit-security-group-close-port-22 + unit-azure-network-security-group-close-port-22 + unit-azure-network-security-group-close-port-3389 + unit-azure-vm-close-port-22 + unit-azure-blob-remove-public-access + unit-azure-storage-allow-only-https [testenv] passenv = @@ -90,3 +95,33 @@ description = Unit test the project changedir = test commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_security_group_close_port_22.py deps = -r remediation_worker/jobs/security_group_close_port_22/requirements-dev.txt + +[testenv:unit-azure-network-security-group-close-port-22] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_azure_network_security_group_close_port_22.py +deps = -r remediation_worker/jobs/azure_network_security_group_close_port_22/requirements-dev.txt + +[testenv:unit-azure-network-security-group-close-port-3389] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_azure_network_security_group_close_port_3389.py +deps = -r remediation_worker/jobs/azure_network_security_group_close_port_3389/requirements-dev.txt + +[testenv:unit-azure-vm-close-port-22] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_azure_vm_close_port_22.py +deps = -r remediation_worker/jobs/azure_vm_close_port_22/requirements-dev.txt + +[testenv:unit-azure-blob-remove-public-access] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_azure_blob_remove_public_access.py +deps = -r remediation_worker/jobs/azure_blob_remove_public_access/requirements-dev.txt + +[testenv:unit-azure-storage-allow-only-https] +description = Unit test the project +changedir = test +commands = pytest --capture=no --basetemp="{envtmpdir}" unit/test_azure_storage_account_allow_https_traffic_only.py +deps = -r remediation_worker/jobs/azure_storage_account_allow_https_traffic_only/requirements-dev.txt