Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(devel-guide): Adding some improves and clarifications to developer guide #3749

Merged
merged 6 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions docs/developer-guide/checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ Here you can find how to create new checks for Prowler.
**To create a check is required to have a Prowler provider service already created, so if the service is not present or the attribute you want to audit is not retrieved by the service, please refer to the [Service](./services.md) documentation.**

## Introduction

The checks are the fundamental piece of Prowler. A check is a simply piece of code that ensures if something is configured against cybersecurity best practices. Then the check generates a finding with the result and includes the check's metadata to give the user more contextual information about the result, the risk and how to remediate it.

To create a new check for a supported Prowler provider, you will need to create a folder with the check name inside the specific service for the selected provider.

We are going to use the `ec2_ami_public` check form the `AWS` provider as an example. So the folder name will `prowler/providers/aws/services/ec2/ec2_ami_public` (following the format `prowler/providers/<provider>/services/<service>/<check_name>`), with the name of check following the pattern: `service_subservice/resource_action`.
We are going to use the `ec2_ami_public` check from the `AWS` provider as an example. So the folder name will be `prowler/providers/aws/services/ec2/ec2_ami_public` (following the format `prowler/providers/<provider>/services/<service>/<check_name>`), with the name of check following the pattern: `service_subservice_resource_action`.

???+ note
A subservice is an specific component of a service that is gonna be audited. Sometimes it could be the shortened name of the class attribute that is gonna be accessed in the check.

Inside that folder, we need to create three files:

Expand Down Expand Up @@ -101,7 +107,7 @@ All the checks MUST fill the `report.status` and `report.status_extended` with t

- Status -- `report.status`
- `PASS` --> If the check is passing against the configured value.
- `FAIL` --> If the check is passing against the configured value.
- `FAIL` --> If the check is failing against the configured value.
- `MANUAL` --> This value cannot be used unless a manual operation is required in order to determine if the `report.status` is whether `PASS` or `FAIL`.
- Status Extended -- `report.status_extended`
- MUST end in a dot `.`
Expand All @@ -111,7 +117,7 @@ All the checks MUST fill the `report.status` and `report.status_extended` with t

All the checks MUST fill the `report.region` with the following criteria:

- If the audited resource is regional use the `region` attribute within the resource object.
- If the audited resource is regional use the `region` (the name changes depending on the provider: `location` in Azure and GCP and `namespace` in K8s) attribute within the resource object.
- If the audited resource is global use the `service_client.region` within the service client object.

### Resource ID, Name and ARN
Expand Down Expand Up @@ -140,7 +146,7 @@ All the checks MUST fill the `report.resource_id` and `report.resource_arn` with
### Python Model
The following is the Python model for the check's class.

