mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
feat: add GitHub provider documentation and CIS v1.0.0 compliance (#6116)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com> Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
484a773f5b
commit
a765c1543e
@@ -466,3 +466,19 @@ The required modules are:
|
||||
|
||||
- [ExchangeOnlineManagement](https://www.powershellgallery.com/packages/ExchangeOnlineManagement/3.6.0): Minimum version 3.6.0. Required for several checks across Exchange, Defender, and Purview.
|
||||
- [MicrosoftTeams](https://www.powershellgallery.com/packages/MicrosoftTeams/6.6.0): Minimum version 6.6.0. Required for all Teams checks.
|
||||
|
||||
## GitHub
|
||||
### Authentication
|
||||
|
||||
Prowler supports multiple methods to [authenticate with GitHub](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api). These include:
|
||||
|
||||
- **Personal Access Token (PAT)**
|
||||
- **OAuth App Token**
|
||||
- **GitHub App Credentials**
|
||||
|
||||
This flexibility allows you to scan and analyze your GitHub account, including repositories, organizations, and applications, using the method that best suits your use case.
|
||||
|
||||
The provided credentials must have the appropriate permissions to perform all the required checks.
|
||||
|
||||
???+ note
|
||||
GitHub App Credentials support less checks than other authentication methods.
|
||||
|
||||
@@ -565,6 +565,7 @@ kubectl logs prowler-XXXXX --namespace prowler-ns
|
||||
???+ note
|
||||
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.
|
||||
|
||||
|
||||
#### Microsoft 365
|
||||
|
||||
With M365 you need to specify which auth method is going to be used:
|
||||
@@ -587,5 +588,29 @@ prowler m365 --browser-auth --tenant-id "XXXXXXXX"
|
||||
|
||||
See more details about M365 Authentication in [Requirements](getting-started/requirements.md#microsoft-365)
|
||||
|
||||
#### GitHub
|
||||
|
||||
Prowler allows you to scan your GitHub account, including your repositories, organizations or applications.
|
||||
|
||||
There are several supported login methods:
|
||||
|
||||
```console
|
||||
# Personal Access Token (PAT):
|
||||
prowler github --personal-access-token pat
|
||||
|
||||
# OAuth App Token:
|
||||
prowler github --oauth-app-token oauth_token
|
||||
|
||||
# GitHub App Credentials:
|
||||
prowler github --github-app-id app_id --github-app-key app_key
|
||||
```
|
||||
|
||||
???+ note
|
||||
If no login method is explicitly provided, Prowler will automatically attempt to authenticate using environment variables in the following order of precedence:
|
||||
|
||||
1. `GITHUB_PERSONAL_ACCESS_TOKEN`
|
||||
2. `OAUTH_APP_TOKEN`
|
||||
3. `GITHUB_APP_ID` and `GITHUB_APP_KEY`
|
||||
|
||||
## Prowler v2 Documentation
|
||||
For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md).
|
||||
|
||||
44
docs/tutorials/github/authentication.md
Normal file
44
docs/tutorials/github/authentication.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# GitHub Authentication
|
||||
|
||||
Prowler supports multiple methods to [authenticate with GitHub](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api). These include:
|
||||
|
||||
- **Personal Access Token (PAT)**
|
||||
- **OAuth App Token**
|
||||
- **GitHub App Credentials**
|
||||
|
||||
This flexibility allows you to scan and analyze your GitHub account, including repositories, organizations, and applications, using the method that best suits your use case.
|
||||
|
||||
## Supported Login Methods
|
||||
|
||||
Here are the available login methods and their respective flags:
|
||||
|
||||
### Personal Access Token (PAT)
|
||||
Use this method by providing your personal access token directly.
|
||||
|
||||
```console
|
||||
prowler github --personal-access-token pat
|
||||
```
|
||||
|
||||
### OAuth App Token
|
||||
Authenticate using an OAuth app token.
|
||||
|
||||
```console
|
||||
prowler github --oauth-app-token oauth_token
|
||||
```
|
||||
|
||||
### GitHub App Credentials
|
||||
Use GitHub App credentials by specifying the App ID and the private key.
|
||||
|
||||
```console
|
||||
prowler github --github-app-id app_id --github-app-key app_key
|
||||
```
|
||||
|
||||
### Automatic Login Method Detection
|
||||
If no login method is explicitly provided, Prowler will automatically attempt to authenticate using environment variables in the following order of precedence:
|
||||
|
||||
1. `GITHUB_PERSONAL_ACCESS_TOKEN`
|
||||
2. `OAUTH_APP_TOKEN`
|
||||
3. `GITHUB_APP_ID` and `GITHUB_APP_KEY`
|
||||
|
||||
???+ note
|
||||
Ensure the corresponding environment variables are set up before running Prowler for automatic detection if you don't plan to specify the login method.
|
||||
@@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692)
|
||||
- Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787)
|
||||
- Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160)
|
||||
- Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116)
|
||||
|
||||
### Fixed
|
||||
- Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699)
|
||||
|
||||
@@ -50,6 +50,7 @@ from prowler.lib.outputs.compliance.aws_well_architected.aws_well_architected im
|
||||
from prowler.lib.outputs.compliance.cis.cis_aws import AWSCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_azure import AzureCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_github import GithubCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
|
||||
from prowler.lib.outputs.compliance.compliance import display_compliance_table
|
||||
@@ -787,6 +788,36 @@ def prowler():
|
||||
generated_outputs["compliance"].append(generic_compliance)
|
||||
generic_compliance.batch_write_data_to_file()
|
||||
|
||||
elif provider == "github":
|
||||
for compliance_name in input_compliance_frameworks:
|
||||
if compliance_name.startswith("cis_"):
|
||||
# Generate CIS Finding Object
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
cis = GithubCIS(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
create_file_descriptor=True,
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(cis)
|
||||
cis.batch_write_data_to_file()
|
||||
else:
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
generic_compliance = GenericCompliance(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
create_file_descriptor=True,
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(generic_compliance)
|
||||
generic_compliance.batch_write_data_to_file()
|
||||
|
||||
# AWS Security Hub Integration
|
||||
if provider == "aws":
|
||||
# Send output to S3 if needed (-B / -D) for all the output formats
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@ Available Cloud Providers:
|
||||
azure Azure Provider
|
||||
gcp GCP Provider
|
||||
kubernetes Kubernetes Provider
|
||||
github GitHub Provider
|
||||
m365 Microsoft 365 Provider
|
||||
nhn NHN Provider (Unofficial)
|
||||
|
||||
|
||||
101
prowler/lib/outputs/compliance/cis/cis_github.py
Normal file
101
prowler/lib/outputs/compliance/cis/cis_github.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from datetime import datetime
|
||||
|
||||
from prowler.lib.check.compliance_models import Compliance
|
||||
from prowler.lib.outputs.compliance.cis.models import GithubCISModel
|
||||
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
|
||||
from prowler.lib.outputs.finding import Finding
|
||||
|
||||
|
||||
class GithubCIS(ComplianceOutput):
|
||||
"""
|
||||
This class represents the GitHub CIS compliance output.
|
||||
|
||||
Attributes:
|
||||
- _data (list): A list to store transformed data from findings.
|
||||
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
|
||||
|
||||
Methods:
|
||||
- transform: Transforms findings into GitHub CIS compliance format.
|
||||
"""
|
||||
|
||||
def transform(
|
||||
self,
|
||||
findings: list[Finding],
|
||||
compliance: Compliance,
|
||||
compliance_name: str,
|
||||
) -> None:
|
||||
"""
|
||||
Transforms a list of findings into GitHub CIS compliance format.
|
||||
|
||||
Parameters:
|
||||
- findings (list): A list of findings.
|
||||
- compliance (Compliance): A compliance model.
|
||||
- compliance_name (str): The name of the compliance model.
|
||||
|
||||
Returns:
|
||||
- None
|
||||
"""
|
||||
for finding in findings:
|
||||
# Get the compliance requirements for the finding
|
||||
finding_requirements = finding.compliance.get(compliance_name, [])
|
||||
for requirement in compliance.Requirements:
|
||||
if requirement.Id in finding_requirements:
|
||||
for attribute in requirement.Attributes:
|
||||
compliance_row = GithubCISModel(
|
||||
Provider=finding.provider,
|
||||
Description=compliance.Description,
|
||||
Account_Id=finding.account_uid,
|
||||
Account_Name=finding.account_name,
|
||||
AssessmentDate=str(finding.timestamp),
|
||||
Requirements_Id=requirement.Id,
|
||||
Requirements_Description=requirement.Description,
|
||||
Requirements_Attributes_Section=attribute.Section,
|
||||
Requirements_Attributes_Profile=attribute.Profile,
|
||||
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
|
||||
Requirements_Attributes_Description=attribute.Description,
|
||||
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
|
||||
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
|
||||
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
|
||||
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
|
||||
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
|
||||
Requirements_Attributes_References=attribute.References,
|
||||
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
|
||||
Status=finding.status,
|
||||
StatusExtended=finding.status_extended,
|
||||
ResourceId=finding.resource_uid,
|
||||
ResourceName=finding.resource_name,
|
||||
CheckId=finding.check_id,
|
||||
Muted=finding.muted,
|
||||
)
|
||||
self._data.append(compliance_row)
|
||||
# Add manual requirements to the compliance output
|
||||
for requirement in compliance.Requirements:
|
||||
if not requirement.Checks:
|
||||
for attribute in requirement.Attributes:
|
||||
compliance_row = GithubCISModel(
|
||||
Provider=compliance.Provider.lower(),
|
||||
Description=compliance.Description,
|
||||
Account_Id="",
|
||||
Account_Name="",
|
||||
AssessmentDate=str(datetime.now()),
|
||||
Requirements_Id=requirement.Id,
|
||||
Requirements_Description=requirement.Description,
|
||||
Requirements_Attributes_Section=attribute.Section,
|
||||
Requirements_Attributes_Profile=attribute.Profile,
|
||||
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
|
||||
Requirements_Attributes_Description=attribute.Description,
|
||||
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
|
||||
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
|
||||
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
|
||||
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
|
||||
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
|
||||
Requirements_Attributes_References=attribute.References,
|
||||
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
|
||||
Status="MANUAL",
|
||||
StatusExtended="Manual check",
|
||||
ResourceId="manual_check",
|
||||
ResourceName="Manual check",
|
||||
CheckId="manual",
|
||||
Muted=False,
|
||||
)
|
||||
self._data.append(compliance_row)
|
||||
@@ -163,6 +163,37 @@ class KubernetesCISModel(BaseModel):
|
||||
Muted: bool
|
||||
|
||||
|
||||
class GithubCISModel(BaseModel):
|
||||
"""
|
||||
GithubCISModel generates a finding's output in Github CIS Compliance format.
|
||||
"""
|
||||
|
||||
Provider: str
|
||||
Description: str
|
||||
Account_Name: str
|
||||
Account_Id: str
|
||||
AssessmentDate: str
|
||||
Requirements_Id: str
|
||||
Requirements_Description: str
|
||||
Requirements_Attributes_Section: str
|
||||
Requirements_Attributes_Profile: str
|
||||
Requirements_Attributes_AssessmentStatus: str
|
||||
Requirements_Attributes_Description: str
|
||||
Requirements_Attributes_RationaleStatement: str
|
||||
Requirements_Attributes_ImpactStatement: str
|
||||
Requirements_Attributes_RemediationProcedure: str
|
||||
Requirements_Attributes_AuditProcedure: str
|
||||
Requirements_Attributes_AdditionalInformation: str
|
||||
Requirements_Attributes_References: str
|
||||
Requirements_Attributes_DefaultValue: str
|
||||
Status: str
|
||||
StatusExtended: str
|
||||
ResourceId: str
|
||||
ResourceName: str
|
||||
CheckId: str
|
||||
Muted: bool
|
||||
|
||||
|
||||
# TODO: Create a parent class for the common fields of CIS and have the specific classes from each provider to inherit from it.
|
||||
# It is not done yet because it is needed to respect the current order of the fields in the output file.
|
||||
|
||||
|
||||
@@ -330,3 +330,55 @@ class TestCompliance:
|
||||
"CIS-2.0": ["2.1.3"],
|
||||
"CIS-2.1": ["2.1.3"],
|
||||
}
|
||||
|
||||
def test_get_check_compliance_github(self):
|
||||
check_compliance = [
|
||||
Compliance(
|
||||
Framework="CIS",
|
||||
Provider="Github",
|
||||
Version="1.0",
|
||||
Description="This document provides prescriptive guidance for establishing a secure configuration posture for securing GitHub.",
|
||||
Requirements=[
|
||||
Compliance_Requirement(
|
||||
Checks=[],
|
||||
Id="1.1.11",
|
||||
Description="Ensure all open comments are resolved before allowing code change merging",
|
||||
Attributes=[
|
||||
CIS_Requirement_Attribute(
|
||||
Section="1.1",
|
||||
Profile="Level 2",
|
||||
AssessmentStatus="Manual",
|
||||
Description='Organizations should enforce a "no open comments" policy before allowing code change merging.',
|
||||
RationaleStatement="In an open code change proposal, reviewers can leave comments containing their questions and suggestions. These comments can also include potential bugs and security issues. Requiring all comments on a code change proposal to be resolved before it can be merged ensures that every concern is properly addressed or acknowledged before the new code changes are introduced to the code base.",
|
||||
ImpactStatement="Code change proposals containing open comments would not be able to be merged into the code base.",
|
||||
RemediationProcedure='For each code repository in use, require open comments to be resolved before the relevant code change can be merged by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the "Code and automation" section of the sidebar, click **Branches**.\n 4. Next to "Branch protection rules", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn\'t, click **Add rule**.\n 5. If you add the rule, under "Branch name pattern", type the branch name or pattern you want to protect.\n 6. Select **Require conversation resolution before merging**.\n 7. Click **Create** or **Save changes**.',
|
||||
AuditProcedure='For every code repository in use, verify that each merged code change does not contain open, unattended comments by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the "Code and automation" section of the sidebar, click **Branches**.\n 4. Next to "Branch protection rules", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn\'t, you are not compliant.\n 5. Ensure that **Require conversation resolution before merging** is checked.',
|
||||
AdditionalInformation="",
|
||||
References="",
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
finding = Check_Report(
|
||||
metadata=load_check_metadata(
|
||||
f"{path.dirname(path.realpath(__file__))}/../fixtures/metadata.json"
|
||||
).json(),
|
||||
resource={},
|
||||
)
|
||||
finding.resource_details = "Test resource details"
|
||||
finding.resource_id = "test-resource"
|
||||
finding.resource_arn = "test-arn"
|
||||
finding.region = "eu-west-1"
|
||||
finding.status = "PASS"
|
||||
finding.status_extended = "This is a test"
|
||||
|
||||
bulk_checks_metadata = {}
|
||||
bulk_checks_metadata["iam_user_accesskey_unused"] = mock.MagicMock()
|
||||
bulk_checks_metadata["iam_user_accesskey_unused"].Compliance = check_compliance
|
||||
|
||||
assert get_check_compliance(finding, "github", bulk_checks_metadata) == {
|
||||
"CIS-1.0": ["1.1.11"],
|
||||
}
|
||||
|
||||
40
util/generate_compliance_json_from_csv_for_cis10_github.py
Normal file
40
util/generate_compliance_json_from_csv_for_cis10_github.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
|
||||
# Convert a CSV file following the CIS 1.0 GitHub benchmark into a Prowler v3.0 Compliance JSON file
|
||||
# CSV fields:
|
||||
# Id, Title,Checks,Attributes_Section,Attributes_Level,Attributes_AssessmentStatus,Attributes_Description,Attributes_RationalStatement,Attributes_ImpactStatement,Attributes_RemediationProcedure,Attributes_AuditProcedure,Attributes_AdditionalInformation,Attributes_References
|
||||
|
||||
# get the CSV filename to convert from
|
||||
file_name = sys.argv[1]
|
||||
|
||||
# read the CSV file rows and use the column fields to form the Prowler compliance JSON file 'cis_1.0_github.json'
|
||||
output = {"Framework": "CIS-GitHub", "Version": "1.5", "Requirements": []}
|
||||
with open(file_name, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f, delimiter=",")
|
||||
for row in reader:
|
||||
attribute = {
|
||||
"Section": row[3],
|
||||
"Profile": row[4],
|
||||
"AssessmentStatus": row[5],
|
||||
"Description": row[6],
|
||||
"RationaleStatement": row[7],
|
||||
"ImpactStatement": row[8],
|
||||
"RemediationProcedure": row[9],
|
||||
"AuditProcedure": row[10],
|
||||
"AdditionalInformation": row[11],
|
||||
"References": row[12],
|
||||
}
|
||||
output["Requirements"].append(
|
||||
{
|
||||
"Id": row[0],
|
||||
"Description": row[1],
|
||||
"Checks": list(map(str.strip, row[2].split(","))),
|
||||
"Attributes": [attribute],
|
||||
}
|
||||
)
|
||||
|
||||
# Write the output Prowler compliance JSON file 'cis_1.0_github.json' locally
|
||||
with open("cis_1.0_github.json", "w", encoding="utf-8") as outfile:
|
||||
json.dump(output, outfile, indent=4, ensure_ascii=False)
|
||||
Reference in New Issue
Block a user