feat(stackit): add new provider with 4 checks#9237
Merged
HugoPBrito merged 85 commits intoMay 28, 2026
Merged
Conversation
…ion check This commit adds comprehensive support for the StackIT cloud provider, a German cloud service focusing on data sovereignty and GDPR compliance. Changes include: - Complete provider infrastructure (provider class, models, exceptions, arguments) - StackIT mutelist implementation for filtering findings - Object Storage service integration using stackit-objectstorage SDK - First security check: objectstorage_bucket_encryption - Validates that all Object Storage buckets have encryption at rest enabled - Aligns with StackIT's GDPR compliance and data sovereignty focus - Provider registration in common provider initialization - CheckReportStackIT model for StackIT-specific findings - Configuration files (config.yaml section and mutelist example) - Added stackit-objectstorage SDK dependency to pyproject.toml The implementation follows Prowler's provider patterns and includes: - Authentication via API token and project ID (env vars supported) - Comprehensive error handling with custom exception classes - Detailed check metadata with remediation guidance - Support for data protection and encryption compliance requirements Authentication: - --stackit-api-token (or STACKIT_API_TOKEN env var) - --stackit-project-id (or STACKIT_PROJECT_ID env var) Usage example: prowler stackit --stackit-api-token <token> --stackit-project-id <project-id>
The StackIT provider requires a compliance directory to function properly. This adds the minimal compliance directory structure with an __init__.py file. Fixes: FileNotFoundError when running prowler stackit
Adds the StackIT provider to the output_options initialization chain. This was missing and caused an UnboundLocalError when running prowler with the stackit provider. Changes: - Import StackITOutputOptions from stackit.models - Add elif block to initialize output_options for stackit provider Fixes: UnboundLocalError: cannot access local variable 'output_options'
Adds the StackIT provider to the entity_type configuration in the summary table. This was missing and caused an UnboundLocalError when displaying scan results. Changes: - Add elif block for stackit provider type - Set entity_type to 'Project ID' - Set audited_entities to provider.identity.project_id Fixes: UnboundLocalError: cannot access local variable 'entity_type'
Adds the StackIT provider to the finding output generation. This ensures findings from StackIT checks are properly formatted and displayed. Changes: - Add elif block for stackit provider type in finding data generation - Set auth_method to 'api_token' - Set account_uid to project_id - Set account_name to project_name (with default empty string) - Set resource_name, resource_uid, and region from check output - Set project_id field in ASFF finding generation Ensures StackIT findings are properly generated and exported.
Resolves dependency conflict between stackit-core (requires urllib3>=2.2.3) and botocore (requires urllib3<1.27) by using boto3 with S3-compatible endpoints instead of the native StackIT SDK. StackIT Object Storage is S3-compatible, so we can use the standard boto3 S3 client with custom endpoints. This approach: - Eliminates dependency conflicts - Uses proven, stable boto3 library (already a Prowler dependency) - Provides better error handling and logging - Works with StackIT's S3-compatible Object Storage API Changes: - Rewrote objectstorage_service.py to use boto3 instead of stackit SDK - Uses S3 endpoint: https://object.storage.eu01.onstackit.cloud - Implements bucket listing, encryption checking, and location detection via S3 API - Updated test_connection to validate credentials via S3 list_buckets call - Removed stackit-objectstorage dependency from pyproject.toml - Added comprehensive error handling for connection and authentication errors Fixes: poetry lock dependency resolution error Enables: Resource discovery and encryption checking to work properly
StackIT Object Storage requires separate S3-compatible credentials
(access key and secret key) that are different from the service account
API token. These credentials must be generated in the STACKIT Portal.
Changes:
- Add CLI arguments: --stackit-objectstorage-access-key and --stackit-objectstorage-secret-key
- Add environment variable support: STACKIT_OBJECTSTORAGE_ACCESS_KEY and STACKIT_OBJECTSTORAGE_SECRET_KEY
- Update provider to accept and validate Object Storage credentials
- Update session to store Object Storage credentials
- Update Object Storage service to use proper S3 credentials
- Add warning when Object Storage credentials are not provided
- Update print_credentials to show Object Storage credential status
How to generate credentials:
1. Go to STACKIT Portal
2. Navigate to Object Storage > Credentials
3. Generate new access key and secret key
4. Provide them via CLI args or environment variables
Usage:
prowler stackit \
--stackit-project-id <project-id> \
--stackit-api-token <api-token> \
--stackit-objectstorage-access-key <access-key> \
--stackit-objectstorage-secret-key <secret-key>
Fixes: No resources found - credentials issue
…token authentication - Bumped minimum Python version from 3.9 to 3.10 in pyproject.toml - Added stackit-core>=0.2.0 and stackit-objectstorage>=0.1.0 dependencies - Updated classifiers to list Python 3.10, 3.11, 3.12 support - Removed S3 credential arguments (--stackit-objectstorage-access-key/secret-key) - Updated objectstorage_service.py to use StackIT SDK instead of boto3 S3 API - Simplified stackit_provider.py to only require API token and project ID - Updated test_connection() to use StackIT SDK for validation - Removed Object Storage credential warnings and display This change resolves the urllib3 dependency conflict between botocore (<1.27) and stackit-core (>=2.2.3) by requiring Python 3.10+, which supports urllib3 2.x in botocore. The provider now uses API token authentication exclusively via the StackIT SDK instead of S3-compatible credentials.
…torageClient The stackit-objectstorage package exports DefaultApi and ApiClient classes, not ObjectStorageClient. Updated imports in: - objectstorage_service.py: Use DefaultApi(ApiClient(config)) - stackit_provider.py: Update test_connection to use correct imports This fixes the ImportError: "cannot import name 'ObjectStorageClient'"
Changed from: from stackit import core config = core.Configuration(...) To: from stackit.core.configuration import Configuration config = Configuration(...) This fixes the AttributeError: module 'stackit.core' has no attribute 'Configuration'
Configuration class only accepts service_account_token, not project_id. The project_id parameter should be passed to API method calls instead. Changed from: config = Configuration(project_id=..., service_account_token=...) To: config = Configuration(service_account_token=...) client.list_buckets(project_id=...) This fixes: Configuration.__init__() got an unexpected keyword argument 'project_id'
Current issue: 'ApiClient' object has no attribute 'custom_endpoint' The plan includes: - Research proper endpoint configuration for StackIT Object Storage API - Fix Configuration to include custom_endpoint parameter - Test with actual StackIT credentials - Handle any additional API method signature issues Next step: Determine the correct endpoint URL and add it to Configuration initialization.
… API Added custom_endpoint parameter to Configuration initialization to properly configure the StackIT Object Storage management API endpoint. Endpoint: https://objectstorage.api.eu01.stackit.cloud This fixes the error: 'ApiClient' object has no attribute 'custom_endpoint' The endpoint follows STACKIT's API pattern: https://{service}.api.{region}.stackit.cloud Updated files: - objectstorage_service.py: Added custom_endpoint to Configuration - stackit_provider.py: Added custom_endpoint to test_connection()
The SDK example shows that DefaultApi constructor accepts Configuration directly, not an ApiClient wrapper. This was causing the error: 'ApiClient' object has no attribute 'custom_endpoint' Changed from: config = Configuration(service_account_token=...) api_client = ApiClient(config) client = DefaultApi(api_client) To: config = Configuration(service_account_token=...) client = DefaultApi(config) Also removed custom_endpoint parameter as the SDK uses default endpoints. References SDK example: config = Configuration() client = DefaultApi(config) client.list_buckets(project_id)
The list_buckets() method requires a region parameter. STACKIT currently supports two regions: - eu01 (Germany South) - eu02 (Austria West) Hardcoded to "eu01" for now as the default region. Future enhancement could add a --stackit-region argument to support multiple regions. This fixes the validation error: Missing required argument: region Updated files: - objectstorage_service.py: Added region="eu01" to list_buckets call - stackit_provider.py: Added region="eu01" to test_connection
…for SDK authentication The STACKIT SDK expects the STACKIT_SERVICE_ACCOUNT_TOKEN environment variable to be set for authentication. Previously, we were passing service_account_token as a parameter, but the SDK's default authentication flow reads from the environment variable instead. Changes: - Set STACKIT_SERVICE_ACCOUNT_TOKEN env var before creating Configuration() - Use Configuration() with no parameters (reads from env var automatically) - Properly restore original env var value after use to avoid side effects Authentication flow: 1. User provides --stackit-api-token or sets STACKIT_API_TOKEN env var 2. Provider stores it in self._api_token 3. Before SDK calls, temporarily set STACKIT_SERVICE_ACCOUNT_TOKEN 4. SDK reads STACKIT_SERVICE_ACCOUNT_TOKEN for authentication 5. Restore original env var value This matches the SDK's documented authentication behavior: "The SDK will always try to use the key flow first and search for credentials in several locations... Environment variable, e.g. STACKIT_SERVICE_ACCOUNT_TOKEN" References: - https://github.com/stackitcloud/stackit-sdk-python - SDK documentation on authentication flows
…_attribute call Fixed two issues preventing successful output generation: 1. Added StackIT case to stdout_report() in outputs.py - The 'details' variable was not being set for stackit provider - Added: if finding.check_metadata.Provider == "stackit": details = finding.location - This fixes: UnboundLocalError: cannot access local variable 'details' 2. Removed invalid 'default' parameter from get_nested_attribute() call - finding.py:314 was calling get_nested_attribute(..., default="") - The function doesn't accept a default parameter (returns "" by default) - This fixes: TypeError: get_nested_attribute() got an unexpected keyword argument 'default' Files modified: - prowler/lib/outputs/outputs.py: Added StackIT provider case for details - prowler/lib/outputs/finding.py: Removed default="" parameter With these fixes, the check should now complete successfully and generate output.
…roup checks Replaced the objectstorage service (encryption check wasn't useful since encryption is enabled by default) with IaaS service for critical security group checks. Added 4 security group checks: 1. iaas_security_group_ssh_unrestricted - SSH (port 22) from 0.0.0.0/0 2. iaas_security_group_rdp_unrestricted - RDP (port 3389) from 0.0.0.0/0 3. iaas_security_group_database_unrestricted - Database ports from 0.0.0.0/0 - MySQL (3306), PostgreSQL (5432), MongoDB (27017) - Redis (6379), SQL Server (1433), CouchDB (5984) 4. iaas_security_group_all_traffic_unrestricted - All ports/protocols from 0.0.0.0/0 All checks are marked as CRITICAL severity and focus on ingress TCP rules that allow unrestricted access from the public internet (0.0.0.0/0 or ::/0). Implementation details: - Added stackit-iaas>=0.1.0 dependency to pyproject.toml - Created IaaSService class with security group and rule discovery - Security group rules include helper methods: is_unrestricted(), is_ingress(), is_tcp(), includes_port() - Each check follows Prowler's architecture with metadata.json - Checks flag if port range includes any sensitive port from internet Removed files: - prowler/providers/stackit/services/objectstorage/ Added files: - prowler/providers/stackit/services/iaas/ - 4 security group check directories with implementations and metadata
The IaaS API methods (list_security_groups and list_security_group_rules) don't accept a region parameter like the objectstorage API did. Removed region parameter from: - list_security_groups(project_id) - list_security_group_rules(project_id, security_group_id) This fixes the validation error: Unexpected keyword argument: region
Some security group rules return None for protocol and ip_range fields. Updated the SecurityGroupRule model to make these fields optional and added None checks in helper methods. Changes: - Added Optional[str] for protocol and ip_range fields - Updated is_unrestricted() to check if ip_range is not None - Updated is_ingress() to check if direction is not None - Updated is_tcp() to check if protocol is not None This fixes the pydantic validation error: none is not an allowed value for protocol/ip_range
…nt key process Updated the authentication section to reflect the official STACKIT documentation: Key Changes: - Added comparison table between Key Flow (recommended) and Token Flow (deprecated) - Documented that Token Flow will be removed on December 17, 2025 - Added detailed step-by-step instructions for creating service account keys via Portal - Added CLI method for creating service account keys - Included RSA 2048 key-pair generation instructions - Added service account key file authentication examples - Documented credential lookup order - Added credentials file format example Authentication Methods: - Key Flow (Recommended): RSA key-pair based, short-lived tokens, more secure - Token Flow (Deprecated): Long-lived tokens, scheduled for removal Reference: https://docs.stackit.cloud/stackit/en/usage-of-the-service-account-keys-in-stackit-175112464.html
…generation - Remove comparison table between Key Flow and Token Flow - Remove deprecated Token Flow authentication method - Add step-by-step instructions for generating access tokens via StackIT CLI - Clarify that Prowler requires access tokens (not service account key files directly) - Update credential lookup order to reflect actual implementation - Add note about short-lived access tokens requiring regeneration
…oudly Other providers (AWS, Azure, GCP, OCI, ...) import their SDK at module level, so a missing dependency raises ModuleNotFoundError when the provider module is imported and Provider.init_global_provider reports it as a critical error with a non-zero exit. The StackIT provider imported stackit.* lazily inside methods and the IaaS check modules, so a missing SDK was only hit at check-load time, where the check loader swallows it per-check and the scan misleadingly printed 'There are no findings'. Move the imports (Configuration, iaas DefaultApi as IaasDefaultApi, resourcemanager DefaultApi as ResourceManagerDefaultApi) to module level and drop the lazy in-method imports and the now-dead ImportError handling. Tests patch the module-level names instead of sys.modules.
StackIT reserved exception codes 10000-10999, but that range is already used by the AlibabaCloud (10000-10007) and OpenStack (10000-10011) providers. Overlapping ranges break the one-provider-per-range convention and make codes ambiguous. Move StackIT to 16000-16999, the next free range after Scaleway (15000-15999).
The HTML summary printed a single 'StackIT Project' line that showed the project name OR the id, so the project id was hidden whenever a name was available. Align with the other providers (e.g. OpenStack): always show the Project ID, add the Project Name as a separate line when known, and list the audited Regions. Also fix the stale 'Authentication Type: API Token' label to 'Service Account Key'. Covered with HTML tests.
Remove the single quotes wrapping the security group name (and the rule identifier in get_rule_display_name) in the check status_extended messages, e.g. "Security group hugo-sg allows unrestricted SSH access" instead of "Security group 'hugo-sg' ...". Update the affected check tests.
The SDK code-quality CI failed at the repo-wide `black --check .` step because tests/lib/outputs/outputs_test.py was left unformatted on the branch. Reformat it with black 25.1.0 (the pinned version) so the check passes. Behaviour unchanged; the test still passes.
7 tasks
- Replace the URL in Remediation.Code.Other with step-by-step remediation instructions (the docs URL is already in AdditionalURLs / Recommendation.Url) - Add markdown emphasis to Description, Risk and Recommendation.Text - Empty SubServiceName to match the rest of the providers - Move AdditionalURLs below RelatedUrl to follow the canonical field order
…entry - Empty the iaas service __init__.py to match the other providers (no re-export) - Remove the StackIT entry from the released 5.27.0 section; the provider PR has not shipped yet, so it stays only under the 5.29.0 UNRELEASED section
HugoPBrito
previously approved these changes
May 28, 2026
jfagoagas
previously approved these changes
May 28, 2026
Member
jfagoagas
left a comment
There was a problem hiding this comment.
🏅 Thank you @johannes-engler-mw for this great contribution 👏
- Add a gated StackIT test block to sdk-tests.yml following the same pattern as the other providers: a changed-files check on prowler/**/stackit/** and tests/**/stackit/**, and a test/coverage step that runs only when those paths change - Add the equivalent block for Scaleway, which was missing the same gating
81ae8b7
danibarranqueroo
approved these changes
May 28, 2026
cesararroba
approved these changes
May 28, 2026
Member
|
Thank you very much for your contribution @johannes-engler-mw! 🚀 |
jfagoagas
approved these changes
May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add StackIT Cloud Provider Support
Summary
This PR adds complete support for StackIT Cloud as a new provider in Prowler, enabling security assessments of StackIT infrastructure. The implementation focuses on critical network security checks for IaaS resources.
What's New
Provider Implementation
Multi-Region Support
eu01,eu02)--stackit-regionto specify target regionsStackITIdentityInfoupdated to track audited regionsSecurity Checks (4 IaaS Checks)
UX & Usability Improvements
Check Features:
Authentication
stackit auth activate-service-account --service-account-key-path <key> --only-print-access-tokenDocumentation
docs/developer-guide/stackit-details.mdxTechnical Details
Dependencies
stackit-core==0.2.0- Core SDK for authenticationstackit-iaas==1.1.0- IaaS service managementstackit-objectstorage==1.2.1- For future object storage checks and connection testTesting
Code Quality
Usage Examples
Basic Scan
Scan Specific Regions
Specific Checks
Breaking Changes
Future Enhancements
Testing Checklist