As per August 5th 2023 the `Check_Metadata_Model` can be found [here](https://github.com/prowler-cloud/prowler/blob/master/prowler/lib/check/models.py#L59-L80).
As per April 11th 2024 the `Check_Metadata_Model` can be found [here](https://github.com/prowler-cloud/prowler/blob/master/prowler/lib/check/models.py#L36-L82).

```python
class Check(ABC, Check_Metadata_Model):
Expand Down
28 changes: 15 additions & 13 deletions docs/developer-guide/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ Here you can find how to create a new service, or to complement an existing one,

## Introduction

To create a new service, you will need to create a folder inside the specific provider, i.e. `prowler/providers/<provider>/services/<service>/`.
In Prowler, a service is basically a solution that is offered by a cloud provider i.e. [ec2](https://aws.amazon.com/ec2/). Essentially it is a class that stores all the necessary stuff that we will need later in the checks to audit some aspects of our Cloud account.

To create a new service, you will need to create a folder inside the specific provider, i.e. `prowler/providers/<provider>/services/<new_service_name>/`.

Inside that folder, you MUST create the following files:

- An empty `__init__.py`: to make Python treat this service folder as a package.
- A `<service>_service.py`, containing all the service's logic and API calls.
- A `<service>_client_.py`, containing the initialization of the service's class we have just created so the checks's checks can use it.
- A `<new_service_name>_service.py`, containing all the service's logic and API calls.
- A `<new_service_name>_client_.py`, containing the initialization of the service's class we have just created so the checks's checks can use it.

## Service

The Prowler's service structure is the following and the way to initialise it is just by importing the service client in a check.

## Service Base Class
### Service Base Class

All the Prowler provider's services inherits from a base class depending on the provider used.

Expand All @@ -26,11 +28,11 @@ All the Prowler provider's services inherits from a base class depending on the

Each class is used to initialize the credentials and the API's clients to be used in the service. If some threading is used it must be coded there.

## Service Class
### Service Class

Due to the complexity and differencies of each provider API we are going to use an example service to guide you in how can it be created.

The following is the `<service>_service.py` file:
The following is the `<new_service_name>_service.py` file:

```python title="Service Class"
from datetime import datetime
Expand Down Expand Up @@ -176,9 +178,9 @@ class <Service>(ServiceParentClass):
)
```

### Service Models
#### Service Models

For each class object we need to model we use the Pydantic's [BaseModel](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel) to take advantage of the data validation.
Service models are classes that are used in the service to design all that we need to store in each class object extrated from API calls. We use the Pydantic's [BaseModel](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel) to take advantage of the data validation.

```python title="Service Model"
# In each service class we have to create some classes using
Expand All @@ -202,7 +204,7 @@ class <Item>(BaseModel):
tags: Optional[list]
"""<Items>[].tags"""
```
### Service Objects
#### Service Objects
In the service each group of resources should be created as a Python [dictionary](https://docs.python.org/3/tutorial/datastructures.html#dictionaries). This is because we are performing lookups all the time and the Python dictionary lookup has [O(1) complexity](https://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions).

We MUST set as the dictionary key a unique ID, like the resource Unique ID or ARN.
Expand All @@ -213,17 +215,17 @@ self.vpcs = {}
self.vpcs["vpc-01234567890abcdef"] = VPC_Object_Class()
```

## Service Client
### Service Client

Each Prowler service requires a service client to use the service in the checks.

The following is the `<service>_client.py` containing the initialization of the service's class we have just created so the service's checks can use them:
The following is the `<new_service_name>_client.py` containing the initialization of the service's class we have just created so the service's checks can use them:

```python
from prowler.providers.<provider>.lib.audit_info.audit_info import audit_info
from prowler.providers.<provider>.services.<service>.<service>_service import <Service>
from prowler.providers.<provider>.services.<new_service_name>.<new_service_name>_service import <Service>

<service>_client = <Service>(audit_info)
<new_service_name>_client = <Service>(audit_info)
```

## Permissions
Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ prowler aws --profile custom-profile -f us-east-1 eu-south-2
???+ note
By default, `prowler` will scan all AWS regions.

See more details about AWS Authentication in [Requirements](getting-started/requirements.md)
See more details about AWS Authentication in [Requirements](getting-started/requirements.md#aws)

### Azure

Expand All @@ -284,7 +284,7 @@ prowler azure --browser-auth --tenant-id "XXXXXXXX"
prowler azure --managed-identity-auth
```

See more details about Azure Authentication in [Requirements](getting-started/requirements.md)
See more details about Azure Authentication in [Requirements](getting-started/requirements.md#azure)

Prowler by default scans all the subscriptions that is allowed to scan, if you want to scan a single subscription or various specific subscriptions you can use the following flag (using az cli auth as example):
```console
Expand All @@ -311,7 +311,7 @@ Prowler by default scans all the GCP Projects that is allowed to scan, if you wa
prowler gcp --project-ids <Project ID 1> <Project ID 2> ... <Project ID N>
```

See more details about GCP Authentication in [Requirements](getting-started/requirements.md)
See more details about GCP Authentication in [Requirements](getting-started/requirements.md#google-cloud)

## Kubernetes

Expand Down