Skip to content

Commit 45d359c

Browse files
MarioRgzLpzMrCloudSecdanibarranqueroo
authored andcommitted
feat(microsof365): Add documentation and compliance file (#6195)
Co-authored-by: MrCloudSec <[email protected]> Co-authored-by: Daniel Barranquero <[email protected]>
1 parent 6049e5d commit 45d359c

File tree

12 files changed

+161
-8
lines changed

12 files changed

+161
-8
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe
7575
| GCP | 77 | 13 | 4 | 3 |
7676
| Azure | 140 | 18 | 5 | 3 |
7777
| Kubernetes | 83 | 7 | 2 | 7 |
78+
| Microsoft365 | 5 | 2 | 1 | 0 |
7879

7980
> You can list the checks, services, compliance frameworks and categories with `prowler <provider> --list-checks`, `prowler <provider> --list-services`, `prowler <provider> --list-compliance` and `prowler <provider> --list-categories`.
8081

docs/developer-guide/provider.md

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ Due to the complexity and differences of each provider use the rest of the provi
175175
- [GCP](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/gcp/gcp_provider.py)
176176
- [Azure](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/azure/azure_provider.py)
177177
- [Kubernetes](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/kubernetes/kubernetes_provider.py)
178+
- [Microsoft365](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/microsoft365/microsoft365_provider.py)
178179

179180
To facilitate understanding here is a pseudocode of how the most basic provider could be with examples.
180181

docs/developer-guide/services.md

+1
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,4 @@ It is really important to check if the current Prowler's permissions for each pr
237237
- AWS: https://docs.prowler.cloud/en/latest/getting-started/requirements/#aws-authentication
238238
- Azure: https://docs.prowler.cloud/en/latest/getting-started/requirements/#permissions
239239
- GCP: https://docs.prowler.cloud/en/latest/getting-started/requirements/#gcp-authentication
240+
- Microsoft365: https://docs.prowler.cloud/en/latest/getting-started/requirements/#microsoft365-authentication

docs/getting-started/requirements.md

+29
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,32 @@ Those credentials must be associated to a user or service account with proper pe
102102

103103
???+ note
104104
By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned.
105+
106+
## Microsoft365
107+
108+
Prowler for Microsoft365 currently supports the following authentication types:
109+
110+
- [Service principal application](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals?tabs=browser#service-principal-object) (recommended).
111+
- Current az cli credentials stored.
112+
- Interactive browser authentication.
113+
114+
115+
???+ warning
116+
For Prowler App only the Service Principal with an application authentication method is supported.
117+
118+
### Service Principal authentication
119+
120+
To allow Prowler assume the service principal identity to start the scan it is needed to configure the following environment variables:
121+
122+
```console
123+
export AZURE_CLIENT_ID="XXXXXXXXX"
124+
export AZURE_CLIENT_SECRET="XXXXXXXXX"
125+
export AZURE_TENANT_ID="XXXXXXXXX"
126+
```
127+
128+
If you try to execute Prowler with the `--sp-env-auth` flag and those variables are empty or not exported, the execution is going to fail.
129+
Follow the instructions in the [Create Prowler Service Principal](../tutorials/azure/create-prowler-service-principal.md) section to create a service principal.
130+
131+
### Interactive Browser authentication
132+
133+
To use `--browser-auth` the user needs to authenticate against Azure using the default browser to start the scan, also `--tenant-id` flag is required.

docs/index.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/),
164164

165165
* `Python >= 3.9`
166166
* `Python pip >= 21.0.0`
167-
* AWS, GCP, Azure and/or Kubernetes credentials
167+
* AWS, GCP, Azure, Microsoft365 and/or Kubernetes credentials
168168

169169
_Commands_:
170170

@@ -417,7 +417,7 @@ While the scan is running, start exploring the findings in these sections:
417417

418418
### Prowler CLI
419419

420-
To run Prowler, you will need to specify the provider (e.g `aws`, `gcp`, `azure` or `kubernetes`):
420+
To run Prowler, you will need to specify the provider (e.g `aws`, `gcp`, `azure`, `microsoft365` or `kubernetes`):
421421

422422
???+ note
423423
If no provider specified, AWS will be used for backward compatibility with most of v2 options.
@@ -559,5 +559,23 @@ kubectl logs prowler-XXXXX --namespace prowler-ns
559559
???+ note
560560
By default, `prowler` will scan all namespaces in your active Kubernetes context. Use the flag `--context` to specify the context to be scanned and `--namespaces` to specify the namespaces to be scanned.
561561

562+
#### Microsoft365
563+
564+
With Microsoft365 you need to specify which auth method is going to be used:
565+
566+
```console
567+
# To use service principal authentication
568+
prowler microsoft365 --sp-env-auth
569+
570+
# To use az cli authentication
571+
prowler microsoft365 --az-cli-auth
572+
573+
# To use browser authentication
574+
prowler microsoft365 --browser-auth --tenant-id "XXXXXXXX"
575+
576+
```
577+
578+
See more details about Microsoft365 Authentication in [Requirements](getting-started/requirements.md#microsoft365)
579+
562580
## Prowler v2 Documentation
563581
For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md).

docs/tutorials/azure/create-prowler-service-principal.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ To allow Prowler assume an identity to start the scan with the required privileg
44

55
To create a Service Principal Application you can use the Azure Portal or the Azure CLI.
66

7-
## From Azure Portal
7+
## From Azure Portal / Entra Admin Center
88

99
1. Access to Microsoft Entra ID
1010
2. In the left menu bar, go to "App registrations"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Microsoft365 authentication
2+
3+
By default Prowler uses MsGraph Python SDK identity package authentication methods using the class `ClientSecretCredential`.
4+
This allows Prowler to authenticate against microsoft365 using the following methods:
5+
6+
- Service principal authentication by environment variables (Enterprise Application)
7+
- Current CLI credentials stored
8+
- Interactive browser authentication
9+
10+
To launch the tool first you need to specify which method is used through the following flags:
11+
12+
```console
13+
# To use service principal authentication
14+
prowler microsoft365 --sp-env-auth
15+
16+
# To use cli authentication
17+
prowler microsoft365 --az-cli-auth
18+
19+
# To use browser authentication
20+
prowler microsoft365 --browser-auth --tenant-id "XXXXXXXX"
21+
```
22+
23+
To use Prowler you need to set up also the permissions required to access your resources in your Microsoft365 account, to more details refer to [Requirements](../../getting-started/requirements.md)

mkdocs.yml

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ nav:
9494
- In-Cluster Execution: tutorials/kubernetes/in-cluster.md
9595
- Non In-Cluster Execution: tutorials/kubernetes/outside-cluster.md
9696
- Miscellaneous: tutorials/kubernetes/misc.md
97+
- Microsoft 365:
98+
- Authentication: tutorials/microsoft365/authentication.md
99+
- Create Prowler Service Principal: tutorials/microsoft365/create-prowler-service-principal.md
97100
- Developer Guide:
98101
- Introduction: developer-guide/introduction.md
99102
- Provider: developer-guide/provider.md

prowler/config/config.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,10 @@ def load_and_validate_config_file(provider: str, config_file_path: str) -> dict:
123123

124124
# Not to introduce a breaking change, allow the old format config file without any provider keys
125125
# and a new format with a key for each provider to include their configuration values within.
126-
if any(key in config_file for key in ["aws", "gcp", "azure", "kubernetes"]):
126+
if any(
127+
key in config_file
128+
for key in ["aws", "gcp", "azure", "kubernetes", "microsoft365"]
129+
):
127130
config = config_file.get(provider, {})
128131
else:
129132
config = config_file if config_file else {}

prowler/lib/outputs/compliance/cis/cis_microsoft365.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def transform(
4242
compliance_row = Microsoft365CISModel(
4343
Provider=finding.provider,
4444
Description=compliance.Description,
45-
SubscriptionId=finding.account_uid,
45+
TenantId=finding.account_uid,
4646
Location=finding.region,
4747
AssessmentDate=str(finding.timestamp),
4848
Requirements_Id=requirement.Id,
@@ -73,8 +73,8 @@ def transform(
7373
compliance_row = Microsoft365CISModel(
7474
Provider=compliance.Provider.lower(),
7575
Description=compliance.Description,
76-
SubscriptionId="",
77-
Location="",
76+
TenantId=finding.account_uid,
77+
Location=finding.region,
7878
AssessmentDate=str(finding.timestamp),
7979
Requirements_Id=requirement.Id,
8080
Requirements_Description=requirement.Description,

prowler/lib/outputs/compliance/cis/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class Microsoft365CISModel(BaseModel):
7373

7474
Provider: str
7575
Description: str
76-
SubscriptionId: str
76+
TenantId: str
7777
Location: str
7878
AssessmentDate: str
7979
Requirements_Id: str
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import csv
2+
import json
3+
import sys
4+
5+
# Convert a CSV file following the CIS 4.0 Microsoft365 Benchmark into a Prowler v3.0 Compliance JSON file
6+
# CSV fields:
7+
# Section #,Recommendation #,Profile,Title,Assessment Status,Description,Rationale Statement,Impact Statement,Remediation Procedure,Audit Procedure,Additional Information,CIS Controls,CIS Safeguards 1 (v8),CIS Safeguards 2 (v8),CIS Safeguards 3 (v8),v8 IG1,v8 IG2,v8 IG3,CIS Safeguards 1 (v7),CIS Safeguards 2 (v7),CIS Safeguards 3 (v7),v7 IG1,v7 IG2,v7 IG3,References,Default Value
8+
9+
# Get the CSV filename to convert from
10+
file_name = sys.argv[1]
11+
12+
# Create the output JSON object
13+
output = {"Framework": "CIS", "Version": "4.0", "Requirements": []}
14+
15+
# Open the CSV file and read the rows
16+
try:
17+
with open(file_name, newline="", encoding="utf-8") as f:
18+
reader = csv.reader(f, delimiter=",")
19+
next(reader) # Skip the header row
20+
for row in reader:
21+
attribute = {
22+
"Section": row[0],
23+
"Profile": row[2],
24+
"AssessmentStatus": row[4],
25+
"Description": row[5],
26+
"RationaleStatement": row[6],
27+
"ImpactStatement": row[7],
28+
"RemediationProcedure": row[8],
29+
"AuditProcedure": row[9],
30+
"AdditionalInformation": row[10],
31+
"References": row[24],
32+
}
33+
if row[4] != "":
34+
output["Requirements"].append(
35+
{
36+
"Id": row[1],
37+
"Description": row[5],
38+
"Checks": [],
39+
"Attributes": [attribute],
40+
}
41+
)
42+
except UnicodeDecodeError:
43+
# If there is an error reading the file with the default encoding, try with ISO-8859-1
44+
with open(file_name, newline="", encoding="ISO-8859-1") as f:
45+
reader = csv.reader(f, delimiter=",")
46+
next(reader) # Skip the header row
47+
for row in reader:
48+
attribute = {
49+
"Section": row[0],
50+
"Profile": row[2],
51+
"AssessmentStatus": row[4],
52+
"Description": row[5],
53+
"RationaleStatement": row[6],
54+
"ImpactStatement": row[7],
55+
"RemediationProcedure": row[8],
56+
"AuditProcedure": row[9],
57+
"AdditionalInformation": row[10],
58+
"References": row[24],
59+
}
60+
if row[4] != "":
61+
output["Requirements"].append(
62+
{
63+
"Id": row[1],
64+
"Description": row[5],
65+
"Checks": [],
66+
"Attributes": [attribute],
67+
}
68+
)
69+
70+
# Save the output JSON file
71+
with open("cis_4.0_microsoft365.json", "w", encoding="utf-8") as outfile:
72+
json.dump(output, outfile, indent=4, ensure_ascii=False)
73+
74+
print("Archivo JSON generado exitosamente.")

0 commit comments

Comments
 (0)