mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
feat(api): add OpenStack provider support (#10003)
This commit is contained in:
committed by
GitHub
parent
e6bea9f25a
commit
b94c8a5e5e
@@ -4,6 +4,10 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
## [1.20.0] (Prowler UNRELEASED)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- OpenStack provider support [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django migration for OpenStack provider support
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import api.db_utils
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("api", "0075_cloudflare_provider"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="provider",
|
||||
name="provider",
|
||||
field=api.db_utils.ProviderEnumField(
|
||||
choices=[
|
||||
("aws", "AWS"),
|
||||
("azure", "Azure"),
|
||||
("gcp", "GCP"),
|
||||
("kubernetes", "Kubernetes"),
|
||||
("m365", "M365"),
|
||||
("github", "GitHub"),
|
||||
("mongodbatlas", "MongoDB Atlas"),
|
||||
("iac", "IaC"),
|
||||
("oraclecloud", "Oracle Cloud Infrastructure"),
|
||||
("alibabacloud", "Alibaba Cloud"),
|
||||
("cloudflare", "Cloudflare"),
|
||||
("openstack", "OpenStack"),
|
||||
],
|
||||
default="aws",
|
||||
),
|
||||
),
|
||||
migrations.RunSQL(
|
||||
"ALTER TYPE provider ADD VALUE IF NOT EXISTS 'openstack';",
|
||||
reverse_sql=migrations.RunSQL.noop,
|
||||
),
|
||||
]
|
||||
@@ -288,6 +288,7 @@ class Provider(RowLevelSecurityProtectedModel):
|
||||
ORACLECLOUD = "oraclecloud", _("Oracle Cloud Infrastructure")
|
||||
ALIBABACLOUD = "alibabacloud", _("Alibaba Cloud")
|
||||
CLOUDFLARE = "cloudflare", _("Cloudflare")
|
||||
OPENSTACK = "openstack", _("OpenStack")
|
||||
|
||||
@staticmethod
|
||||
def validate_aws_uid(value):
|
||||
@@ -410,6 +411,15 @@ class Provider(RowLevelSecurityProtectedModel):
|
||||
pointer="/data/attributes/uid",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def validate_openstack_uid(value):
|
||||
if not re.match(r"^[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$", value):
|
||||
raise ModelValidationError(
|
||||
detail="OpenStack provider ID must be a valid project ID (UUID or project name).",
|
||||
code="openstack-uid",
|
||||
pointer="/data/attributes/uid",
|
||||
)
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
|
||||
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
|
||||
updated_at = models.DateTimeField(auto_now=True, editable=False)
|
||||
|
||||
@@ -367,6 +367,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -380,6 +381,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -398,6 +400,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -413,6 +416,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -1348,6 +1352,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -1361,6 +1366,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -1379,6 +1385,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -1394,6 +1401,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -1938,6 +1946,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -1951,6 +1960,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -1969,6 +1979,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -1984,6 +1995,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -2436,6 +2448,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -2449,6 +2462,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -2467,6 +2481,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -2482,6 +2497,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -2932,6 +2948,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -2945,6 +2962,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -2963,6 +2981,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -2978,6 +2997,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -3416,6 +3436,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -3429,6 +3450,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -3447,6 +3469,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -3462,6 +3485,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -5241,6 +5265,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5254,6 +5279,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5272,6 +5298,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5287,6 +5314,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5404,6 +5432,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5417,6 +5446,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5435,6 +5465,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5450,6 +5481,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5556,6 +5588,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5569,6 +5602,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5586,6 +5620,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5601,6 +5636,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5739,6 +5775,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5752,6 +5789,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5770,6 +5808,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5785,6 +5824,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -5936,6 +5976,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5949,6 +5990,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5967,6 +6009,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5982,6 +6025,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6127,6 +6171,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6140,6 +6185,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6157,6 +6203,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6172,6 +6219,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -6359,6 +6407,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6372,6 +6421,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6390,6 +6440,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6405,6 +6456,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6521,6 +6573,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6534,6 +6587,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6552,6 +6606,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6567,6 +6622,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6707,6 +6763,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6720,6 +6777,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6738,6 +6796,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6753,6 +6812,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -7534,6 +7594,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -7547,6 +7608,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider__in]
|
||||
schema:
|
||||
@@ -7565,6 +7627,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -7580,6 +7643,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -7598,6 +7662,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -7611,6 +7676,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -7629,6 +7695,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -7644,6 +7711,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -8285,6 +8353,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -8298,6 +8367,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -8316,6 +8386,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -8331,6 +8402,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -8787,6 +8859,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -8800,6 +8873,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -8818,6 +8892,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -8833,6 +8908,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -9102,6 +9178,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -9115,6 +9192,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -9133,6 +9211,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -9148,6 +9227,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -9423,6 +9503,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -9436,6 +9517,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -9454,6 +9536,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -9469,6 +9552,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -10278,6 +10362,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -10291,6 +10376,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -10309,6 +10395,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -10324,6 +10411,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -17348,6 +17436,50 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration
|
||||
file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g.,
|
||||
https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
@@ -18347,6 +18479,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -18360,6 +18493,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
uid:
|
||||
type: string
|
||||
@@ -18477,6 +18611,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
description: |-
|
||||
@@ -18493,6 +18628,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
uid:
|
||||
type: string
|
||||
title: Unique identifier for the provider, set by the provider
|
||||
@@ -18541,6 +18677,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
description: |-
|
||||
@@ -18557,6 +18694,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
uid:
|
||||
type: string
|
||||
minLength: 3
|
||||
@@ -19378,6 +19516,48 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -19764,6 +19944,50 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration
|
||||
file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g.,
|
||||
https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -20162,6 +20386,48 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
|
||||
@@ -27,6 +27,7 @@ from prowler.providers.iac.iac_provider import IacProvider
|
||||
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
|
||||
from prowler.providers.m365.m365_provider import M365Provider
|
||||
from prowler.providers.mongodbatlas.mongodbatlas_provider import MongodbatlasProvider
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider
|
||||
|
||||
|
||||
@@ -120,6 +121,7 @@ class TestReturnProwlerProvider:
|
||||
(Provider.ProviderChoices.IAC.value, IacProvider),
|
||||
(Provider.ProviderChoices.ALIBABACLOUD.value, AlibabacloudProvider),
|
||||
(Provider.ProviderChoices.CLOUDFLARE.value, CloudflareProvider),
|
||||
(Provider.ProviderChoices.OPENSTACK.value, OpenstackProvider),
|
||||
],
|
||||
)
|
||||
def test_return_prowler_provider(self, provider_type, expected_provider):
|
||||
@@ -227,6 +229,10 @@ class TestGetProwlerProviderKwargs:
|
||||
Provider.ProviderChoices.CLOUDFLARE.value,
|
||||
{"filter_accounts": ["provider_uid"]},
|
||||
),
|
||||
(
|
||||
Provider.ProviderChoices.OPENSTACK.value,
|
||||
{},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs):
|
||||
|
||||
@@ -1179,6 +1179,11 @@ class TestProviderViewSet:
|
||||
"uid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
|
||||
"alias": "Cloudflare Account",
|
||||
},
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"alias": "OpenStack Project",
|
||||
},
|
||||
]
|
||||
),
|
||||
)
|
||||
@@ -1598,6 +1603,26 @@ class TestProviderViewSet:
|
||||
"cloudflare-uid",
|
||||
"uid",
|
||||
),
|
||||
# OpenStack UID validation - starts with special character
|
||||
(
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "-invalid-project",
|
||||
"alias": "test",
|
||||
},
|
||||
"openstack-uid",
|
||||
"uid",
|
||||
),
|
||||
# OpenStack UID validation - too short (below min_length)
|
||||
(
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "ab",
|
||||
"alias": "test",
|
||||
},
|
||||
"min_length",
|
||||
"uid",
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
@@ -1771,21 +1796,21 @@ class TestProviderViewSet:
|
||||
(
|
||||
"uid.icontains",
|
||||
"1",
|
||||
9,
|
||||
10,
|
||||
),
|
||||
("alias", "aws_testing_1", 1),
|
||||
("alias.icontains", "aws", 2),
|
||||
("inserted_at", TODAY, 10),
|
||||
("inserted_at", TODAY, 11),
|
||||
(
|
||||
"inserted_at.gte",
|
||||
"2024-01-01",
|
||||
10,
|
||||
11,
|
||||
),
|
||||
("inserted_at.lte", "2024-01-01", 0),
|
||||
(
|
||||
"updated_at.gte",
|
||||
"2024-01-01",
|
||||
10,
|
||||
11,
|
||||
),
|
||||
("updated_at.lte", "2024-01-01", 0),
|
||||
]
|
||||
@@ -2392,6 +2417,15 @@ class TestProviderSecretViewSet:
|
||||
"api_email": "user@example.com",
|
||||
},
|
||||
),
|
||||
# OpenStack with clouds.yaml content
|
||||
(
|
||||
Provider.ProviderChoices.OPENSTACK.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"clouds_yaml_content": "clouds:\n mycloud:\n auth:\n auth_url: https://openstack.example.com:5000/v3\n",
|
||||
"clouds_yaml_cloud": "mycloud",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_provider_secrets_create_valid(
|
||||
|
||||
@@ -33,6 +33,7 @@ if TYPE_CHECKING:
|
||||
from prowler.providers.mongodbatlas.mongodbatlas_provider import (
|
||||
MongodbatlasProvider,
|
||||
)
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider
|
||||
|
||||
|
||||
@@ -78,12 +79,14 @@ def return_prowler_provider(
|
||||
AlibabacloudProvider
|
||||
| AwsProvider
|
||||
| AzureProvider
|
||||
| CloudflareProvider
|
||||
| GcpProvider
|
||||
| GithubProvider
|
||||
| IacProvider
|
||||
| KubernetesProvider
|
||||
| M365Provider
|
||||
| MongodbatlasProvider
|
||||
| OpenstackProvider
|
||||
| OraclecloudProvider
|
||||
):
|
||||
"""Return the Prowler provider class based on the given provider type.
|
||||
@@ -92,7 +95,7 @@ def return_prowler_provider(
|
||||
provider (Provider): The provider object containing the provider type and associated secrets.
|
||||
|
||||
Returns:
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: The corresponding provider class.
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: The corresponding provider class.
|
||||
|
||||
Raises:
|
||||
ValueError: If the provider type specified in `provider.provider` is not supported.
|
||||
@@ -152,6 +155,10 @@ def return_prowler_provider(
|
||||
)
|
||||
|
||||
prowler_provider = CloudflareProvider
|
||||
case Provider.ProviderChoices.OPENSTACK.value:
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
|
||||
prowler_provider = OpenstackProvider
|
||||
case _:
|
||||
raise ValueError(f"Provider type {provider.provider} not supported")
|
||||
return prowler_provider
|
||||
@@ -208,6 +215,12 @@ def get_prowler_provider_kwargs(
|
||||
**prowler_provider_kwargs,
|
||||
"filter_accounts": [provider.uid],
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.OPENSTACK.value:
|
||||
# No extra kwargs needed: clouds_yaml_content and clouds_yaml_cloud from the
|
||||
# secret are sufficient. Validating project_id (provider.uid) against the
|
||||
# clouds.yaml is not feasible because not all auth methods include it and the
|
||||
# Keystone API is unavailable on public clouds.
|
||||
pass
|
||||
|
||||
if mutelist_processor:
|
||||
mutelist_content = mutelist_processor.configuration.get("Mutelist", {})
|
||||
@@ -232,6 +245,7 @@ def initialize_prowler_provider(
|
||||
| KubernetesProvider
|
||||
| M365Provider
|
||||
| MongodbatlasProvider
|
||||
| OpenstackProvider
|
||||
| OraclecloudProvider
|
||||
):
|
||||
"""Initialize a Prowler provider instance based on the given provider type.
|
||||
@@ -241,7 +255,7 @@ def initialize_prowler_provider(
|
||||
mutelist_processor (Processor): The mutelist processor object containing the mutelist configuration.
|
||||
|
||||
Returns:
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: An instance of the corresponding provider class
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: An instance of the corresponding provider class
|
||||
initialized with the provider's secrets.
|
||||
"""
|
||||
prowler_provider = return_prowler_provider(provider)
|
||||
@@ -276,6 +290,13 @@ def prowler_provider_connection_test(provider: Provider) -> Connection:
|
||||
if "access_token" in prowler_provider_kwargs:
|
||||
iac_test_kwargs["access_token"] = prowler_provider_kwargs["access_token"]
|
||||
return prowler_provider.test_connection(**iac_test_kwargs)
|
||||
elif provider.provider == Provider.ProviderChoices.OPENSTACK.value:
|
||||
openstack_kwargs = {
|
||||
"clouds_yaml_content": prowler_provider_kwargs["clouds_yaml_content"],
|
||||
"clouds_yaml_cloud": prowler_provider_kwargs["clouds_yaml_cloud"],
|
||||
"raise_on_exception": False,
|
||||
}
|
||||
return prowler_provider.test_connection(**openstack_kwargs)
|
||||
else:
|
||||
return prowler_provider.test_connection(
|
||||
**prowler_provider_kwargs,
|
||||
|
||||
@@ -373,6 +373,21 @@ from rest_framework_json_api import serializers
|
||||
},
|
||||
"required": ["api_key", "api_email"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "OpenStack clouds.yaml Credentials",
|
||||
"properties": {
|
||||
"clouds_yaml_content": {
|
||||
"type": "string",
|
||||
"description": "The full content of a clouds.yaml configuration file.",
|
||||
},
|
||||
"clouds_yaml_cloud": {
|
||||
"type": "string",
|
||||
"description": "The name of the cloud to use from the clouds.yaml file.",
|
||||
},
|
||||
},
|
||||
"required": ["clouds_yaml_content", "clouds_yaml_cloud"],
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1525,6 +1525,8 @@ class BaseWriteProviderSecretSerializer(BaseWriteSerializer):
|
||||
"or both 'api_key' and 'api_email'."
|
||||
}
|
||||
)
|
||||
elif provider_type == Provider.ProviderChoices.OPENSTACK.value:
|
||||
serializer = OpenStackCloudsYamlProviderSecret(data=secret)
|
||||
else:
|
||||
raise serializers.ValidationError(
|
||||
{"provider": f"Provider type not supported {provider_type}"}
|
||||
@@ -1691,6 +1693,14 @@ class CloudflareApiKeyProviderSecret(serializers.Serializer):
|
||||
resource_name = "provider-secrets"
|
||||
|
||||
|
||||
class OpenStackCloudsYamlProviderSecret(serializers.Serializer):
|
||||
clouds_yaml_content = serializers.CharField()
|
||||
clouds_yaml_cloud = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
resource_name = "provider-secrets"
|
||||
|
||||
|
||||
class AlibabaCloudProviderSecret(serializers.Serializer):
|
||||
access_key_id = serializers.CharField()
|
||||
access_key_secret = serializers.CharField()
|
||||
|
||||
@@ -18,6 +18,10 @@ DATABASES = {
|
||||
|
||||
DATABASE_ROUTERS = []
|
||||
TESTING = True
|
||||
# Override page size for testing to a value only slightly above the current fixture count.
|
||||
# We explicitly set PAGE_SIZE to 15 (round number just above fixture) to avoid masking pagination bugs, while not setting it excessively high.
|
||||
# If you add more providers to the fixture, please review that the total value is below the current one and update this value if needed.
|
||||
REST_FRAMEWORK["PAGE_SIZE"] = 15 # noqa: F405
|
||||
SECRETS_ENCRYPTION_KEY = "ZMiYVo7m4Fbe2eXXPyrwxdJss2WSalXSv3xHBcJkPl0="
|
||||
|
||||
# DRF Simple API Key settings
|
||||
|
||||
@@ -537,6 +537,12 @@ def providers_fixture(tenants_fixture):
|
||||
alias="cloudflare_testing",
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
provider11 = Provider.objects.create(
|
||||
provider="openstack",
|
||||
uid="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
alias="openstack_testing",
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
|
||||
return (
|
||||
provider1,
|
||||
@@ -549,6 +555,7 @@ def providers_fixture(tenants_fixture):
|
||||
provider8,
|
||||
provider9,
|
||||
provider10,
|
||||
provider11,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- OpenStack provider `clouds_yaml_content` parameter for API integration [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003)
|
||||
- `defender_safe_attachments_policy_enabled` check for M365 provider [(#9833)](https://github.com/prowler-cloud/prowler/pull/9833)
|
||||
- `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832)
|
||||
- AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975)
|
||||
|
||||
@@ -297,6 +297,9 @@ class Provider(ABC):
|
||||
elif "openstack" in provider_class_name.lower():
|
||||
provider_class(
|
||||
clouds_yaml_file=getattr(arguments, "clouds_yaml_file", None),
|
||||
clouds_yaml_content=getattr(
|
||||
arguments, "clouds_yaml_content", None
|
||||
),
|
||||
clouds_yaml_cloud=getattr(arguments, "clouds_yaml_cloud", None),
|
||||
auth_url=getattr(arguments, "os_auth_url", None),
|
||||
identity_api_version=getattr(
|
||||
|
||||
@@ -6,6 +6,7 @@ from colorama import Fore, Style
|
||||
from openstack import config, connect
|
||||
from openstack import exceptions as openstack_exceptions
|
||||
from openstack.connection import Connection as OpenStackConnection
|
||||
from yaml import YAMLError, safe_load
|
||||
|
||||
from prowler.config.config import (
|
||||
default_config_file_path,
|
||||
@@ -49,6 +50,7 @@ class OpenstackProvider(Provider):
|
||||
def __init__(
|
||||
self,
|
||||
clouds_yaml_file: Optional[str] = None,
|
||||
clouds_yaml_content: Optional[str] = None,
|
||||
clouds_yaml_cloud: Optional[str] = None,
|
||||
auth_url: Optional[str] = None,
|
||||
identity_api_version: Optional[str] = None,
|
||||
@@ -68,6 +70,7 @@ class OpenstackProvider(Provider):
|
||||
|
||||
self._session = self.setup_session(
|
||||
clouds_yaml_file=clouds_yaml_file,
|
||||
clouds_yaml_content=clouds_yaml_content,
|
||||
clouds_yaml_cloud=clouds_yaml_cloud,
|
||||
auth_url=auth_url,
|
||||
identity_api_version=identity_api_version,
|
||||
@@ -132,6 +135,7 @@ class OpenstackProvider(Provider):
|
||||
@staticmethod
|
||||
def setup_session(
|
||||
clouds_yaml_file: Optional[str] = None,
|
||||
clouds_yaml_content: Optional[str] = None,
|
||||
clouds_yaml_cloud: Optional[str] = None,
|
||||
auth_url: Optional[str] = None,
|
||||
identity_api_version: Optional[str] = None,
|
||||
@@ -145,10 +149,16 @@ class OpenstackProvider(Provider):
|
||||
"""Collect authentication information from clouds.yaml, explicit parameters, or environment variables.
|
||||
|
||||
Authentication priority:
|
||||
1. clouds.yaml file (if clouds_yaml_file or clouds_yaml_cloud provided)
|
||||
1. clouds.yaml content/file (if clouds_yaml_content, clouds_yaml_file, or clouds_yaml_cloud provided)
|
||||
2. Explicit parameters + environment variable fallback
|
||||
"""
|
||||
# Priority 1: clouds.yaml authentication
|
||||
if clouds_yaml_content:
|
||||
logger.info("Using clouds.yaml content string for authentication")
|
||||
return OpenstackProvider._setup_session_from_clouds_yaml_content(
|
||||
clouds_yaml_content=clouds_yaml_content,
|
||||
clouds_yaml_cloud=clouds_yaml_cloud,
|
||||
)
|
||||
if clouds_yaml_file or clouds_yaml_cloud:
|
||||
logger.info("Using clouds.yaml configuration for authentication")
|
||||
return OpenstackProvider._setup_session_from_clouds_yaml(
|
||||
@@ -203,6 +213,73 @@ class OpenstackProvider(Provider):
|
||||
project_domain_name=resolved_project_domain,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _setup_session_from_clouds_yaml_content(
|
||||
clouds_yaml_content: str,
|
||||
clouds_yaml_cloud: Optional[str] = None,
|
||||
) -> OpenStackSession:
|
||||
"""Setup session from clouds.yaml content provided as a string.
|
||||
|
||||
Parses the YAML content directly instead of writing to a temporary file,
|
||||
following the same pattern as KubernetesProvider.setup_session().
|
||||
|
||||
Args:
|
||||
clouds_yaml_content: The full YAML content of a clouds.yaml file.
|
||||
clouds_yaml_cloud: Cloud name to use from the clouds.yaml content.
|
||||
|
||||
Returns:
|
||||
OpenStackSession configured from the provided clouds.yaml content.
|
||||
|
||||
Raises:
|
||||
OpenStackInvalidConfigError: If the YAML is malformed or missing required fields.
|
||||
OpenStackCloudNotFoundError: If the specified cloud is not found in the content.
|
||||
"""
|
||||
if not clouds_yaml_cloud:
|
||||
raise OpenStackInvalidConfigError(
|
||||
message="Cloud name (--clouds-yaml-cloud) is required when using clouds.yaml content",
|
||||
)
|
||||
|
||||
try:
|
||||
parsed = safe_load(clouds_yaml_content)
|
||||
except YAMLError as error:
|
||||
raise OpenStackInvalidConfigError(
|
||||
original_exception=error,
|
||||
message=f"Failed to parse clouds.yaml content: {error}",
|
||||
)
|
||||
|
||||
if not isinstance(parsed, dict) or "clouds" not in parsed:
|
||||
raise OpenStackInvalidConfigError(
|
||||
message="Invalid clouds.yaml content: missing 'clouds' key",
|
||||
)
|
||||
|
||||
cloud_config = parsed["clouds"].get(clouds_yaml_cloud)
|
||||
if not cloud_config:
|
||||
raise OpenStackCloudNotFoundError(
|
||||
message=f"Cloud '{clouds_yaml_cloud}' not found in clouds.yaml content",
|
||||
)
|
||||
|
||||
auth_dict = cloud_config.get("auth", {})
|
||||
|
||||
required_fields = ["auth_url", "username", "password"]
|
||||
missing_fields = [
|
||||
field for field in required_fields if not auth_dict.get(field)
|
||||
]
|
||||
if missing_fields:
|
||||
raise OpenStackInvalidConfigError(
|
||||
message=f"Missing required fields in clouds.yaml for cloud '{clouds_yaml_cloud}': {', '.join(missing_fields)}",
|
||||
)
|
||||
|
||||
return OpenStackSession(
|
||||
auth_url=auth_dict.get("auth_url"),
|
||||
identity_api_version=str(cloud_config.get("identity_api_version", "3")),
|
||||
username=auth_dict.get("username"),
|
||||
password=auth_dict.get("password"),
|
||||
project_id=auth_dict.get("project_id") or auth_dict.get("project_name"),
|
||||
region_name=cloud_config.get("region_name"),
|
||||
user_domain_name=auth_dict.get("user_domain_name", "Default"),
|
||||
project_domain_name=auth_dict.get("project_domain_name", "Default"),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _setup_session_from_clouds_yaml(
|
||||
clouds_yaml_file: Optional[str] = None,
|
||||
@@ -394,6 +471,7 @@ class OpenstackProvider(Provider):
|
||||
@staticmethod
|
||||
def test_connection(
|
||||
clouds_yaml_file: Optional[str] = None,
|
||||
clouds_yaml_content: Optional[str] = None,
|
||||
clouds_yaml_cloud: Optional[str] = None,
|
||||
auth_url: Optional[str] = None,
|
||||
identity_api_version: Optional[str] = None,
|
||||
@@ -412,6 +490,7 @@ class OpenstackProvider(Provider):
|
||||
|
||||
Args:
|
||||
clouds_yaml_file: Path to clouds.yaml configuration file
|
||||
clouds_yaml_content: The full content of a clouds.yaml file as a string
|
||||
clouds_yaml_cloud: Cloud name from clouds.yaml to use
|
||||
auth_url: OpenStack Keystone authentication URL
|
||||
identity_api_version: Keystone API version (default: "3")
|
||||
@@ -456,6 +535,7 @@ class OpenstackProvider(Provider):
|
||||
# Setup session with provided credentials
|
||||
session = OpenstackProvider.setup_session(
|
||||
clouds_yaml_file=clouds_yaml_file,
|
||||
clouds_yaml_content=clouds_yaml_content,
|
||||
clouds_yaml_cloud=clouds_yaml_cloud,
|
||||
auth_url=auth_url,
|
||||
identity_api_version=identity_api_version,
|
||||
|
||||
Reference in New Issue
Block a user