mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
feat(ProviderSecret): PRWLR-5128 Implement role assumption provider credentials for AWS (#64)
* feat(ProviderSecret): PRWLR-5128 add role assumption logic * feat(Provider): PRWLR-5128 add static kwargs to Prowler provider initialization * chore: PRWLR-5128 update API spec * test(ProviderSecret): PRWLR-5128 add new unit tests * chore: PRWLR-5128 update API spec
This commit is contained in:
committed by
GitHub
parent
c188028de5
commit
fc19fbac68
@@ -626,6 +626,7 @@ class ResourceFindingMapping(PostgresPartitionedModel, RowLevelSecurityProtected
|
||||
class ProviderSecret(RowLevelSecurityProtectedModel):
|
||||
class TypeChoices(models.TextChoices):
|
||||
STATIC = "static", _("Key-value pairs")
|
||||
ROLE = "role", _("Role assumption")
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
|
||||
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
|
||||
|
||||
+449
-50
@@ -11,12 +11,11 @@ paths:
|
||||
get:
|
||||
operationId: findings_list
|
||||
description: Retrieve a list of all findings with options for filtering by various
|
||||
criteria. If no `scan` or `inserted_at` filter is provided, a default filter
|
||||
will be applied that will return all findings for the current day.
|
||||
criteria.
|
||||
summary: List all findings
|
||||
parameters:
|
||||
- in: query
|
||||
name: fields[Findings]
|
||||
name: fields[Finding]
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
@@ -452,7 +451,7 @@ paths:
|
||||
summary: Retrieve data from a specific finding
|
||||
parameters:
|
||||
- in: query
|
||||
name: fields[Findings]
|
||||
name: fields[Finding]
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
@@ -859,6 +858,7 @@ paths:
|
||||
- inserted_at
|
||||
- updated_at
|
||||
- name
|
||||
- secret_type
|
||||
- provider
|
||||
- url
|
||||
description: endpoint return only specific fields in the response on a per-type
|
||||
@@ -976,6 +976,7 @@ paths:
|
||||
- inserted_at
|
||||
- updated_at
|
||||
- name
|
||||
- secret_type
|
||||
- provider
|
||||
- url
|
||||
description: endpoint return only specific fields in the response on a per-type
|
||||
@@ -1290,6 +1291,7 @@ paths:
|
||||
type: string
|
||||
enum:
|
||||
- findings
|
||||
- provider
|
||||
description: include query parameter to allow the client to customize which
|
||||
related resources should be returned.
|
||||
explode: false
|
||||
@@ -1386,6 +1388,7 @@ paths:
|
||||
type: string
|
||||
enum:
|
||||
- findings
|
||||
- provider
|
||||
description: include query parameter to allow the client to customize which
|
||||
related resources should be returned.
|
||||
explode: false
|
||||
@@ -2609,7 +2612,7 @@ components:
|
||||
properties:
|
||||
uid:
|
||||
type: string
|
||||
maxLength: 150
|
||||
maxLength: 300
|
||||
delta:
|
||||
enum:
|
||||
- new
|
||||
@@ -2698,25 +2701,30 @@ components:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- Resource
|
||||
title: Resource Type Name
|
||||
description: The [type](https://jsonapi.org/format/#document-resource-object-identification)
|
||||
member is used to describe resource objects that share common
|
||||
attributes and relationships.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
title: Resource Identifier
|
||||
description: The identifier of the related object.
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- Resource
|
||||
title: Resource Type Name
|
||||
description: The [type](https://jsonapi.org/format/#document-resource-object-identification)
|
||||
member is used to describe resource objects that share common
|
||||
attributes and relationships.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
required:
|
||||
- data
|
||||
description: The identifier of the related object.
|
||||
title: Resource Identifier
|
||||
description: A related resource object from type Resource
|
||||
title: Resource
|
||||
readOnly: true
|
||||
required:
|
||||
- scan
|
||||
@@ -2730,7 +2738,7 @@ components:
|
||||
FindingTypeEnum:
|
||||
type: string
|
||||
enum:
|
||||
- Findings
|
||||
- Finding
|
||||
Membership:
|
||||
type: object
|
||||
required:
|
||||
@@ -2941,7 +2949,118 @@ components:
|
||||
nullable: true
|
||||
maxLength: 100
|
||||
minLength: 3
|
||||
secret_type:
|
||||
enum:
|
||||
- static
|
||||
- role
|
||||
type: string
|
||||
description: |-
|
||||
* `static` - Key-value pairs
|
||||
* `role` - Role assumption
|
||||
readOnly: true
|
||||
secret:
|
||||
oneOf:
|
||||
- type: object
|
||||
title: AWS Static Credentials
|
||||
properties:
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Required for environments
|
||||
where no IAM role is being assumed and direct AWS access
|
||||
is needed.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Must accompany 'aws_access_key_id'
|
||||
to authorize access to AWS resources.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token associated with temporary credentials.
|
||||
Only needed for session-based or temporary AWS access.
|
||||
required:
|
||||
- aws_access_key_id
|
||||
- aws_secret_access_key
|
||||
- type: object
|
||||
title: AWS Assume Role
|
||||
properties:
|
||||
role_arn:
|
||||
type: string
|
||||
description: The Amazon Resource Name (ARN) of the role to
|
||||
assume. Required for AWS role assumption.
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Only required if the environment
|
||||
lacks pre-configured AWS credentials.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Required if 'aws_access_key_id'
|
||||
is provided or if no AWS credentials are pre-configured.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token for temporary credentials,
|
||||
if applicable.
|
||||
session_duration:
|
||||
type: integer
|
||||
minimum: 900
|
||||
maximum: 43200
|
||||
default: 3600
|
||||
description: The duration (in seconds) for the role session.
|
||||
external_id:
|
||||
type: string
|
||||
description: An optional identifier to enhance security for
|
||||
role assumption; may be required by the role administrator.
|
||||
role_session_name:
|
||||
type: string
|
||||
description: An identifier for the role session, useful for
|
||||
tracking sessions in AWS logs.
|
||||
required:
|
||||
- role_arn
|
||||
- type: object
|
||||
title: Azure Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The Azure application (client) ID for authentication
|
||||
in Azure AD.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the application
|
||||
(client) ID, providing secure access.
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory
|
||||
where the application is registered.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- tenant_id
|
||||
- type: object
|
||||
title: GCP Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The client ID from Google Cloud, used to identify
|
||||
the application for GCP access.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the GCP client
|
||||
ID, required for secure access.
|
||||
refresh_token:
|
||||
type: string
|
||||
description: A refresh token that allows the application to
|
||||
obtain new access tokens for extended use.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- refresh_token
|
||||
- type: object
|
||||
title: Kubernetes Static Credentials
|
||||
properties:
|
||||
kubeconfig_content:
|
||||
type: string
|
||||
description: The content of the Kubernetes kubeconfig file,
|
||||
encoded as a string.
|
||||
required:
|
||||
- kubeconfig_content
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
@@ -3132,6 +3251,7 @@ components:
|
||||
type: string
|
||||
format: email
|
||||
minLength: 1
|
||||
description: Case insensitive
|
||||
maxLength: 254
|
||||
company_name:
|
||||
type: string
|
||||
@@ -3364,6 +3484,16 @@ components:
|
||||
nullable: true
|
||||
maxLength: 100
|
||||
minLength: 3
|
||||
secret_type:
|
||||
enum:
|
||||
- static
|
||||
- role
|
||||
type: string
|
||||
description: |-
|
||||
* `static` - Key-value pairs
|
||||
* `role` - Role assumption
|
||||
required:
|
||||
- secret_type
|
||||
relationships:
|
||||
type: object
|
||||
properties:
|
||||
@@ -3424,49 +3554,113 @@ components:
|
||||
secret_type:
|
||||
enum:
|
||||
- static
|
||||
- role
|
||||
type: string
|
||||
description: '* `static` - Key-value pairs'
|
||||
description: |-
|
||||
* `static` - Key-value pairs
|
||||
* `role` - Role assumption
|
||||
secret:
|
||||
oneOf:
|
||||
- type: object
|
||||
title: AWS static credentials
|
||||
title: AWS Static Credentials
|
||||
properties:
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Required for environments
|
||||
where no IAM role is being assumed and direct AWS access is
|
||||
needed.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Must accompany 'aws_access_key_id'
|
||||
to authorize access to AWS resources.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token associated with temporary credentials.
|
||||
Only needed for session-based or temporary AWS access.
|
||||
required:
|
||||
- aws_access_key_id
|
||||
- aws_secret_access_key
|
||||
- type: object
|
||||
title: Azure static credentials
|
||||
title: AWS Assume Role
|
||||
properties:
|
||||
role_arn:
|
||||
type: string
|
||||
description: The Amazon Resource Name (ARN) of the role to assume.
|
||||
Required for AWS role assumption.
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Only required if the environment
|
||||
lacks pre-configured AWS credentials.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Required if 'aws_access_key_id'
|
||||
is provided or if no AWS credentials are pre-configured.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token for temporary credentials, if applicable.
|
||||
session_duration:
|
||||
type: integer
|
||||
minimum: 900
|
||||
maximum: 43200
|
||||
default: 3600
|
||||
description: The duration (in seconds) for the role session.
|
||||
external_id:
|
||||
type: string
|
||||
description: An optional identifier to enhance security for role
|
||||
assumption; may be required by the role administrator.
|
||||
role_session_name:
|
||||
type: string
|
||||
description: An identifier for the role session, useful for tracking
|
||||
sessions in AWS logs.
|
||||
required:
|
||||
- role_arn
|
||||
- type: object
|
||||
title: Azure Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The Azure application (client) ID for authentication
|
||||
in Azure AD.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the application
|
||||
(client) ID, providing secure access.
|
||||
tenant_id:
|
||||
type: string
|
||||
description: Azure tenant ID
|
||||
description: The Azure tenant ID, representing the directory where
|
||||
the application is registered.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- tenant_id
|
||||
- type: object
|
||||
title: GCP static credentials
|
||||
title: GCP Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The client ID from Google Cloud, used to identify
|
||||
the application for GCP access.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the GCP client
|
||||
ID, required for secure access.
|
||||
refresh_token:
|
||||
type: string
|
||||
description: A refresh token that allows the application to obtain
|
||||
new access tokens for extended use.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- refresh_token
|
||||
- type: object
|
||||
title: Kubernetes Static Credentials
|
||||
properties:
|
||||
kubeconfig_content:
|
||||
type: string
|
||||
description: The content of the Kubernetes kubeconfig file, encoded
|
||||
as a string.
|
||||
required:
|
||||
- kubeconfig_content
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -3535,49 +3729,114 @@ components:
|
||||
secret_type:
|
||||
enum:
|
||||
- static
|
||||
- role
|
||||
type: string
|
||||
description: '* `static` - Key-value pairs'
|
||||
description: |-
|
||||
* `static` - Key-value pairs
|
||||
* `role` - Role assumption
|
||||
secret:
|
||||
oneOf:
|
||||
- type: object
|
||||
title: AWS static credentials
|
||||
title: AWS Static Credentials
|
||||
properties:
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Required for environments
|
||||
where no IAM role is being assumed and direct AWS access
|
||||
is needed.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Must accompany 'aws_access_key_id'
|
||||
to authorize access to AWS resources.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token associated with temporary credentials.
|
||||
Only needed for session-based or temporary AWS access.
|
||||
required:
|
||||
- aws_access_key_id
|
||||
- aws_secret_access_key
|
||||
- type: object
|
||||
title: Azure static credentials
|
||||
title: AWS Assume Role
|
||||
properties:
|
||||
role_arn:
|
||||
type: string
|
||||
description: The Amazon Resource Name (ARN) of the role to
|
||||
assume. Required for AWS role assumption.
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Only required if the environment
|
||||
lacks pre-configured AWS credentials.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Required if 'aws_access_key_id'
|
||||
is provided or if no AWS credentials are pre-configured.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token for temporary credentials,
|
||||
if applicable.
|
||||
session_duration:
|
||||
type: integer
|
||||
minimum: 900
|
||||
maximum: 43200
|
||||
default: 3600
|
||||
description: The duration (in seconds) for the role session.
|
||||
external_id:
|
||||
type: string
|
||||
description: An optional identifier to enhance security for
|
||||
role assumption; may be required by the role administrator.
|
||||
role_session_name:
|
||||
type: string
|
||||
description: An identifier for the role session, useful for
|
||||
tracking sessions in AWS logs.
|
||||
required:
|
||||
- role_arn
|
||||
- type: object
|
||||
title: Azure Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The Azure application (client) ID for authentication
|
||||
in Azure AD.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the application
|
||||
(client) ID, providing secure access.
|
||||
tenant_id:
|
||||
type: string
|
||||
description: Azure tenant ID
|
||||
description: The Azure tenant ID, representing the directory
|
||||
where the application is registered.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- tenant_id
|
||||
- type: object
|
||||
title: GCP static credentials
|
||||
title: GCP Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The client ID from Google Cloud, used to identify
|
||||
the application for GCP access.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the GCP client
|
||||
ID, required for secure access.
|
||||
refresh_token:
|
||||
type: string
|
||||
description: A refresh token that allows the application to
|
||||
obtain new access tokens for extended use.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- refresh_token
|
||||
- type: object
|
||||
title: Kubernetes Static Credentials
|
||||
properties:
|
||||
kubeconfig_content:
|
||||
type: string
|
||||
description: The content of the Kubernetes kubeconfig file,
|
||||
encoded as a string.
|
||||
required:
|
||||
- kubeconfig_content
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -3657,7 +3916,117 @@ components:
|
||||
nullable: true
|
||||
maxLength: 100
|
||||
minLength: 3
|
||||
secret_type:
|
||||
enum:
|
||||
- static
|
||||
- role
|
||||
type: string
|
||||
description: |-
|
||||
* `static` - Key-value pairs
|
||||
* `role` - Role assumption
|
||||
readOnly: true
|
||||
secret:
|
||||
oneOf:
|
||||
- type: object
|
||||
title: AWS Static Credentials
|
||||
properties:
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Required for environments
|
||||
where no IAM role is being assumed and direct AWS access is
|
||||
needed.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Must accompany 'aws_access_key_id'
|
||||
to authorize access to AWS resources.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token associated with temporary credentials.
|
||||
Only needed for session-based or temporary AWS access.
|
||||
required:
|
||||
- aws_access_key_id
|
||||
- aws_secret_access_key
|
||||
- type: object
|
||||
title: AWS Assume Role
|
||||
properties:
|
||||
role_arn:
|
||||
type: string
|
||||
description: The Amazon Resource Name (ARN) of the role to assume.
|
||||
Required for AWS role assumption.
|
||||
aws_access_key_id:
|
||||
type: string
|
||||
description: The AWS access key ID. Only required if the environment
|
||||
lacks pre-configured AWS credentials.
|
||||
aws_secret_access_key:
|
||||
type: string
|
||||
description: The AWS secret access key. Required if 'aws_access_key_id'
|
||||
is provided or if no AWS credentials are pre-configured.
|
||||
aws_session_token:
|
||||
type: string
|
||||
description: The session token for temporary credentials, if applicable.
|
||||
session_duration:
|
||||
type: integer
|
||||
minimum: 900
|
||||
maximum: 43200
|
||||
default: 3600
|
||||
description: The duration (in seconds) for the role session.
|
||||
external_id:
|
||||
type: string
|
||||
description: An optional identifier to enhance security for role
|
||||
assumption; may be required by the role administrator.
|
||||
role_session_name:
|
||||
type: string
|
||||
description: An identifier for the role session, useful for tracking
|
||||
sessions in AWS logs.
|
||||
required:
|
||||
- role_arn
|
||||
- type: object
|
||||
title: Azure Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The Azure application (client) ID for authentication
|
||||
in Azure AD.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the application
|
||||
(client) ID, providing secure access.
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory where
|
||||
the application is registered.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- tenant_id
|
||||
- type: object
|
||||
title: GCP Static Credentials
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
description: The client ID from Google Cloud, used to identify
|
||||
the application for GCP access.
|
||||
client_secret:
|
||||
type: string
|
||||
description: The client secret associated with the GCP client
|
||||
ID, required for secure access.
|
||||
refresh_token:
|
||||
type: string
|
||||
description: A refresh token that allows the application to obtain
|
||||
new access tokens for extended use.
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- refresh_token
|
||||
- type: object
|
||||
title: Kubernetes Static Credentials
|
||||
properties:
|
||||
kubeconfig_content:
|
||||
type: string
|
||||
description: The content of the Kubernetes kubeconfig file, encoded
|
||||
as a string.
|
||||
required:
|
||||
- kubeconfig_content
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
@@ -3781,25 +4150,30 @@ components:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- Finding
|
||||
title: Resource Type Name
|
||||
description: The [type](https://jsonapi.org/format/#document-resource-object-identification)
|
||||
member is used to describe resource objects that share common
|
||||
attributes and relationships.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
title: Resource Identifier
|
||||
description: The identifier of the related object.
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- Finding
|
||||
title: Resource Type Name
|
||||
description: The [type](https://jsonapi.org/format/#document-resource-object-identification)
|
||||
member is used to describe resource objects that share common
|
||||
attributes and relationships.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
required:
|
||||
- data
|
||||
description: The identifier of the related object.
|
||||
title: Resource Identifier
|
||||
description: A related resource object from type Finding
|
||||
title: Finding
|
||||
readOnly: true
|
||||
required:
|
||||
- provider
|
||||
@@ -4424,6 +4798,7 @@ components:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
description: Case insensitive
|
||||
maxLength: 254
|
||||
company_name:
|
||||
type: string
|
||||
@@ -4492,6 +4867,7 @@ components:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
description: Case insensitive
|
||||
maxLength: 254
|
||||
company_name:
|
||||
type: string
|
||||
@@ -4530,6 +4906,7 @@ components:
|
||||
type: string
|
||||
format: email
|
||||
minLength: 1
|
||||
description: Case insensitive
|
||||
maxLength: 254
|
||||
company_name:
|
||||
type: string
|
||||
@@ -4583,6 +4960,7 @@ components:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
description: Case insensitive
|
||||
maxLength: 254
|
||||
company_name:
|
||||
type: string
|
||||
@@ -4602,3 +4980,24 @@ components:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
tags:
|
||||
- name: User
|
||||
description: Endpoints for managing user accounts.
|
||||
- name: Token
|
||||
description: Endpoints for token management, including obtaining a new token and
|
||||
refreshing an existing token for authentication purposes.
|
||||
- name: Tenant
|
||||
description: Endpoints for managing tenants, along with their memberships.
|
||||
- name: Provider
|
||||
description: Endpoints for managing providers (AWS, GCP, Azure, etc...).
|
||||
- name: Scan
|
||||
description: Endpoints for triggering manual scans and viewing scan results.
|
||||
- name: Resource
|
||||
description: Endpoints for managing resources discovered by scans, allowing retrieval
|
||||
and filtering of resource information.
|
||||
- name: Finding
|
||||
description: Endpoints for managing findings, allowing retrieval and filtering of
|
||||
findings that result from scans.
|
||||
- name: Task
|
||||
description: Endpoints for task management, allowing retrieval of task status and
|
||||
revoking tasks that have not started.
|
||||
|
||||
@@ -12,6 +12,7 @@ from api.utils import (
|
||||
return_prowler_provider,
|
||||
initialize_prowler_provider,
|
||||
prowler_provider_connection_test,
|
||||
get_prowler_provider_kwargs,
|
||||
)
|
||||
|
||||
|
||||
@@ -136,3 +137,75 @@ class TestProwlerProviderConnectionTest:
|
||||
mock_return_prowler_provider.return_value.test_connection.assert_called_once_with(
|
||||
key="value", provider_id="1234567890", raise_on_exception=False
|
||||
)
|
||||
|
||||
|
||||
class TestGetProwlerProviderKwargs:
|
||||
@pytest.mark.parametrize(
|
||||
"provider_type, expected_extra_kwargs",
|
||||
[
|
||||
(
|
||||
Provider.ProviderChoices.AWS.value,
|
||||
{},
|
||||
),
|
||||
(
|
||||
Provider.ProviderChoices.AZURE.value,
|
||||
{"subscription_ids": ["provider_uid"]},
|
||||
),
|
||||
(
|
||||
Provider.ProviderChoices.GCP.value,
|
||||
{"project_ids": ["provider_uid"]},
|
||||
),
|
||||
(
|
||||
Provider.ProviderChoices.KUBERNETES.value,
|
||||
{"context": "provider_uid"},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs):
|
||||
provider_uid = "provider_uid"
|
||||
secret_dict = {"key": "value"}
|
||||
secret_mock = MagicMock()
|
||||
secret_mock.secret = secret_dict
|
||||
|
||||
provider = MagicMock()
|
||||
provider.provider = provider_type
|
||||
provider.secret = secret_mock
|
||||
provider.uid = provider_uid
|
||||
|
||||
result = get_prowler_provider_kwargs(provider)
|
||||
|
||||
expected_result = {**secret_dict, **expected_extra_kwargs}
|
||||
assert result == expected_result
|
||||
|
||||
def test_get_prowler_provider_kwargs_unsupported_provider(self):
|
||||
# Setup
|
||||
provider_uid = "provider_uid"
|
||||
secret_dict = {"key": "value"}
|
||||
secret_mock = MagicMock()
|
||||
secret_mock.secret = secret_dict
|
||||
|
||||
provider = MagicMock()
|
||||
provider.provider = "UNSUPPORTED_PROVIDER"
|
||||
provider.secret = secret_mock
|
||||
provider.uid = provider_uid
|
||||
|
||||
result = get_prowler_provider_kwargs(provider)
|
||||
|
||||
expected_result = secret_dict.copy()
|
||||
assert result == expected_result
|
||||
|
||||
def test_get_prowler_provider_kwargs_no_secret(self):
|
||||
# Setup
|
||||
provider_uid = "provider_uid"
|
||||
secret_mock = MagicMock()
|
||||
secret_mock.secret = {}
|
||||
|
||||
provider = MagicMock()
|
||||
provider.provider = Provider.ProviderChoices.AWS.value
|
||||
provider.secret = secret_mock
|
||||
provider.uid = provider_uid
|
||||
|
||||
result = get_prowler_provider_kwargs(provider)
|
||||
|
||||
expected_result = {}
|
||||
assert result == expected_result
|
||||
|
||||
@@ -1139,21 +1139,82 @@ class TestProviderSecretViewSet:
|
||||
)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"provider_type, secret_type, secret_data",
|
||||
[
|
||||
# AWS with STATIC secret
|
||||
(
|
||||
Provider.ProviderChoices.AWS.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"aws_access_key_id": "value",
|
||||
"aws_secret_access_key": "value",
|
||||
"aws_session_token": "value",
|
||||
},
|
||||
),
|
||||
# AWS with ROLE secret
|
||||
(
|
||||
Provider.ProviderChoices.AWS.value,
|
||||
ProviderSecret.TypeChoices.ROLE,
|
||||
{
|
||||
"role_arn": "arn:aws:iam::123456789012:role/example-role",
|
||||
# Optional fields
|
||||
"external_id": "external-id",
|
||||
"role_session_name": "session-name",
|
||||
"session_duration": 3600,
|
||||
"aws_access_key_id": "value",
|
||||
"aws_secret_access_key": "value",
|
||||
"aws_session_token": "value",
|
||||
},
|
||||
),
|
||||
# Azure with STATIC secret
|
||||
(
|
||||
Provider.ProviderChoices.AZURE.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"client_id": "client-id",
|
||||
"client_secret": "client-secret",
|
||||
"tenant_id": "tenant-id",
|
||||
},
|
||||
),
|
||||
# GCP with STATIC secret
|
||||
(
|
||||
Provider.ProviderChoices.GCP.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"client_id": "client-id",
|
||||
"client_secret": "client-secret",
|
||||
"refresh_token": "refresh-token",
|
||||
},
|
||||
),
|
||||
# Kubernetes with STATIC secret
|
||||
(
|
||||
Provider.ProviderChoices.KUBERNETES.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"kubeconfig_content": "kubeconfig-content",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_provider_secrets_create_valid(
|
||||
self, authenticated_client, providers_fixture
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
provider_type,
|
||||
secret_type,
|
||||
secret_data,
|
||||
):
|
||||
provider, *_ = providers_fixture
|
||||
# Get the provider from the fixture and set its type
|
||||
provider = Provider.objects.filter(provider=provider_type)[0]
|
||||
|
||||
data = {
|
||||
"data": {
|
||||
"type": "ProviderSecret",
|
||||
"attributes": {
|
||||
"name": "My Secret",
|
||||
"secret_type": "static",
|
||||
"secret": {
|
||||
"aws_access_key_id": "value",
|
||||
"aws_secret_access_key": "value",
|
||||
"aws_session_token": "value",
|
||||
},
|
||||
"secret_type": secret_type,
|
||||
"secret": secret_data,
|
||||
},
|
||||
"relationships": {
|
||||
"provider": {"data": {"type": "Provider", "id": str(provider.id)}}
|
||||
@@ -1167,13 +1228,11 @@ class TestProviderSecretViewSet:
|
||||
)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert ProviderSecret.objects.count() == 1
|
||||
assert ProviderSecret.objects.get().name == data["data"]["attributes"]["name"]
|
||||
provider_secret = ProviderSecret.objects.first()
|
||||
assert provider_secret.name == data["data"]["attributes"]["name"]
|
||||
assert provider_secret.secret_type == data["data"]["attributes"]["secret_type"]
|
||||
assert (
|
||||
ProviderSecret.objects.get().secret_type
|
||||
== data["data"]["attributes"]["secret_type"]
|
||||
)
|
||||
assert (
|
||||
str(ProviderSecret.objects.get().provider.id)
|
||||
str(provider_secret.provider.id)
|
||||
== data["data"]["relationships"]["provider"]["data"]["id"]
|
||||
)
|
||||
|
||||
|
||||
@@ -62,6 +62,31 @@ def return_prowler_provider(
|
||||
return prowler_provider
|
||||
|
||||
|
||||
def get_prowler_provider_kwargs(provider: Provider) -> dict:
|
||||
"""Get the Prowler provider kwargs based on the given provider type.
|
||||
|
||||
Args:
|
||||
provider (Provider): The provider object containing the provider type and associated secret.
|
||||
|
||||
Returns:
|
||||
dict: The provider kwargs for the corresponding provider class.
|
||||
"""
|
||||
prowler_provider_kwargs = provider.secret.secret
|
||||
if provider.provider == Provider.ProviderChoices.AZURE.value:
|
||||
prowler_provider_kwargs = {
|
||||
**prowler_provider_kwargs,
|
||||
"subscription_ids": [provider.uid],
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.GCP.value:
|
||||
prowler_provider_kwargs = {
|
||||
**prowler_provider_kwargs,
|
||||
"project_ids": [provider.uid],
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.KUBERNETES.value:
|
||||
prowler_provider_kwargs = {**prowler_provider_kwargs, "context": provider.uid}
|
||||
return prowler_provider_kwargs
|
||||
|
||||
|
||||
def initialize_prowler_provider(
|
||||
provider: Provider,
|
||||
) -> AwsProvider | AzureProvider | GcpProvider | KubernetesProvider:
|
||||
@@ -76,7 +101,7 @@ def initialize_prowler_provider(
|
||||
provider's secrets.
|
||||
"""
|
||||
prowler_provider = return_prowler_provider(provider)
|
||||
prowler_provider_kwargs = provider.secret.secret
|
||||
prowler_provider_kwargs = get_prowler_provider_kwargs(provider)
|
||||
return prowler_provider(**prowler_provider_kwargs)
|
||||
|
||||
|
||||
@@ -90,7 +115,7 @@ def prowler_provider_connection_test(provider: Provider) -> Connection:
|
||||
Connection: A connection object representing the result of the connection test for the specified provider.
|
||||
"""
|
||||
prowler_provider = return_prowler_provider(provider)
|
||||
prowler_provider_kwargs = provider.secret.secret
|
||||
prowler_provider_kwargs = get_prowler_provider_kwargs(provider)
|
||||
return prowler_provider.test_connection(
|
||||
**prowler_provider_kwargs, provider_id=provider.uid, raise_on_exception=False
|
||||
)
|
||||
|
||||
@@ -611,16 +611,27 @@ class FindingSerializer(RLSSerializer):
|
||||
# Provider secrets
|
||||
class BaseWriteProviderSecretSerializer(BaseWriteSerializer):
|
||||
@staticmethod
|
||||
def validate_secret_based_on_provider(provider_type: str, secret: dict):
|
||||
if provider_type == Provider.ProviderChoices.AWS.value:
|
||||
serializer = AwsProviderSecret(data=secret)
|
||||
elif provider_type == Provider.ProviderChoices.AZURE.value:
|
||||
serializer = AzureProviderSecret(data=secret)
|
||||
elif provider_type == Provider.ProviderChoices.GCP.value:
|
||||
serializer = GCPProviderSecret(data=secret)
|
||||
def validate_secret_based_on_provider(
|
||||
provider_type: str, secret_type: ProviderSecret.TypeChoices, secret: dict
|
||||
):
|
||||
if secret_type == ProviderSecret.TypeChoices.STATIC:
|
||||
if provider_type == Provider.ProviderChoices.AWS.value:
|
||||
serializer = AwsProviderSecret(data=secret)
|
||||
elif provider_type == Provider.ProviderChoices.AZURE.value:
|
||||
serializer = AzureProviderSecret(data=secret)
|
||||
elif provider_type == Provider.ProviderChoices.GCP.value:
|
||||
serializer = GCPProviderSecret(data=secret)
|
||||
elif provider_type == Provider.ProviderChoices.KUBERNETES.value:
|
||||
serializer = KubernetesProviderSecret(data=secret)
|
||||
else:
|
||||
raise serializers.ValidationError(
|
||||
{"provider": f"Provider type not supported {provider_type}"}
|
||||
)
|
||||
elif secret_type == ProviderSecret.TypeChoices.ROLE:
|
||||
serializer = AWSRoleAssumptionProviderSecret(data=secret)
|
||||
else:
|
||||
raise serializers.ValidationError(
|
||||
{"provider": f"Provider type not supported {provider_type}"}
|
||||
{"secret_type": f"Secret type not supported: {secret_type}"}
|
||||
)
|
||||
try:
|
||||
serializer.is_valid(raise_exception=True)
|
||||
@@ -660,46 +671,148 @@ class GCPProviderSecret(serializers.Serializer):
|
||||
resource_name = "ProviderSecret"
|
||||
|
||||
|
||||
class KubernetesProviderSecret(serializers.Serializer):
|
||||
kubeconfig_content = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
resource_name = "ProviderSecret"
|
||||
|
||||
|
||||
class AWSRoleAssumptionProviderSecret(serializers.Serializer):
|
||||
role_arn = serializers.CharField()
|
||||
external_id = serializers.CharField(required=False)
|
||||
role_session_name = serializers.CharField(required=False)
|
||||
session_duration = serializers.IntegerField(
|
||||
required=False, min_value=900, max_value=43200
|
||||
)
|
||||
aws_access_key_id = serializers.CharField(required=False)
|
||||
aws_secret_access_key = serializers.CharField(required=False)
|
||||
aws_session_token = serializers.CharField(required=False)
|
||||
|
||||
class Meta:
|
||||
resource_name = "ProviderSecret"
|
||||
|
||||
|
||||
@extend_schema_field(
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"title": "AWS static credentials",
|
||||
"title": "AWS Static Credentials",
|
||||
"properties": {
|
||||
"aws_access_key_id": {"type": "string"},
|
||||
"aws_secret_access_key": {"type": "string"},
|
||||
"aws_session_token": {"type": "string"},
|
||||
"aws_access_key_id": {
|
||||
"type": "string",
|
||||
"description": "The AWS access key ID. Required for environments where no IAM role is being "
|
||||
"assumed and direct AWS access is needed.",
|
||||
},
|
||||
"aws_secret_access_key": {
|
||||
"type": "string",
|
||||
"description": "The AWS secret access key. Must accompany 'aws_access_key_id' to authorize "
|
||||
"access to AWS resources.",
|
||||
},
|
||||
"aws_session_token": {
|
||||
"type": "string",
|
||||
"description": "The session token associated with temporary credentials. Only needed for "
|
||||
"session-based or temporary AWS access.",
|
||||
},
|
||||
},
|
||||
"required": ["aws_access_key_id", "aws_secret_access_key"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "Azure static credentials",
|
||||
"title": "AWS Assume Role",
|
||||
"properties": {
|
||||
"client_id": {"type": "string"},
|
||||
"client_secret": {"type": "string"},
|
||||
"tenant_id": {"type": "string", "description": "Azure tenant ID"},
|
||||
"role_arn": {
|
||||
"type": "string",
|
||||
"description": "The Amazon Resource Name (ARN) of the role to assume. Required for AWS role "
|
||||
"assumption.",
|
||||
},
|
||||
"aws_access_key_id": {
|
||||
"type": "string",
|
||||
"description": "The AWS access key ID. Only required if the environment lacks pre-configured "
|
||||
"AWS credentials.",
|
||||
},
|
||||
"aws_secret_access_key": {
|
||||
"type": "string",
|
||||
"description": "The AWS secret access key. Required if 'aws_access_key_id' is provided or if "
|
||||
"no AWS credentials are pre-configured.",
|
||||
},
|
||||
"aws_session_token": {
|
||||
"type": "string",
|
||||
"description": "The session token for temporary credentials, if applicable.",
|
||||
},
|
||||
"session_duration": {
|
||||
"type": "integer",
|
||||
"minimum": 900,
|
||||
"maximum": 43200,
|
||||
"default": 3600,
|
||||
"description": "The duration (in seconds) for the role session.",
|
||||
},
|
||||
"external_id": {
|
||||
"type": "string",
|
||||
"description": "An optional identifier to enhance security for role assumption; may be "
|
||||
"required by the role administrator.",
|
||||
},
|
||||
"role_session_name": {
|
||||
"type": "string",
|
||||
"description": "An identifier for the role session, useful for tracking sessions in AWS logs.",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"tenant_id",
|
||||
],
|
||||
"required": ["role_arn"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "GCP static credentials",
|
||||
"title": "Azure Static Credentials",
|
||||
"properties": {
|
||||
"client_id": {"type": "string"},
|
||||
"client_secret": {"type": "string"},
|
||||
"refresh_token": {"type": "string"},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "The Azure application (client) ID for authentication in Azure AD.",
|
||||
},
|
||||
"client_secret": {
|
||||
"type": "string",
|
||||
"description": "The client secret associated with the application (client) ID, providing "
|
||||
"secure access.",
|
||||
},
|
||||
"tenant_id": {
|
||||
"type": "string",
|
||||
"description": "The Azure tenant ID, representing the directory where the application is "
|
||||
"registered.",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"refresh_token",
|
||||
],
|
||||
"required": ["client_id", "client_secret", "tenant_id"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "GCP Static Credentials",
|
||||
"properties": {
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "The client ID from Google Cloud, used to identify the application for GCP "
|
||||
"access.",
|
||||
},
|
||||
"client_secret": {
|
||||
"type": "string",
|
||||
"description": "The client secret associated with the GCP client ID, required for secure "
|
||||
"access.",
|
||||
},
|
||||
"refresh_token": {
|
||||
"type": "string",
|
||||
"description": "A refresh token that allows the application to obtain new access tokens for "
|
||||
"extended use.",
|
||||
},
|
||||
},
|
||||
"required": ["client_id", "client_secret", "refresh_token"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "Kubernetes Static Credentials",
|
||||
"properties": {
|
||||
"kubeconfig_content": {
|
||||
"type": "string",
|
||||
"description": "The content of the Kubernetes kubeconfig file, encoded as a string.",
|
||||
}
|
||||
},
|
||||
"required": ["kubeconfig_content"],
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -746,15 +859,16 @@ class ProviderSecretCreateSerializer(RLSSerializer, BaseWriteProviderSecretSeria
|
||||
|
||||
def validate(self, attrs):
|
||||
provider = attrs.get("provider")
|
||||
secret_type = attrs.get("secret_type")
|
||||
secret = attrs.get("secret")
|
||||
|
||||
validated_attrs = super().validate(attrs)
|
||||
self.validate_secret_based_on_provider(provider.provider, secret)
|
||||
self.validate_secret_based_on_provider(provider.provider, secret_type, secret)
|
||||
return validated_attrs
|
||||
|
||||
|
||||
class ProviderSecretUpdateSerializer(BaseWriteProviderSecretSerializer):
|
||||
secret = serializers.JSONField(write_only=True)
|
||||
secret = ProviderSecretField(write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ProviderSecret
|
||||
@@ -775,8 +889,9 @@ class ProviderSecretUpdateSerializer(BaseWriteProviderSecretSerializer):
|
||||
|
||||
def validate(self, attrs):
|
||||
provider = self.instance.provider
|
||||
secret_type = self.instance.secret_type
|
||||
secret = attrs.get("secret")
|
||||
|
||||
validated_attrs = super().validate(attrs)
|
||||
self.validate_secret_based_on_provider(provider.provider, secret)
|
||||
self.validate_secret_based_on_provider(provider.provider, secret_type, secret)
|
||||
return validated_attrs
|
||||
|
||||
@@ -139,6 +139,41 @@ class SchemaView(SpectacularAPIView):
|
||||
spectacular_settings.DESCRIPTION = (
|
||||
"Prowler API specification.\n\nThis file is auto-generated."
|
||||
)
|
||||
spectacular_settings.TAGS = [
|
||||
{"name": "User", "description": "Endpoints for managing user accounts."},
|
||||
{
|
||||
"name": "Token",
|
||||
"description": "Endpoints for token management, including obtaining a new token and "
|
||||
"refreshing an existing token for authentication purposes.",
|
||||
},
|
||||
{
|
||||
"name": "Tenant",
|
||||
"description": "Endpoints for managing tenants, along with their memberships.",
|
||||
},
|
||||
{
|
||||
"name": "Provider",
|
||||
"description": "Endpoints for managing providers (AWS, GCP, Azure, etc...).",
|
||||
},
|
||||
{
|
||||
"name": "Scan",
|
||||
"description": "Endpoints for triggering manual scans and viewing scan results.",
|
||||
},
|
||||
{
|
||||
"name": "Resource",
|
||||
"description": "Endpoints for managing resources discovered by scans, allowing "
|
||||
"retrieval and filtering of resource information.",
|
||||
},
|
||||
{
|
||||
"name": "Finding",
|
||||
"description": "Endpoints for managing findings, allowing retrieval and filtering of "
|
||||
"findings that result from scans.",
|
||||
},
|
||||
{
|
||||
"name": "Task",
|
||||
"description": "Endpoints for task management, allowing retrieval of task status and "
|
||||
"revoking tasks that have not started.",
|
||||
},
|
||||
]
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user